summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.eslintrc.yml21
-rw-r--r--.gitlab-ci.yml21
-rw-r--r--.rubocop.yml21
-rw-r--r--.rubocop_todo.yml14
-rw-r--r--CHANGELOG.md259
-rw-r--r--CONTRIBUTING.md12
-rw-r--r--GITALY_SERVER_VERSION2
-rw-r--r--GITLAB_WORKHORSE_VERSION2
-rw-r--r--Gemfile8
-rw-r--r--Gemfile.lock16
-rw-r--r--Gemfile.rails5.lock18
-rw-r--r--PROCESS.md55
-rw-r--r--VERSION2
-rw-r--r--app/assets/images/cluster_app_logos/elasticsearch.pngbin0 -> 796 bytes
-rw-r--r--app/assets/images/cluster_app_logos/gitlab.pngbin0 -> 1757 bytes
-rw-r--r--app/assets/images/cluster_app_logos/helm.pngbin0 -> 1438 bytes
-rw-r--r--app/assets/images/cluster_app_logos/jeager.pngbin0 -> 2619 bytes
-rw-r--r--app/assets/images/cluster_app_logos/jupyterhub.pngbin0 -> 895 bytes
-rw-r--r--app/assets/images/cluster_app_logos/kubernetes.pngbin0 -> 1437 bytes
-rw-r--r--app/assets/images/cluster_app_logos/meltano.pngbin0 -> 580 bytes
-rw-r--r--app/assets/images/cluster_app_logos/prometheus.pngbin0 -> 923 bytes
-rw-r--r--app/assets/javascripts/badges/components/badge.vue2
-rw-r--r--app/assets/javascripts/behaviors/index.js6
-rw-r--r--app/assets/javascripts/behaviors/markdown/gfm_auto_complete.js19
-rw-r--r--app/assets/javascripts/behaviors/markdown/render_gfm.js2
-rw-r--r--app/assets/javascripts/behaviors/preview_markdown.js (renamed from app/assets/javascripts/preview_markdown.js)0
-rw-r--r--app/assets/javascripts/behaviors/shortcuts.js35
-rw-r--r--app/assets/javascripts/behaviors/shortcuts/shortcuts.js (renamed from app/assets/javascripts/shortcuts.js)6
-rw-r--r--app/assets/javascripts/behaviors/shortcuts/shortcuts_blob.js (renamed from app/assets/javascripts/shortcuts_blob.js)2
-rw-r--r--app/assets/javascripts/behaviors/shortcuts/shortcuts_find_file.js (renamed from app/assets/javascripts/shortcuts_find_file.js)0
-rw-r--r--app/assets/javascripts/behaviors/shortcuts/shortcuts_issuable.js (renamed from app/assets/javascripts/shortcuts_issuable.js)4
-rw-r--r--app/assets/javascripts/behaviors/shortcuts/shortcuts_navigation.js (renamed from app/assets/javascripts/shortcuts_navigation.js)2
-rw-r--r--app/assets/javascripts/behaviors/shortcuts/shortcuts_network.js (renamed from app/assets/javascripts/shortcuts_network.js)0
-rw-r--r--app/assets/javascripts/behaviors/shortcuts/shortcuts_wiki.js (renamed from app/assets/javascripts/shortcuts_wiki.js)2
-rw-r--r--app/assets/javascripts/blob/3d_viewer/index.js4
-rw-r--r--app/assets/javascripts/boards/components/board_blank_state.vue2
-rw-r--r--app/assets/javascripts/boards/components/board_list.vue4
-rw-r--r--app/assets/javascripts/boards/components/board_new_issue.vue2
-rw-r--r--app/assets/javascripts/boards/components/issue_card_inner.vue9
-rw-r--r--app/assets/javascripts/boards/components/modal/lists_dropdown.vue8
-rw-r--r--app/assets/javascripts/boards/index.js6
-rw-r--r--app/assets/javascripts/build_variables.js10
-rw-r--r--app/assets/javascripts/clusters/components/application_row.vue137
-rw-r--r--app/assets/javascripts/clusters/components/applications.vue439
-rw-r--r--app/assets/javascripts/commons/gitlab_ui.js25
-rw-r--r--app/assets/javascripts/commons/polyfills.js2
-rw-r--r--app/assets/javascripts/commons/polyfills/element.js23
-rw-r--r--app/assets/javascripts/commons/polyfills/svg.js5
-rw-r--r--app/assets/javascripts/deploy_keys/components/key.vue10
-rw-r--r--app/assets/javascripts/diffs/components/app.vue7
-rw-r--r--app/assets/javascripts/diffs/components/commit_item.vue119
-rw-r--r--app/assets/javascripts/diffs/components/commit_widget.vue40
-rw-r--r--app/assets/javascripts/diffs/components/diff_file_header.vue4
-rw-r--r--app/assets/javascripts/diffs/components/diff_gutter_avatars.vue2
-rw-r--r--app/assets/javascripts/diffs/components/diff_line_note_form.vue50
-rw-r--r--app/assets/javascripts/diffs/components/inline_diff_table_row.vue6
-rw-r--r--app/assets/javascripts/diffs/components/inline_diff_view.vue4
-rw-r--r--app/assets/javascripts/diffs/components/no_changes.vue2
-rw-r--r--app/assets/javascripts/diffs/components/parallel_diff_comment_row.vue4
-rw-r--r--app/assets/javascripts/diffs/components/parallel_diff_table_row.vue5
-rw-r--r--app/assets/javascripts/diffs/components/parallel_diff_view.vue2
-rw-r--r--app/assets/javascripts/diffs/constants.js1
-rw-r--r--app/assets/javascripts/diffs/store/actions.js40
-rw-r--r--app/assets/javascripts/diffs/store/mutations.js8
-rw-r--r--app/assets/javascripts/diffs/store/utils.js32
-rw-r--r--app/assets/javascripts/dispatcher.js89
-rw-r--r--app/assets/javascripts/dropzone_input.js2
-rw-r--r--app/assets/javascripts/environments/components/empty_state.vue2
-rw-r--r--app/assets/javascripts/environments/components/environments_app.vue2
-rw-r--r--app/assets/javascripts/environments/components/environments_table.vue4
-rw-r--r--app/assets/javascripts/feature_highlight/feature_highlight.js2
-rw-r--r--app/assets/javascripts/filtered_search/admin_runners_filtered_search_token_keys.js9
-rw-r--r--app/assets/javascripts/filtered_search/components/recent_searches_dropdown_content.vue4
-rw-r--r--app/assets/javascripts/filtered_search/dropdown_hint.js2
-rw-r--r--app/assets/javascripts/filtered_search/filtered_search_dropdown_manager.js5
-rw-r--r--app/assets/javascripts/filtered_search/issuable_filtered_search_token_keys.js12
-rw-r--r--app/assets/javascripts/frequent_items/components/frequent_items_list_item.vue2
-rw-r--r--app/assets/javascripts/gl_form.js2
-rw-r--r--app/assets/javascripts/groups/components/item_actions.vue4
-rw-r--r--app/assets/javascripts/ide/components/branches/search_list.vue2
-rw-r--r--app/assets/javascripts/ide/components/commit_sidebar/editor_header.vue1
-rw-r--r--app/assets/javascripts/ide/components/commit_sidebar/list.vue4
-rw-r--r--app/assets/javascripts/ide/components/commit_sidebar/list_item.vue4
-rw-r--r--app/assets/javascripts/ide/components/file_finder/index.vue2
-rw-r--r--app/assets/javascripts/ide/components/file_finder/item.vue12
-rw-r--r--app/assets/javascripts/ide/components/file_row_extra.vue104
-rw-r--r--app/assets/javascripts/ide/components/ide.vue12
-rw-r--r--app/assets/javascripts/ide/components/ide_side_bar.vue6
-rw-r--r--app/assets/javascripts/ide/components/ide_status_bar.vue6
-rw-r--r--app/assets/javascripts/ide/components/ide_tree_list.vue18
-rw-r--r--app/assets/javascripts/ide/components/jobs/stage.vue2
-rw-r--r--app/assets/javascripts/ide/components/panes/right.vue139
-rw-r--r--app/assets/javascripts/ide/components/repo_editor.vue6
-rw-r--r--app/assets/javascripts/ide/components/repo_file.vue227
-rw-r--r--app/assets/javascripts/ide/components/repo_file_status_icon.vue2
-rw-r--r--app/assets/javascripts/ide/components/repo_loading_file.vue42
-rw-r--r--app/assets/javascripts/ide/constants.js8
-rw-r--r--app/assets/javascripts/ide/index.js38
-rw-r--r--app/assets/javascripts/ide/stores/actions.js4
-rw-r--r--app/assets/javascripts/ide/stores/index.js2
-rw-r--r--app/assets/javascripts/ide/stores/modules/file_templates/actions.js15
-rw-r--r--app/assets/javascripts/ide/stores/modules/file_templates/mutations.js2
-rw-r--r--app/assets/javascripts/ide/stores/modules/pane/actions.js30
-rw-r--r--app/assets/javascripts/ide/stores/modules/pane/getters.js4
-rw-r--r--app/assets/javascripts/ide/stores/modules/pane/index.js12
-rw-r--r--app/assets/javascripts/ide/stores/modules/pane/mutation_types.js3
-rw-r--r--app/assets/javascripts/ide/stores/modules/pane/mutations.js19
-rw-r--r--app/assets/javascripts/ide/stores/modules/pane/state.js5
-rw-r--r--app/assets/javascripts/ide/stores/modules/pipelines/actions.js2
-rw-r--r--app/assets/javascripts/ide/stores/mutation_types.js2
-rw-r--r--app/assets/javascripts/ide/stores/mutations.js5
-rw-r--r--app/assets/javascripts/ide/stores/state.js1
-rw-r--r--app/assets/javascripts/issuable_bulk_update_actions.js8
-rw-r--r--app/assets/javascripts/issuable_bulk_update_sidebar.js6
-rw-r--r--app/assets/javascripts/issue_show/components/app.vue1
-rw-r--r--app/assets/javascripts/issue_show/components/edit_actions.vue17
-rw-r--r--app/assets/javascripts/issue_show/components/form.vue5
-rw-r--r--app/assets/javascripts/issue_show/components/title.vue2
-rw-r--r--app/assets/javascripts/job.js4
-rw-r--r--app/assets/javascripts/jobs/components/artifacts_block.vue68
-rw-r--r--app/assets/javascripts/jobs/components/commit_block.vue72
-rw-r--r--app/assets/javascripts/jobs/components/empty_state.vue4
-rw-r--r--app/assets/javascripts/jobs/components/erased_block.vue49
-rw-r--r--app/assets/javascripts/jobs/components/header.vue2
-rw-r--r--app/assets/javascripts/jobs/components/job_log.vue4
-rw-r--r--app/assets/javascripts/jobs/components/job_log_controllers.vue76
-rw-r--r--app/assets/javascripts/jobs/components/jobs_container.vue2
-rw-r--r--app/assets/javascripts/jobs/components/sidebar_details_block.vue197
-rw-r--r--app/assets/javascripts/jobs/components/stuck_block.vue6
-rw-r--r--app/assets/javascripts/jobs/components/trigger_block.vue28
-rw-r--r--app/assets/javascripts/jobs/job_details_bundle.js45
-rw-r--r--app/assets/javascripts/jobs/job_details_mediator.js67
-rw-r--r--app/assets/javascripts/jobs/services/job_service.js11
-rw-r--r--app/assets/javascripts/jobs/store/mutations.js3
-rw-r--r--app/assets/javascripts/jobs/stores/job_store.js11
-rw-r--r--app/assets/javascripts/labels_select.js4
-rw-r--r--app/assets/javascripts/lib/utils/common_utils.js67
-rw-r--r--app/assets/javascripts/lib/utils/logoutput_behaviours.js17
-rw-r--r--app/assets/javascripts/lib/utils/navigation_utility.js (renamed from app/assets/javascripts/shortcuts_dashboard_navigation.js)2
-rw-r--r--app/assets/javascripts/lib/utils/scroll_utils.js24
-rw-r--r--app/assets/javascripts/main.js14
-rw-r--r--app/assets/javascripts/merge_request_tabs.js3
-rw-r--r--app/assets/javascripts/monitoring/components/dashboard.vue39
-rw-r--r--app/assets/javascripts/monitoring/components/graph.vue13
-rw-r--r--app/assets/javascripts/monitoring/components/graph/legend.vue4
-rw-r--r--app/assets/javascripts/notebook/index.vue4
-rw-r--r--app/assets/javascripts/notes.js12
-rw-r--r--app/assets/javascripts/notes/components/comment_form.vue2
-rw-r--r--app/assets/javascripts/notes/components/diff_file_header.vue2
-rw-r--r--app/assets/javascripts/notes/components/diff_with_note.vue6
-rw-r--r--app/assets/javascripts/notes/components/note_awards_list.vue2
-rw-r--r--app/assets/javascripts/notes/components/note_form.vue4
-rw-r--r--app/assets/javascripts/notes/components/noteable_discussion.vue4
-rw-r--r--app/assets/javascripts/notes/components/notes_app.vue4
-rw-r--r--app/assets/javascripts/notes/stores/actions.js39
-rw-r--r--app/assets/javascripts/notes/stores/mutations.js8
-rw-r--r--app/assets/javascripts/notes/stores/utils.js2
-rw-r--r--app/assets/javascripts/pages/admin/application_settings/index.js5
-rw-r--r--app/assets/javascripts/pages/admin/application_settings/metrics_and_profiling/index.js8
-rw-r--r--app/assets/javascripts/pages/admin/users/components/delete_user_modal.vue5
-rw-r--r--app/assets/javascripts/pages/groups/boards/index.js2
-rw-r--r--app/assets/javascripts/pages/groups/show/index.js2
-rw-r--r--app/assets/javascripts/pages/ide/index.js10
-rw-r--r--app/assets/javascripts/pages/projects/activity/index.js2
-rw-r--r--app/assets/javascripts/pages/projects/artifacts/browse/index.js2
-rw-r--r--app/assets/javascripts/pages/projects/artifacts/file/index.js2
-rw-r--r--app/assets/javascripts/pages/projects/boards/index.js2
-rw-r--r--app/assets/javascripts/pages/projects/commit/show/index.js2
-rw-r--r--app/assets/javascripts/pages/projects/commits/show/index.js2
-rw-r--r--app/assets/javascripts/pages/projects/find_file/show/index.js2
-rw-r--r--app/assets/javascripts/pages/projects/index.js2
-rw-r--r--app/assets/javascripts/pages/projects/init_blob.js4
-rw-r--r--app/assets/javascripts/pages/projects/issues/form.js2
-rw-r--r--app/assets/javascripts/pages/projects/issues/index/index.js2
-rw-r--r--app/assets/javascripts/pages/projects/issues/show.js2
-rw-r--r--app/assets/javascripts/pages/projects/merge_requests/index/index.js2
-rw-r--r--app/assets/javascripts/pages/projects/merge_requests/init_merge_request.js2
-rw-r--r--app/assets/javascripts/pages/projects/merge_requests/init_merge_request_show.js2
-rw-r--r--app/assets/javascripts/pages/projects/network/show/index.js2
-rw-r--r--app/assets/javascripts/pages/projects/pipeline_schedules/shared/components/interval_pattern_input.vue2
-rw-r--r--app/assets/javascripts/pages/projects/shared/permissions/components/settings_panel.vue12
-rw-r--r--app/assets/javascripts/pages/projects/show/index.js2
-rw-r--r--app/assets/javascripts/pages/projects/tree/show/index.js2
-rw-r--r--app/assets/javascripts/pages/projects/wikis/index.js2
-rw-r--r--app/assets/javascripts/performance_bar/components/performance_bar_app.vue4
-rw-r--r--app/assets/javascripts/performance_bar/components/simple_metric.vue37
-rw-r--r--app/assets/javascripts/pipelines/components/graph/graph_component.vue2
-rw-r--r--app/assets/javascripts/pipelines/components/graph/job_component.vue4
-rw-r--r--app/assets/javascripts/pipelines/components/graph/stage_column_component.vue2
-rw-r--r--app/assets/javascripts/pipelines/components/nav_controls.vue2
-rw-r--r--app/assets/javascripts/pipelines/components/pipeline_url.vue8
-rw-r--r--app/assets/javascripts/pipelines/components/stage.vue2
-rw-r--r--app/assets/javascripts/registry/components/collapsible_container.vue2
-rw-r--r--app/assets/javascripts/registry/components/table_registry.vue2
-rw-r--r--app/assets/javascripts/reports/components/grouped_test_reports_app.vue4
-rw-r--r--app/assets/javascripts/reports/components/report_issues.vue4
-rw-r--r--app/assets/javascripts/search_autocomplete.js6
-rw-r--r--app/assets/javascripts/sidebar/components/time_tracking/time_tracker.vue4
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/deployment.vue2
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/mr_widget_header.vue60
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merged.vue8
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_squash_before_merge.js15
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/nothing_to_merge.vue2
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue8
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/squash_before_merge.vue (renamed from app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_squash_before_merge.vue)2
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/dependencies.js2
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/index.js5
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue6
-rw-r--r--app/assets/javascripts/vue_shared/components/bar_chart.vue2
-rw-r--r--app/assets/javascripts/vue_shared/components/content_viewer/viewers/markdown_viewer.vue6
-rw-r--r--app/assets/javascripts/vue_shared/components/diff_viewer/diff_viewer.vue2
-rw-r--r--app/assets/javascripts/vue_shared/components/file_row.vue210
-rw-r--r--app/assets/javascripts/vue_shared/components/header_ci_component.vue6
-rw-r--r--app/assets/javascripts/vue_shared/components/markdown/toolbar.vue17
-rw-r--r--app/assets/javascripts/vue_shared/components/notes/skeleton_note.vue24
-rw-r--r--app/assets/javascripts/vue_shared/components/skeleton_loading_container.vue37
-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.vue2
-rw-r--r--app/assets/javascripts/vue_shared/components/user_avatar/user_avatar_link.vue2
-rw-r--r--app/assets/stylesheets/application.scss2
-rw-r--r--app/assets/stylesheets/bootstrap_migration.scss1
-rw-r--r--app/assets/stylesheets/framework/buttons.scss8
-rw-r--r--app/assets/stylesheets/framework/common.scss10
-rw-r--r--app/assets/stylesheets/framework/filters.scss5
-rw-r--r--app/assets/stylesheets/framework/lists.scss1
-rw-r--r--app/assets/stylesheets/framework/responsive_tables.scss2
-rw-r--r--app/assets/stylesheets/framework/snippets.scss2
-rw-r--r--app/assets/stylesheets/framework/typography.scss2
-rw-r--r--app/assets/stylesheets/framework/variables.scss6
-rw-r--r--app/assets/stylesheets/page_bundles/ide.scss142
-rw-r--r--app/assets/stylesheets/page_bundles/xterm.scss (renamed from app/assets/stylesheets/pages/xterm.scss)2
-rw-r--r--app/assets/stylesheets/pages/boards.scss12
-rw-r--r--app/assets/stylesheets/pages/clusters.scss57
-rw-r--r--app/assets/stylesheets/pages/groups.scss4
-rw-r--r--app/assets/stylesheets/pages/issuable.scss8
-rw-r--r--app/assets/stylesheets/pages/members.scss2
-rw-r--r--app/assets/stylesheets/pages/merge_requests.scss2
-rw-r--r--app/assets/stylesheets/pages/note_form.scss2
-rw-r--r--app/assets/stylesheets/pages/profile.scss4
-rw-r--r--app/assets/stylesheets/pages/search.scss2
-rw-r--r--app/controllers/abuse_reports_controller.rb2
-rw-r--r--app/controllers/admin/abuse_reports_controller.rb2
-rw-r--r--app/controllers/admin/appearances_controller.rb2
-rw-r--r--app/controllers/admin/application_controller.rb2
-rw-r--r--app/controllers/admin/application_settings_controller.rb37
-rw-r--r--app/controllers/admin/applications_controller.rb2
-rw-r--r--app/controllers/admin/background_jobs_controller.rb2
-rw-r--r--app/controllers/admin/broadcast_messages_controller.rb2
-rw-r--r--app/controllers/admin/dashboard_controller.rb2
-rw-r--r--app/controllers/admin/deploy_keys_controller.rb2
-rw-r--r--app/controllers/admin/gitaly_servers_controller.rb2
-rw-r--r--app/controllers/admin/groups_controller.rb2
-rw-r--r--app/controllers/admin/health_check_controller.rb2
-rw-r--r--app/controllers/admin/hook_logs_controller.rb2
-rw-r--r--app/controllers/admin/hooks_controller.rb2
-rw-r--r--app/controllers/admin/identities_controller.rb2
-rw-r--r--app/controllers/admin/impersonation_tokens_controller.rb2
-rw-r--r--app/controllers/admin/impersonations_controller.rb2
-rw-r--r--app/controllers/admin/jobs_controller.rb2
-rw-r--r--app/controllers/admin/keys_controller.rb2
-rw-r--r--app/controllers/admin/labels_controller.rb2
-rw-r--r--app/controllers/admin/logs_controller.rb2
-rw-r--r--app/controllers/admin/projects_controller.rb2
-rw-r--r--app/controllers/admin/requests_profiles_controller.rb2
-rw-r--r--app/controllers/admin/runner_projects_controller.rb2
-rw-r--r--app/controllers/admin/runners_controller.rb2
-rw-r--r--app/controllers/admin/spam_logs_controller.rb2
-rw-r--r--app/controllers/admin/system_info_controller.rb2
-rw-r--r--app/controllers/admin/users_controller.rb2
-rw-r--r--app/controllers/application_controller.rb10
-rw-r--r--app/controllers/autocomplete_controller.rb2
-rw-r--r--app/controllers/boards/application_controller.rb2
-rw-r--r--app/controllers/boards/issues_controller.rb2
-rw-r--r--app/controllers/boards/lists_controller.rb2
-rw-r--r--app/controllers/ci/lints_controller.rb2
-rw-r--r--app/controllers/concerns/accepts_pending_invitations.rb2
-rw-r--r--app/controllers/concerns/authenticates_with_two_factor.rb2
-rw-r--r--app/controllers/concerns/boards_responses.rb2
-rw-r--r--app/controllers/concerns/checks_collaboration.rb2
-rw-r--r--app/controllers/concerns/continue_params.rb2
-rw-r--r--app/controllers/concerns/controller_with_cross_project_access_check.rb2
-rw-r--r--app/controllers/concerns/creates_commit.rb4
-rw-r--r--app/controllers/concerns/cycle_analytics_params.rb2
-rw-r--r--app/controllers/concerns/diff_for_path.rb2
-rw-r--r--app/controllers/concerns/enforces_two_factor_authentication.rb2
-rw-r--r--app/controllers/concerns/group_tree.rb2
-rw-r--r--app/controllers/concerns/hooks_execution.rb2
-rw-r--r--app/controllers/concerns/internal_redirect.rb8
-rw-r--r--app/controllers/concerns/invalid_utf8_error_handler.rb27
-rw-r--r--app/controllers/concerns/issuable_actions.rb2
-rw-r--r--app/controllers/concerns/issuable_collections.rb2
-rw-r--r--app/controllers/concerns/issues_action.rb2
-rw-r--r--app/controllers/concerns/issues_calendar.rb2
-rw-r--r--app/controllers/concerns/lfs_request.rb2
-rw-r--r--app/controllers/concerns/members_presentation.rb2
-rw-r--r--app/controllers/concerns/membership_actions.rb2
-rw-r--r--app/controllers/concerns/merge_requests_action.rb2
-rw-r--r--app/controllers/concerns/milestone_actions.rb2
-rw-r--r--app/controllers/concerns/notes_actions.rb50
-rw-r--r--app/controllers/concerns/oauth_applications.rb2
-rw-r--r--app/controllers/concerns/params_backward_compatibility.rb2
-rw-r--r--app/controllers/concerns/preview_markdown.rb2
-rw-r--r--app/controllers/concerns/renders_blob.rb2
-rw-r--r--app/controllers/concerns/renders_commits.rb2
-rw-r--r--app/controllers/concerns/renders_member_access.rb2
-rw-r--r--app/controllers/concerns/renders_notes.rb2
-rw-r--r--app/controllers/concerns/repository_settings_redirect.rb2
-rw-r--r--app/controllers/concerns/requires_whitelisted_monitoring_client.rb2
-rw-r--r--app/controllers/concerns/routable_actions.rb2
-rw-r--r--app/controllers/concerns/send_file_upload.rb2
-rw-r--r--app/controllers/concerns/service_params.rb2
-rw-r--r--app/controllers/concerns/snippets_actions.rb2
-rw-r--r--app/controllers/concerns/spammable_actions.rb2
-rw-r--r--app/controllers/concerns/todos_actions.rb2
-rw-r--r--app/controllers/concerns/toggle_award_emoji.rb2
-rw-r--r--app/controllers/concerns/toggle_subscription_action.rb2
-rw-r--r--app/controllers/concerns/uploads_actions.rb2
-rw-r--r--app/controllers/concerns/with_performance_bar.rb8
-rw-r--r--app/controllers/concerns/workhorse_request.rb2
-rw-r--r--app/controllers/confirmations_controller.rb4
-rw-r--r--app/controllers/dashboard/application_controller.rb2
-rw-r--r--app/controllers/dashboard/groups_controller.rb2
-rw-r--r--app/controllers/dashboard/labels_controller.rb2
-rw-r--r--app/controllers/dashboard/milestones_controller.rb2
-rw-r--r--app/controllers/dashboard/projects_controller.rb2
-rw-r--r--app/controllers/dashboard/snippets_controller.rb2
-rw-r--r--app/controllers/dashboard/todos_controller.rb2
-rw-r--r--app/controllers/dashboard_controller.rb4
-rw-r--r--app/controllers/explore/application_controller.rb2
-rw-r--r--app/controllers/explore/groups_controller.rb2
-rw-r--r--app/controllers/explore/projects_controller.rb2
-rw-r--r--app/controllers/explore/snippets_controller.rb2
-rw-r--r--app/controllers/google_api/authorizations_controller.rb2
-rw-r--r--app/controllers/graphql_controller.rb2
-rw-r--r--app/controllers/groups/application_controller.rb2
-rw-r--r--app/controllers/groups/avatars_controller.rb2
-rw-r--r--app/controllers/groups/boards_controller.rb2
-rw-r--r--app/controllers/groups/children_controller.rb2
-rw-r--r--app/controllers/groups/group_members_controller.rb2
-rw-r--r--app/controllers/groups/labels_controller.rb7
-rw-r--r--app/controllers/groups/milestones_controller.rb2
-rw-r--r--app/controllers/groups/runners_controller.rb2
-rw-r--r--app/controllers/groups/settings/ci_cd_controller.rb2
-rw-r--r--app/controllers/groups/shared_projects_controller.rb2
-rw-r--r--app/controllers/groups/uploads_controller.rb2
-rw-r--r--app/controllers/groups/variables_controller.rb2
-rw-r--r--app/controllers/groups_controller.rb2
-rw-r--r--app/controllers/health_check_controller.rb2
-rw-r--r--app/controllers/health_controller.rb2
-rw-r--r--app/controllers/help_controller.rb2
-rw-r--r--app/controllers/ide_controller.rb2
-rw-r--r--app/controllers/import/base_controller.rb2
-rw-r--r--app/controllers/import/bitbucket_controller.rb2
-rw-r--r--app/controllers/import/fogbugz_controller.rb2
-rw-r--r--app/controllers/import/gitea_controller.rb2
-rw-r--r--app/controllers/import/github_controller.rb2
-rw-r--r--app/controllers/import/gitlab_controller.rb2
-rw-r--r--app/controllers/import/gitlab_projects_controller.rb10
-rw-r--r--app/controllers/import/google_code_controller.rb2
-rw-r--r--app/controllers/import/manifest_controller.rb2
-rw-r--r--app/controllers/invites_controller.rb8
-rw-r--r--app/controllers/jwt_controller.rb2
-rw-r--r--app/controllers/koding_controller.rb2
-rw-r--r--app/controllers/ldap/omniauth_callbacks_controller.rb2
-rw-r--r--app/controllers/metrics_controller.rb2
-rw-r--r--app/controllers/notification_settings_controller.rb2
-rw-r--r--app/controllers/oauth/applications_controller.rb4
-rw-r--r--app/controllers/oauth/authorizations_controller.rb2
-rw-r--r--app/controllers/oauth/authorized_applications_controller.rb2
-rw-r--r--app/controllers/omniauth_callbacks_controller.rb9
-rw-r--r--app/controllers/passwords_controller.rb2
-rw-r--r--app/controllers/profiles/accounts_controller.rb2
-rw-r--r--app/controllers/profiles/active_sessions_controller.rb2
-rw-r--r--app/controllers/profiles/application_controller.rb2
-rw-r--r--app/controllers/profiles/avatars_controller.rb2
-rw-r--r--app/controllers/profiles/chat_names_controller.rb2
-rw-r--r--app/controllers/profiles/emails_controller.rb2
-rw-r--r--app/controllers/profiles/gpg_keys_controller.rb2
-rw-r--r--app/controllers/profiles/keys_controller.rb2
-rw-r--r--app/controllers/profiles/notifications_controller.rb2
-rw-r--r--app/controllers/profiles/passwords_controller.rb2
-rw-r--r--app/controllers/profiles/personal_access_tokens_controller.rb2
-rw-r--r--app/controllers/profiles/preferences_controller.rb2
-rw-r--r--app/controllers/profiles/two_factor_auths_controller.rb4
-rw-r--r--app/controllers/profiles/u2f_registrations_controller.rb2
-rw-r--r--app/controllers/profiles_controller.rb2
-rw-r--r--app/controllers/projects/application_controller.rb2
-rw-r--r--app/controllers/projects/artifacts_controller.rb2
-rw-r--r--app/controllers/projects/autocomplete_sources_controller.rb2
-rw-r--r--app/controllers/projects/avatars_controller.rb2
-rw-r--r--app/controllers/projects/badges_controller.rb2
-rw-r--r--app/controllers/projects/blame_controller.rb2
-rw-r--r--app/controllers/projects/blob_controller.rb2
-rw-r--r--app/controllers/projects/boards_controller.rb2
-rw-r--r--app/controllers/projects/branches_controller.rb2
-rw-r--r--app/controllers/projects/build_artifacts_controller.rb2
-rw-r--r--app/controllers/projects/builds_controller.rb2
-rw-r--r--app/controllers/projects/ci/lints_controller.rb2
-rw-r--r--app/controllers/projects/clusters/applications_controller.rb2
-rw-r--r--app/controllers/projects/clusters_controller.rb5
-rw-r--r--app/controllers/projects/commit_controller.rb2
-rw-r--r--app/controllers/projects/commits_controller.rb2
-rw-r--r--app/controllers/projects/compare_controller.rb2
-rw-r--r--app/controllers/projects/cycle_analytics/events_controller.rb2
-rw-r--r--app/controllers/projects/cycle_analytics_controller.rb2
-rw-r--r--app/controllers/projects/deploy_keys_controller.rb2
-rw-r--r--app/controllers/projects/deploy_tokens_controller.rb2
-rw-r--r--app/controllers/projects/deployments_controller.rb2
-rw-r--r--app/controllers/projects/discussions_controller.rb2
-rw-r--r--app/controllers/projects/environments_controller.rb2
-rw-r--r--app/controllers/projects/find_file_controller.rb2
-rw-r--r--app/controllers/projects/forks_controller.rb2
-rw-r--r--app/controllers/projects/git_http_client_controller.rb2
-rw-r--r--app/controllers/projects/git_http_controller.rb2
-rw-r--r--app/controllers/projects/graphs_controller.rb2
-rw-r--r--app/controllers/projects/group_links_controller.rb2
-rw-r--r--app/controllers/projects/hook_logs_controller.rb2
-rw-r--r--app/controllers/projects/hooks_controller.rb2
-rw-r--r--app/controllers/projects/imports_controller.rb2
-rw-r--r--app/controllers/projects/issues_controller.rb2
-rw-r--r--app/controllers/projects/jobs_controller.rb2
-rw-r--r--app/controllers/projects/labels_controller.rb9
-rw-r--r--app/controllers/projects/lfs_api_controller.rb2
-rw-r--r--app/controllers/projects/lfs_locks_api_controller.rb2
-rw-r--r--app/controllers/projects/lfs_storage_controller.rb2
-rw-r--r--app/controllers/projects/mattermosts_controller.rb2
-rw-r--r--app/controllers/projects/merge_requests/application_controller.rb2
-rw-r--r--app/controllers/projects/merge_requests/conflicts_controller.rb2
-rw-r--r--app/controllers/projects/merge_requests/creations_controller.rb2
-rw-r--r--app/controllers/projects/merge_requests/diffs_controller.rb4
-rw-r--r--app/controllers/projects/merge_requests_controller.rb2
-rw-r--r--app/controllers/projects/milestones_controller.rb9
-rw-r--r--app/controllers/projects/mirrors_controller.rb2
-rw-r--r--app/controllers/projects/network_controller.rb2
-rw-r--r--app/controllers/projects/notes_controller.rb2
-rw-r--r--app/controllers/projects/pages_controller.rb2
-rw-r--r--app/controllers/projects/pages_domains_controller.rb2
-rw-r--r--app/controllers/projects/pipeline_schedules_controller.rb2
-rw-r--r--app/controllers/projects/pipelines_controller.rb4
-rw-r--r--app/controllers/projects/pipelines_settings_controller.rb2
-rw-r--r--app/controllers/projects/project_members_controller.rb2
-rw-r--r--app/controllers/projects/prometheus/metrics_controller.rb2
-rw-r--r--app/controllers/projects/protected_branches_controller.rb2
-rw-r--r--app/controllers/projects/protected_refs_controller.rb2
-rw-r--r--app/controllers/projects/protected_tags_controller.rb2
-rw-r--r--app/controllers/projects/raw_controller.rb2
-rw-r--r--app/controllers/projects/refs_controller.rb2
-rw-r--r--app/controllers/projects/registry/application_controller.rb2
-rw-r--r--app/controllers/projects/registry/repositories_controller.rb2
-rw-r--r--app/controllers/projects/registry/tags_controller.rb2
-rw-r--r--app/controllers/projects/releases_controller.rb2
-rw-r--r--app/controllers/projects/repositories_controller.rb2
-rw-r--r--app/controllers/projects/runner_projects_controller.rb2
-rw-r--r--app/controllers/projects/runners_controller.rb2
-rw-r--r--app/controllers/projects/services_controller.rb2
-rw-r--r--app/controllers/projects/settings/ci_cd_controller.rb2
-rw-r--r--app/controllers/projects/settings/integrations_controller.rb2
-rw-r--r--app/controllers/projects/settings/repository_controller.rb6
-rw-r--r--app/controllers/projects/snippets_controller.rb2
-rw-r--r--app/controllers/projects/tags_controller.rb2
-rw-r--r--app/controllers/projects/templates_controller.rb2
-rw-r--r--app/controllers/projects/todos_controller.rb2
-rw-r--r--app/controllers/projects/tree_controller.rb2
-rw-r--r--app/controllers/projects/triggers_controller.rb2
-rw-r--r--app/controllers/projects/uploads_controller.rb2
-rw-r--r--app/controllers/projects/variables_controller.rb2
-rw-r--r--app/controllers/projects/wikis_controller.rb2
-rw-r--r--app/controllers/projects_controller.rb4
-rw-r--r--app/controllers/registrations_controller.rb2
-rw-r--r--app/controllers/root_controller.rb2
-rw-r--r--app/controllers/search_controller.rb2
-rw-r--r--app/controllers/sent_notifications_controller.rb2
-rw-r--r--app/controllers/sessions_controller.rb2
-rw-r--r--app/controllers/sherlock/application_controller.rb2
-rw-r--r--app/controllers/sherlock/file_samples_controller.rb2
-rw-r--r--app/controllers/sherlock/queries_controller.rb2
-rw-r--r--app/controllers/sherlock/transactions_controller.rb2
-rw-r--r--app/controllers/snippets/notes_controller.rb2
-rw-r--r--app/controllers/snippets_controller.rb2
-rw-r--r--app/controllers/uploads_controller.rb2
-rw-r--r--app/controllers/user_callouts_controller.rb2
-rw-r--r--app/controllers/users/terms_controller.rb2
-rw-r--r--app/controllers/users_controller.rb2
-rw-r--r--app/finders/admin/runners_finder.rb18
-rw-r--r--app/finders/group_labels_finder.rb17
-rw-r--r--app/finders/members_finder.rb2
-rw-r--r--app/finders/snippets_finder.rb4
-rw-r--r--app/finders/todos_finder.rb13
-rw-r--r--app/finders/union_finder.rb10
-rw-r--r--app/helpers/application_helper.rb17
-rw-r--r--app/helpers/application_settings_helper.rb11
-rw-r--r--app/helpers/avatars_helper.rb21
-rw-r--r--app/helpers/ci_status_helper.rb5
-rw-r--r--app/helpers/services_helper.rb2
-rw-r--r--app/helpers/sorting_helper.rb11
-rw-r--r--app/helpers/tab_helper.rb16
-rw-r--r--app/mailers/previews/notify_preview.rb6
-rw-r--r--app/models/ability.rb2
-rw-r--r--app/models/application_setting.rb21
-rw-r--r--app/models/badge.rb2
-rw-r--r--app/models/ci/build.rb82
-rw-r--r--app/models/ci/job_artifact.rb42
-rw-r--r--app/models/ci/runner.rb44
-rw-r--r--app/models/clusters/applications/jupyter.rb5
-rw-r--r--app/models/concerns/bulk_member_access_load.rb6
-rw-r--r--app/models/concerns/cacheable_attributes.rb6
-rw-r--r--app/models/concerns/from_union.rb51
-rw-r--r--app/models/concerns/mentionable.rb13
-rw-r--r--app/models/concerns/mentionable/reference_regexes.rb12
-rw-r--r--app/models/concerns/protected_ref_access.rb18
-rw-r--r--app/models/container_repository.rb2
-rw-r--r--app/models/dashboard_group_milestone.rb6
-rw-r--r--app/models/deploy_key.rb2
-rw-r--r--app/models/diff_note.rb2
-rw-r--r--app/models/epic.rb4
-rw-r--r--app/models/event.rb1
-rw-r--r--app/models/group.rb4
-rw-r--r--app/models/label.rb1
-rw-r--r--app/models/legacy_diff_note.rb6
-rw-r--r--app/models/merge_request.rb15
-rw-r--r--app/models/milestone.rb5
-rw-r--r--app/models/namespace.rb5
-rw-r--r--app/models/network/commit.rb2
-rw-r--r--app/models/network/graph.rb4
-rw-r--r--app/models/note.rb1
-rw-r--r--app/models/project.rb39
-rw-r--r--app/models/project_authorization.rb8
-rw-r--r--app/models/project_feature.rb26
-rw-r--r--app/models/project_services/asana_service.rb2
-rw-r--r--app/models/project_services/chat_message/merge_message.rb9
-rw-r--r--app/models/project_wiki.rb9
-rw-r--r--app/models/repository.rb17
-rw-r--r--app/models/site_statistic.rb2
-rw-r--r--app/models/snippet.rb1
-rw-r--r--app/models/todo.rb1
-rw-r--r--app/models/user.rb55
-rw-r--r--app/models/wiki_page.rb4
-rw-r--r--app/serializers/build_details_entity.rb33
-rw-r--r--app/serializers/commit_entity.rb17
-rw-r--r--app/serializers/diffs_entity.rb7
-rw-r--r--app/serializers/runner_entity.rb7
-rw-r--r--app/serializers/stage_entity.rb16
-rw-r--r--app/services/boards/create_service.rb2
-rw-r--r--app/services/boards/issues/list_service.rb5
-rw-r--r--app/services/ci/fetch_kubernetes_token_service.rb75
-rw-r--r--app/services/clusters/gcp/finalize_creation_service.rb50
-rw-r--r--app/services/clusters/gcp/kubernetes.rb13
-rw-r--r--app/services/clusters/gcp/kubernetes/create_service_account_service.rb51
-rw-r--r--app/services/clusters/gcp/kubernetes/fetch_kubernetes_token_service.rb30
-rw-r--r--app/services/clusters/gcp/provision_service.rb4
-rw-r--r--app/services/files/base_service.rb6
-rw-r--r--app/services/files/multi_service.rb2
-rw-r--r--app/services/labels/transfer_service.rb14
-rw-r--r--app/services/merge_requests/reload_diffs_service.rb10
-rw-r--r--app/services/notes/build_service.rb6
-rw-r--r--app/services/projects/container_repository/destroy_service.rb2
-rw-r--r--app/services/projects/destroy_service.rb19
-rw-r--r--app/services/projects/update_remote_mirror_service.rb1
-rw-r--r--app/services/quick_actions/interpret_service.rb31
-rw-r--r--app/validators/url_validator.rb14
-rw-r--r--app/views/abuse_reports/new.html.haml2
-rw-r--r--app/views/admin/appearances/_form.html.haml8
-rw-r--r--app/views/admin/appearances/preview_sign_in.html.haml2
-rw-r--r--app/views/admin/application_settings/_background_jobs.html.haml27
-rw-r--r--app/views/admin/application_settings/_influx.html.haml2
-rw-r--r--app/views/admin/application_settings/_repository_mirrors_form.html.haml4
-rw-r--r--app/views/admin/application_settings/_signin.html.haml2
-rw-r--r--app/views/admin/application_settings/ci_cd.html.haml26
-rw-r--r--app/views/admin/application_settings/integrations.html.haml31
-rw-r--r--app/views/admin/application_settings/metrics_and_profiling.html.haml50
-rw-r--r--app/views/admin/application_settings/network.html.haml36
-rw-r--r--app/views/admin/application_settings/preferences.html.haml58
-rw-r--r--app/views/admin/application_settings/reporting.html.haml36
-rw-r--r--app/views/admin/application_settings/repository.html.haml36
-rw-r--r--app/views/admin/application_settings/show.html.haml306
-rw-r--r--app/views/admin/applications/_form.html.haml6
-rw-r--r--app/views/admin/broadcast_messages/_form.html.haml4
-rw-r--r--app/views/admin/dashboard/index.html.haml6
-rw-r--r--app/views/admin/deploy_keys/edit.html.haml2
-rw-r--r--app/views/admin/deploy_keys/index.html.haml2
-rw-r--r--app/views/admin/deploy_keys/new.html.haml2
-rw-r--r--app/views/admin/groups/_form.html.haml4
-rw-r--r--app/views/admin/groups/index.html.haml2
-rw-r--r--app/views/admin/groups/show.html.haml2
-rw-r--r--app/views/admin/hooks/edit.html.haml2
-rw-r--r--app/views/admin/hooks/index.html.haml2
-rw-r--r--app/views/admin/identities/_form.html.haml2
-rw-r--r--app/views/admin/identities/index.html.haml2
-rw-r--r--app/views/admin/labels/_form.html.haml2
-rw-r--r--app/views/admin/labels/index.html.haml2
-rw-r--r--app/views/admin/projects/index.html.haml2
-rw-r--r--app/views/admin/runners/_runner.html.haml104
-rw-r--r--app/views/admin/runners/_runner_table_cell.html.haml4
-rw-r--r--app/views/admin/runners/index.html.haml28
-rw-r--r--app/views/admin/services/_form.html.haml2
-rw-r--r--app/views/admin/users/_form.html.haml4
-rw-r--r--app/views/admin/users/index.html.haml2
-rw-r--r--app/views/ci/runner/_how_to_setup_runner.html.haml2
-rw-r--r--app/views/ci/runner/_how_to_setup_specific_runner.html.haml2
-rw-r--r--app/views/dashboard/_groups_head.html.haml2
-rw-r--r--app/views/dashboard/_projects_head.html.haml2
-rw-r--r--app/views/dashboard/_snippets_head.html.haml2
-rw-r--r--app/views/dashboard/snippets/index.html.haml2
-rw-r--r--app/views/devise/passwords/edit.html.haml6
-rw-r--r--app/views/devise/sessions/_new_base.html.haml6
-rw-r--r--app/views/devise/sessions/_new_crowd.html.haml2
-rw-r--r--app/views/devise/sessions/_new_ldap.html.haml6
-rw-r--r--app/views/devise/sessions/two_factor.html.haml2
-rw-r--r--app/views/devise/shared/_tabs_ldap.html.haml6
-rw-r--r--app/views/devise/shared/_tabs_normal.html.haml4
-rw-r--r--app/views/doorkeeper/applications/_form.html.haml2
-rw-r--r--app/views/doorkeeper/applications/index.html.haml3
-rw-r--r--app/views/errors/precondition_failed.html.haml8
-rw-r--r--app/views/groups/_group_admin_settings.html.haml6
-rw-r--r--app/views/groups/group_members/_new_group_member.html.haml2
-rw-r--r--app/views/groups/labels/index.html.haml2
-rw-r--r--app/views/groups/milestones/_form.html.haml4
-rw-r--r--app/views/groups/milestones/index.html.haml2
-rw-r--r--app/views/groups/new.html.haml2
-rw-r--r--app/views/groups/settings/_permissions.html.haml2
-rw-r--r--app/views/groups/show.html.haml10
-rw-r--r--app/views/help/index.html.haml3
-rw-r--r--app/views/help/instance_configuration/_gitlab_pages.html.haml2
-rw-r--r--app/views/help/ui.html.haml2
-rw-r--r--app/views/import/fogbugz/new.html.haml2
-rw-r--r--app/views/import/fogbugz/new_user_map.html.haml2
-rw-r--r--app/views/import/gitea/new.html.haml2
-rw-r--r--app/views/import/gitlab_projects/new.html.haml4
-rw-r--r--app/views/import/google_code/new.html.haml2
-rw-r--r--app/views/import/google_code/new_user_map.html.haml2
-rw-r--r--app/views/layouts/nav/sidebar/_admin.html.haml52
-rw-r--r--app/views/layouts/nav/sidebar/_group.html.haml2
-rw-r--r--app/views/layouts/nav/sidebar/_profile.html.haml23
-rw-r--r--app/views/layouts/nav/sidebar/_project.html.haml4
-rw-r--r--app/views/profiles/emails/index.html.haml2
-rw-r--r--app/views/profiles/gpg_keys/_form.html.haml2
-rw-r--r--app/views/profiles/keys/_form.html.haml8
-rw-r--r--app/views/profiles/keys/_key_details.html.haml2
-rw-r--r--app/views/profiles/passwords/edit.html.haml2
-rw-r--r--app/views/profiles/passwords/new.html.haml4
-rw-r--r--app/views/profiles/preferences/show.html.haml2
-rw-r--r--app/views/profiles/show.html.haml7
-rw-r--r--app/views/profiles/two_factor_auths/_codes.html.haml4
-rw-r--r--app/views/projects/_commit_button.html.haml2
-rw-r--r--app/views/projects/_fork_suggestion.html.haml2
-rw-r--r--app/views/projects/_new_project_fields.html.haml4
-rw-r--r--app/views/projects/_readme.html.haml2
-rw-r--r--app/views/projects/blob/_new_dir.html.haml2
-rw-r--r--app/views/projects/blob/_upload.html.haml2
-rw-r--r--app/views/projects/branches/index.html.haml2
-rw-r--r--app/views/projects/branches/new.html.haml2
-rw-r--r--app/views/projects/clusters/gcp/_form.html.haml10
-rw-r--r--app/views/projects/clusters/gcp/_show.html.haml9
-rw-r--r--app/views/projects/clusters/user/_form.html.haml1
-rw-r--r--app/views/projects/commit/_change.html.haml2
-rw-r--r--app/views/projects/commits/_commit.html.haml6
-rw-r--r--app/views/projects/compare/_form.html.haml2
-rw-r--r--app/views/projects/deploy_keys/_form.html.haml2
-rw-r--r--app/views/projects/deploy_keys/edit.html.haml2
-rw-r--r--app/views/projects/edit.html.haml10
-rw-r--r--app/views/projects/environments/_form.html.haml2
-rw-r--r--app/views/projects/environments/terminal.html.haml2
-rw-r--r--app/views/projects/forks/_fork_button.html.haml4
-rw-r--r--app/views/projects/forks/index.html.haml4
-rw-r--r--app/views/projects/hooks/_index.html.haml2
-rw-r--r--app/views/projects/hooks/edit.html.haml2
-rw-r--r--app/views/projects/imports/new.html.haml2
-rw-r--r--app/views/projects/issues/_issue.html.haml6
-rw-r--r--app/views/projects/issues/_nav_btns.html.haml2
-rw-r--r--app/views/projects/issues/show.html.haml2
-rw-r--r--app/views/projects/jobs/_header.html.haml2
-rw-r--r--app/views/projects/jobs/_sidebar.html.haml57
-rw-r--r--app/views/projects/jobs/show.html.haml5
-rw-r--r--app/views/projects/labels/index.html.haml2
-rw-r--r--app/views/projects/mattermosts/_team_selection.html.haml2
-rw-r--r--app/views/projects/merge_requests/_merge_request.html.haml6
-rw-r--r--app/views/projects/merge_requests/_nav_btns.html.haml2
-rw-r--r--app/views/projects/merge_requests/creations/_new_compare.html.haml2
-rw-r--r--app/views/projects/merge_requests/diffs/_commit_widget.html.haml4
-rw-r--r--app/views/projects/merge_requests/diffs/_diffs.html.haml2
-rw-r--r--app/views/projects/milestones/_form.html.haml4
-rw-r--r--app/views/projects/milestones/index.html.haml2
-rw-r--r--app/views/projects/mirrors/_mirror_repos.html.haml2
-rw-r--r--app/views/projects/pages/show.html.haml2
-rw-r--r--app/views/projects/pages_domains/edit.html.haml2
-rw-r--r--app/views/projects/pages_domains/new.html.haml2
-rw-r--r--app/views/projects/pipeline_schedules/_form.html.haml2
-rw-r--r--app/views/projects/pipeline_schedules/index.html.haml2
-rw-r--r--app/views/projects/project_members/_new_project_group.html.haml2
-rw-r--r--app/views/projects/project_members/_new_project_member.html.haml2
-rw-r--r--app/views/projects/project_members/import.html.haml2
-rw-r--r--app/views/projects/protected_branches/shared/_create_protected_branch.html.haml2
-rw-r--r--app/views/projects/protected_tags/shared/_create_protected_tag.html.haml2
-rw-r--r--app/views/projects/releases/edit.html.haml2
-rw-r--r--app/views/projects/runners/_group_runners.html.haml2
-rw-r--r--app/views/projects/services/mattermost_slash_commands/_detailed_help.html.haml2
-rw-r--r--app/views/projects/services/slack_slash_commands/_help.html.haml2
-rw-r--r--app/views/projects/settings/ci_cd/_form.html.haml2
-rw-r--r--app/views/projects/snippets/_actions.html.haml2
-rw-r--r--app/views/projects/snippets/index.html.haml2
-rw-r--r--app/views/projects/tags/index.html.haml2
-rw-r--r--app/views/projects/tags/new.html.haml2
-rw-r--r--app/views/projects/triggers/_form.html.haml2
-rw-r--r--app/views/projects/update.js.haml2
-rw-r--r--app/views/projects/wikis/_form.html.haml4
-rw-r--r--app/views/projects/wikis/_main_links.html.haml2
-rw-r--r--app/views/projects/wikis/_new.html.haml2
-rw-r--r--app/views/projects/wikis/edit.html.haml2
-rw-r--r--app/views/shared/_event_filter.html.haml12
-rw-r--r--app/views/shared/_new_project_item_select.html.haml4
-rw-r--r--app/views/shared/_personal_access_tokens_form.html.haml2
-rw-r--r--app/views/shared/_recaptcha_form.html.haml2
-rw-r--r--app/views/shared/_visibility_level.html.haml2
-rw-r--r--app/views/shared/empty_states/_labels.html.haml2
-rw-r--r--app/views/shared/empty_states/_merge_requests.html.haml2
-rw-r--r--app/views/shared/empty_states/_wikis.html.haml4
-rw-r--r--app/views/shared/issuable/_board_create_list_dropdown.html.haml2
-rw-r--r--app/views/shared/issuable/_form.html.haml4
-rw-r--r--app/views/shared/issuable/_search_bar.html.haml5
-rw-r--r--app/views/shared/issuable/_sidebar.html.haml2
-rw-r--r--app/views/shared/issuable/form/_metadata.html.haml2
-rw-r--r--app/views/shared/issuable/form/_title.html.haml2
-rw-r--r--app/views/shared/labels/_form.html.haml4
-rw-r--r--app/views/shared/members/_member.html.haml2
-rw-r--r--app/views/shared/notes/_comment_button.html.haml2
-rw-r--r--app/views/shared/notes/_edit_form.html.haml2
-rw-r--r--app/views/shared/runners/_form.html.haml2
-rw-r--r--app/views/shared/runners/_runner_description.html.haml2
-rw-r--r--app/views/shared/snippets/_form.html.haml4
-rw-r--r--app/views/snippets/_actions.html.haml2
-rw-r--r--app/views/snippets/new.html.haml3
-rw-r--r--app/views/u2f/_register.html.haml4
-rw-r--r--app/workers/expire_build_instance_artifacts_worker.rb2
-rw-r--r--app/workers/new_merge_request_worker.rb2
-rwxr-xr-xbin/pkgr_before_precompile.sh2
-rwxr-xr-xbin/setup2
-rw-r--r--changelogs/archive.md16
-rw-r--r--changelogs/unreleased/#47282-Improving-Contributor-On-Boarding-Documentation.yml4
-rw-r--r--changelogs/unreleased/-48445-Issue-card-in-board-view-is-too-sensitive-to-drag-event.yml5
-rw-r--r--changelogs/unreleased/1801-allow-event_filter-to-be-set-in-the-url.yml5
-rw-r--r--changelogs/unreleased/21305-breadcrumb-link-to-issues-on-new-issue-page.yml5
-rw-r--r--changelogs/unreleased/21307-send-deployment-information-in-job-api.yml5
-rw-r--r--changelogs/unreleased/21326-avoid-nil-safe-message.yml5
-rw-r--r--changelogs/unreleased/21371-avatar-fix.yml5
-rw-r--r--changelogs/unreleased/24128-fix-comment-unresolve-discussions.yml5
-rw-r--r--changelogs/unreleased/25990-web-terminal-improvements.yml5
-rw-r--r--changelogs/unreleased/2747-protected-environments-backend-ce.yml5
-rw-r--r--changelogs/unreleased/28930-add-project-reference-filter.yml5
-rw-r--r--changelogs/unreleased/2934-create-new-project-re-add-project-name-field.yml5
-rw-r--r--changelogs/unreleased/29398-support-kubernetes-rbac-for-gitlab-managed-apps.yml5
-rw-r--r--changelogs/unreleased/29398-support-rbac-for-gitlab-provisioned-clusters.yml5
-rw-r--r--changelogs/unreleased/36048-move-default-branch-settings-under-repository.yml5
-rw-r--r--changelogs/unreleased/36534-show-commit-behind-mr-api.yml5
-rw-r--r--changelogs/unreleased/37356-relative-submodule-link.yml5
-rw-r--r--changelogs/unreleased/37433-solve-n-1-in-refs-controller-logs-tree.yml6
-rw-r--r--changelogs/unreleased/38208-due-dates-system-notes.yml5
-rw-r--r--changelogs/unreleased/39665-restrict-issue-reopen.yml5
-rw-r--r--changelogs/unreleased/39923-automatically-disable-auto-devops-for-project.yml5
-rw-r--r--changelogs/unreleased/41040-long-webhook-url-problem.yml5
-rw-r--r--changelogs/unreleased/41292-users-stuck-on-a-redirect-loop-after-transferring-project.yml5
-rw-r--r--changelogs/unreleased/41441-add-target-branch-name-to-cherrypick-confirmation.yml5
-rw-r--r--changelogs/unreleased/41738-fix-sorting-issues-is-wrong-in-list-with-pagination.yml5
-rw-r--r--changelogs/unreleased/41996-copy-to-clipboard-tooltip-appears-under-modal.yml5
-rw-r--r--changelogs/unreleased/42754-runners-pagination.yml5
-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/43140-reduce-logs-tree-load.yml5
-rw-r--r--changelogs/unreleased/43625-increase-modal-checkout.yml5
-rw-r--r--changelogs/unreleased/43832-adds-chdmod-to-commits-actions-api.yml5
-rw-r--r--changelogs/unreleased/44005-improve-handling-of-projects-shared-with-a-group.yml5
-rw-r--r--changelogs/unreleased/44596-double-title-merge-request-message.yml5
-rw-r--r--changelogs/unreleased/44704-improve-project-overview-ui.yml5
-rw-r--r--changelogs/unreleased/44768-lazy-load-xterm-css.yml5
-rw-r--r--changelogs/unreleased/44943-update-presentation-for-sso-providers-on-log-in-page.yml5
-rw-r--r--changelogs/unreleased/44998-split-admin-settings-into-multiple-sub-pages.yml5
-rw-r--r--changelogs/unreleased/45663-tag-quick-action-on-commit-comments.yml5
-rw-r--r--changelogs/unreleased/45754-issue-mr-and-archived-projects.yml5
-rw-r--r--changelogs/unreleased/45754-open-issues-from-archived-project-listed-in-group-issue-board.yml5
-rw-r--r--changelogs/unreleased/45938-postgres-timeout-when-counting-number-of-ci-builds-for-usage-ping.yml5
-rw-r--r--changelogs/unreleased/46340-remove-extra-spaces-from-mr-discussion-notes.yml5
-rw-r--r--changelogs/unreleased/46591-fix-ide-height-issues.yml5
-rw-r--r--changelogs/unreleased/46733-move-filter-dropdown-from-font-awesome-to-our-own-icons.yml5
-rw-r--r--changelogs/unreleased/47398-user-is-unable-revoke-a-authorized-application-unless-user-oauth-applications-is-checked-in-admin-settings.yml6
-rw-r--r--changelogs/unreleased/47440-recognize-unlicense-license-file.yml5
-rw-r--r--changelogs/unreleased/47752-buttons-on-new-file-page-wrap-outside-of-container-for-long-branch-names.yml5
-rw-r--r--changelogs/unreleased/47765-group-visibility-error-due-to-string-conversion.yml6
-rw-r--r--changelogs/unreleased/47845-propagate_failure_reason-to-job-webhook.yml5
-rw-r--r--changelogs/unreleased/47943-project-milestone-page-deprecation-message.yml5
-rw-r--r--changelogs/unreleased/48145-illustration.yml5
-rw-r--r--changelogs/unreleased/48167-fix-outdated-discussions-new-datastructure.yml5
-rw-r--r--changelogs/unreleased/48320-cancel-a-created-job.yml5
-rw-r--r--changelogs/unreleased/48399-skip-auto-devops-jobs-based-on-license.yml6
-rw-r--r--changelogs/unreleased/48778-remove-old-storage-logic-from-import-export.yml5
-rw-r--r--changelogs/unreleased/48869-wiki-slugs-with-spaces.yml5
-rw-r--r--changelogs/unreleased/48942-rename-backlog-list-to-open-issue-boards.yml5
-rw-r--r--changelogs/unreleased/48967-disable-statement-timeout.yml5
-rw-r--r--changelogs/unreleased/4907-improve-build-create-performance-for-license-management.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/49329-mr-show-commit-details.yml5
-rw-r--r--changelogs/unreleased/49632-clean-up-the-top-section-of-the-cluster-page.yml5
-rw-r--r--changelogs/unreleased/49644-make-margin-of-user-status-emoji-consistent.yml5
-rw-r--r--changelogs/unreleased/49770-fixes-input-alignment-on-user-admin-form-with-errors.yml5
-rw-r--r--changelogs/unreleased/49796-project-deletion-may-not-log-audit-events-during-group-deletion.yml5
-rw-r--r--changelogs/unreleased/49796-project-deletion-may-not-log-audit-events-during-user-deletion.yml5
-rw-r--r--changelogs/unreleased/49905-fix-checkboxes-runners.yml5
-rw-r--r--changelogs/unreleased/49953-add-user_show_add_ssh_key_message-setting.yml5
-rw-r--r--changelogs/unreleased/49993-fix-remember-sorting-issue-mr.yml5
-rw-r--r--changelogs/unreleased/50019-remove-redundant-header-from-metrics-page.yml5
-rw-r--r--changelogs/unreleased/50047-spam-logs-pagination.yml5
-rw-r--r--changelogs/unreleased/50063-add-missing-i18n-strings-to-issue-boards.yml5
-rw-r--r--changelogs/unreleased/50101-add-artifact-information-to-job-api.yml5
-rw-r--r--changelogs/unreleased/50101-aritfacts-block.yml5
-rw-r--r--changelogs/unreleased/50101-builds-dropdown.yml6
-rw-r--r--changelogs/unreleased/50101-commit-block.yml5
-rw-r--r--changelogs/unreleased/50101-empty-state-component.yml5
-rw-r--r--changelogs/unreleased/50101-env-block.yml5
-rw-r--r--changelogs/unreleased/50101-erased-block.yml5
-rw-r--r--changelogs/unreleased/50101-job-log-component.yml5
-rw-r--r--changelogs/unreleased/50101-stuck-component.yml5
-rw-r--r--changelogs/unreleased/50101-trigger.yml5
-rw-r--r--changelogs/unreleased/50101-truncated-job-information.yml5
-rw-r--r--changelogs/unreleased/50111-improve-design-of-cluster-apps-to-handle-larger-quantity.yml5
-rw-r--r--changelogs/unreleased/50126-blocked-user-card.yml5
-rw-r--r--changelogs/unreleased/50180-fa-icon-google-audit.yml5
-rw-r--r--changelogs/unreleased/50243-auto-devops-behind-a-proxy.yml6
-rw-r--r--changelogs/unreleased/50289-vendor-ci-yml-for-the-last-time.yml5
-rw-r--r--changelogs/unreleased/50345-hashed-storage-feature-flag.yml5
-rw-r--r--changelogs/unreleased/50414-rubocop-rule-to-enforce-class-methods-over-module.yml5
-rw-r--r--changelogs/unreleased/50441-high-number-of-statement-timeouts-in-groupdestroyworker-due-to-sitestatistics.yml5
-rw-r--r--changelogs/unreleased/50452-breadcrumb-link-to-new-merge-requests.yml5
-rw-r--r--changelogs/unreleased/50461-add-retried-builds-in-pipeline-stage-endpoint.yml5
-rw-r--r--changelogs/unreleased/50524-artifacts-sm.yml5
-rw-r--r--changelogs/unreleased/50535-display-banner-to-notify-user-if-project-is-implicitly-opted-ado.yml5
-rw-r--r--changelogs/unreleased/50564-chat-service-refactoring.yml5
-rw-r--r--changelogs/unreleased/50567-remove-usage-ping-payload-from-cohorts-add-to-settings.yml5
-rw-r--r--changelogs/unreleased/50584-fix-ide-commit-twice.yml5
-rw-r--r--changelogs/unreleased/50657-migrate-issue-labels-and-milestone-to-related-mr-on-creation.yml5
-rw-r--r--changelogs/unreleased/50801-error-getting-performance-bar-results-for-uuid.yml5
-rw-r--r--changelogs/unreleased/50823-not-properly-filled-in-activity-RSS-feed-yml.yml5
-rw-r--r--changelogs/unreleased/50853-vendor-auto-devops-gitlab-ci-yml-to-resolve-redeploying-deleted-app-gives-helm-error.yml5
-rw-r--r--changelogs/unreleased/50879-unused-css-container-fluid.yml5
-rw-r--r--changelogs/unreleased/50904-move-job-page-vue.yml5
-rw-r--r--changelogs/unreleased/50904-update-scroll-utils.yml5
-rw-r--r--changelogs/unreleased/50904-use-vuex-store-job.yml5
-rw-r--r--changelogs/unreleased/50930-update-rubyzip-to-1-2-2.yml5
-rw-r--r--changelogs/unreleased/50936-docs-run-review-cleanup-only-for-gitlab-org-repos.yml5
-rw-r--r--changelogs/unreleased/51050-fix.yml5
-rw-r--r--changelogs/unreleased/51092-fix-mr-diff-file-filter-clear-button.yml5
-rw-r--r--changelogs/unreleased/51117-send-terminal-path-in-job-api.yml5
-rw-r--r--changelogs/unreleased/51180-update-ffi-to-1-9-25.yml5
-rw-r--r--changelogs/unreleased/51273-expose-runners-for-build-in-job-api.yml5
-rw-r--r--changelogs/unreleased/51281-on-master-diff-view-contains-extra-and-signs.yml5
-rw-r--r--changelogs/unreleased/51282-link-to-user-snippets-on-new-user-snippet-page.yml5
-rw-r--r--changelogs/unreleased/51318-project-export-broken-when-avatar-is-set.yml5
-rw-r--r--changelogs/unreleased/51404-update-groups-and-projects-api-docs.yml5
-rw-r--r--changelogs/unreleased/51412-username-alignment-issue-on-mr-page.yml5
-rw-r--r--changelogs/unreleased/51476-private-profile-help-url-should-not-toggle-checkbox.yml5
-rw-r--r--changelogs/unreleased/51509-remove-sidekiq-limit-fetch.yml5
-rw-r--r--changelogs/unreleased/51522-add-new-project-via-import-by-url-auto-populates-slug-but-not-project-name.yml5
-rw-r--r--changelogs/unreleased/51549-runners-table.yml5
-rw-r--r--changelogs/unreleased/51564-fix-commit-email-usage.yml5
-rw-r--r--changelogs/unreleased/51569-performance-bar.yml5
-rw-r--r--changelogs/unreleased/51571-wrapper-rake-task-uploads-migrate-os.yml5
-rw-r--r--changelogs/unreleased/51651-fill-pipeline-source-for-external-pipelines.yml5
-rw-r--r--changelogs/unreleased/51725-push-mirrors-default-branch-reset-to-master.yml5
-rw-r--r--changelogs/unreleased/51747-gitlab-com-unable-to-import-a-project-that-was-just-exported.yml5
-rw-r--r--changelogs/unreleased/51839-remove-sorting-on-project-tags.yml5
-rw-r--r--changelogs/unreleased/51925-expose-has_trace-in-job-api.yml5
-rw-r--r--changelogs/unreleased/6010_remove_gemnasium_service.yml5
-rw-r--r--changelogs/unreleased/6028-show-generic-percent-stacked-progress-bar.yml6
-rw-r--r--changelogs/unreleased/6717_extend_reports_for_security_products.yml5
-rw-r--r--changelogs/unreleased/7573-show-click-to-expand-on-not-rendered-diffs.yml6
-rw-r--r--changelogs/unreleased/_acet-disable-ide-button.yml5
-rw-r--r--changelogs/unreleased/ab-49446-internal-ids-inconsistency.yml5
-rw-r--r--changelogs/unreleased/add-2fa-button.yml5
-rw-r--r--changelogs/unreleased/add-background-migration-for-legacy-traces.yml5
-rw-r--r--changelogs/unreleased/add-ci_archive_traces_cron_worker-to-gitlab-yml.yml5
-rw-r--r--changelogs/unreleased/add-most-stars-for-filter-option.yml5
-rw-r--r--changelogs/unreleased/add-rake-command-to-migrate-locally-persisted-archived-traces.yml5
-rw-r--r--changelogs/unreleased/add_google_noto_color_emoji_font.yml5
-rw-r--r--changelogs/unreleased/align-form-labels.yml5
-rw-r--r--changelogs/unreleased/an-ap_log_gitaly_calls.yml5
-rw-r--r--changelogs/unreleased/an-api-route-logger.yml5
-rw-r--r--changelogs/unreleased/api-empty-commit-message.yml5
-rw-r--r--changelogs/unreleased/api-empty-project-snippets.yml5
-rw-r--r--changelogs/unreleased/api-promote-find-branch.yml5
-rw-r--r--changelogs/unreleased/api-protected-tags.yml5
-rw-r--r--changelogs/unreleased/api-shared_group_expires-at.yml5
-rw-r--r--changelogs/unreleased/arguments-keyword-sast.yml5
-rw-r--r--changelogs/unreleased/ash-mckenzie-geo-git-push-ssh-proxy.yml5
-rw-r--r--changelogs/unreleased/auto-devops-gitlab-ci-glic-228.yml5
-rw-r--r--changelogs/unreleased/bvl-add-czech.yml5
-rw-r--r--changelogs/unreleased/bvl-add-galician.yml5
-rw-r--r--changelogs/unreleased/bvl-merge-base-api.yml5
-rw-r--r--changelogs/unreleased/bvl-remove-sha-from-help.yml5
-rw-r--r--changelogs/unreleased/bw-commonmark-for-files.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/ccr-6699_image_for_object_error.yml6
-rw-r--r--changelogs/unreleased/ce-5666-optimize_querying_manageable_groups.yml5
-rw-r--r--changelogs/unreleased/ci-builds-status-index.yml5
-rw-r--r--changelogs/unreleased/dm-create-note-return-discussion.yml5
-rw-r--r--changelogs/unreleased/dm-fix-assign-unassign-quick-actions.yml6
-rw-r--r--changelogs/unreleased/dz-fix-sql-error-admin-users-2fa.yml5
-rw-r--r--changelogs/unreleased/dz-group-labels-search.yml5
-rw-r--r--changelogs/unreleased/ee-6381-multiseries.yml5
-rw-r--r--changelogs/unreleased/emoji-cutoff-1px.yml5
-rw-r--r--changelogs/unreleased/enable-force-write-auth-keys-restore.yml5
-rw-r--r--changelogs/unreleased/expose-all-artifacts-sizes-in-jobs-api.yml5
-rw-r--r--changelogs/unreleased/expose-users-id-in-admin-users-show-page.yml5
-rw-r--r--changelogs/unreleased/fa-handle_invalid_utf8_errors.yml5
-rw-r--r--changelogs/unreleased/feat-add-default-avatar-to-group.yml5
-rw-r--r--changelogs/unreleased/feat-update-contribution-calendar.yml5
-rw-r--r--changelogs/unreleased/feature--32877-add-default-field-branch-api.yml5
-rw-r--r--changelogs/unreleased/feature-add-public-email-to-users-api.yml5
-rw-r--r--changelogs/unreleased/feature-gb-allow-to-extend-keys-in-gitlab-ci-yml.yml5
-rw-r--r--changelogs/unreleased/feature-git-v2-flag.yml5
-rw-r--r--changelogs/unreleased/feature-runner-type-filter-for-admin-view.yml5
-rw-r--r--changelogs/unreleased/feature-whitelist-new-users-as-internal.yml5
-rw-r--r--changelogs/unreleased/filter-web-hooks-by-branch.yml5
-rw-r--r--changelogs/unreleased/fix-api-group-createdat.yml5
-rw-r--r--changelogs/unreleased/fix-chat-notification-service-for-ee.yml5
-rw-r--r--changelogs/unreleased/fix-closing-issues.yml5
-rw-r--r--changelogs/unreleased/fix-committer-typo.yml5
-rw-r--r--changelogs/unreleased/fix-download-dropdown-link.yml5
-rw-r--r--changelogs/unreleased/fix-help-text-font-color-in-merge-request-creation.yml5
-rw-r--r--changelogs/unreleased/fix-junit-parser.yml5
-rw-r--r--changelogs/unreleased/fix-labels-list-item-height-with-no-description.yml5
-rw-r--r--changelogs/unreleased/fix-leading-slash-in-redirects-plus-rubocop.yml5
-rw-r--r--changelogs/unreleased/fix-mr-title-fallback-logic.yml5
-rw-r--r--changelogs/unreleased/fix-namespace-upload.yml5
-rw-r--r--changelogs/unreleased/fix-namespace-uploader.yml5
-rw-r--r--changelogs/unreleased/fix-pipeline-fixture-seeder.yml5
-rw-r--r--changelogs/unreleased/fix_emojis_cutting_and_regressions.yml5
-rw-r--r--changelogs/unreleased/fix_event_api_permissions.yml5
-rw-r--r--changelogs/unreleased/fj-2635-enable-rss-for-tags.yml5
-rw-r--r--changelogs/unreleased/fj-33475-files-inside-wiki-repo.yml5
-rw-r--r--changelogs/unreleased/fj-47229-fix-logo-lfs-tracked.yml5
-rw-r--r--changelogs/unreleased/fj-51194-fix-wiki-attachments-with-whitespaces.yml5
-rw-r--r--changelogs/unreleased/fl-reduce-ee-conflicts-reports-code.yml5
-rw-r--r--changelogs/unreleased/force-post-migration-dir-schema-load.yml5
-rw-r--r--changelogs/unreleased/frozen-string-app-controller-more.yml (renamed from changelogs/unreleased/frozen-string-enable-app-vestigial.yml)2
-rw-r--r--changelogs/unreleased/frozen-string-app-controller.yml5
-rw-r--r--changelogs/unreleased/frozen-string-app-controllers-much-more.yml5
-rw-r--r--changelogs/unreleased/frozen-string-app-enforce.yml5
-rw-r--r--changelogs/unreleased/frozen-string-docs.yml5
-rw-r--r--changelogs/unreleased/frozen-string-enable-app-mailers.yml5
-rw-r--r--changelogs/unreleased/frozen-string-enable-app-models-even-more-still.yml5
-rw-r--r--changelogs/unreleased/gitaly-install-path.yml5
-rw-r--r--changelogs/unreleased/ide-commit-panel-improved.yml5
-rw-r--r--changelogs/unreleased/ide-delete-new-files-state.yml5
-rw-r--r--changelogs/unreleased/ide-fetch-templates-pages.yml5
-rw-r--r--changelogs/unreleased/ide-file-templates.yml5
-rw-r--r--changelogs/unreleased/ide-header-buttons-tooltip.yml5
-rw-r--r--changelogs/unreleased/ide-job-top-bar-ui-polish.yml5
-rw-r--r--changelogs/unreleased/ide-multiple-file-uploads.yml5
-rw-r--r--changelogs/unreleased/ide-open-empty-merge-request.yml5
-rw-r--r--changelogs/unreleased/ide-row-hover-scroll.yml5
-rw-r--r--changelogs/unreleased/import-all-common-metrics-into-database.yml5
-rw-r--r--changelogs/unreleased/issue_36138.yml5
-rw-r--r--changelogs/unreleased/issue_50488.yml5
-rw-r--r--changelogs/unreleased/jivl-fix-monitoring-dashboard-resizing-navbar.yml5
-rw-r--r--changelogs/unreleased/jprovazn-fix-form-uploads.yml5
-rw-r--r--changelogs/unreleased/label-event.yml6
-rw-r--r--changelogs/unreleased/leipert-fix-mr-widget-header-margins.yml5
-rw-r--r--changelogs/unreleased/limit-navbar-search-for-current-project-or-group-for-small-viewports.yml5
-rw-r--r--changelogs/unreleased/mk-asymmetric-exists-cache.yml (renamed from changelogs/unreleased/sh-set-secure-cookies.yml)7
-rw-r--r--changelogs/unreleased/mk-bump-rainbow-gem.yml5
-rw-r--r--changelogs/unreleased/monaco-upgrade.yml5
-rw-r--r--changelogs/unreleased/more-table-widths.yml5
-rw-r--r--changelogs/unreleased/mr-fixed-expanded-state-not-working.yml5
-rw-r--r--changelogs/unreleased/mr-legacy-diff-notes.yml5
-rw-r--r--changelogs/unreleased/mr-widget-discussion-state-fix.yml5
-rw-r--r--changelogs/unreleased/n8rzz-consolidate-specs-testing-emoji-awards.yml6
-rw-r--r--changelogs/unreleased/osw-clean-up-phase-for-diff-files-removal.yml5
-rw-r--r--changelogs/unreleased/osw-gitaly-diff-stats-client.yml5
-rw-r--r--changelogs/unreleased/osw-send-max-patch-bytes-to-gitaly.yml5
-rw-r--r--changelogs/unreleased/osw-use-diff-stats-rpc-on-comparison-views.yml5
-rw-r--r--changelogs/unreleased/osw-write-cache-upon-mr-creation-and-cache-refactoring.yml5
-rw-r--r--changelogs/unreleased/pedroms-master-patch-57786.yml5
-rw-r--r--changelogs/unreleased/rails5-explicit-hashed-path-check.yml6
-rw-r--r--changelogs/unreleased/rails5-fix-duplicate-gpg-signature.yml5
-rw-r--r--changelogs/unreleased/rails5-fix-import-merge-request-creator.yml5
-rw-r--r--changelogs/unreleased/rails5-fix-job-artifact-hashed-path.yml6
-rw-r--r--changelogs/unreleased/rails5-include-opclasses-in-schema-dump.yml5
-rw-r--r--changelogs/unreleased/rails5-mysql-binary-column-index-length.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/rails5-verbose-query-logs.yml5
-rw-r--r--changelogs/unreleased/rd-26044-new-option-to-prevent-too-big-git-pushes.yml5
-rw-r--r--changelogs/unreleased/remove-background-migration-worker-feature-flag.yml5
-rw-r--r--changelogs/unreleased/remove-zebra-table-background.yml5
-rw-r--r--changelogs/unreleased/rename-local-variable.yml5
-rw-r--r--changelogs/unreleased/rename-squash-before-merge-vue-component.yml5
-rw-r--r--changelogs/unreleased/repopulate_site_statistics.yml5
-rw-r--r--changelogs/unreleased/runners-online.yml5
-rw-r--r--changelogs/unreleased/schema-changed-ee-backport.yml5
-rw-r--r--changelogs/unreleased/security-49085-persistent-xss-rendering.yml5
-rw-r--r--changelogs/unreleased/sh-add-ua-to-lograge-logs.yml5
-rw-r--r--changelogs/unreleased/sh-block-link-local-master.yml5
-rw-r--r--changelogs/unreleased/sh-bump-fog-google.yml5
-rw-r--r--changelogs/unreleased/sh-bump-gitlab-pages-v1-1-0.yml5
-rw-r--r--changelogs/unreleased/sh-bump-unauth-expiration.yml5
-rw-r--r--changelogs/unreleased/sh-delete-container-registry-async.yml5
-rw-r--r--changelogs/unreleased/sh-delete-tags-outside-transaction.yml5
-rw-r--r--changelogs/unreleased/sh-disable-sidekiq-session.yml5
-rw-r--r--changelogs/unreleased/sh-disable-unnecessary-avatar-revalidation.yml5
-rw-r--r--changelogs/unreleased/sh-fix-attachments-inline.yml5
-rw-r--r--changelogs/unreleased/sh-fix-bitbucket-cloud-importer-replies.yml5
-rw-r--r--changelogs/unreleased/sh-fix-confidential-note-option.yml5
-rw-r--r--changelogs/unreleased/sh-fix-dedupe-group-importer.yml5
-rw-r--r--changelogs/unreleased/sh-fix-error-500-updating-wikis.yml5
-rw-r--r--changelogs/unreleased/sh-fix-forks-with-no-gravatar.yml5
-rw-r--r--changelogs/unreleased/sh-fix-issue-50562.yml5
-rw-r--r--changelogs/unreleased/sh-fix-issue-52009.yml5
-rw-r--r--changelogs/unreleased/sh-guard-against-ldap-login-csrf-fail.yml5
-rw-r--r--changelogs/unreleased/sh-improve-bitbucket-server-logging.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-remove-orphaned-label-links.yml5
-rw-r--r--changelogs/unreleased/sh-sanitize-project-import-names.yml5
-rw-r--r--changelogs/unreleased/sh-send-put-headers-object-storage.yml5
-rw-r--r--changelogs/unreleased/skip-irrelevant-sql-commands-in-metrics.yml5
-rw-r--r--changelogs/unreleased/tc-api-fork-owners.yml5
-rw-r--r--changelogs/unreleased/toon-copy-meta-data-fix.yml5
-rw-r--r--changelogs/unreleased/tz-mr-incremental-rendering.yml4
-rw-r--r--changelogs/unreleased/update-gitlab-shell-8-3-3.yml5
-rw-r--r--changelogs/unreleased/update-gitlab-shell.yml5
-rw-r--r--changelogs/unreleased/update-padding-markdown.yml5
-rw-r--r--changelogs/unreleased/usage_consent.yml5
-rw-r--r--changelogs/unreleased/vendor-gitlab-ci-auto-devops-yml.yml5
-rw-r--r--changelogs/unreleased/visual-improvements-language-bar.yml5
-rw-r--r--changelogs/unreleased/winh-default-status-emoji.yml5
-rw-r--r--changelogs/unreleased/winh-move-badge-settings.yml5
-rw-r--r--changelogs/unreleased/winh-page-title-margin.yml5
-rw-r--r--changelogs/unreleased/zj-cleanup-port-gitaly.yml5
-rw-r--r--config/application.rb3
-rw-r--r--config/gitlab.yml.example4
-rw-r--r--config/initializers/0_post_deployment_migrations.rb12
-rw-r--r--config/initializers/devise.rb2
-rw-r--r--config/initializers/postgresql_opclasses_support.rb4
-rw-r--r--config/initializers/sidekiq.rb2
-rw-r--r--config/initializers/warden.rb5
-rw-r--r--config/routes/admin.rb1
-rw-r--r--config/routes/instance_statistics.rb2
-rw-r--r--config/routes/wiki.rb2
-rw-r--r--danger/commit_messages/Dangerfile45
-rw-r--r--db/migrate/20170222111732_create_gpg_keys.rb6
-rw-r--r--db/migrate/20170613154149_create_gpg_signatures.rb6
-rw-r--r--db/migrate/20170827123848_add_index_on_merge_request_diff_commit_sha.rb2
-rw-r--r--db/migrate/20170927161718_create_gpg_key_subkeys.rb6
-rw-r--r--db/migrate/20180813101999_change_default_of_auto_devops_instance_wide.rb15
-rw-r--r--db/migrate/20180813102000_enable_auto_devops_instance_wide_for_everyone.rb15
-rw-r--r--db/migrate/20180907015926_add_legacy_abac_to_cluster_providers_gcp.rb17
-rw-r--r--db/migrate/20180916011959_add_index_pipelines_project_id_source.rb20
-rw-r--r--db/post_migrate/20180913051323_consume_remaining_diff_files_deletion_jobs.rb23
-rw-r--r--db/post_migrate/20180914201132_remove_sidekiq_throttling_from_application_settings.rb17
-rw-r--r--db/post_migrate/20180916014356_populate_external_pipeline_source.rb33
-rw-r--r--db/post_migrate/20180917172041_remove_wikis_count_from_site_statistics.rb6
-rw-r--r--db/schema.rb10
-rw-r--r--doc/README.md2
-rw-r--r--doc/administration/auth/ldap.md4
-rw-r--r--doc/administration/external_database.md2
-rw-r--r--doc/administration/gitaly/index.md8
-rw-r--r--doc/administration/high_availability/database.md2
-rw-r--r--doc/administration/high_availability/redis.md10
-rw-r--r--doc/administration/high_availability/redis_source.md4
-rw-r--r--doc/administration/index.md2
-rw-r--r--doc/administration/job_artifacts.md1
-rw-r--r--doc/administration/logs.md6
-rw-r--r--doc/administration/operations/img/sidekiq_job_throttling.pngbin32224 -> 0 bytes
-rw-r--r--doc/administration/operations/index.md2
-rw-r--r--doc/administration/operations/sidekiq_job_throttling.md33
-rw-r--r--doc/administration/operations/ssh_certificates.md4
-rw-r--r--doc/administration/raketasks/maintenance.md8
-rw-r--r--doc/administration/raketasks/uploads/migrate.md37
-rw-r--r--doc/administration/reply_by_email.md2
-rw-r--r--doc/administration/reply_by_email_postfix_setup.md2
-rw-r--r--doc/administration/repository_checks.md3
-rw-r--r--doc/administration/uploads.md3
-rw-r--r--doc/api/commits.md12
-rw-r--r--doc/api/deployments.md45
-rw-r--r--doc/api/jobs.md95
-rw-r--r--doc/api/keys.md8
-rw-r--r--doc/api/members.md2
-rw-r--r--doc/api/merge_requests.md5
-rw-r--r--doc/api/oauth2.md8
-rw-r--r--doc/api/protected_branches.md2
-rw-r--r--doc/api/repository_files.md6
-rw-r--r--doc/api/runners.md23
-rw-r--r--doc/api/settings.md5
-rw-r--r--doc/api/users.md4
-rw-r--r--doc/ci/README.md2
-rw-r--r--doc/ci/autodeploy/quick_start_guide.md4
-rw-r--r--doc/ci/caching/index.md12
-rw-r--r--doc/ci/docker/using_docker_build.md4
-rw-r--r--doc/ci/environments.md2
-rw-r--r--doc/ci/examples/README.md6
-rw-r--r--doc/ci/examples/browser_performance.md2
-rw-r--r--doc/ci/examples/devops_and_game_dev_with_gitlab_ci_cd/index.md2
-rw-r--r--doc/ci/examples/laravel_with_gitlab_and_envoy/index.md8
-rw-r--r--doc/ci/examples/php.md2
-rw-r--r--doc/ci/examples/test-scala-application.md2
-rw-r--r--doc/ci/interactive_web_terminal/index.md2
-rw-r--r--doc/ci/junit_test_reports.md21
-rw-r--r--doc/ci/runners/README.md6
-rw-r--r--doc/ci/yaml/README.md14
-rw-r--r--doc/development/README.md12
-rw-r--r--doc/development/automatic_ce_ee_merge.md2
-rw-r--r--doc/development/contributing/community_roles.md12
-rw-r--r--doc/development/contributing/design.md53
-rw-r--r--doc/development/contributing/index.md39
-rw-r--r--doc/development/contributing/issue_workflow.md60
-rw-r--r--doc/development/contributing/merge_request_workflow.md17
-rw-r--r--doc/development/database_debugging.md2
-rw-r--r--doc/development/database_helpers.md63
-rw-r--r--doc/development/documentation/index.md123
-rw-r--r--doc/development/documentation/styleguide.md20
-rw-r--r--doc/development/fe_guide/components.md2
-rw-r--r--doc/development/feature_flags.md7
-rw-r--r--doc/development/file_storage.md7
-rw-r--r--doc/development/gitaly.md2
-rw-r--r--doc/development/i18n/index.md2
-rw-r--r--doc/development/i18n/merging_translations.md60
-rw-r--r--doc/development/i18n/proofreader.md1
-rw-r--r--doc/development/merge_request_performance_guidelines.md5
-rw-r--r--doc/development/module_with_instance_variables.md2
-rw-r--r--doc/development/ordering_table_columns.md73
-rw-r--r--doc/development/performance.md6
-rw-r--r--doc/development/rake_tasks.md2
-rw-r--r--doc/development/rolling_out_changes_using_feature_flags.md153
-rw-r--r--doc/development/testing_guide/index.md6
-rw-r--r--doc/development/testing_guide/review_apps.md82
-rw-r--r--doc/development/ux_guide/users.md6
-rw-r--r--doc/gitlab-basics/add-image.md2
-rw-r--r--doc/install/azure/index.md12
-rw-r--r--doc/install/database_mysql.md2
-rw-r--r--doc/install/digitaloceandocker.md2
-rw-r--r--doc/install/installation.md2
-rw-r--r--doc/install/kubernetes/gitlab_chart.md2
-rw-r--r--doc/install/openshift_and_gitlab/index.md2
-rw-r--r--doc/install/relative_url.md2
-rw-r--r--doc/install/requirements.md12
-rw-r--r--doc/integration/github.md4
-rw-r--r--doc/integration/gmail_action_buttons_for_gitlab.md2
-rw-r--r--doc/policy/maintenance.md2
-rw-r--r--doc/raketasks/backup_restore.md5
-rw-r--r--doc/security/two_factor_authentication.md2
-rw-r--r--doc/security/user_email_confirmation.md2
-rw-r--r--doc/topics/authentication/index.md2
-rw-r--r--doc/topics/autodevops/index.md24
-rw-r--r--doc/university/README.md2
-rw-r--r--doc/university/glossary/README.md4
-rw-r--r--doc/university/high-availability/aws/README.md2
-rw-r--r--doc/university/support/README.md2
-rw-r--r--doc/university/training/end-user/README.md2
-rw-r--r--doc/update/4.2-to-5.0.md2
-rw-r--r--doc/update/7.5-to-7.6.md2
-rw-r--r--doc/update/7.6-to-7.7.md2
-rw-r--r--doc/update/7.7-to-7.8.md2
-rw-r--r--doc/update/7.8-to-7.9.md2
-rw-r--r--doc/update/7.9-to-7.10.md2
-rw-r--r--doc/update/9.4-to-9.5.md2
-rw-r--r--doc/update/9.5-to-10.0.md2
-rw-r--r--doc/update/README.md3
-rw-r--r--doc/user/gitlab_com/index.md2
-rw-r--r--doc/user/group/subgroups/index.md32
-rw-r--r--doc/user/index.md2
-rw-r--r--doc/user/profile/account/delete_account.md3
-rw-r--r--doc/user/profile/account/two_factor_authentication.md2
-rw-r--r--doc/user/project/clusters/index.md91
-rw-r--r--doc/user/project/container_registry.md8
-rw-r--r--doc/user/project/cycle_analytics.md2
-rw-r--r--doc/user/project/deploy_tokens/index.md2
-rw-r--r--doc/user/project/img/issue_board_milestone_lists.pngbin0 -> 58740 bytes
-rw-r--r--doc/user/project/img/issue_board_summed_weights.pngbin0 -> 26691 bytes
-rwxr-xr-xdoc/user/project/img/issue_boards_core.pngbin0 -> 61230 bytes
-rwxr-xr-xdoc/user/project/img/issue_boards_premium.pngbin0 -> 72434 bytes
-rw-r--r--doc/user/project/integrations/hangouts_chat.md2
-rw-r--r--doc/user/project/integrations/img/webhooks_ssl.pngbin27790 -> 58529 bytes
-rw-r--r--doc/user/project/integrations/jira.md2
-rw-r--r--doc/user/project/integrations/mattermost.md2
-rw-r--r--doc/user/project/integrations/mattermost_slash_commands.md2
-rw-r--r--doc/user/project/integrations/microsoft_teams.md2
-rw-r--r--doc/user/project/integrations/mock_ci.md2
-rw-r--r--doc/user/project/integrations/prometheus.md2
-rw-r--r--doc/user/project/integrations/webhooks.md10
-rw-r--r--doc/user/project/issue_board.md289
-rw-r--r--doc/user/project/issues/issues_functionalities.md2
-rw-r--r--doc/user/project/pages/img/icons/click.pngbin0 -> 10148 bytes
-rw-r--r--doc/user/project/pages/img/icons/cogs.pngbin0 -> 9670 bytes
-rw-r--r--doc/user/project/pages/img/icons/fork.pngbin0 -> 9597 bytes
-rw-r--r--doc/user/project/pages/img/icons/free.pngbin0 -> 8689 bytes
-rw-r--r--doc/user/project/pages/img/icons/lock.pngbin0 -> 7892 bytes
-rw-r--r--doc/user/project/pages/img/icons/monitor.pngbin0 -> 5039 bytes
-rw-r--r--doc/user/project/pages/img/icons/terminal.pngbin0 -> 4972 bytes
-rw-r--r--doc/user/project/pages/img/ssgs_pages.pngbin0 -> 12010 bytes
-rw-r--r--doc/user/project/pages/index.md188
-rw-r--r--doc/user/project/pipelines/job_artifacts.md14
-rw-r--r--doc/user/project/repository/index.md4
-rw-r--r--doc/user/project/wiki/index.md13
-rw-r--r--doc/workflow/lfs/lfs_administration.md3
-rw-r--r--lib/api/commits.rb21
-rw-r--r--lib/api/entities.rb2
-rw-r--r--lib/api/protected_branches.rb4
-rw-r--r--lib/api/protected_tags.rb2
-rw-r--r--lib/api/runners.rb31
-rw-r--r--lib/api/settings.rb7
-rw-r--r--lib/banzai/filter/abstract_reference_filter.rb4
-rw-r--r--lib/banzai/filter/external_issue_reference_filter.rb4
-rw-r--r--lib/banzai/filter/relative_link_filter.rb6
-rw-r--r--lib/banzai/reference_parser/base_parser.rb4
-rw-r--r--lib/banzai/request_store_reference_cache.rb4
-rw-r--r--lib/event_filter.rb86
-rw-r--r--lib/extracts_path.rb2
-rw-r--r--lib/feature.rb12
-rw-r--r--lib/gitlab/auth/ldap/access.rb6
-rw-r--r--lib/gitlab/background_migration/populate_external_pipeline_source.rb50
-rw-r--r--lib/gitlab/cache/request_cache.rb4
-rw-r--r--lib/gitlab/ci/config/entry/reports.rb8
-rw-r--r--lib/gitlab/ci/parsers.rb9
-rw-r--r--lib/gitlab/ci/parsers/junit.rb66
-rw-r--r--lib/gitlab/ci/parsers/test.rb21
-rw-r--r--lib/gitlab/ci/parsers/test/junit.rb70
-rw-r--r--lib/gitlab/ci/templates/Android.gitlab-ci.yml (renamed from vendor/gitlab-ci-yml/Android.gitlab-ci.yml)0
-rw-r--r--lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml (renamed from vendor/gitlab-ci-yml/Auto-DevOps.gitlab-ci.yml)39
-rw-r--r--lib/gitlab/ci/templates/Bash.gitlab-ci.yml (renamed from vendor/gitlab-ci-yml/Bash.gitlab-ci.yml)0
-rw-r--r--lib/gitlab/ci/templates/C++.gitlab-ci.yml (renamed from vendor/gitlab-ci-yml/C++.gitlab-ci.yml)0
-rw-r--r--lib/gitlab/ci/templates/Chef.gitlab-ci.yml (renamed from vendor/gitlab-ci-yml/Chef.gitlab-ci.yml)0
-rw-r--r--lib/gitlab/ci/templates/Clojure.gitlab-ci.yml (renamed from vendor/gitlab-ci-yml/Clojure.gitlab-ci.yml)0
-rw-r--r--lib/gitlab/ci/templates/Crystal.gitlab-ci.yml (renamed from vendor/gitlab-ci-yml/Crystal.gitlab-ci.yml)0
-rw-r--r--lib/gitlab/ci/templates/Django.gitlab-ci.yml (renamed from vendor/gitlab-ci-yml/Django.gitlab-ci.yml)0
-rw-r--r--lib/gitlab/ci/templates/Docker.gitlab-ci.yml (renamed from vendor/gitlab-ci-yml/Docker.gitlab-ci.yml)0
-rw-r--r--lib/gitlab/ci/templates/Elixir.gitlab-ci.yml (renamed from vendor/gitlab-ci-yml/Elixir.gitlab-ci.yml)0
-rw-r--r--lib/gitlab/ci/templates/Go.gitlab-ci.yml (renamed from vendor/gitlab-ci-yml/Go.gitlab-ci.yml)0
-rw-r--r--lib/gitlab/ci/templates/Gradle.gitlab-ci.yml (renamed from vendor/gitlab-ci-yml/Gradle.gitlab-ci.yml)0
-rw-r--r--lib/gitlab/ci/templates/Grails.gitlab-ci.yml (renamed from vendor/gitlab-ci-yml/Grails.gitlab-ci.yml)0
-rw-r--r--lib/gitlab/ci/templates/Julia.gitlab-ci.yml (renamed from vendor/gitlab-ci-yml/Julia.gitlab-ci.yml)54
-rw-r--r--lib/gitlab/ci/templates/LaTeX.gitlab-ci.yml (renamed from vendor/gitlab-ci-yml/LaTeX.gitlab-ci.yml)0
-rw-r--r--lib/gitlab/ci/templates/Laravel.gitlab-ci.yml (renamed from vendor/gitlab-ci-yml/Laravel.gitlab-ci.yml)0
-rw-r--r--lib/gitlab/ci/templates/Maven.gitlab-ci.yml (renamed from vendor/gitlab-ci-yml/Maven.gitlab-ci.yml)0
-rw-r--r--lib/gitlab/ci/templates/Mono.gitlab-ci.yml (renamed from vendor/gitlab-ci-yml/Mono.gitlab-ci.yml)0
-rw-r--r--lib/gitlab/ci/templates/Nodejs.gitlab-ci.yml (renamed from vendor/gitlab-ci-yml/Nodejs.gitlab-ci.yml)0
-rw-r--r--lib/gitlab/ci/templates/OpenShift.gitlab-ci.yml (renamed from vendor/gitlab-ci-yml/OpenShift.gitlab-ci.yml)0
-rw-r--r--lib/gitlab/ci/templates/PHP.gitlab-ci.yml (renamed from vendor/gitlab-ci-yml/PHP.gitlab-ci.yml)0
-rw-r--r--lib/gitlab/ci/templates/Packer.gitlab-ci.yml (renamed from vendor/gitlab-ci-yml/Packer.gitlab-ci.yml)0
-rw-r--r--lib/gitlab/ci/templates/Pages/Brunch.gitlab-ci.yml (renamed from vendor/gitlab-ci-yml/Pages/Brunch.gitlab-ci.yml)0
-rw-r--r--lib/gitlab/ci/templates/Pages/Doxygen.gitlab-ci.yml (renamed from vendor/gitlab-ci-yml/Pages/Doxygen.gitlab-ci.yml)0
-rw-r--r--lib/gitlab/ci/templates/Pages/Gatsby.gitlab-ci.yml (renamed from vendor/gitlab-ci-yml/Pages/Gatsby.gitlab-ci.yml)0
-rw-r--r--lib/gitlab/ci/templates/Pages/HTML.gitlab-ci.yml (renamed from vendor/gitlab-ci-yml/Pages/HTML.gitlab-ci.yml)0
-rw-r--r--lib/gitlab/ci/templates/Pages/Harp.gitlab-ci.yml (renamed from vendor/gitlab-ci-yml/Pages/Harp.gitlab-ci.yml)0
-rw-r--r--lib/gitlab/ci/templates/Pages/Hexo.gitlab-ci.yml (renamed from vendor/gitlab-ci-yml/Pages/Hexo.gitlab-ci.yml)0
-rw-r--r--lib/gitlab/ci/templates/Pages/Hugo.gitlab-ci.yml (renamed from vendor/gitlab-ci-yml/Pages/Hugo.gitlab-ci.yml)0
-rw-r--r--lib/gitlab/ci/templates/Pages/Hyde.gitlab-ci.yml (renamed from vendor/gitlab-ci-yml/Pages/Hyde.gitlab-ci.yml)0
-rw-r--r--lib/gitlab/ci/templates/Pages/JBake.gitlab-ci.yml (renamed from vendor/gitlab-ci-yml/Pages/JBake.gitlab-ci.yml)0
-rw-r--r--lib/gitlab/ci/templates/Pages/Jekyll.gitlab-ci.yml (renamed from vendor/gitlab-ci-yml/Pages/Jekyll.gitlab-ci.yml)0
-rw-r--r--lib/gitlab/ci/templates/Pages/Jigsaw.gitlab-ci.yml42
-rw-r--r--lib/gitlab/ci/templates/Pages/Lektor.gitlab-ci.yml (renamed from vendor/gitlab-ci-yml/Pages/Lektor.gitlab-ci.yml)0
-rw-r--r--lib/gitlab/ci/templates/Pages/Metalsmith.gitlab-ci.yml (renamed from vendor/gitlab-ci-yml/Pages/Metalsmith.gitlab-ci.yml)0
-rw-r--r--lib/gitlab/ci/templates/Pages/Middleman.gitlab-ci.yml (renamed from vendor/gitlab-ci-yml/Pages/Middleman.gitlab-ci.yml)0
-rw-r--r--lib/gitlab/ci/templates/Pages/Nanoc.gitlab-ci.yml (renamed from vendor/gitlab-ci-yml/Pages/Nanoc.gitlab-ci.yml)0
-rw-r--r--lib/gitlab/ci/templates/Pages/Octopress.gitlab-ci.yml (renamed from vendor/gitlab-ci-yml/Pages/Octopress.gitlab-ci.yml)0
-rw-r--r--lib/gitlab/ci/templates/Pages/Pelican.gitlab-ci.yml (renamed from vendor/gitlab-ci-yml/Pages/Pelican.gitlab-ci.yml)0
-rw-r--r--lib/gitlab/ci/templates/Python.gitlab-ci.yml (renamed from vendor/gitlab-ci-yml/Python.gitlab-ci.yml)0
-rw-r--r--lib/gitlab/ci/templates/Ruby.gitlab-ci.yml (renamed from vendor/gitlab-ci-yml/Ruby.gitlab-ci.yml)0
-rw-r--r--lib/gitlab/ci/templates/Rust.gitlab-ci.yml (renamed from vendor/gitlab-ci-yml/Rust.gitlab-ci.yml)0
-rw-r--r--lib/gitlab/ci/templates/Scala.gitlab-ci.yml (renamed from vendor/gitlab-ci-yml/Scala.gitlab-ci.yml)0
-rw-r--r--lib/gitlab/ci/templates/Swift.gitlab-ci.yml (renamed from vendor/gitlab-ci-yml/Swift.gitlab-ci.yml)0
-rw-r--r--lib/gitlab/ci/templates/Terraform.gitlab-ci.yml (renamed from vendor/gitlab-ci-yml/Terraform.gitlab-ci.yml)0
-rw-r--r--lib/gitlab/ci/templates/dotNET.gitlab-ci.yml (renamed from vendor/gitlab-ci-yml/dotNET.gitlab-ci.yml)0
-rw-r--r--lib/gitlab/contributions_calendar.rb5
-rw-r--r--lib/gitlab/current_settings.rb6
-rw-r--r--lib/gitlab/database.rb16
-rw-r--r--lib/gitlab/database/grant.rb6
-rw-r--r--lib/gitlab/database/migration_helpers.rb4
-rw-r--r--lib/gitlab/database/subquery.rb24
-rw-r--r--lib/gitlab/diff/file.rb7
-rw-r--r--lib/gitlab/diff/file_collection/base.rb25
-rw-r--r--lib/gitlab/diff/position.rb26
-rw-r--r--lib/gitlab/favicon.rb2
-rw-r--r--lib/gitlab/git/diff_stats_collection.rb30
-rw-r--r--lib/gitlab/git/hook_env.rb10
-rw-r--r--lib/gitlab/git/repository.rb20
-rw-r--r--lib/gitlab/git/storage/circuit_breaker.rb2
-rw-r--r--lib/gitlab/git/storage/failure_info.rb2
-rw-r--r--lib/gitlab/git/wiki.rb6
-rw-r--r--lib/gitlab/gitaly_client.rb78
-rw-r--r--lib/gitlab/gitaly_client/commit_service.rb42
-rw-r--r--lib/gitlab/gitaly_client/operation_service.rb3
-rw-r--r--lib/gitlab/gitaly_client/storage_settings.rb2
-rw-r--r--lib/gitlab/group_hierarchy.rb8
-rw-r--r--lib/gitlab/import_export/project_tree_restorer.rb15
-rw-r--r--lib/gitlab/import_export/relation_factory.rb3
-rw-r--r--lib/gitlab/issuables_count_for_state.rb9
-rw-r--r--lib/gitlab/kubernetes/kube_client.rb2
-rw-r--r--lib/gitlab/kubernetes/service_account_token.rb36
-rw-r--r--lib/gitlab/logger.rb2
-rw-r--r--lib/gitlab/null_request_store.rb41
-rw-r--r--lib/gitlab/performance_bar/peek_query_tracker.rb2
-rw-r--r--lib/gitlab/project_authorizations/with_nested_groups.rb4
-rw-r--r--lib/gitlab/project_authorizations/without_nested_groups.rb4
-rw-r--r--lib/gitlab/repository_cache.rb16
-rw-r--r--lib/gitlab/repository_cache_adapter.rb181
-rw-r--r--lib/gitlab/request_context.rb4
-rw-r--r--lib/gitlab/safe_request_store.rb23
-rw-r--r--lib/gitlab/sidekiq_throttler.rb25
-rw-r--r--lib/gitlab/template/finders/global_template_finder.rb2
-rw-r--r--lib/gitlab/template/finders/repo_template_finder.rb2
-rw-r--r--lib/gitlab/template/gitlab_ci_yml_template.rb2
-rw-r--r--lib/gitlab/temporarily_allow.rb6
-rw-r--r--lib/gitlab/testing/request_inspector_middleware.rb6
-rw-r--r--lib/gitlab/tree_summary.rb28
-rw-r--r--lib/gitlab/user_extractor.rb6
-rw-r--r--lib/google_api/cloud_platform/client.rb4
-rw-r--r--lib/quality/helm_client.rb47
-rw-r--r--lib/quality/kubernetes_client.rb32
-rw-r--r--lib/support/nginx/gitlab4
-rw-r--r--lib/support/nginx/gitlab-ssl4
-rw-r--r--lib/system_check/incoming_email/imap_authentication_check.rb2
-rw-r--r--lib/tasks/gemojione.rake2
-rw-r--r--lib/tasks/gitlab/artifacts/migrate.rake2
-rw-r--r--lib/tasks/gitlab/db.rake2
-rw-r--r--lib/tasks/gitlab/shell.rake46
-rw-r--r--lib/tasks/gitlab/site_statistics.rake8
-rw-r--r--lib/tasks/gitlab/update_templates.rake4
-rw-r--r--lib/tasks/gitlab/uploads/migrate.rake26
-rw-r--r--locale/ar_SA/gitlab.po10
-rw-r--r--locale/bg/gitlab.po12
-rw-r--r--locale/ca_ES/gitlab.po10
-rw-r--r--locale/cs_CZ/gitlab.po10
-rw-r--r--locale/da_DK/gitlab.po10
-rw-r--r--locale/de/gitlab.po12
-rw-r--r--locale/eo/gitlab.po10
-rw-r--r--locale/es/gitlab.po12
-rw-r--r--locale/et_EE/gitlab.po10
-rw-r--r--locale/fil_PH/gitlab.po10
-rw-r--r--locale/fr/gitlab.po16
-rw-r--r--locale/gitlab.pot78
-rw-r--r--locale/gl_ES/gitlab.po10
-rw-r--r--locale/he_IL/gitlab.po10
-rw-r--r--locale/id_ID/gitlab.po10
-rw-r--r--locale/it/gitlab.po20
-rw-r--r--locale/ja/gitlab.po10
-rw-r--r--locale/ko/gitlab.po10
-rw-r--r--locale/nl_NL/gitlab.po10
-rw-r--r--locale/pl_PL/gitlab.po10
-rw-r--r--locale/pt_BR/gitlab.po24
-rw-r--r--locale/ro_RO/gitlab.po10
-rw-r--r--locale/ru/gitlab.po12
-rw-r--r--locale/sq_AL/gitlab.po10
-rw-r--r--locale/tr_TR/gitlab.po10
-rw-r--r--locale/uk/gitlab.po28
-rw-r--r--locale/zh_CN/gitlab.po14
-rw-r--r--locale/zh_HK/gitlab.po10
-rw-r--r--locale/zh_TW/gitlab.po16
-rw-r--r--package.json54
-rw-r--r--qa/qa.rb2
-rw-r--r--qa/qa/factory/repository/project_push.rb18
-rw-r--r--qa/qa/factory/repository/push.rb18
-rw-r--r--qa/qa/factory/repository/wiki_push.rb4
-rw-r--r--qa/qa/factory/resource/branch.rb2
-rw-r--r--qa/qa/factory/resource/fork.rb37
-rw-r--r--qa/qa/factory/resource/kubernetes_cluster.rb2
-rw-r--r--qa/qa/factory/resource/project.rb7
-rw-r--r--qa/qa/factory/resource/ssh_key.rb40
-rw-r--r--qa/qa/factory/resource/user.rb5
-rw-r--r--qa/qa/git/repository.rb37
-rw-r--r--qa/qa/page/admin/settings/main.rb4
-rw-r--r--qa/qa/page/base.rb4
-rw-r--r--qa/qa/page/group/show.rb35
-rw-r--r--qa/qa/page/main/login.rb84
-rw-r--r--qa/qa/page/main/sign_up.rb2
-rw-r--r--qa/qa/page/menu/main.rb9
-rw-r--r--qa/qa/page/menu/profile.rb7
-rw-r--r--qa/qa/page/menu/side.rb3
-rw-r--r--qa/qa/page/merge_request/show.rb22
-rw-r--r--qa/qa/page/profile/ssh_keys.rb34
-rw-r--r--qa/qa/page/project/activity.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/1_manage/login/register_spec.rb30
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/repository/add_ssh_key_spec.rb31
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/repository/use_ssh_key_spec.rb40
-rw-r--r--qa/qa/specs/features/sanity/framework_spec.rb4
-rw-r--r--rubocop/cop/avoid_route_redirect_leading_slash.rb52
-rw-r--r--rubocop/cop/gitlab/union.rb27
-rw-r--r--rubocop/cop/ruby_interpolation_in_translation.rb1
-rw-r--r--rubocop/rubocop.rb2
-rwxr-xr-xscripts/review_apps/automated_cleanup.rb109
-rwxr-xr-xscripts/review_apps/review-apps.sh184
-rwxr-xr-xscripts/trigger-build210
-rwxr-xr-xscripts/trigger-build-docs6
-rw-r--r--spec/controllers/application_controller_spec.rb34
-rw-r--r--spec/controllers/import/gitlab_projects_controller_spec.rb2
-rw-r--r--spec/controllers/oauth/applications_controller_spec.rb34
-rw-r--r--spec/controllers/projects/clusters_controller_spec.rb16
-rw-r--r--spec/controllers/projects/jobs_controller_spec.rb149
-rw-r--r--spec/controllers/projects/notes_controller_spec.rb8
-rw-r--r--spec/controllers/projects/pipelines_controller_spec.rb46
-rw-r--r--spec/factories/ci/job_artifacts.rb27
-rw-r--r--spec/factories/events.rb2
-rw-r--r--spec/factories/site_statistics.rb1
-rw-r--r--spec/factories/users.rb8
-rw-r--r--spec/features/admin/admin_runners_spec.rb78
-rw-r--r--spec/features/admin/admin_settings_spec.rb505
-rw-r--r--spec/features/admin/admin_uses_repository_checks_spec.rb2
-rw-r--r--spec/features/dashboard/group_spec.rb2
-rw-r--r--spec/features/dashboard/projects_spec.rb8
-rw-r--r--spec/features/issues/filtered_search/filter_issues_spec.rb2
-rw-r--r--spec/features/labels_hierarchy_spec.rb2
-rw-r--r--spec/features/merge_request/user_posts_diff_notes_spec.rb15
-rw-r--r--spec/features/merge_request/user_posts_notes_spec.rb4
-rw-r--r--spec/features/merge_request/user_resolves_conflicts_spec.rb18
-rw-r--r--spec/features/merge_request/user_resolves_diff_notes_and_discussions_resolve_spec.rb79
-rw-r--r--spec/features/merge_request/user_sees_merge_widget_spec.rb4
-rw-r--r--spec/features/projects/activity/user_sees_activity_spec.rb12
-rw-r--r--spec/features/projects/artifacts/user_downloads_artifacts_spec.rb14
-rw-r--r--spec/features/projects/blobs/blob_show_spec.rb6
-rw-r--r--spec/features/projects/clusters/gcp_spec.rb52
-rw-r--r--spec/features/projects/clusters/user_spec.rb56
-rw-r--r--spec/features/projects/fork_spec.rb12
-rw-r--r--spec/features/projects/import_export/export_file_spec.rb2
-rw-r--r--spec/features/projects/jobs_spec.rb58
-rw-r--r--spec/features/projects/members/invite_group_spec.rb4
-rw-r--r--spec/features/projects/pipelines/pipelines_spec.rb2
-rw-r--r--spec/features/projects/services/user_activates_mattermost_slash_command_spec.rb2
-rw-r--r--spec/features/projects/settings/user_tags_project_spec.rb14
-rw-r--r--spec/features/projects/show/user_sees_setup_shortcut_buttons_spec.rb184
-rw-r--r--spec/features/projects/tree/create_directory_spec.rb2
-rw-r--r--spec/features/projects/tree/create_file_spec.rb2
-rw-r--r--spec/features/runners_spec.rb4
-rw-r--r--spec/features/snippets/notes_on_personal_snippets_spec.rb2
-rw-r--r--spec/features/snippets/user_sees_breadcrumb_links.rb17
-rw-r--r--spec/features/u2f_spec.rb10
-rw-r--r--spec/finders/admin/runners_finder_spec.rb8
-rw-r--r--spec/finders/group_labels_finder_spec.rb33
-rw-r--r--spec/fixtures/api/schemas/deployment.json70
-rw-r--r--spec/fixtures/api/schemas/entities/commit.json27
-rw-r--r--spec/fixtures/api/schemas/entities/user.json12
-rw-r--r--spec/fixtures/api/schemas/environment.json38
-rw-r--r--spec/fixtures/api/schemas/job/deployment_status.json27
-rw-r--r--spec/fixtures/api/schemas/job/job.json4
-rw-r--r--spec/fixtures/api/schemas/job/job_details.json12
-rw-r--r--spec/fixtures/api/schemas/job/runner.json17
-rw-r--r--spec/fixtures/api/schemas/job/runners.json13
-rw-r--r--spec/fixtures/api/schemas/pipeline_stage.json5
-rw-r--r--spec/fixtures/api/schemas/types/nullable_string.json6
-rw-r--r--spec/helpers/application_helper_spec.rb63
-rw-r--r--spec/helpers/auto_devops_helper_spec.rb10
-rw-r--r--spec/helpers/avatars_helper_spec.rb24
-rw-r--r--spec/helpers/commits_helper_spec.rb2
-rw-r--r--spec/helpers/tab_helper_spec.rb76
-rw-r--r--spec/javascripts/.eslintrc.yml6
-rw-r--r--spec/javascripts/behaviors/shortcuts/shortcuts_issuable_spec.js (renamed from spec/javascripts/shortcuts_issuable_spec.js)2
-rw-r--r--spec/javascripts/boards/board_blank_state_spec.js4
-rw-r--r--spec/javascripts/boards/modal_store_spec.js2
-rw-r--r--spec/javascripts/close_reopen_report_toggle_spec.js2
-rw-r--r--spec/javascripts/deploy_keys/components/app_spec.js2
-rw-r--r--spec/javascripts/diffs/components/app_spec.js8
-rw-r--r--spec/javascripts/diffs/components/commit_item_spec.js128
-rw-r--r--spec/javascripts/diffs/components/commit_widget_spec.js24
-rw-r--r--spec/javascripts/diffs/components/diff_line_note_form_spec.js29
-rw-r--r--spec/javascripts/diffs/mock_data/diff_with_commit.js12
-rw-r--r--spec/javascripts/diffs/store/actions_spec.js201
-rw-r--r--spec/javascripts/diffs/store/mutations_spec.js71
-rw-r--r--spec/javascripts/diffs/store/utils_spec.js124
-rw-r--r--spec/javascripts/fixtures/merge_requests_diffs.rb14
-rw-r--r--spec/javascripts/ide/components/commit_sidebar/list_item_spec.js4
-rw-r--r--spec/javascripts/ide/components/file_row_extra_spec.js159
-rw-r--r--spec/javascripts/ide/components/ide_status_bar_spec.js5
-rw-r--r--spec/javascripts/ide/components/panes/right_spec.js24
-rw-r--r--spec/javascripts/ide/components/repo_commit_section_spec.js59
-rw-r--r--spec/javascripts/ide/components/repo_editor_spec.js4
-rw-r--r--spec/javascripts/ide/components/repo_file_spec.js145
-rw-r--r--spec/javascripts/ide/components/repo_loading_file_spec.js63
-rw-r--r--spec/javascripts/ide/helpers.js2
-rw-r--r--spec/javascripts/ide/stores/modules/file_templates/actions_spec.js46
-rw-r--r--spec/javascripts/ide/stores/modules/pane/actions_spec.js87
-rw-r--r--spec/javascripts/ide/stores/modules/pane/getters_spec.js61
-rw-r--r--spec/javascripts/ide/stores/modules/pane/mutations_spec.js42
-rw-r--r--spec/javascripts/ide/stores/modules/pipelines/actions_spec.js10
-rw-r--r--spec/javascripts/issue_show/components/edit_actions_spec.js13
-rw-r--r--spec/javascripts/issue_show/components/form_spec.js1
-rw-r--r--spec/javascripts/jobs/components/artifacts_block_spec.js66
-rw-r--r--spec/javascripts/jobs/components/commit_block_spec.js41
-rw-r--r--spec/javascripts/jobs/components/empty_state_spec.js2
-rw-r--r--spec/javascripts/jobs/components/erased_block_spec.js8
-rw-r--r--spec/javascripts/jobs/components/job_details_mediator_spec.js39
-rw-r--r--spec/javascripts/jobs/components/job_log_controllers_spec.js167
-rw-r--r--spec/javascripts/jobs/components/job_log_spec.js6
-rw-r--r--spec/javascripts/jobs/components/job_store_spec.js26
-rw-r--r--spec/javascripts/jobs/components/trigger_block_spec.js (renamed from spec/javascripts/jobs/components/trigger_value_spec.js)25
-rw-r--r--spec/javascripts/jobs/store/mutations_spec.js7
-rw-r--r--spec/javascripts/lib/utils/navigation_utility_spec.js (renamed from spec/javascripts/shortcuts_dashboard_navigation_spec.js)2
-rw-r--r--spec/javascripts/lib/utils/poll_spec.js2
-rw-r--r--spec/javascripts/monitoring/dashboard_spec.js42
-rw-r--r--spec/javascripts/monitoring/graph_spec.js18
-rw-r--r--spec/javascripts/notes/stores/actions_spec.js192
-rw-r--r--spec/javascripts/notes/stores/mutation_spec.js35
-rw-r--r--spec/javascripts/right_sidebar_spec.js2
-rw-r--r--spec/javascripts/search_autocomplete_spec.js4
-rw-r--r--spec/javascripts/shortcuts_spec.js2
-rw-r--r--spec/javascripts/sidebar/sidebar_subscriptions_spec.js2
-rw-r--r--spec/javascripts/u2f/register_spec.js2
-rw-r--r--spec/javascripts/vue_mr_widget/mr_widget_options_spec.js4
-rw-r--r--spec/javascripts/vue_shared/components/file_row_spec.js74
-rw-r--r--spec/javascripts/vue_shared/components/skeleton_loading_container_spec.js49
-rw-r--r--spec/javascripts/vue_shared/components/table_pagination_spec.js22
-rw-r--r--spec/lib/banzai/filter/external_issue_reference_filter_spec.rb6
-rw-r--r--spec/lib/banzai/filter/relative_link_filter_spec.rb5
-rw-r--r--spec/lib/banzai/reference_parser/base_parser_spec.rb3
-rw-r--r--spec/lib/event_filter_spec.rb131
-rw-r--r--spec/lib/feature_spec.rb20
-rw-r--r--spec/lib/gitlab/auth/ldap/access_spec.rb10
-rw-r--r--spec/lib/gitlab/background_migration/populate_external_pipeline_source_spec.rb62
-rw-r--r--spec/lib/gitlab/ci/config/entry/reports_spec.rb60
-rw-r--r--spec/lib/gitlab/ci/external/file/local_spec.rb10
-rw-r--r--spec/lib/gitlab/ci/external/mapper_spec.rb4
-rw-r--r--spec/lib/gitlab/ci/external/processor_spec.rb8
-rw-r--r--spec/lib/gitlab/ci/parsers/test/junit_spec.rb (renamed from spec/lib/gitlab/ci/parsers/junit_spec.rb)2
-rw-r--r--spec/lib/gitlab/ci/parsers/test_spec.rb (renamed from spec/lib/gitlab/ci/parsers_spec.rb)4
-rw-r--r--spec/lib/gitlab/ci/templates/templates_spec.rb11
-rw-r--r--spec/lib/gitlab/ci/yaml_processor_spec.rb12
-rw-r--r--spec/lib/gitlab/database/subquery_spec.rb17
-rw-r--r--spec/lib/gitlab/diff/file_collection/commit_spec.rb15
-rw-r--r--spec/lib/gitlab/diff/file_collection/compare_spec.rb29
-rw-r--r--spec/lib/gitlab/diff/file_collection/merge_request_diff_spec.rb8
-rw-r--r--spec/lib/gitlab/diff/file_spec.rb64
-rw-r--r--spec/lib/gitlab/git/diff_stats_collection_spec.rb26
-rw-r--r--spec/lib/gitlab/git/hook_env_spec.rb20
-rw-r--r--spec/lib/gitlab/git/repository_spec.rb34
-rw-r--r--spec/lib/gitlab/gitaly_client/commit_service_spec.rb16
-rw-r--r--spec/lib/gitlab/import_export/project.json4
-rw-r--r--spec/lib/gitlab/import_export/project_tree_restorer_spec.rb6
-rw-r--r--spec/lib/gitlab/kubernetes/kube_client_spec.rb2
-rw-r--r--spec/lib/gitlab/kubernetes/service_account_token_spec.rb35
-rw-r--r--spec/lib/gitlab/middleware/read_only_spec.rb2
-rw-r--r--spec/lib/gitlab/null_request_store_spec.rb75
-rw-r--r--spec/lib/gitlab/repository_cache_adapter_spec.rb138
-rw-r--r--spec/lib/gitlab/repository_cache_spec.rb85
-rw-r--r--spec/lib/gitlab/safe_request_store_spec.rb245
-rw-r--r--spec/lib/gitlab/sidekiq_throttler_spec.rb44
-rw-r--r--spec/lib/gitlab/template/gitlab_ci_yml_template_spec.rb2
-rw-r--r--spec/lib/google_api/cloud_platform/client_spec.rb47
-rw-r--r--spec/lib/mattermost/session_spec.rb4
-rw-r--r--spec/lib/quality/helm_client_spec.rb62
-rw-r--r--spec/lib/quality/kubernetes_client_spec.rb25
-rw-r--r--spec/models/ci/build_spec.rb118
-rw-r--r--spec/models/ci/job_artifact_spec.rb62
-rw-r--r--spec/models/ci/pipeline_spec.rb7
-rw-r--r--spec/models/clusters/applications/jupyter_spec.rb7
-rw-r--r--spec/models/clusters/providers/gcp_spec.rb18
-rw-r--r--spec/models/commit_spec.rb10
-rw-r--r--spec/models/concerns/from_union_spec.rb40
-rw-r--r--spec/models/event_collection_spec.rb2
-rw-r--r--spec/models/instance_configuration_spec.rb2
-rw-r--r--spec/models/issue_spec.rb29
-rw-r--r--spec/models/milestone_spec.rb18
-rw-r--r--spec/models/project_feature_spec.rb42
-rw-r--r--spec/models/project_services/chat_message/merge_message_spec.rb25
-rw-r--r--spec/models/project_spec.rb58
-rw-r--r--spec/models/project_wiki_spec.rb29
-rw-r--r--spec/models/repository_spec.rb101
-rw-r--r--spec/models/site_statistic_spec.rb2
-rw-r--r--spec/models/user_spec.rb28
-rw-r--r--spec/presenters/ci/build_runner_presenter_spec.rb49
-rw-r--r--spec/presenters/project_presenter_spec.rb2
-rw-r--r--spec/requests/api/commits_spec.rb80
-rw-r--r--spec/requests/api/jobs_spec.rb2
-rw-r--r--spec/requests/api/pipelines_spec.rb16
-rw-r--r--spec/requests/api/runners_spec.rb221
-rw-r--r--spec/requests/openid_connect_spec.rb2
-rw-r--r--spec/rubocop/cop/avoid_route_redirect_leading_slash_spec.rb32
-rw-r--r--spec/rubocop/cop/gitlab/union_spec.rb25
-rw-r--r--spec/serializers/commit_entity_spec.rb33
-rw-r--r--spec/services/auth/container_registry_authentication_service_spec.rb2
-rw-r--r--spec/services/boards/issues/list_service_spec.rb12
-rw-r--r--spec/services/ci/fetch_kubernetes_token_service_spec.rb64
-rw-r--r--spec/services/ci/retry_build_service_spec.rb18
-rw-r--r--spec/services/clusters/gcp/finalize_creation_service_spec.rb123
-rw-r--r--spec/services/clusters/gcp/kubernetes/create_service_account_service_spec.rb96
-rw-r--r--spec/services/clusters/gcp/kubernetes/fetch_kubernetes_token_service_spec.rb60
-rw-r--r--spec/services/files/create_service_spec.rb16
-rw-r--r--spec/services/files/delete_service_spec.rb11
-rw-r--r--spec/services/files/multi_service_spec.rb36
-rw-r--r--spec/services/files/update_service_spec.rb11
-rw-r--r--spec/services/git_push_service_spec.rb8
-rw-r--r--spec/services/groups/destroy_service_spec.rb8
-rw-r--r--spec/services/groups/transfer_service_spec.rb2
-rw-r--r--spec/services/merge_requests/rebase_service_spec.rb2
-rw-r--r--spec/services/notes/build_service_spec.rb15
-rw-r--r--spec/services/projects/container_repository/destroy_service_spec.rb1
-rw-r--r--spec/services/projects/destroy_service_spec.rb2
-rw-r--r--spec/services/projects/update_remote_mirror_service_spec.rb30
-rw-r--r--spec/services/quick_actions/interpret_service_spec.rb9
-rw-r--r--spec/support/helpers/kubernetes_helpers.rb54
-rw-r--r--spec/support/helpers/markdown_feature.rb8
-rw-r--r--spec/support/helpers/migrations_helpers.rb4
-rw-r--r--spec/support/helpers/test_env.rb4
-rw-r--r--spec/support/services/clusters/create_service_shared.rb8
-rw-r--r--spec/support/shared_examples/diff_file_collections.rb47
-rw-r--r--spec/tasks/gitlab/db_rake_spec.rb33
-rw-r--r--spec/tasks/gitlab/site_statistics_rake_spec.rb5
-rw-r--r--spec/validators/url_validator_spec.rb15
-rw-r--r--spec/views/help/index.html.haml_spec.rb4
-rw-r--r--spec/views/projects/jobs/show.html.haml_spec.rb36
-rw-r--r--vendor/gitlab-ci-yml/.gitlab-ci.yml4
-rw-r--r--vendor/gitlab-ci-yml/CONTRIBUTING.md46
-rw-r--r--vendor/gitlab-ci-yml/LICENSE25
-rw-r--r--vendor/licenses.csv1
-rw-r--r--yarn.lock1905
1609 files changed, 15169 insertions, 8370 deletions
diff --git a/.eslintrc.yml b/.eslintrc.yml
index ebf8048f19c..a954bb4ff37 100644
--- a/.eslintrc.yml
+++ b/.eslintrc.yml
@@ -56,6 +56,10 @@ rules:
component: always
svg: always
math: always
+ camelcase:
+ - error
+ - properties: never
+ ignoreDestructuring: true
## Conflicting rules with prettier:
space-before-function-paren: off
curly: off
@@ -63,7 +67,7 @@ rules:
function-paren-newline: off
object-curly-newline: off
padded-blocks: off
- # Disabled for now, to make the eslint 3 -> eslint 4 update smoother
+ # Disabled for now, to make the eslint 3 -> eslint 5 update smoother
## Indent rule. We are using the old for now: https://eslint.org/docs/user-guide/migrating-to-4.0.0#indent-rewrite
indent: off
indent-legacy:
@@ -78,3 +82,18 @@ rules:
FunctionExpression:
parameters: 1
body: 1
+ # Disabled for now, to make the airbnb-base 12.1.0 -> 13.1.0 update smoother
+ operator-linebreak: off
+ implicit-arrow-linebreak: off
+ no-else-return:
+ - error
+ - allowElseIf: true
+ import/no-useless-path-segments: off
+ lines-between-class-members: off
+ # Disabled for now, to make the plugin-vue 4.5 -> 5.0 update smoother
+ vue/html-closing-bracket-newline: off
+ vue/html-closing-bracket-spacing: off
+ vue/no-confusing-v-for-v-if: error
+ vue/no-unused-components: off
+ vue/no-use-v-if-with-v-for: off
+ vue/no-v-html: off
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index cc27ac3677b..9c5b40dce21 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -95,7 +95,7 @@ stages:
# Skip all jobs except the ones that begin with 'docs/'.
# Used for commits including ONLY documentation changes.
-# https://docs.gitlab.com/ce/development/writing_documentation.html#testing
+# https://docs.gitlab.com/ce/development/documentation/#testing
.except-docs: &except-docs
except:
- /(^docs[\/-].*|.*-docs$)/
@@ -130,7 +130,6 @@ stages:
.single-script-job: &single-script-job
image: ruby:2.4-alpine
- before_script: []
stage: test
cache: {}
dependencies: []
@@ -259,6 +258,7 @@ package-and-qa:
SCRIPT_NAME: trigger-build
retry: 0
script:
+ - gem install gitlab --no-document
- ./$SCRIPT_NAME omnibus
when: manual
only:
@@ -285,7 +285,7 @@ review-docs-deploy-manual:
<<: *review-docs
stage: build
script:
- - gem install gitlab --no-ri --no-rdoc
+ - gem install gitlab --no-document
- ./$SCRIPT_NAME deploy
when: manual
only:
@@ -299,7 +299,7 @@ review-docs-deploy:
<<: *review-docs
stage: post-test
script:
- - gem install gitlab --no-ri --no-rdoc
+ - gem install gitlab --no-document
- ./$SCRIPT_NAME deploy
only:
- /(^docs[\/-].*|.*-docs$)/@gitlab-org/gitlab-ce
@@ -314,7 +314,7 @@ review-docs-cleanup:
name: review-docs/$CI_COMMIT_REF_SLUG
action: stop
script:
- - gem install gitlab --no-ri --no-rdoc
+ - gem install gitlab --no-document
- ./$SCRIPT_NAME cleanup
when: manual
only:
@@ -327,14 +327,14 @@ review-docs-cleanup:
cloud-native-image:
image: ruby:2.4-alpine
before_script: []
- stage: build
+ stage: test
allow_failure: true
variables:
GIT_DEPTH: "1"
cache: {}
script:
- - gem install gitlab --no-ri --no-rdoc
- - BUILD_TRIGGER_TOKEN=$CI_JOB_TOKEN scripts/trigger-build cng
+ - gem install gitlab --no-document
+ - CNG_PROJECT_PATH="gitlab-org/build/CNG" BUILD_TRIGGER_TOKEN=$CI_JOB_TOKEN ./scripts/trigger-build cng
only:
- tags@gitlab-org/gitlab-ce
- tags@gitlab-org/gitlab-ee
@@ -366,7 +366,7 @@ update-tests-metadata:
- rspec_flaky/
policy: push
script:
- - retry gem install fog-aws mime-types activesupport --no-ri --no-rdoc
+ - retry gem install fog-aws mime-types activesupport --no-document
- scripts/merge-reports ${KNAPSACK_RSPEC_SUITE_REPORT_PATH} knapsack/${CI_PROJECT_NAME}/rspec-pg_node_*.json
- scripts/merge-reports ${FLAKY_RSPEC_SUITE_REPORT_PATH} rspec_flaky/all_*_*.json
- FLAKY_RSPEC_GENERATE_REPORT=1 scripts/prune-old-flaky-specs ${FLAKY_RSPEC_SUITE_REPORT_PATH}
@@ -729,6 +729,9 @@ karma:
dependencies:
- compile-assets
- setup-test-env
+ variables:
+ # we override the max_old_space_size to prevent OOM errors
+ NODE_OPTIONS: --max_old_space_size=3584
script:
- export BABEL_ENV=coverage CHROME_LOG_FILE=chrome_debug.log
- date
diff --git a/.rubocop.yml b/.rubocop.yml
index 9858bbe0ddd..b7aec5b8b14 100644
--- a/.rubocop.yml
+++ b/.rubocop.yml
@@ -35,6 +35,25 @@ Style/MutableConstant:
Style/SafeNavigation:
Enabled: false
+# Frozen String Literal
+Style/FrozenStringLiteralComment:
+ Enabled: true
+ Exclude:
+ - 'config.ru'
+ - 'Dangerfile'
+ - 'Gemfile'
+ - 'Rakefile'
+ - 'app/views/**/*'
+ - 'config/**/*'
+ - 'danger/**/*'
+ - 'db/**/*'
+ - 'ee/**/*'
+ - 'lib/**/*'
+ - 'qa/**/*'
+ - 'rubocop/**/*'
+ - 'scripts/**/*'
+ - 'spec/**/*'
+
Naming/FileName:
ExpectMatchingDefinition: true
Exclude:
@@ -111,7 +130,7 @@ Naming/FileName:
- XSRF
- XSS
-# Gitlab ###################################################################
+# GitLab ###################################################################
Gitlab/ModuleWithInstanceVariables:
Enable: true
diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml
index 54e3b8217d8..d8c4e965190 100644
--- a/.rubocop_todo.yml
+++ b/.rubocop_todo.yml
@@ -808,20 +808,6 @@ Style/UnlessElse:
Style/UnneededInterpolation:
Enabled: false
-# Offense count: 11
-# Cop supports --auto-correct.
-Style/ZeroLengthPredicate:
- Exclude:
- - 'app/models/deploy_key.rb'
- - 'app/models/network/commit.rb'
- - 'app/models/network/graph.rb'
- - 'app/models/project_services/asana_service.rb'
- - 'app/services/boards/create_service.rb'
- - 'app/services/merge_requests/conflicts/list_service.rb'
- - 'lib/declarative_policy/dsl.rb'
- - 'lib/extracts_path.rb'
- - 'lib/gitlab/git/repository.rb'
-
# Offense count: 22840
# Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns.
# URISchemes: http, https
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c1d5a638cd0..e514a42108c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,253 @@
documentation](doc/development/changelog.md) for instructions on adding your own
entry.
+## 11.3.0 (2018-09-22)
+
+### Security (5 changes, 1 of them is from the community)
+
+- Disable the Sidekiq Admin Rack session. !21441
+- Set issuable_sort, diff_view, and perf_bar_enabled cookies to secure when possible. !21442
+- Update rubyzip to 1.2.2 (CVE-2018-1000544). !21460 (Takuya Noguchi)
+- Fixed persistent XSS rendering/escaping of diff location lines.
+- Block link-local addresses in URLBlocker.
+
+### Removed (1 change)
+
+- Remove Gemnasium service. !21185
+
+### Fixed (83 changes, 24 of them are from the community)
+
+- Hide PAT creation advice for HTTP clone if PAT exists. !18208 (George Thomas @thegeorgeous)
+- Allow spaces in wiki markdown links when using CommonMark. !20417
+- disable_statement_timeout no longer leak to other migrations. !20503
+- Events API now requires the read_user or api scope. !20627 (Warren Parad)
+- Fix If-Check the result that a function was executed several times. !20640 (Max Dicker)
+- Add migration to cleanup internal_ids inconsistency. !20926
+- Fix fallback logic for automatic MR title assignment. !20930 (Franz Liedke)
+- Fixed bug when the project logo file is stored in LFS. !20948
+- Fix buttons on the new file page wrapping outside of the container. !21015
+- Solve tooltip appears under modal. !21017
+- Fix Bitbucket Cloud importer omitting replies. !21076
+- Fix pipeline fixture seeder. !21088
+- Fix blocked user card style. !21095
+- Fix empty merge requests not opening in the Web IDE. !21102
+- Fix label list item container height when there is no label description. !21106
+- Fixes input alignment in user admin form with errors. !21108 (Jacopo Beschi @jacopo-beschi)
+- Rails5 fix specs duplicate key value violates unique constraint 'index_gpg_signatures_on_commit_sha'. !21119 (Jasper Maes)
+- Add gitlab theme to spam logs pagination. !21145
+- Split remembering sorting for issues and merge requests. !21153 (Jacopo Beschi @jacopo-beschi)
+- Fix git submodule link for subgroup projects with relative path. !21154
+- Fix: Project deletion may not log audit events during group deletion. !21162
+- Fix 1px cutoff of emojis. !21180 (gfyoung)
+- Auto-DevOps.gitlab-ci.yml: update glibc package to 2.28. !21191 (sgerrand)
+- Show google icon in audit log. !21207 (Jan Beckmann)
+- Fix bin/secpick error and security branch prefixing. !21210
+- Importing a project no longer fails when visibility level holds a string value type. !21242
+- Fix attachments not displaying inline with Google Cloud Storage. !21265
+- Fix IDE issues with persistent banners. !21283
+- Fix "Confidential comments" button not saving in project hooks. !21289
+- Bump fog-google to 1.7.0 and google-api-client to 0.23.0. !21295
+- Don't use arguments keyword in gettext script. !21296 (gfyoung)
+- Fix breadcrumb link to issues on new issue page. !21305 (J.D. Bean)
+- Show '< 1%' when percent value evaluated is less than 1 on Stacked Progress Bar. !21306
+- API: Catch empty commit messages. !21322 (Robert Schilling)
+- Fix SQL error when sorting 2FA-enabled users by name in admin area. !21324
+- API: Catch empty code content for project snippets. !21325 (Robert Schilling)
+- Avoid nil safe message. !21326 (Yi Siliang)
+- Allow date parameters on Issues, Notes, and Discussions API for group owners. !21342 (Florent Dubois)
+- Fix remote mirrors failing if Git remotes have not been added. !21351
+- Removing a group no longer triggers hooks for project deletion twice. !21366
+- Use slugs for default project path and sanitize names before import. !21367
+- Vertically centres landscape avatars. !21371 (Vicary Archangel)
+- Fix Web IDE unable to commit to same file twice. !21372
+- Fix project transfer name validation issues causing a redirect loop. !21408
+- Fix Error 500s due to encoding issues when Wiki hooks fire. !21414
+- Rails 5: include opclasses in rails 5 schema dump. !21416 (Jasper Maes)
+- Bump GitLab Pages to v1.1.0. !21419
+- Fix links in RSS feed elements. !21424 (Marc Schwede)
+- Allow gaps in multiseries metrics charts. !21427
+- Auto-DevOps.gitlab-ci.yml: fix redeploying deleted app gives helm error. !21429
+- Use sample data for push event when no commits created. !21440 (Takuya Noguchi)
+- Fix importers not assigning a new default group. !21456
+- Fix edge cases of JUnitParser. !21469
+- Fix breadcrumb link to merge requests on new merge request page. !21502 (J.D. Bean)
+- Handle database statement timeouts in usage ping. !21523
+- Handles exception during file upload - replaces the stack trace with a small error message. !21528
+- Fix closing issue default pattern. !21531 (Samuele Kaplun)
+- Fix outdated discussions being shown on Merge Request Changes tab. !21543
+- Remove orphaned label links. !21552
+- Delete a container registry asynchronously. !21553
+- Make MR diff file filter input Clear button functional. !21556
+- Replace white spaces in wiki attachments file names. !21569
+- API: Use find_branch! in all places. !21614 (Robert Schilling)
+- Fixes double +/- on inline diff view. !21634
+- Fix broken exports when they include a projet avatar. !21649
+- Fix workhorse temp path for namespace uploads. !21650
+- Fixed resolved discussions not toggling expanded state on changes tab. !21676
+- Update GitLab Shell to v8.3.2. !21701
+- Fix absent Click to Expand link on diffs not rendered on first load of Merge Requests Changes tab. !21716
+- Update GitLab Shell to v8.3.3. !21750
+- Fix import error when archive does not have the correct extension. !21765
+- Fixed IDE deleting new files creating wrong state.
+- Does not collapse runners section when using pagination.
+- Fix Emojis cutting in the right way. (Alexander Popov)
+- Fix NamespaceUploader.base_dir for remote uploads.
+- Increase width of checkout branch modal box.
+- Fixes SVGs for empty states in job page overflowing on mobile.
+- Fix checkboxes on runner admin settings - The labels are now clickable.
+- Fixed IDE file row scrolling into view when hovering.
+- Accept upload files in public/uplaods/tmp when using accelerated uploads.
+- Include correct CSS file for xterm in environments page.
+- Increase padding in code blocks.
+- Fix: Project deletion may not log audit events during user deletion.
+
+### Changed (32 changes, 5 of them are from the community)
+
+- Add default avatar to group. !17271 (George Tsiolis)
+- Allow project owners to set up forking relation through API. !18104
+- Limit navbar search for current project or group for small viewports. !18634 (George Tsiolis)
+- Add Noto Color Emoji font support. !19036 (Alexander Popov)
+- Update design of project overview page. !20536
+- Improve visuals of language bar on projects. !21006
+- Migrate NULL wiki_access_level to correct number so we count active wikis correctly. !21030
+- Support a custom action, such as proxying to another server, after /api/v4/internal/allowed check succeeds. !21034
+- Remove storage path dependency of gitaly install task. !21101
+- Support Kubernetes RBAC for GitLab Managed Apps when adding a existing cluster. !21127
+- Change 'Backlog' list title to 'Open' in Issue Boards. !21131
+- Enable Auto DevOps Instance Wide Default. !21157
+- Allow author to vote on their own issue and MRs. !21203
+- Truncate branch names and update "commits behind" text in MR page. !21206
+- Adds count for different board list types (label lists, assignee lists, and milestone lists) to usage statistics. !21208
+- Render files (`.md`) and wikis using CommonMark. !21228
+- Show deprecation message on project milestone page for category tabs. !21236
+- Remove redundant header from metrics page. !21282
+- Add default parameter to branches API. !21294 (Riccardo Padovani)
+- Restrict reopening locked issues for non authorized issue authors. !21299
+- Send back required object storage PUT headers in /uploads/authorize API. !21319
+- Display default status emoji if only message is entered. !21330
+- Move badge settings to general settings. !21333
+- Move project settings for default branch under "Repository". !21380
+- Import all common metrics into database. !21459
+- Improved commit panel in Web IDE. !21471
+- Administrative cleanup rake tasks now leverage Gitaly. !21588
+- Remove health check feature flag in BackgroundMigrationWorker.
+- Expose user's id in /admin/users/ show page. (Eva Kadlecova)
+- Improved styling of top bar in IDE job trace pane.
+- Make terminal button more visible.
+- Shows download artifacts button for pipelines on small screens.
+
+### Performance (13 changes, 2 of them are from the community)
+
+- Enable frozen string in rest of app/models/**/*.rb.
+- Add background migrations for legacy artifacts. !18615
+- Optimize querying User#manageable_groups. !21050
+- Incremental rendering with Vue on merge request page. !21063
+- Remove redundant ci_builds (status) index. !21070
+- Enable frozen in app/mailers/**/*.rb. !21147 (gfyoung)
+- Improve performance when fetching related merge requests for an issue. !21237
+- Speed up diff comparisons by limiting number of commit messages rendered. !21335
+- Write diff highlighting cache upon MR creation (refactors caching). !21489
+- Bulk-render commit titles in the tree view to improve performance. !21500
+- Enable frozen string in vestigial app files. (gfyoung)
+- Disable project avatar validation if avatar has not changed.
+- Bitbucket Server importer: Eliminate most idle-in-transaction issues.
+
+### Added (41 changes, 17 of them are from the community)
+
+- API: Protected tags. !14986 (Robert Schilling)
+- Include private contributions to contributions calendar. !17296 (George Tsiolis)
+- Add an option to whitelist users based on email address as internal when the "New user set to external" setting is enabled. !17711 (Roger Rüttimann)
+- Overhaul listing of projects in the group overview page. !20262
+- Add the ability to reference projects in comments and other markdown text. !20285 (Reuben Pereira)
+- Add branch filter to project webhooks. !20338 (Duana Saskia)
+- Allows to cancel a Created job. !20635 (Jacopo Beschi @jacopo-beschi)
+- First Improvements made to the contributor on-boarding experience. !20682 (Eddie Stubbington)
+- `/tag` quick action on Commit comments. !20694 (Peter Leitzen)
+- Allow admins to configure the maximum Git push size. !20758
+- Expose all artifacts sizes in jobs api. !20821 (Peter Marko)
+- Get the merge base of two refs through the API. !20929
+- Add ability to suppress the global "You won't be able to use SSH" message. !21027 (Ævar Arnfjörð Bjarmason)
+- API: Add expiration date for shared projects to the project entity. !21104 (Robert Schilling)
+- Added tooltips to tree list header. !21138
+- #47845 Add failure_reason to job webhook. !21143 (matemaciek)
+- Vendor Auto-DevOps.gitlab-ci.yml with new proxy env vars passed through to docker. !21159 (kinolaev)
+- Disable Auto DevOps for project upon first pipeline failure. !21172
+- Add rake command to migrate archived traces from local storage to object storage. !21193
+- Add Czech as an available language. !21201
+- Add Galician as an available language. !21202
+- Add support for extendable CI/CD config with. !21243
+- Disable Web IDE button if user is not allowed to push the source branch. !21288
+- Feature flag to disable Hashed Storage migration when renaming a repository. !21291
+- Store wiki uploads inside git repository. !21362
+- Adds Rubocop rule to enforce class_methods over module ClassMethods. !21379 (Jacopo Beschi @jacopo-beschi)
+- Merge request copies all associated issue labels and milestone on creation. !21383
+- Add group name badge under group milestone. !21384
+- Adds diverged_commits_count field to GET api/v4/projects/:project_id/merge_requests/:merge_request_iid. !21405 (Jacopo Beschi @jacopo-beschi)
+- Update Import/Export to only use new storage uploaders logic. !21409
+- Ask user explicitly about usage stats agreement on single user deployments. !21423
+- Added atom feed for tags. !21428
+- Add search to a group labels page. !21480
+- Display banner on project page if AutoDevOps is implicitly enabled. !21503
+- Recognize 'UNLICENSE' license files. !21508 (J.D. Bean)
+- Add git_v2 feature flag. !21520
+- Added file templates to the Web IDE.
+- Enabled multiple file uploads in the Web IDE.
+- Allow to delete group milestones.
+- Use separate model for tracking resource label changes and render label system notes based on data from this model.
+- Add system note when due date is changed. (Eva Kadlecova)
+
+### Other (48 changes, 16 of them are from the community)
+
+- Remove extra spaces from MR discussion notes. !18946 (Takuya Noguchi)
+- Add an example of the configuration of archive trace cron worker in gitlab.yml.example. !20583
+- Add target branch name to cherrypick confirmation message. !20846 (George Andrinopoulos)
+- CE Port of Protected Environments backend. !20859
+- Added missing i18n strings to issue boards lables dropdown. !21081
+- Combines emoji award spec files into single user_interacts_with_awards_in_issue_spec.rb file. !21126 (Nate Geslin)
+- Clarify current runners online text. !21151 (Ben Bodenmiller)
+- Rails5: Enable verbose query logs. !21231 (Jasper Maes)
+- Update presentation for SSO providers on log in page. !21233
+- Make margin of user status emoji consistent. !21268
+- Move usage ping payload from User Cohorts page to admin application settings. !21343
+- Add JSON logging for Bitbucket Server importer. !21378
+- Re-add project name field on "Create new project" page. !21386
+- Rails 5: replace removed silence_stream. !21387 (Jasper Maes)
+- Rails5 update Gemfile.rails5.lock. !21388 (Jasper Maes)
+- Rails5: fix can't quote ActiveSupport::HashWithIndifferentAccess. !21397 (Jasper Maes)
+- Don't show flash messages for performance bar errors. !21411
+- Backport schema_changed.sh from EE which prints the diff if the schema is different. !21422 (Jasper Maes)
+- Remove unused CSS part in mobile framework. !21439 (Takuya Noguchi)
+- Bump unauthenticated session time from 1 hour to 2 hours. !21453
+- Run review-docs-cleanup job for gitlab-org repos only. !21463 (Takuya Noguchi)
+- Rails 5: support schema t.index for mysql. !21485 (Jasper Maes)
+- Add route information to lograge structured logging for API logs. !21487
+- Add gitaly_calls attribute to API logs. !21496
+- Ignore irrelevant sql commands in metrics. !21498
+- Rails 5: fix hashed_path? method that looks up file_location that doesn't exist when running certain migration specs. !21510 (Jasper Maes)
+- Explicit hashed path check for trace, prevents background migration from accessing file_location column that doesn't exist. !21533 (Jasper Maes)
+- Add terminal_path to job API response. !21537
+- Add User-Agent to production_json.log. !21546
+- Make cluster page settings easier to read. !21550
+- Remove striped table styling of Find files and Admin Area Applications views. !21560 (Andreas Kämmerle)
+- Update ffi to 1.9.25. !21561 (Takuya Noguchi)
+- Send max_patch_bytes to Gitaly via Gitaly::CommitDiffRequest. !21575
+- Add margin between username and subsequent text in issuable header. !21697
+- Send artifact information in job API. !50460
+- Reduce differences between CE and EE code base in reports components.
+- Move project services log to a separate file.
+- Creates vue component for job log top bar with controllers.
+- Creates Vue component for trigger variables block in job log page.
+- Creates Vvue component for warning block about stuck runners.
+- Creates vue component for job log trace.
+- Creates vue component for erased block on job view.
+- Creates vue component for environments information in job log view.
+- Upgrade Monaco editor.
+- Creates empty state vue component for job view.
+- Creates vue component for commit block in job log page.
+- Creates vue components for stage dropdowns and job list container for job log view.
+- Creates Vue component for artifacts block on job page.
+
+
## 11.2.3 (2018-08-28)
### Fixed (1 change)
@@ -879,7 +1126,7 @@ entry.
- Use the default strings of timeago.js for timeago. !19350 (Takuya Noguchi)
- Update selenium-webdriver to 3.12.0. !19351 (Takuya Noguchi)
- Include username in output when testing SSH to GitLab. !19358
-- Update screenshot in Gitlab.com integration documentation. !19433 (Tuğçe Nur Taş)
+- Update screenshot in GitLab.com integration documentation. !19433 (Tuğçe Nur Taş)
- Users can accept terms during registration. !19583
- Fix issue count on sidebar.
- Add merge requests list endpoint for groups.
@@ -1009,7 +1256,7 @@ entry.
- Make toggle markdown preview shortcut only toggle selected field.
- Verifiy if pipeline has commit idetails and render information in MR widget when branch is deleted.
- Fixed inconsistent protected branch pill baseline.
-- Fix setting Gitlab metrics content types.
+- Fix setting GitLab metrics content types.
- Display only generic message on merge error to avoid exposing any potentially sensitive or user unfriendly backend messages.
- Fix label links update on project transfer.
- Breaks commit not found message in pipelines table.
@@ -1379,7 +1626,7 @@ entry.
- Add 'Assigned Issues' and 'Assigned Merge Requests' as dashboard view choices for users. !17860 (Elias Werberich)
- Extend API for importing a project export with overwrite support. !17883
- Create Deploy Tokens to allow permanent access to repository and registry. !17894
-- Detect commit message trailers and link users properly to their accounts on Gitlab. !17919 (cousine)
+- Detect commit message trailers and link users properly to their accounts on GitLab. !17919 (cousine)
- Adds cancel btn to new pages domain page. !18026 (Jacopo Beschi @jacopo-beschi)
- API: Add parameter merge_method to projects. !18031 (Jan Beckmann)
- Introduce simpler env vars for auto devops REPLICAS and CANARY_REPLICAS #41436. !18036
@@ -2827,7 +3074,7 @@ entry.
- [FIXED] Fix broken wiki pages that link to a wiki file. !15019
- [FIXED] Don't rename paths that were freed up when upgrading. !15029
- [FIXED] Fix bitbucket login. !15051
-- [FIXED] Update gitaly in Gitlab 10.1 to 0.43.1 for temp file cleanup. !15055
+- [FIXED] Update gitaly in GitLab 10.1 to 0.43.1 for temp file cleanup. !15055
- [FIXED] Use the correct visibility attribute for projects in system hooks. !15065
- [FIXED] Normalize LDAP DN when looking up identity.
- [FIXED] Adds callback functions for initial request in clusters page.
@@ -4537,7 +4784,7 @@ entry.
- Make user mentions case-insensitive. !10285 (blackst0ne)
- Update rugged to 0.25.1.1. !10286 (Elan Ruusamäe)
- Handle parsing OpenBSD ps output properly to display sidekiq infos on admin->monitoring->background. !10303 (Sebastian Reitenbach)
-- Log errors during generating of Gitlab Pages to debug log. !10335 (Danilo Bargen)
+- Log errors during generating of GitLab Pages to debug log. !10335 (Danilo Bargen)
- Update issue board cards design. !10353
- Tags can be protected, restricting creation of matching tags by user role. !10356
- Set GIT_TERMINAL_PROMPT env variable in initializer. !10372
@@ -4950,7 +5197,7 @@ entry.
- Restore keyboard shortcuts for "Activity" and "Charts". !9680
- Added commit array to Syshook json. !9685 (Gabriele Pongelli)
- Document ability to list issues with no labels using API. !9697 (Vignesh Ravichandran)
-- Fix typo in Gitlab config file. !9702 (medied)
+- Fix typo in GitLab config file. !9702 (medied)
- Fix json response in branches controller. !9710 (George Andrinopoulos)
- Refactor dropdown_assignee_spec. !9711 (George Andrinopoulos)
- Delete artifacts for pages unless expiry date is specified. !9716
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 7f1da58fa9d..81fc46c2b6f 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -36,7 +36,7 @@ _This notice should stay as the first item in the CONTRIBUTING.md file._
- [Release Scoping labels](#release-scoping-labels)
- [Priority labels](#priority-labels)
- [Severity labels](#severity-labels)
- - [Severity impact guidance](#severity-impact-guidance)
+ - [Severity impact guidance](#severity-impact-guidance)
- [Label for community contributors](#label-for-community-contributors)
- [Implement design & UI elements](#implement-design--ui-elements)
- [Issue tracker](#issue-tracker)
@@ -70,13 +70,15 @@ to contribute to GitLab in a way that is easy for everyone.
For a first-time step-by-step guide to the contribution process, please see
["Contributing to GitLab"](https://about.gitlab.com/contributing/).
-Looking for something to work on? Look for issues with the label [Accepting Merge Requests](#i-want-to-contribute).
+Looking for something to work on? Look for issues in the [Backlog (Accepting merge requests) milestone](#i-want-to-contribute).
-GitLab comes into two flavors, GitLab Community Edition (CE) our free and open
+GitLab comes in two flavors, GitLab Community Edition (CE) our free and open
source edition, and GitLab Enterprise Edition (EE) which is our commercial
edition. Throughout this guide you will see references to CE and EE for
abbreviation.
+To get an overview of GitLab community membership including those that would be reviewing or merging your contributions, please visit [the community roles page](doc/development/contributing/community_roles.md).
+
If you want to know how the GitLab [core team]
operates please see [the GitLab contributing process](PROCESS.md).
@@ -151,8 +153,8 @@ the remaining issues on the GitHub issue tracker.
## I want to contribute!
-If you want to contribute to GitLab [issues with the label `Accepting Merge Requests` and small weight][accepting-mrs-weight]
-is a great place to start. Issues with a lower weight (1 or 2) are deemed
+If you want to contribute to GitLab, [issues in the Backlog (Accepting merge requests)](https://gitlab.com/gitlab-org/gitlab-ce/issues?scope=all&utf8=✓&state=opened&assignee_id=0&milestone_title=Backlog%20&#40;Accepting%20merge%20requests&#41;)
+are a great place to start. Issues with a lower weight (1 or 2) are deemed
suitable for beginners. These issues will be of reasonable size and challenge,
for anyone to start contributing to GitLab. If you have any questions or need help visit [Getting Help](https://about.gitlab.com/getting-help/#discussion) to
learn how to communicate with GitLab. If you're looking for a Gitter or Slack channel
diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION
index 61825a7bf03..3ba7bd5ba83 100644
--- a/GITALY_SERVER_VERSION
+++ b/GITALY_SERVER_VERSION
@@ -1 +1 @@
-0.121.0
+0.123.0
diff --git a/GITLAB_WORKHORSE_VERSION b/GITLAB_WORKHORSE_VERSION
index dfda3e0b4f0..f3b5af39e43 100644
--- a/GITLAB_WORKHORSE_VERSION
+++ b/GITLAB_WORKHORSE_VERSION
@@ -1 +1 @@
-6.1.0
+6.1.1
diff --git a/Gemfile b/Gemfile
index 106ae35efa4..ecf5e6392c0 100644
--- a/Gemfile
+++ b/Gemfile
@@ -89,7 +89,7 @@ gem 'gitlab-gollum-rugged_adapter', '~> 0.4.4', require: false
gem 'github-linguist', '~> 5.3.3', require: 'linguist'
# API
-gem 'grape', '~> 1.0'
+gem 'grape', '~> 1.1'
gem 'grape-entity', '~> 0.7.1'
gem 'rack-cors', '~> 1.0.0', require: 'rack/cors'
@@ -112,9 +112,6 @@ gem 'hamlit', '~> 2.8.8'
gem 'carrierwave', '= 1.2.3'
gem 'mini_magick'
-# Drag and Drop UI
-gem 'dropzonejs-rails', '~> 0.7.1'
-
# for backups
gem 'fog-aws', '~> 2.0.1'
gem 'fog-core', '~> 1.44'
@@ -173,7 +170,6 @@ gem 'acts-as-taggable-on', '~> 5.0'
gem 'sidekiq', '~> 5.2.1'
gem 'sidekiq-cron', '~> 0.6.0'
gem 'redis-namespace', '~> 1.6.0'
-gem 'sidekiq-limit_fetch', '~> 3.4', require: false
# Cron Parser
gem 'rufus-scheduler', '~> 3.4'
@@ -424,7 +420,7 @@ group :ed25519 do
end
# Gitaly GRPC client
-gem 'gitaly-proto', '~> 0.117.0', require: 'gitaly'
+gem 'gitaly-proto', '~> 0.118.1', require: 'gitaly'
gem 'grpc', '~> 1.11.0'
# Locked until https://github.com/google/protobuf/issues/4210 is closed
diff --git a/Gemfile.lock b/Gemfile.lock
index 328cc55cb8c..910e07f4a66 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -175,8 +175,6 @@ GEM
doorkeeper-openid_connect (1.5.0)
doorkeeper (~> 4.3)
json-jwt (~> 1.6)
- dropzonejs-rails (0.7.2)
- rails (> 3.1)
ed25519 (1.2.4)
email_reply_trimmer (0.1.6)
email_spec (2.2.0)
@@ -276,7 +274,7 @@ GEM
gettext_i18n_rails (>= 0.7.1)
po_to_json (>= 1.0.0)
rails (>= 3.2.0)
- gitaly-proto (0.117.0)
+ gitaly-proto (0.118.1)
google-protobuf (~> 3.1)
grpc (~> 1.10)
github-linguist (5.3.3)
@@ -343,7 +341,7 @@ GEM
signet (~> 0.7)
gpgme (2.0.13)
mini_portile2 (~> 2.1)
- grape (1.0.3)
+ grape (1.1.0)
activesupport
builder
mustermann-grape (~> 1.0.0)
@@ -501,7 +499,7 @@ GEM
multi_json (1.13.1)
multi_xml (0.6.0)
multipart-post (2.0.0)
- mustermann (1.0.2)
+ mustermann (1.0.3)
mustermann-grape (1.0.0)
mustermann (~> 1.0.0)
mysql2 (0.4.10)
@@ -846,8 +844,6 @@ GEM
sidekiq-cron (0.6.0)
rufus-scheduler (>= 3.3.0)
sidekiq (>= 4.2.1)
- sidekiq-limit_fetch (3.4.0)
- sidekiq (>= 4)
signet (0.8.1)
addressable (~> 2.3)
faraday (~> 0.9)
@@ -1008,7 +1004,6 @@ DEPENDENCIES
diffy (~> 3.1.0)
doorkeeper (~> 4.3)
doorkeeper-openid_connect (~> 1.5)
- dropzonejs-rails (~> 0.7.1)
ed25519 (~> 1.2)
email_reply_trimmer (~> 0.1)
email_spec (~> 2.2.0)
@@ -1033,7 +1028,7 @@ DEPENDENCIES
gettext (~> 3.2.2)
gettext_i18n_rails (~> 1.8.0)
gettext_i18n_rails_js (~> 1.3)
- gitaly-proto (~> 0.117.0)
+ gitaly-proto (~> 0.118.1)
github-linguist (~> 5.3.3)
gitlab-flowdock-git-hook (~> 1.0.1)
gitlab-gollum-lib (~> 4.2)
@@ -1045,7 +1040,7 @@ DEPENDENCIES
google-api-client (~> 0.23)
google-protobuf (= 3.5.1)
gpgme
- grape (~> 1.0)
+ grape (~> 1.1)
grape-entity (~> 0.7.1)
grape-path-helpers (~> 1.0)
grape_logging (~> 1.7)
@@ -1162,7 +1157,6 @@ DEPENDENCIES
shoulda-matchers (~> 3.1.2)
sidekiq (~> 5.2.1)
sidekiq-cron (~> 0.6.0)
- sidekiq-limit_fetch (~> 3.4)
simple_po_parser (~> 1.1.2)
simplecov (~> 0.14.0)
slack-notifier (~> 1.5.1)
diff --git a/Gemfile.rails5.lock b/Gemfile.rails5.lock
index 48b1190fd56..5959dc0e114 100644
--- a/Gemfile.rails5.lock
+++ b/Gemfile.rails5.lock
@@ -128,7 +128,7 @@ GEM
coderay (1.1.2)
coercible (1.0.0)
descendants_tracker (~> 0.0.1)
- commonmarker (0.17.8)
+ commonmarker (0.17.13)
ruby-enum (~> 0.5)
concord (0.1.5)
adamantium (~> 0.2.0)
@@ -178,8 +178,6 @@ GEM
doorkeeper-openid_connect (1.5.0)
doorkeeper (~> 4.3)
json-jwt (~> 1.6)
- dropzonejs-rails (0.7.2)
- rails (> 3.1)
ed25519 (1.2.4)
email_reply_trimmer (0.1.6)
email_spec (2.2.0)
@@ -279,7 +277,7 @@ GEM
gettext_i18n_rails (>= 0.7.1)
po_to_json (>= 1.0.0)
rails (>= 3.2.0)
- gitaly-proto (0.117.0)
+ gitaly-proto (0.118.1)
google-protobuf (~> 3.1)
grpc (~> 1.10)
github-linguist (5.3.3)
@@ -346,7 +344,7 @@ GEM
signet (~> 0.7)
gpgme (2.0.13)
mini_portile2 (~> 2.1)
- grape (1.0.3)
+ grape (1.1.0)
activesupport
builder
mustermann-grape (~> 1.0.0)
@@ -504,7 +502,7 @@ GEM
multi_json (1.13.1)
multi_xml (0.6.0)
multipart-post (2.0.0)
- mustermann (1.0.2)
+ mustermann (1.0.3)
mustermann-grape (1.0.0)
mustermann (~> 1.0.0)
mysql2 (0.4.10)
@@ -854,8 +852,6 @@ GEM
sidekiq-cron (0.6.0)
rufus-scheduler (>= 3.3.0)
sidekiq (>= 4.2.1)
- sidekiq-limit_fetch (3.4.0)
- sidekiq (>= 4)
signet (0.8.1)
addressable (~> 2.3)
faraday (~> 0.9)
@@ -1017,7 +1013,6 @@ DEPENDENCIES
diffy (~> 3.1.0)
doorkeeper (~> 4.3)
doorkeeper-openid_connect (~> 1.5)
- dropzonejs-rails (~> 0.7.1)
ed25519 (~> 1.2)
email_reply_trimmer (~> 0.1)
email_spec (~> 2.2.0)
@@ -1042,7 +1037,7 @@ DEPENDENCIES
gettext (~> 3.2.2)
gettext_i18n_rails (~> 1.8.0)
gettext_i18n_rails_js (~> 1.3)
- gitaly-proto (~> 0.117.0)
+ gitaly-proto (~> 0.118.1)
github-linguist (~> 5.3.3)
gitlab-flowdock-git-hook (~> 1.0.1)
gitlab-gollum-lib (~> 4.2)
@@ -1054,7 +1049,7 @@ DEPENDENCIES
google-api-client (~> 0.23)
google-protobuf (= 3.5.1)
gpgme
- grape (~> 1.0)
+ grape (~> 1.1)
grape-entity (~> 0.7.1)
grape-path-helpers (~> 1.0)
grape_logging (~> 1.7)
@@ -1172,7 +1167,6 @@ DEPENDENCIES
shoulda-matchers (~> 3.1.2)
sidekiq (~> 5.2.1)
sidekiq-cron (~> 0.6.0)
- sidekiq-limit_fetch (~> 3.4)
simple_po_parser (~> 1.1.2)
simplecov (~> 0.14.0)
slack-notifier (~> 1.5.1)
diff --git a/PROCESS.md b/PROCESS.md
index 583f36b820f..38ec01f9de0 100644
--- a/PROCESS.md
+++ b/PROCESS.md
@@ -74,14 +74,31 @@ star, smile, etc.). Some good tips about code reviews can be found in our
## Feature freeze on the 7th for the release on the 22nd
-After 7th at 23:59 (Pacific Time Zone) of each month, RC1 of the upcoming release (to be shipped on the 22nd) is created and deployed to GitLab.com and the stable branch for this release is frozen, which means master is no longer merged into it.
-Merge requests may still be merged into master during this period,
-but they will go into the _next_ release, unless they are manually cherry-picked into the stable branch.
+After 7th at 23:59 (Pacific Time Zone) of each month, RC1 of the upcoming
+release (to be shipped on the 22nd) is created and deployed to GitLab.com and
+the stable branch for this release is frozen, which means master is no longer
+merged into it. Merge requests may still be merged into master during this
+period, but they will go into the _next_ release, unless they are manually
+cherry-picked into the stable branch.
-By freezing the stable branches 2 weeks prior to a release, we reduce the risk of a last minute merge request potentially breaking things.
+By freezing the stable branches 2 weeks prior to a release, we reduce the risk
+of a last minute merge request potentially breaking things.
-Any release candidate that gets created after this date can become a final release,
-hence the name release candidate.
+Any release candidate that gets created after this date can become a final
+release, hence the name release candidate.
+
+### Feature flags
+
+Merge requests that make changes hidden behind a feature flag, or remove an
+existing feature flag because a feature is deemed stable, may be merged (and
+picked into the stable branches) up to the 19th of the month. Such merge
+requests should have the ~"feature flag" label assigned, and don't require a
+corresponding exception request to be created.
+
+While rare, release managers may decide to reject picking a change into a stable
+branch, even when feature flags are used. This might be necessary if the changes
+are deemed problematic, too invasive, or there simply isn't enough time to
+properly test how the changes behave on GitLab.com.
### Between the 1st and the 7th
@@ -223,36 +240,36 @@ Check [this guide](https://gitlab.com/gitlab-org/release/docs/blob/master/genera
A ~bug is a defect, error, failure which causes the system to behave incorrectly or prevents it from fulfilling the product requirements.
-The level of impact of a ~bug can vary from blocking a whole functionality
-or a feature usability bug. A bug should always be linked to a severity level.
+The level of impact of a ~bug can vary from blocking a whole functionality
+or a feature usability bug. A bug should always be linked to a severity level.
Refer to our [severity levels](../CONTRIBUTING.md#severity-labels)
-Whether the bug is also a regression or not, the triage process should start as soon as possible.
+Whether the bug is also a regression or not, the triage process should start as soon as possible.
Ensure that the Engineering Manager and/or the Product Manager for the relative area is involved to prioritize the work as needed.
### Regressions
A ~regression implies that a previously **verified working functionality** no longer works.
Regressions are a subset of bugs. We use the ~regression label to imply that the defect caused the functionality to regress.
-The label tells us that something worked before and it needs extra attention from Engineering and Product Managers to schedule/reschedule.
+The label tells us that something worked before and it needs extra attention from Engineering and Product Managers to schedule/reschedule.
-The regression label does not apply to ~bugs for new features for which functionality was **never verified as working**.
-These, by definition, are not regressions.
+The regression label does not apply to ~bugs for new features for which functionality was **never verified as working**.
+These, by definition, are not regressions.
A regression should always have the `regression:xx.x` label on it to designate when it was introduced.
-Regressions should be considered high priority issues that should be solved as soon as possible, especially if they have severe impact on users.
+Regressions should be considered high priority issues that should be solved as soon as possible, especially if they have severe impact on users.
### Managing bugs
-**Prioritization:** We give higher priority to regressions on features that worked in the last recent monthly release and the current release candidates.
-The two scenarios below can [bypass the exception request in the release process](https://gitlab.com/gitlab-org/release/docs/blob/master/general/exception-request/process.md#after-the-7th), where the affected regression version matches the current monthly release version.
+**Prioritization:** We give higher priority to regressions on features that worked in the last recent monthly release and the current release candidates.
+The two scenarios below can [bypass the exception request in the release process](https://gitlab.com/gitlab-org/release/docs/blob/master/general/exception-request/process.md#after-the-7th), where the affected regression version matches the current monthly release version.
* A regression which worked in the **Last monthly release**
* **Example:** In 11.0 we released a new `feature X` that is verified as working. Then in release 11.1 the feature no longer works, this is regression for 11.1. The issue should have the `regression:11.1` label.
* *Note:* When we say `the last recent monthly release`, this can refer to either the version currently running on GitLab.com, or the most recent version available in the package repositories.
* A regression which worked in the **Current release candidates**
* **Example:** In 11.1-RC3 we shipped a new feature which has been verified as working. Then in 11.1-RC5 the feature no longer works, this is regression for 11.1. The issue should have the `regression:11.1` label.
- * *Note:* Because GitLab.com runs release candidates of new releases, a regression can be reported in a release before its 'official' release date on the 22nd of the month.
+ * *Note:* Because GitLab.com runs release candidates of new releases, a regression can be reported in a release before its 'official' release date on the 22nd of the month.
When a bug is found:
1. Create an issue describing the problem in the most detailed way possible.
@@ -264,11 +281,11 @@ When a bug is found:
The counterpart Product Manager is included to weigh-in on prioritization as needed.
1. If the ~bug is **NOT** a regression:
1. The Engineering Manager decides which milestone the bug will be fixed. The appropriate milestone is applied.
-1. If the bug is a ~regression:
+1. If the bug is a ~regression:
1. Determine the release that the regression affects and add the corresponding `regression:xx.x` label.
1. If the affected release version can't be determined, add the generic ~regression label for the time being.
- 1. If the affected version `xx.x` in `regression:xx.x` is the **current release**, it's recommended to schedule the fix for the current milestone.
- 1. This falls under regressions which worked in the last release and the current RCs. More detailed explanations in the **Prioritization** section above.
+ 1. If the affected version `xx.x` in `regression:xx.x` is the **current release**, it's recommended to schedule the fix for the current milestone.
+ 1. This falls under regressions which worked in the last release and the current RCs. More detailed explanations in the **Prioritization** section above.
1. If the affected version `xx.x` in `regression:xx.x` is older than the **current release**
1. If the regression is an ~S1 severity, it's recommended to schedule the fix for the current milestone. We would like to fix the highest severity regression as soon as we can.
1. If the regression is an ~S2, ~S3 or ~S4 severity, the regression may be scheduled for later milestones at the discretion of the Engineering Manager and Product Manager.
diff --git a/VERSION b/VERSION
index e1ceae704b9..39a87ed80d7 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-11.3.0-pre
+11.4.0-pre
diff --git a/app/assets/images/cluster_app_logos/elasticsearch.png b/app/assets/images/cluster_app_logos/elasticsearch.png
new file mode 100644
index 00000000000..96e9e0ff934
--- /dev/null
+++ b/app/assets/images/cluster_app_logos/elasticsearch.png
Binary files differ
diff --git a/app/assets/images/cluster_app_logos/gitlab.png b/app/assets/images/cluster_app_logos/gitlab.png
new file mode 100644
index 00000000000..cb2195fc6a2
--- /dev/null
+++ b/app/assets/images/cluster_app_logos/gitlab.png
Binary files differ
diff --git a/app/assets/images/cluster_app_logos/helm.png b/app/assets/images/cluster_app_logos/helm.png
new file mode 100644
index 00000000000..2989cae7b93
--- /dev/null
+++ b/app/assets/images/cluster_app_logos/helm.png
Binary files differ
diff --git a/app/assets/images/cluster_app_logos/jeager.png b/app/assets/images/cluster_app_logos/jeager.png
new file mode 100644
index 00000000000..be5bf2a0c9c
--- /dev/null
+++ b/app/assets/images/cluster_app_logos/jeager.png
Binary files differ
diff --git a/app/assets/images/cluster_app_logos/jupyterhub.png b/app/assets/images/cluster_app_logos/jupyterhub.png
new file mode 100644
index 00000000000..80c7343067f
--- /dev/null
+++ b/app/assets/images/cluster_app_logos/jupyterhub.png
Binary files differ
diff --git a/app/assets/images/cluster_app_logos/kubernetes.png b/app/assets/images/cluster_app_logos/kubernetes.png
new file mode 100644
index 00000000000..4d774909c10
--- /dev/null
+++ b/app/assets/images/cluster_app_logos/kubernetes.png
Binary files differ
diff --git a/app/assets/images/cluster_app_logos/meltano.png b/app/assets/images/cluster_app_logos/meltano.png
new file mode 100644
index 00000000000..7a2d82fbe27
--- /dev/null
+++ b/app/assets/images/cluster_app_logos/meltano.png
Binary files differ
diff --git a/app/assets/images/cluster_app_logos/prometheus.png b/app/assets/images/cluster_app_logos/prometheus.png
new file mode 100644
index 00000000000..a8663449b88
--- /dev/null
+++ b/app/assets/images/cluster_app_logos/prometheus.png
Binary files differ
diff --git a/app/assets/javascripts/badges/components/badge.vue b/app/assets/javascripts/badges/components/badge.vue
index b08dc454d12..97232d7f783 100644
--- a/app/assets/javascripts/badges/components/badge.vue
+++ b/app/assets/javascripts/badges/components/badge.vue
@@ -103,8 +103,8 @@ export default {
</div>
<button
- v-tooltip
v-show="hasError"
+ v-tooltip
:title="s__('Badges|Reload badge image')"
class="btn btn-transparent btn-sm text-primary"
type="button"
diff --git a/app/assets/javascripts/behaviors/index.js b/app/assets/javascripts/behaviors/index.js
index 84fef4d8b4f..8c4eccc34a3 100644
--- a/app/assets/javascripts/behaviors/index.js
+++ b/app/assets/javascripts/behaviors/index.js
@@ -1,15 +1,19 @@
import './autosize';
import './bind_in_out';
import './markdown/render_gfm';
+import initGFMInput from './markdown/gfm_auto_complete';
import initCopyAsGFM from './markdown/copy_as_gfm';
import initCopyToClipboard from './copy_to_clipboard';
import './details_behavior';
import installGlEmojiElement from './gl_emoji';
import './quick_submit';
import './requires_input';
+import initPageShortcuts from './shortcuts';
import './toggler_behavior';
-import '../preview_markdown';
+import './preview_markdown';
installGlEmojiElement();
+initGFMInput();
initCopyAsGFM();
initCopyToClipboard();
+initPageShortcuts();
diff --git a/app/assets/javascripts/behaviors/markdown/gfm_auto_complete.js b/app/assets/javascripts/behaviors/markdown/gfm_auto_complete.js
new file mode 100644
index 00000000000..a303e504cc7
--- /dev/null
+++ b/app/assets/javascripts/behaviors/markdown/gfm_auto_complete.js
@@ -0,0 +1,19 @@
+import $ from 'jquery';
+import { convertPermissionToBoolean } from '~/lib/utils/common_utils';
+import GfmAutoComplete from '~/gfm_auto_complete';
+
+export default function initGFMInput() {
+ $('.js-gfm-input:not(.js-vue-textarea)').each((i, el) => {
+ const gfm = new GfmAutoComplete(gl.GfmAutoComplete && gl.GfmAutoComplete.dataSources);
+ const enableGFM = convertPermissionToBoolean(el.dataset.supportsAutocomplete);
+
+ gfm.setup($(el), {
+ emojis: true,
+ members: enableGFM,
+ issues: enableGFM,
+ milestones: enableGFM,
+ mergeRequests: enableGFM,
+ labels: enableGFM,
+ });
+ });
+}
diff --git a/app/assets/javascripts/behaviors/markdown/render_gfm.js b/app/assets/javascripts/behaviors/markdown/render_gfm.js
index dbff2bd4b10..429455f97ec 100644
--- a/app/assets/javascripts/behaviors/markdown/render_gfm.js
+++ b/app/assets/javascripts/behaviors/markdown/render_gfm.js
@@ -3,7 +3,7 @@ import syntaxHighlight from '~/syntax_highlight';
import renderMath from './render_math';
import renderMermaid from './render_mermaid';
-// Render Gitlab flavoured Markdown
+// Render GitLab flavoured Markdown
//
// Delegates to syntax highlight and render math & mermaid diagrams.
//
diff --git a/app/assets/javascripts/preview_markdown.js b/app/assets/javascripts/behaviors/preview_markdown.js
index 0964baf8954..0964baf8954 100644
--- a/app/assets/javascripts/preview_markdown.js
+++ b/app/assets/javascripts/behaviors/preview_markdown.js
diff --git a/app/assets/javascripts/behaviors/shortcuts.js b/app/assets/javascripts/behaviors/shortcuts.js
new file mode 100644
index 00000000000..7987a533ae5
--- /dev/null
+++ b/app/assets/javascripts/behaviors/shortcuts.js
@@ -0,0 +1,35 @@
+import Shortcuts from './shortcuts/shortcuts';
+
+export default function initPageShortcuts() {
+ const { page } = document.body.dataset;
+ const pagesWithCustomShortcuts = [
+ 'projects:activity',
+ 'projects:artifacts:browse',
+ 'projects:artifacts:file',
+ 'projects:blame:show',
+ 'projects:blob:show',
+ 'projects:commit:show',
+ 'projects:commits:show',
+ 'projects:find_file:show',
+ 'projects:issues:edit',
+ 'projects:issues:index',
+ 'projects:issues:new',
+ 'projects:issues:show',
+ 'projects:merge_requests:creations:diffs',
+ 'projects:merge_requests:creations:new',
+ 'projects:merge_requests:edit',
+ 'projects:merge_requests:index',
+ 'projects:merge_requests:show',
+ 'projects:network:show',
+ 'projects:show',
+ 'projects:tree:show',
+ 'groups:show',
+ ];
+
+ // the pages above have their own shortcuts sub-classes instantiated elsewhere
+ // TODO: replace this whitelist with something more automated/maintainable
+ if (page && !pagesWithCustomShortcuts.includes(page)) {
+ return new Shortcuts();
+ }
+ return false;
+}
diff --git a/app/assets/javascripts/shortcuts.js b/app/assets/javascripts/behaviors/shortcuts/shortcuts.js
index 99c71d6524a..6719bfd6d22 100644
--- a/app/assets/javascripts/shortcuts.js
+++ b/app/assets/javascripts/behaviors/shortcuts/shortcuts.js
@@ -1,9 +1,9 @@
import $ from 'jquery';
import Cookies from 'js-cookie';
import Mousetrap from 'mousetrap';
-import axios from './lib/utils/axios_utils';
-import { refreshCurrentPage, visitUrl } from './lib/utils/url_utility';
-import findAndFollowLink from './shortcuts_dashboard_navigation';
+import axios from '../../lib/utils/axios_utils';
+import { refreshCurrentPage, visitUrl } from '../../lib/utils/url_utility';
+import findAndFollowLink from '../../lib/utils/navigation_utility';
const defaultStopCallback = Mousetrap.stopCallback;
Mousetrap.stopCallback = (e, element, combo) => {
diff --git a/app/assets/javascripts/shortcuts_blob.js b/app/assets/javascripts/behaviors/shortcuts/shortcuts_blob.js
index 908b9cab93d..052e33b4a2b 100644
--- a/app/assets/javascripts/shortcuts_blob.js
+++ b/app/assets/javascripts/behaviors/shortcuts/shortcuts_blob.js
@@ -1,5 +1,5 @@
import Mousetrap from 'mousetrap';
-import { getLocationHash, visitUrl } from './lib/utils/url_utility';
+import { getLocationHash, visitUrl } from '../../lib/utils/url_utility';
import Shortcuts from './shortcuts';
const defaults = {
diff --git a/app/assets/javascripts/shortcuts_find_file.js b/app/assets/javascripts/behaviors/shortcuts/shortcuts_find_file.js
index 8658081c6c2..8658081c6c2 100644
--- a/app/assets/javascripts/shortcuts_find_file.js
+++ b/app/assets/javascripts/behaviors/shortcuts/shortcuts_find_file.js
diff --git a/app/assets/javascripts/shortcuts_issuable.js b/app/assets/javascripts/behaviors/shortcuts/shortcuts_issuable.js
index e9451be31fd..5e48bf5a35c 100644
--- a/app/assets/javascripts/shortcuts_issuable.js
+++ b/app/assets/javascripts/behaviors/shortcuts/shortcuts_issuable.js
@@ -1,9 +1,9 @@
import $ from 'jquery';
import Mousetrap from 'mousetrap';
import _ from 'underscore';
-import Sidebar from './right_sidebar';
+import Sidebar from '../../right_sidebar';
import Shortcuts from './shortcuts';
-import { CopyAsGFM } from './behaviors/markdown/copy_as_gfm';
+import { CopyAsGFM } from '../markdown/copy_as_gfm';
export default class ShortcutsIssuable extends Shortcuts {
constructor(isMergeRequest) {
diff --git a/app/assets/javascripts/shortcuts_navigation.js b/app/assets/javascripts/behaviors/shortcuts/shortcuts_navigation.js
index 6b595764bc5..fa9b2c9f755 100644
--- a/app/assets/javascripts/shortcuts_navigation.js
+++ b/app/assets/javascripts/behaviors/shortcuts/shortcuts_navigation.js
@@ -1,5 +1,5 @@
import Mousetrap from 'mousetrap';
-import findAndFollowLink from './shortcuts_dashboard_navigation';
+import findAndFollowLink from '../../lib/utils/navigation_utility';
import Shortcuts from './shortcuts';
export default class ShortcutsNavigation extends Shortcuts {
diff --git a/app/assets/javascripts/shortcuts_network.js b/app/assets/javascripts/behaviors/shortcuts/shortcuts_network.js
index a88c280fa3b..a88c280fa3b 100644
--- a/app/assets/javascripts/shortcuts_network.js
+++ b/app/assets/javascripts/behaviors/shortcuts/shortcuts_network.js
diff --git a/app/assets/javascripts/shortcuts_wiki.js b/app/assets/javascripts/behaviors/shortcuts/shortcuts_wiki.js
index 41865dcf4ba..8b7e6a56d25 100644
--- a/app/assets/javascripts/shortcuts_wiki.js
+++ b/app/assets/javascripts/behaviors/shortcuts/shortcuts_wiki.js
@@ -1,6 +1,6 @@
import Mousetrap from 'mousetrap';
import ShortcutsNavigation from './shortcuts_navigation';
-import findAndFollowLink from './shortcuts_dashboard_navigation';
+import findAndFollowLink from '../../lib/utils/navigation_utility';
export default class ShortcutsWiki extends ShortcutsNavigation {
constructor() {
diff --git a/app/assets/javascripts/blob/3d_viewer/index.js b/app/assets/javascripts/blob/3d_viewer/index.js
index 68d4ddad551..1bdf1aeb76c 100644
--- a/app/assets/javascripts/blob/3d_viewer/index.js
+++ b/app/assets/javascripts/blob/3d_viewer/index.js
@@ -29,12 +29,12 @@ export default class Renderer {
this.scene.add(this.camera);
- // Setup the viewer
+ // Set up the viewer
this.setupRenderer();
this.setupGrid();
this.setupLight();
- // Setup OrbitControls
+ // Set up OrbitControls
this.controls = new OrbitControls(
this.camera,
this.renderer.domElement,
diff --git a/app/assets/javascripts/boards/components/board_blank_state.vue b/app/assets/javascripts/boards/components/board_blank_state.vue
index 286529b4d13..cde22725a89 100644
--- a/app/assets/javascripts/boards/components/board_blank_state.vue
+++ b/app/assets/javascripts/boards/components/board_blank_state.vue
@@ -83,7 +83,7 @@ export default {
right on the way to making the most of your board.
</p>
<button
- class="btn btn-create btn-inverted btn-block"
+ class="btn btn-success btn-inverted btn-block"
type="button"
@click.stop="addDefaultLists">
Add default lists
diff --git a/app/assets/javascripts/boards/components/board_list.vue b/app/assets/javascripts/boards/components/board_list.vue
index 606c9e81db4..7ddb22ad824 100644
--- a/app/assets/javascripts/boards/components/board_list.vue
+++ b/app/assets/javascripts/boards/components/board_list.vue
@@ -231,14 +231,14 @@ export default {
<board-card
v-for="(issue, index) in issues"
ref="issue"
+ :key="issue.id"
:index="index"
:list="list"
:issue="issue"
:issue-link-base="issueLinkBase"
:group-id="groupId"
:root-path="rootPath"
- :disabled="disabled"
- :key="issue.id" />
+ :disabled="disabled" />
<li
v-if="showCount"
class="board-list-count text-center"
diff --git a/app/assets/javascripts/boards/components/board_new_issue.vue b/app/assets/javascripts/boards/components/board_new_issue.vue
index 1e3cd43d1f0..f248f53fa51 100644
--- a/app/assets/javascripts/boards/components/board_new_issue.vue
+++ b/app/assets/javascripts/boards/components/board_new_issue.vue
@@ -110,9 +110,9 @@ export default {
Title
</label>
<input
+ :id="list.id + '-title'"
ref="input"
v-model="title"
- :id="list.id + '-title'"
class="form-control"
type="text"
name="issue_title"
diff --git a/app/assets/javascripts/boards/components/issue_card_inner.vue b/app/assets/javascripts/boards/components/issue_card_inner.vue
index d50641dc3a9..8b5536200e1 100644
--- a/app/assets/javascripts/boards/components/issue_card_inner.vue
+++ b/app/assets/javascripts/boards/components/issue_card_inner.vue
@@ -149,10 +149,11 @@
<a
:href="issue.path"
:title="issue.title"
- class="js-no-trigger">{{ issue.title }}</a>
+ class="js-no-trigger"
+ @mousemove.stop>{{ issue.title }}</a>
<span
v-if="issueId"
- class="board-card-number"
+ class="board-card-number append-right-5"
>
{{ issue.referencePath }}
</span>
@@ -170,8 +171,8 @@
tooltip-placement="bottom"
/>
<span
- v-tooltip
v-if="shouldRenderCounter"
+ v-tooltip
:title="assigneeCounterTooltip"
class="avatar-counter"
>
@@ -184,10 +185,10 @@
class="board-card-footer"
>
<button
- v-tooltip
v-for="label in issue.labels"
v-if="showLabel(label)"
:key="label.id"
+ v-tooltip
:style="labelStyle(label)"
:title="label.description"
class="badge color-label"
diff --git a/app/assets/javascripts/boards/components/modal/lists_dropdown.vue b/app/assets/javascripts/boards/components/modal/lists_dropdown.vue
index 6a5a39099bd..4f23e5db35c 100644
--- a/app/assets/javascripts/boards/components/modal/lists_dropdown.vue
+++ b/app/assets/javascripts/boards/components/modal/lists_dropdown.vue
@@ -1,7 +1,11 @@
<script>
+import { Link } from '@gitlab-org/gitlab-ui';
import ModalStore from '../../stores/modal_store';
export default {
+ components: {
+ 'gl-link': Link,
+ },
data() {
return {
modal: ModalStore.store,
@@ -38,7 +42,7 @@ export default {
v-for="(list, i) in state.lists"
v-if="list.type == 'label'"
:key="i">
- <a
+ <gl-link
:class="{ 'is-active': list.id == selected.id }"
href="#"
role="button"
@@ -48,7 +52,7 @@ export default {
class="dropdown-label-box">
</span>
{{ list.title }}
- </a>
+ </gl-link>
</li>
</ul>
</div>
diff --git a/app/assets/javascripts/boards/index.js b/app/assets/javascripts/boards/index.js
index bc263cbbfea..662363a6f26 100644
--- a/app/assets/javascripts/boards/index.js
+++ b/app/assets/javascripts/boards/index.js
@@ -9,7 +9,7 @@ import '~/vue_shared/models/assignee';
import FilteredSearchBoards from './filtered_search_boards';
import eventHub from './eventhub';
-import sidebarEventHub from '~/sidebar/event_hub'; // eslint-disable-line import/first
+import sidebarEventHub from '~/sidebar/event_hub';
import './models/issue';
import './models/list';
import './models/milestone';
@@ -24,7 +24,7 @@ import './components/board';
import './components/board_sidebar';
import './components/new_list_dropdown';
import BoardAddIssuesModal from './components/modal/index.vue';
-import '~/vue_shared/vue_resource_interceptor'; // eslint-disable-line import/first
+import '~/vue_shared/vue_resource_interceptor';
export default () => {
const $boardApp = document.getElementById('board-app');
@@ -229,7 +229,7 @@ export default () => {
template: `
<div class="board-extra-actions">
<button
- class="btn btn-create prepend-left-10"
+ class="btn btn-success prepend-left-10"
type="button"
data-placement="bottom"
ref="addIssuesButton"
diff --git a/app/assets/javascripts/build_variables.js b/app/assets/javascripts/build_variables.js
deleted file mode 100644
index d398e4a4c83..00000000000
--- a/app/assets/javascripts/build_variables.js
+++ /dev/null
@@ -1,10 +0,0 @@
-import $ from 'jquery';
-
-export default function handleRevealVariables() {
- $('.js-reveal-variables')
- .off('click')
- .on('click', function click() {
- $('.js-build-variables').toggle();
- $(this).hide();
- });
-}
diff --git a/app/assets/javascripts/clusters/components/application_row.vue b/app/assets/javascripts/clusters/components/application_row.vue
index 651f3b50236..0452729d3ff 100644
--- a/app/assets/javascripts/clusters/components/application_row.vue
+++ b/app/assets/javascripts/clusters/components/application_row.vue
@@ -2,6 +2,7 @@
/* eslint-disable vue/require-default-prop */
import { s__, sprintf } from '../../locale';
import eventHub from '../event_hub';
+ import identicon from '../../vue_shared/components/identicon.vue';
import loadingButton from '../../vue_shared/components/loading_button.vue';
import {
APPLICATION_STATUS,
@@ -13,6 +14,7 @@
export default {
components: {
loadingButton,
+ identicon,
},
props: {
id: {
@@ -31,6 +33,16 @@
type: String,
required: false,
},
+ logoUrl: {
+ type: String,
+ required: false,
+ default: null,
+ },
+ disabled: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
status: {
type: String,
required: false,
@@ -60,6 +72,18 @@
isKnownStatus() {
return Object.values(APPLICATION_STATUS).includes(this.status);
},
+ isInstalled() {
+ return (
+ this.status === APPLICATION_STATUS.INSTALLED || this.status === APPLICATION_STATUS.UPDATED
+ );
+ },
+ hasLogo() {
+ return !!this.logoUrl;
+ },
+ identiconId() {
+ // generate a deterministic integer id for the identicon background
+ return this.id.charCodeAt(0);
+ },
rowJsClass() {
return `js-cluster-application-row-${this.id}`;
},
@@ -128,37 +152,81 @@
<template>
<div
- :class="rowJsClass"
- class="gl-responsive-table-row gl-responsive-table-row-col-span"
+ :class="[
+ rowJsClass,
+ isInstalled && 'cluster-application-installed',
+ disabled && 'cluster-application-disabled'
+ ]"
+ class="cluster-application-row gl-responsive-table-row gl-responsive-table-row-col-span"
>
<div
class="gl-responsive-table-row-layout"
role="row"
>
- <a
- v-if="titleLink"
- :href="titleLink"
- target="blank"
- rel="noopener noreferrer"
+ <div
+ class="table-section append-right-8 section-align-top"
role="gridcell"
- class="table-section section-15 section-align-top js-cluster-application-title"
>
- {{ title }}
- </a>
- <span
- v-else
- class="table-section section-15 section-align-top js-cluster-application-title"
- >
- {{ title }}
- </span>
+ <img
+ v-if="hasLogo"
+ :src="logoUrl"
+ :alt="`${title} logo`"
+ class="cluster-application-logo avatar s40"
+ />
+ <identicon
+ v-else
+ :entity-id="identiconId"
+ :entity-name="title"
+ size-class="s40"
+ />
+ </div>
<div
- class="table-section section-wrap"
+ class="table-section cluster-application-description section-wrap"
role="gridcell"
>
+ <strong>
+ <a
+ v-if="titleLink"
+ :href="titleLink"
+ target="blank"
+ rel="noopener noreferrer"
+ class="js-cluster-application-title"
+ >
+ {{ title }}
+ </a>
+ <span
+ v-else
+ class="js-cluster-application-title"
+ >
+ {{ title }}
+ </span>
+ </strong>
<slot name="description"></slot>
+ <div
+ v-if="hasError || isUnknownStatus"
+ class="cluster-application-error text-danger prepend-top-10"
+ >
+ <p class="js-cluster-application-general-error-message append-bottom-0">
+ {{ generalErrorDescription }}
+ </p>
+ <ul v-if="statusReason || requestReason">
+ <li
+ v-if="statusReason"
+ class="js-cluster-application-status-error-message"
+ >
+ {{ statusReason }}
+ </li>
+ <li
+ v-if="requestReason"
+ class="js-cluster-application-request-error-message"
+ >
+ {{ requestReason }}
+ </li>
+ </ul>
+ </div>
</div>
<div
- :class="{ 'section-20': showManageButton, 'section-15': !showManageButton }"
+ :class="{ 'section-25': showManageButton, 'section-15': !showManageButton }"
class="table-section table-button-footer section-align-top"
role="gridcell"
>
@@ -168,6 +236,7 @@
>
<a
:href="manageLink"
+ :class="{ disabled: disabled }"
class="btn"
>
{{ manageButtonLabel }}
@@ -176,7 +245,7 @@
<div class="btn-group table-action-buttons">
<loading-button
:loading="installButtonLoading"
- :disabled="installButtonDisabled"
+ :disabled="disabled || installButtonDisabled"
:label="installButtonLabel"
class="js-cluster-application-install-button"
@click="installClicked"
@@ -184,35 +253,5 @@
</div>
</div>
</div>
- <div
- v-if="hasError || isUnknownStatus"
- class="gl-responsive-table-row-layout"
- role="row"
- >
- <div
- class="alert alert-danger alert-block append-bottom-0 clusters-error-alert"
- role="gridcell"
- >
- <div>
- <p class="js-cluster-application-general-error-message">
- {{ generalErrorDescription }}
- </p>
- <ul v-if="statusReason || requestReason">
- <li
- v-if="statusReason"
- class="js-cluster-application-status-error-message"
- >
- {{ statusReason }}
- </li>
- <li
- v-if="requestReason"
- class="js-cluster-application-request-error-message"
- >
- {{ requestReason }}
- </li>
- </ul>
- </div>
- </div>
- </div>
</div>
</template>
diff --git a/app/assets/javascripts/clusters/components/applications.vue b/app/assets/javascripts/clusters/components/applications.vue
index d708a9e595a..a1069985178 100644
--- a/app/assets/javascripts/clusters/components/applications.vue
+++ b/app/assets/javascripts/clusters/components/applications.vue
@@ -1,5 +1,14 @@
<script>
import _ from 'underscore';
+import helmInstallIllustration from '@gitlab-org/gitlab-svgs/illustrations/kubernetes-installation.svg';
+import elasticsearchLogo from 'images/cluster_app_logos/elasticsearch.png';
+import gitlabLogo from 'images/cluster_app_logos/gitlab.png';
+import helmLogo from 'images/cluster_app_logos/helm.png';
+import jeagerLogo from 'images/cluster_app_logos/jeager.png';
+import jupyterhubLogo from 'images/cluster_app_logos/jupyterhub.png';
+import kubernetesLogo from 'images/cluster_app_logos/kubernetes.png';
+import meltanoLogo from 'images/cluster_app_logos/meltano.png';
+import prometheusLogo from 'images/cluster_app_logos/prometheus.png';
import { s__, sprintf } from '../../locale';
import applicationRow from './application_row.vue';
import clipboardButton from '../../vue_shared/components/clipboard_button.vue';
@@ -37,21 +46,21 @@ export default {
default: '',
},
},
+ data: () => ({
+ elasticsearchLogo,
+ gitlabLogo,
+ helmLogo,
+ jeagerLogo,
+ jupyterhubLogo,
+ kubernetesLogo,
+ meltanoLogo,
+ prometheusLogo,
+ }),
computed: {
- generalApplicationDescription() {
- return sprintf(
- _.escape(
- s__(
- `ClusterIntegration|Install applications on your Kubernetes cluster.
- Read more about %{helpLink}`,
- ),
- ),
- {
- helpLink: `<a href="${this.helpPath}">
- ${_.escape(s__('ClusterIntegration|installing applications'))}
- </a>`,
- },
- false,
+ helmInstalled() {
+ return (
+ this.applications.helm.status === APPLICATION_STATUS.INSTALLED ||
+ this.applications.helm.status === APPLICATION_STATUS.UPDATED
);
},
ingressId() {
@@ -128,224 +137,240 @@ export default {
return this.applications.jupyter.hostname;
},
},
+ created() {
+ this.helmInstallIllustration = helmInstallIllustration;
+ },
};
</script>
<template>
- <section
- id="cluster-applications"
- class="settings no-animate expanded"
- >
- <div class="settings-header">
- <h4>
- {{ s__('ClusterIntegration|Applications') }}
- </h4>
- <p
- class="append-bottom-0"
- v-html="generalApplicationDescription"
- >
- </p>
- </div>
+ <section id="cluster-applications">
+ <h4>
+ {{ s__('ClusterIntegration|Applications') }}
+ </h4>
+ <p class="append-bottom-0">
+ {{ s__(`ClusterIntegration|Choose which applications to install on your Kubernetes cluster.
+ Helm Tiller is required to install any of the following applications.`) }}
+ <a :href="helpPath">
+ {{ __('More information') }}
+ </a>
+ </p>
- <div class="settings-content">
- <div class="append-bottom-20">
- <application-row
- id="helm"
- :title="applications.helm.title"
- :status="applications.helm.status"
- :status-reason="applications.helm.statusReason"
- :request-status="applications.helm.requestStatus"
- :request-reason="applications.helm.requestReason"
- title-link="https://docs.helm.sh/"
- >
- <div slot="description">
- {{ s__(`ClusterIntegration|Helm streamlines installing
- and managing Kubernetes applications.
- Tiller runs inside of your Kubernetes Cluster,
- and manages releases of your charts.`) }}
- </div>
- </application-row>
- <application-row
- :id="ingressId"
- :title="applications.ingress.title"
- :status="applications.ingress.status"
- :status-reason="applications.ingress.statusReason"
- :request-status="applications.ingress.requestStatus"
- :request-reason="applications.ingress.requestReason"
- title-link="https://kubernetes.io/docs/concepts/services-networking/ingress/"
+ <div class="cluster-application-list prepend-top-10">
+ <application-row
+ id="helm"
+ :logo-url="helmLogo"
+ :title="applications.helm.title"
+ :status="applications.helm.status"
+ :status-reason="applications.helm.statusReason"
+ :request-status="applications.helm.requestStatus"
+ :request-reason="applications.helm.requestReason"
+ class="rounded-top"
+ title-link="https://docs.helm.sh/"
+ >
+ <div slot="description">
+ {{ s__(`ClusterIntegration|Helm streamlines installing
+ and managing Kubernetes applications.
+ Tiller runs inside of your Kubernetes Cluster,
+ and manages releases of your charts.`) }}
+ </div>
+ </application-row>
+ <div
+ v-show="!helmInstalled"
+ class="cluster-application-warning"
+ >
+ <div
+ class="svg-container"
+ v-html="helmInstallIllustration"
>
- <div slot="description">
- <p>
- {{ s__(`ClusterIntegration|Ingress gives you a way to route
- requests to services based on the request host or path,
- centralizing a number of services into a single entrypoint.`) }}
- </p>
+ </div>
+ {{ s__(`ClusterIntegration|You must first install Helm Tiller before
+ installing the applications below`) }}
+ </div>
+ <application-row
+ :id="ingressId"
+ :logo-url="kubernetesLogo"
+ :title="applications.ingress.title"
+ :status="applications.ingress.status"
+ :status-reason="applications.ingress.statusReason"
+ :request-status="applications.ingress.requestStatus"
+ :request-reason="applications.ingress.requestReason"
+ :disabled="!helmInstalled"
+ title-link="https://kubernetes.io/docs/concepts/services-networking/ingress/"
+ >
+ <div slot="description">
+ <p>
+ {{ s__(`ClusterIntegration|Ingress gives you a way to route
+ requests to services based on the request host or path,
+ centralizing a number of services into a single entrypoint.`) }}
+ </p>
- <template v-if="ingressInstalled">
- <div class="form-group">
- <label for="ingress-ip-address">
- {{ s__('ClusterIntegration|Ingress IP Address') }}
- </label>
- <div
- v-if="ingressExternalIp"
- class="input-group"
- >
- <input
- id="ingress-ip-address"
- :value="ingressExternalIp"
- type="text"
- class="form-control js-ip-address"
- readonly
- />
- <span class="input-group-append">
- <clipboard-button
- :text="ingressExternalIp"
- :title="s__('ClusterIntegration|Copy Ingress IP Address to clipboard')"
- class="input-group-text js-clipboard-btn"
- />
- </span>
- </div>
+ <template v-if="ingressInstalled">
+ <div class="form-group">
+ <label for="ingress-ip-address">
+ {{ s__('ClusterIntegration|Ingress IP Address') }}
+ </label>
+ <div
+ v-if="ingressExternalIp"
+ class="input-group"
+ >
<input
- v-else
+ id="ingress-ip-address"
+ :value="ingressExternalIp"
type="text"
class="form-control js-ip-address"
readonly
- value="?"
/>
+ <span class="input-group-append">
+ <clipboard-button
+ :text="ingressExternalIp"
+ :title="s__('ClusterIntegration|Copy Ingress IP Address to clipboard')"
+ class="input-group-text js-clipboard-btn"
+ />
+ </span>
</div>
+ <input
+ v-else
+ type="text"
+ class="form-control js-ip-address"
+ readonly
+ value="?"
+ />
+ </div>
- <p
- v-if="!ingressExternalIp"
- class="settings-message js-no-ip-message"
- >
- {{ s__(`ClusterIntegration|The IP address is in
- the process of being assigned. Please check your Kubernetes
- cluster or Quotas on Google Kubernetes Engine if it takes a long time.`) }}
+ <p
+ v-if="!ingressExternalIp"
+ class="settings-message js-no-ip-message"
+ >
+ {{ s__(`ClusterIntegration|The IP address is in
+ the process of being assigned. Please check your Kubernetes
+ cluster or Quotas on Google Kubernetes Engine if it takes a long time.`) }}
- <a
- :href="ingressHelpPath"
- target="_blank"
- rel="noopener noreferrer"
- >
- {{ __('More information') }}
- </a>
- </p>
+ <a
+ :href="ingressHelpPath"
+ target="_blank"
+ rel="noopener noreferrer"
+ >
+ {{ __('More information') }}
+ </a>
+ </p>
- <p>
- {{ s__(`ClusterIntegration|Point a wildcard DNS to this
- generated IP address in order to access
- your application after it has been deployed.`) }}
- <a
- :href="ingressDnsHelpPath"
- target="_blank"
- rel="noopener noreferrer"
- >
- {{ __('More information') }}
- </a>
- </p>
+ <p>
+ {{ s__(`ClusterIntegration|Point a wildcard DNS to this
+ generated IP address in order to access
+ your application after it has been deployed.`) }}
+ <a
+ :href="ingressDnsHelpPath"
+ target="_blank"
+ rel="noopener noreferrer"
+ >
+ {{ __('More information') }}
+ </a>
+ </p>
- </template>
- <div
- v-else
- v-html="ingressDescription"
- >
- </div>
- </div>
- </application-row>
- <application-row
- id="prometheus"
- :title="applications.prometheus.title"
- :manage-link="managePrometheusPath"
- :status="applications.prometheus.status"
- :status-reason="applications.prometheus.statusReason"
- :request-status="applications.prometheus.requestStatus"
- :request-reason="applications.prometheus.requestReason"
- title-link="https://prometheus.io/docs/introduction/overview/"
- >
+ </template>
<div
- slot="description"
- v-html="prometheusDescription"
+ v-html="ingressDescription"
>
</div>
- </application-row>
- <application-row
- id="runner"
- :title="applications.runner.title"
- :status="applications.runner.status"
- :status-reason="applications.runner.statusReason"
- :request-status="applications.runner.requestStatus"
- :request-reason="applications.runner.requestReason"
- title-link="https://docs.gitlab.com/runner/"
- >
- <div slot="description">
- {{ s__(`ClusterIntegration|GitLab Runner connects to this
- project's repository and executes CI/CD jobs,
- pushing results back and deploying,
- applications to production.`) }}
- </div>
- </application-row>
- <application-row
- id="jupyter"
- :title="applications.jupyter.title"
- :status="applications.jupyter.status"
- :status-reason="applications.jupyter.statusReason"
- :request-status="applications.jupyter.requestStatus"
- :request-reason="applications.jupyter.requestReason"
- :install-application-request-params="{ hostname: applications.jupyter.hostname }"
- title-link="https://jupyterhub.readthedocs.io/en/stable/"
+ </div>
+ </application-row>
+ <application-row
+ id="prometheus"
+ :logo-url="prometheusLogo"
+ :title="applications.prometheus.title"
+ :manage-link="managePrometheusPath"
+ :status="applications.prometheus.status"
+ :status-reason="applications.prometheus.statusReason"
+ :request-status="applications.prometheus.requestStatus"
+ :request-reason="applications.prometheus.requestReason"
+ :disabled="!helmInstalled"
+ title-link="https://prometheus.io/docs/introduction/overview/"
+ >
+ <div
+ slot="description"
+ v-html="prometheusDescription"
>
- <div slot="description">
- <p>
- {{ s__(`ClusterIntegration|JupyterHub, a multi-user Hub, spawns,
- manages, and proxies multiple instances of the single-user
- Jupyter notebook server. JupyterHub can be used to serve
- notebooks to a class of students, a corporate data science group,
- or a scientific research group.`) }}
- </p>
+ </div>
+ </application-row>
+ <application-row
+ id="runner"
+ :logo-url="gitlabLogo"
+ :title="applications.runner.title"
+ :status="applications.runner.status"
+ :status-reason="applications.runner.statusReason"
+ :request-status="applications.runner.requestStatus"
+ :request-reason="applications.runner.requestReason"
+ :disabled="!helmInstalled"
+ title-link="https://docs.gitlab.com/runner/"
+ >
+ <div slot="description">
+ {{ s__(`ClusterIntegration|GitLab Runner connects to this
+ project's repository and executes CI/CD jobs,
+ pushing results back and deploying,
+ applications to production.`) }}
+ </div>
+ </application-row>
+ <application-row
+ id="jupyter"
+ :logo-url="jupyterhubLogo"
+ :title="applications.jupyter.title"
+ :status="applications.jupyter.status"
+ :status-reason="applications.jupyter.statusReason"
+ :request-status="applications.jupyter.requestStatus"
+ :request-reason="applications.jupyter.requestReason"
+ :install-application-request-params="{ hostname: applications.jupyter.hostname }"
+ :disabled="!helmInstalled"
+ class="hide-bottom-border rounded-bottom"
+ title-link="https://jupyterhub.readthedocs.io/en/stable/"
+ >
+ <div slot="description">
+ <p>
+ {{ s__(`ClusterIntegration|JupyterHub, a multi-user Hub, spawns,
+ manages, and proxies multiple instances of the single-user
+ Jupyter notebook server. JupyterHub can be used to serve
+ notebooks to a class of students, a corporate data science group,
+ or a scientific research group.`) }}
+ </p>
- <template v-if="ingressExternalIp">
- <div class="form-group">
- <label for="jupyter-hostname">
- {{ s__('ClusterIntegration|Jupyter Hostname') }}
- </label>
+ <template v-if="ingressExternalIp">
+ <div class="form-group">
+ <label for="jupyter-hostname">
+ {{ s__('ClusterIntegration|Jupyter Hostname') }}
+ </label>
- <div class="input-group">
- <input
- v-model="applications.jupyter.hostname"
- :readonly="jupyterInstalled"
- type="text"
- class="form-control js-hostname"
+ <div class="input-group">
+ <input
+ v-model="applications.jupyter.hostname"
+ :readonly="jupyterInstalled"
+ type="text"
+ class="form-control js-hostname"
+ />
+ <span
+ class="input-group-btn"
+ >
+ <clipboard-button
+ :text="jupyterHostname"
+ :title="s__('ClusterIntegration|Copy Jupyter Hostname to clipboard')"
+ class="js-clipboard-btn"
/>
- <span
- class="input-group-btn"
- >
- <clipboard-button
- :text="jupyterHostname"
- :title="s__('ClusterIntegration|Copy Jupyter Hostname to clipboard')"
- class="js-clipboard-btn"
- />
- </span>
- </div>
+ </span>
</div>
- <p v-if="ingressInstalled">
- {{ s__(`ClusterIntegration|Replace this with your own hostname if you want.
- If you do so, point hostname to Ingress IP Address from above.`) }}
- <a
- :href="ingressDnsHelpPath"
- target="_blank"
- rel="noopener noreferrer"
- >
- {{ __('More information') }}
- </a>
- </p>
- </template>
- </div>
- </application-row>
- <!--
- NOTE: Don't forget to update `clusters.scss`
- min-height for this block and uncomment `application_spec` tests
- -->
- </div>
+ </div>
+ <p v-if="ingressInstalled">
+ {{ s__(`ClusterIntegration|Replace this with your own hostname if you want.
+ If you do so, point hostname to Ingress IP Address from above.`) }}
+ <a
+ :href="ingressDnsHelpPath"
+ target="_blank"
+ rel="noopener noreferrer"
+ >
+ {{ __('More information') }}
+ </a>
+ </p>
+ </template>
+ </div>
+ </application-row>
</div>
</section>
</template>
diff --git a/app/assets/javascripts/commons/gitlab_ui.js b/app/assets/javascripts/commons/gitlab_ui.js
index aed26adfa5c..1411f7ffd5e 100644
--- a/app/assets/javascripts/commons/gitlab_ui.js
+++ b/app/assets/javascripts/commons/gitlab_ui.js
@@ -1,16 +1,17 @@
import Vue from 'vue';
-import Pagination from '@gitlab-org/gitlab-ui/dist/components/base/pagination';
-import progressBar from '@gitlab-org/gitlab-ui/dist/components/base/progress_bar';
-import modal from '@gitlab-org/gitlab-ui/dist/components/base/modal';
-import loadingIcon from '@gitlab-org/gitlab-ui/dist/components/base/loading_icon';
-
-import dModal from '@gitlab-org/gitlab-ui/dist/directives/modal';
-import dTooltip from '@gitlab-org/gitlab-ui/dist/directives/tooltip';
+import {
+ Pagination,
+ ProgressBar,
+ Modal,
+ LoadingIcon,
+ ModalDirective,
+ TooltipDirective,
+} from '@gitlab-org/gitlab-ui';
Vue.component('gl-pagination', Pagination);
-Vue.component('gl-progress-bar', progressBar);
-Vue.component('gl-ui-modal', modal);
-Vue.component('gl-loading-icon', loadingIcon);
+Vue.component('gl-progress-bar', ProgressBar);
+Vue.component('gl-ui-modal', Modal);
+Vue.component('gl-loading-icon', LoadingIcon);
-Vue.directive('gl-modal', dModal);
-Vue.directive('gl-tooltip', dTooltip);
+Vue.directive('gl-modal', ModalDirective);
+Vue.directive('gl-tooltip', TooltipDirective);
diff --git a/app/assets/javascripts/commons/polyfills.js b/app/assets/javascripts/commons/polyfills.js
index 742cf490ad2..539d0d29e0d 100644
--- a/app/assets/javascripts/commons/polyfills.js
+++ b/app/assets/javascripts/commons/polyfills.js
@@ -14,10 +14,10 @@ import 'core-js/es6/map';
import 'core-js/es6/weak-map';
// Browser polyfills
-import 'classlist-polyfill';
import 'formdata-polyfill';
import './polyfills/custom_event';
import './polyfills/element';
import './polyfills/event';
import './polyfills/nodelist';
import './polyfills/request_idle_callback';
+import './polyfills/svg';
diff --git a/app/assets/javascripts/commons/polyfills/element.js b/app/assets/javascripts/commons/polyfills/element.js
index b593bde6aa2..dde5e8f54f9 100644
--- a/app/assets/javascripts/commons/polyfills/element.js
+++ b/app/assets/javascripts/commons/polyfills/element.js
@@ -1,12 +1,17 @@
-Element.prototype.closest = Element.prototype.closest ||
+// polyfill Element.classList and DOMTokenList with classList.js
+import 'classlist-polyfill';
+
+Element.prototype.closest =
+ Element.prototype.closest ||
function closest(selector, selectedElement = this) {
if (!selectedElement) return null;
- return selectedElement.matches(selector) ?
- selectedElement :
- Element.prototype.closest(selector, selectedElement.parentElement);
+ return selectedElement.matches(selector)
+ ? selectedElement
+ : Element.prototype.closest(selector, selectedElement.parentElement);
};
-Element.prototype.matches = Element.prototype.matches ||
+Element.prototype.matches =
+ Element.prototype.matches ||
Element.prototype.matchesSelector ||
Element.prototype.mozMatchesSelector ||
Element.prototype.msMatchesSelector ||
@@ -15,13 +20,15 @@ Element.prototype.matches = Element.prototype.matches ||
function matches(selector) {
const elms = (this.document || this.ownerDocument).querySelectorAll(selector);
let i = elms.length - 1;
- while (i >= 0 && elms.item(i) !== this) { i -= 1; }
+ while (i >= 0 && elms.item(i) !== this) {
+ i -= 1;
+ }
return i > -1;
};
// From the polyfill on MDN, https://developer.mozilla.org/en-US/docs/Web/API/ChildNode/remove#Polyfill
-((arr) => {
- arr.forEach((item) => {
+(arr => {
+ arr.forEach(item => {
if (Object.prototype.hasOwnProperty.call(item, 'remove')) {
return;
}
diff --git a/app/assets/javascripts/commons/polyfills/svg.js b/app/assets/javascripts/commons/polyfills/svg.js
new file mode 100644
index 00000000000..8648a568f6f
--- /dev/null
+++ b/app/assets/javascripts/commons/polyfills/svg.js
@@ -0,0 +1,5 @@
+import svg4everybody from 'svg4everybody';
+
+// polyfill support for external SVG file references via <use xlink:href>
+// @see https://css-tricks.com/svg-use-external-source/
+svg4everybody();
diff --git a/app/assets/javascripts/deploy_keys/components/key.vue b/app/assets/javascripts/deploy_keys/components/key.vue
index f66ca070445..c05b9b1de79 100644
--- a/app/assets/javascripts/deploy_keys/components/key.vue
+++ b/app/assets/javascripts/deploy_keys/components/key.vue
@@ -145,8 +145,8 @@ export default {
<icon :name="firstProject.can_push ? 'lock-open' : 'lock'"/>
</a>
<a
- v-tooltip
v-if="isExpandable"
+ v-tooltip
:title="restProjectsTooltip"
class="label deploy-project-label"
@click="toggleExpanded"
@@ -154,10 +154,10 @@ export default {
<span>{{ restProjectsLabel }}</span>
</a>
<a
- v-tooltip
v-for="deployKeysProject in restProjects"
v-else-if="isExpanded"
:key="deployKeysProject.project.full_path"
+ v-tooltip
:href="deployKeysProject.project.full_path"
:title="projectTooltipTitle(deployKeysProject)"
class="label deploy-project-label"
@@ -198,8 +198,8 @@ export default {
{{ __('Enable') }}
</action-btn>
<a
- v-tooltip
v-if="deployKey.can_edit"
+ v-tooltip
:href="editDeployKeyPath"
:title="__('Edit')"
class="btn btn-default text-secondary"
@@ -208,8 +208,8 @@ export default {
<icon name="pencil"/>
</a>
<action-btn
- v-tooltip
v-if="isRemovable"
+ v-tooltip
:deploy-key="deployKey"
:title="__('Remove')"
btn-css-class="btn-danger"
@@ -219,8 +219,8 @@ export default {
<icon name="remove"/>
</action-btn>
<action-btn
- v-tooltip
v-else-if="isEnabled"
+ v-tooltip
:deploy-key="deployKey"
:title="__('Disable')"
btn-css-class="btn-warning"
diff --git a/app/assets/javascripts/diffs/components/app.vue b/app/assets/javascripts/diffs/components/app.vue
index bfb992340bc..fc41ee4b777 100644
--- a/app/assets/javascripts/diffs/components/app.vue
+++ b/app/assets/javascripts/diffs/components/app.vue
@@ -9,6 +9,7 @@ import ChangedFiles from './changed_files.vue';
import DiffFile from './diff_file.vue';
import NoChanges from './no_changes.vue';
import HiddenFilesWarning from './hidden_files_warning.vue';
+import CommitWidget from './commit_widget.vue';
export default {
name: 'DiffsApp',
@@ -19,6 +20,7 @@ export default {
DiffFile,
NoChanges,
HiddenFilesWarning,
+ CommitWidget,
},
props: {
endpoint: {
@@ -208,6 +210,11 @@ export default {
</div>
</div>
+ <commit-widget
+ v-if="commit"
+ :commit="commit"
+ />
+
<changed-files
:diff-files="diffFiles"
/>
diff --git a/app/assets/javascripts/diffs/components/commit_item.vue b/app/assets/javascripts/diffs/components/commit_item.vue
new file mode 100644
index 00000000000..5758588e82e
--- /dev/null
+++ b/app/assets/javascripts/diffs/components/commit_item.vue
@@ -0,0 +1,119 @@
+<script>
+import tooltip from '~/vue_shared/directives/tooltip';
+import UserAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link.vue';
+import Icon from '~/vue_shared/components/icon.vue';
+import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
+import CIIcon from '~/vue_shared/components/ci_icon.vue';
+import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
+
+/**
+ * CommitItem
+ *
+ * -----------------------------------------------------------------
+ * WARNING: Please keep changes up-to-date with the following files:
+ * - `views/projects/commits/_commit.html.haml`
+ * -----------------------------------------------------------------
+ *
+ * This Component was cloned from a HAML view. For the time being they
+ * coexist, but there is an issue to remove the duplication.
+ * https://gitlab.com/gitlab-org/gitlab-ce/issues/51613
+ *
+ */
+export default {
+ directives: {
+ tooltip,
+ },
+ components: {
+ UserAvatarLink,
+ Icon,
+ ClipboardButton,
+ CIIcon,
+ TimeAgoTooltip,
+ },
+ props: {
+ commit: {
+ type: Object,
+ required: true,
+ },
+ },
+ computed: {
+ authorName() {
+ return (this.commit.author && this.commit.author.name) || this.commit.authorName;
+ },
+ authorUrl() {
+ return (this.commit.author && this.commit.author.webUrl) || `mailto:${this.commit.authorEmail}`;
+ },
+ authorAvatar() {
+ return (this.commit.author && this.commit.author.avatarUrl) || this.commit.authorGravatarUrl;
+ },
+ },
+};
+</script>
+
+<template>
+ <li class="commit flex-row js-toggle-container">
+ <user-avatar-link
+ :link-href="authorUrl"
+ :img-src="authorAvatar"
+ :img-alt="authorName"
+ :img-size="36"
+ class="avatar-cell d-none d-sm-block"
+ />
+ <div class="commit-detail flex-list">
+ <div class="commit-content qa-commit-content">
+ <a
+ :href="commit.commitUrl"
+ class="commit-row-message item-title"
+ v-html="commit.titleHtml"
+ ></a>
+
+ <span class="commit-row-message d-block d-sm-none">
+ &middot;
+ {{ commit.shortId }}
+ </span>
+
+ <button
+ v-if="commit.descriptionHtml"
+ class="text-expander js-toggle-button"
+ type="button"
+ :aria-label="__('Toggle commit description')"
+ >
+ <icon
+ :size="12"
+ name="ellipsis_h"
+ />
+ </button>
+
+ <div class="commiter">
+ <a
+ :href="authorUrl"
+ v-text="authorName"
+ ></a>
+ {{ s__('CommitWidget|authored') }}
+ <time-ago-tooltip
+ :time="commit.authoredDate"
+ />
+ </div>
+
+ <pre
+ v-if="commit.descriptionHtml"
+ class="commit-row-description js-toggle-content append-bottom-8"
+ v-html="commit.descriptionHtml"
+ ></pre>
+ </div>
+ <div class="commit-actions flex-row d-none d-sm-flex">
+ <div class="commit-sha-group">
+ <div
+ class="label label-monospace"
+ v-text="commit.shortId"
+ ></div>
+ <clipboard-button
+ :text="commit.id"
+ :title="__('Copy commit SHA to clipboard')"
+ class="btn btn-default"
+ />
+ </div>
+ </div>
+ </div>
+ </li>
+</template>
diff --git a/app/assets/javascripts/diffs/components/commit_widget.vue b/app/assets/javascripts/diffs/components/commit_widget.vue
new file mode 100644
index 00000000000..cc8e72eb1c8
--- /dev/null
+++ b/app/assets/javascripts/diffs/components/commit_widget.vue
@@ -0,0 +1,40 @@
+<script>
+import CommitItem from './commit_item.vue';
+
+/**
+ * CommitWidget
+ *
+ * -----------------------------------------------------------------
+ * WARNING: Please keep changes up-to-date with the following files:
+ * - `views/projects/merge_requests/diffs/_commit_widget.html.haml`
+ * -----------------------------------------------------------------
+ *
+ * This Component was cloned from a HAML view. For the time being,
+ * they coexist, but there is an issue to remove the duplication.
+ * https://gitlab.com/gitlab-org/gitlab-ce/issues/51613
+ *
+ */
+export default {
+ components: {
+ CommitItem,
+ },
+ props: {
+ commit: {
+ type: Object,
+ required: true,
+ },
+ },
+};
+</script>
+
+<template>
+ <div class="info-well prepend-top-default">
+ <div class="well-segment">
+ <ul class="blob-commit-info">
+ <commit-item
+ :commit="commit"
+ />
+ </ul>
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/diffs/components/diff_file_header.vue b/app/assets/javascripts/diffs/components/diff_file_header.vue
index d3ffbe0415a..517fbf400e8 100644
--- a/app/assets/javascripts/diffs/components/diff_file_header.vue
+++ b/app/assets/javascripts/diffs/components/diff_file_header.vue
@@ -181,8 +181,8 @@ export default {
</span>
<strong
- v-tooltip
v-else
+ v-tooltip
:title="filePath"
class="file-title-name"
data-container="body"
@@ -255,8 +255,8 @@ export default {
</a>
<a
- v-tooltip
v-if="diffFile.externalUrl"
+ v-tooltip
:href="diffFile.externalUrl"
:title="`View on ${diffFile.formattedExternalUrl}`"
target="_blank"
diff --git a/app/assets/javascripts/diffs/components/diff_gutter_avatars.vue b/app/assets/javascripts/diffs/components/diff_gutter_avatars.vue
index a02c41f39ab..1b59777f901 100644
--- a/app/assets/javascripts/diffs/components/diff_gutter_avatars.vue
+++ b/app/assets/javascripts/diffs/components/diff_gutter_avatars.vue
@@ -87,8 +87,8 @@ export default {
@click.native="toggleDiscussions"
/>
<span
- v-gl-tooltip
v-if="moreText"
+ v-gl-tooltip
:title="moreText"
class="diff-comments-more-count js-diff-comment-avatar js-diff-comment-plus"
data-container="body"
diff --git a/app/assets/javascripts/diffs/components/diff_line_note_form.vue b/app/assets/javascripts/diffs/components/diff_line_note_form.vue
index a0dc381ccc7..bb9bb821de3 100644
--- a/app/assets/javascripts/diffs/components/diff_line_note_form.vue
+++ b/app/assets/javascripts/diffs/components/diff_line_note_form.vue
@@ -1,12 +1,9 @@
<script>
import { mapState, mapGetters, mapActions } from 'vuex';
-import createFlash from '~/flash';
import { s__ } from '~/locale';
import noteForm from '../../notes/components/note_form.vue';
-import { getNoteFormData } from '../store/utils';
import autosave from '../../notes/mixins/autosave';
import { DIFF_NOTE_TYPE } from '../constants';
-import { reduceDiscussionsToLineCodes } from '../../notes/stores/utils';
export default {
components: {
@@ -22,7 +19,7 @@ export default {
type: Object,
required: true,
},
- position: {
+ linePosition: {
type: String,
required: false,
default: '',
@@ -39,6 +36,16 @@ export default {
}),
...mapGetters('diffs', ['getDiffFileByHash']),
...mapGetters(['isLoggedIn', 'noteableType', 'getNoteableData', 'getNotesDataByProp']),
+ formData() {
+ return {
+ noteableData: this.noteableData,
+ noteableType: this.noteableType,
+ noteTargetLine: this.noteTargetLine,
+ diffViewType: this.diffViewType,
+ diffFile: this.getDiffFileByHash(this.diffFileHash),
+ linePosition: this.linePosition,
+ };
+ },
},
mounted() {
if (this.isLoggedIn) {
@@ -53,8 +60,7 @@ export default {
}
},
methods: {
- ...mapActions('diffs', ['cancelCommentForm', 'assignDiscussionsToDiff']),
- ...mapActions(['saveNote', 'refetchDiscussionById']),
+ ...mapActions('diffs', ['cancelCommentForm', 'assignDiscussionsToDiff', 'saveDiffDiscussion']),
handleCancelCommentForm(shouldConfirm, isDirty) {
if (shouldConfirm && isDirty) {
const msg = s__('Notes|Are you sure you want to cancel creating this comment?');
@@ -73,35 +79,9 @@ export default {
});
},
handleSaveNote(note) {
- const selectedDiffFile = this.getDiffFileByHash(this.diffFileHash);
- const postData = getNoteFormData({
- note,
- noteableData: this.noteableData,
- noteableType: this.noteableType,
- noteTargetLine: this.noteTargetLine,
- diffViewType: this.diffViewType,
- diffFile: selectedDiffFile,
- linePosition: this.position,
- });
-
- this.saveNote(postData)
- .then(result => {
- const endpoint = this.getNotesDataByProp('discussionsPath');
-
- this.refetchDiscussionById({ path: endpoint, discussionId: result.discussion_id })
- .then(selectedDiscussion => {
- const lineCodeDiscussions = reduceDiscussionsToLineCodes([selectedDiscussion]);
- this.assignDiscussionsToDiff(lineCodeDiscussions);
-
- this.handleCancelCommentForm();
- })
- .catch(() => {
- createFlash(s__('MergeRequests|Updating discussions failed'));
- });
- })
- .catch(() => {
- createFlash(s__('MergeRequests|Saving the comment failed'));
- });
+ return this.saveDiffDiscussion({ note, formData: this.formData }).then(() =>
+ this.handleCancelCommentForm(),
+ );
},
},
};
diff --git a/app/assets/javascripts/diffs/components/inline_diff_table_row.vue b/app/assets/javascripts/diffs/components/inline_diff_table_row.vue
index 0e306f39a9f..62fa34e835a 100644
--- a/app/assets/javascripts/diffs/components/inline_diff_table_row.vue
+++ b/app/assets/javascripts/diffs/components/inline_diff_table_row.vue
@@ -1,5 +1,5 @@
<script>
-import { mapGetters } from 'vuex';
+import { mapGetters, mapActions } from 'vuex';
import DiffTableCell from './diff_table_cell.vue';
import {
NEW_LINE_TYPE,
@@ -63,7 +63,11 @@ export default {
this.linePositionLeft = LINE_POSITION_LEFT;
this.linePositionRight = LINE_POSITION_RIGHT;
},
+ mounted() {
+ this.scrollToLineIfNeededInline(this.line);
+ },
methods: {
+ ...mapActions('diffs', ['scrollToLineIfNeededInline']),
handleMouseMove(e) {
// To show the comment icon on the gutter we need to know if we hover the line.
// Current table structure doesn't allow us to do this with CSS in both of the diff view types
diff --git a/app/assets/javascripts/diffs/components/inline_diff_view.vue b/app/assets/javascripts/diffs/components/inline_diff_view.vue
index 947e7c98fae..fbf9e77ac07 100644
--- a/app/assets/javascripts/diffs/components/inline_diff_view.vue
+++ b/app/assets/javascripts/diffs/components/inline_diff_view.vue
@@ -43,18 +43,18 @@ export default {
v-for="(line, index) in diffLines"
>
<inline-diff-table-row
+ :key="line.lineCode"
:file-hash="diffFile.fileHash"
:context-lines-path="diffFile.contextLinesPath"
:line="line"
:is-bottom="index + 1 === diffLinesLength"
- :key="line.lineCode"
/>
<inline-diff-comment-row
v-if="shouldRenderInlineCommentRow(line)"
+ :key="index"
:diff-file-hash="diffFile.fileHash"
:line="line"
:line-index="index"
- :key="index"
/>
</template>
</tbody>
diff --git a/app/assets/javascripts/diffs/components/no_changes.vue b/app/assets/javascripts/diffs/components/no_changes.vue
index d817157fbcd..6905630ad8c 100644
--- a/app/assets/javascripts/diffs/components/no_changes.vue
+++ b/app/assets/javascripts/diffs/components/no_changes.vue
@@ -38,7 +38,7 @@ export default {
<div class="text-center">
<a
:href="newBlobPath"
- class="btn btn-save"
+ class="btn btn-success"
>
{{ __('Create commit') }}
</a>
diff --git a/app/assets/javascripts/diffs/components/parallel_diff_comment_row.vue b/app/assets/javascripts/diffs/components/parallel_diff_comment_row.vue
index 26417c350cb..3339c56cbb6 100644
--- a/app/assets/javascripts/diffs/components/parallel_diff_comment_row.vue
+++ b/app/assets/javascripts/diffs/components/parallel_diff_comment_row.vue
@@ -92,7 +92,7 @@ export default {
:diff-file-hash="diffFileHash"
:line="line.left"
:note-target-line="line.left"
- position="left"
+ line-position="left"
/>
</td>
<td class="notes_line new"></td>
@@ -111,7 +111,7 @@ export default {
:diff-file-hash="diffFileHash"
:line="line.right"
:note-target-line="line.right"
- position="right"
+ line-position="right"
/>
</td>
</tr>
diff --git a/app/assets/javascripts/diffs/components/parallel_diff_table_row.vue b/app/assets/javascripts/diffs/components/parallel_diff_table_row.vue
index fb68d191091..fcc3b3e9117 100644
--- a/app/assets/javascripts/diffs/components/parallel_diff_table_row.vue
+++ b/app/assets/javascripts/diffs/components/parallel_diff_table_row.vue
@@ -1,4 +1,5 @@
<script>
+import { mapActions } from 'vuex';
import $ from 'jquery';
import DiffTableCell from './diff_table_cell.vue';
import {
@@ -64,7 +65,11 @@ export default {
this.oldLineType = OLD_LINE_TYPE;
this.parallelDiffViewType = PARALLEL_DIFF_VIEW_TYPE;
},
+ mounted() {
+ this.scrollToLineIfNeededParallel(this.line);
+ },
methods: {
+ ...mapActions('diffs', ['scrollToLineIfNeededParallel']),
handleMouseMove(e) {
const isHover = e.type === 'mouseover';
const hoveringCell = e.target.closest('td');
diff --git a/app/assets/javascripts/diffs/components/parallel_diff_view.vue b/app/assets/javascripts/diffs/components/parallel_diff_view.vue
index 501bd4450d8..3452f0d2b00 100644
--- a/app/assets/javascripts/diffs/components/parallel_diff_view.vue
+++ b/app/assets/javascripts/diffs/components/parallel_diff_view.vue
@@ -45,11 +45,11 @@ export default {
v-for="(line, index) in diffLines"
>
<parallel-diff-table-row
+ :key="index"
:file-hash="diffFile.fileHash"
:context-lines-path="diffFile.contextLinesPath"
:line="line"
:is-bottom="index + 1 === diffLinesLength"
- :key="index"
/>
<parallel-diff-comment-row
v-if="shouldRenderParallelCommentRow(line)"
diff --git a/app/assets/javascripts/diffs/constants.js b/app/assets/javascripts/diffs/constants.js
index f68afa44837..2795dddfc48 100644
--- a/app/assets/javascripts/diffs/constants.js
+++ b/app/assets/javascripts/diffs/constants.js
@@ -7,6 +7,7 @@ export const CONTEXT_LINE_TYPE = 'context';
export const EMPTY_CELL_TYPE = 'empty-cell';
export const COMMENT_FORM_TYPE = 'commentForm';
export const DIFF_NOTE_TYPE = 'DiffNote';
+export const LEGACY_DIFF_NOTE_TYPE = 'LegacyDiffNote';
export const NOTE_TYPE = 'Note';
export const NEW_LINE_TYPE = 'new';
export const OLD_LINE_TYPE = 'old';
diff --git a/app/assets/javascripts/diffs/store/actions.js b/app/assets/javascripts/diffs/store/actions.js
index 027df2ec841..98d8d5943f9 100644
--- a/app/assets/javascripts/diffs/store/actions.js
+++ b/app/assets/javascripts/diffs/store/actions.js
@@ -1,9 +1,12 @@
import Vue from 'vue';
import axios from '~/lib/utils/axios_utils';
import Cookies from 'js-cookie';
+import createFlash from '~/flash';
+import { s__ } from '~/locale';
import { handleLocationHash, historyPushState } from '~/lib/utils/common_utils';
-import { mergeUrlParams } from '~/lib/utils/url_utility';
-import { getDiffPositionByLineCode } from './utils';
+import { mergeUrlParams, getLocationHash } from '~/lib/utils/url_utility';
+import { reduceDiscussionsToLineCodes } from '../../notes/stores/utils';
+import { getDiffPositionByLineCode, getNoteFormData } from './utils';
import * as types from './mutation_types';
import {
PARALLEL_DIFF_VIEW_TYPE,
@@ -120,6 +123,25 @@ export const loadMoreLines = ({ commit }, options) => {
});
};
+export const scrollToLineIfNeededInline = (_, line) => {
+ const hash = getLocationHash();
+
+ if (hash && line.lineCode === hash) {
+ handleLocationHash();
+ }
+};
+
+export const scrollToLineIfNeededParallel = (_, line) => {
+ const hash = getLocationHash();
+
+ if (
+ hash &&
+ ((line.left && line.left.lineCode === hash) || (line.right && line.right.lineCode === hash))
+ ) {
+ handleLocationHash();
+ }
+};
+
export const loadCollapsedDiff = ({ commit }, file) =>
axios.get(file.loadCollapsedDiffUrl).then(res => {
commit(types.ADD_COLLAPSED_DIFFS, {
@@ -159,5 +181,19 @@ export const toggleFileDiscussions = ({ getters, dispatch }, diff) => {
});
};
+export const saveDiffDiscussion = ({ dispatch }, { note, formData }) => {
+ const postData = getNoteFormData({
+ note,
+ ...formData,
+ });
+
+ return dispatch('saveNote', postData, { root: true })
+ .then(result => dispatch('updateDiscussion', result.discussion, { root: true }))
+ .then(discussion =>
+ dispatch('assignDiscussionsToDiff', reduceDiscussionsToLineCodes([discussion])),
+ )
+ .catch(() => createFlash(s__('MergeRequests|Saving the comment failed')));
+};
+
// prevent babel-plugin-rewire from generating an invalid default during karma tests
export default () => {};
diff --git a/app/assets/javascripts/diffs/store/mutations.js b/app/assets/javascripts/diffs/store/mutations.js
index 6dc5bf16c65..59a2c09e54f 100644
--- a/app/assets/javascripts/diffs/store/mutations.js
+++ b/app/assets/javascripts/diffs/store/mutations.js
@@ -90,16 +90,18 @@ export default {
const firstDiscussion = discussions[0];
const isDiffDiscussion = firstDiscussion.diff_discussion;
const hasLineCode = firstDiscussion.line_code;
- const isResolvable = firstDiscussion.resolvable;
const diffPosition = diffPositionByLineCode[firstDiscussion.line_code];
if (
selectedFile &&
isDiffDiscussion &&
hasLineCode &&
- isResolvable &&
diffPosition &&
- isDiscussionApplicableToLine(firstDiscussion, diffPosition)
+ isDiscussionApplicableToLine({
+ discussion: firstDiscussion,
+ diffPosition,
+ latestDiff: state.latestDiff,
+ })
) {
const targetLine = selectedFile.parallelDiffLines.find(
line =>
diff --git a/app/assets/javascripts/diffs/store/utils.js b/app/assets/javascripts/diffs/store/utils.js
index b7e52a8f37f..631e3de311e 100644
--- a/app/assets/javascripts/diffs/store/utils.js
+++ b/app/assets/javascripts/diffs/store/utils.js
@@ -4,6 +4,7 @@ import {
LINE_POSITION_LEFT,
LINE_POSITION_RIGHT,
TEXT_DIFF_POSITION_TYPE,
+ LEGACY_DIFF_NOTE_TYPE,
DIFF_NOTE_TYPE,
NEW_LINE_TYPE,
OLD_LINE_TYPE,
@@ -54,13 +55,17 @@ export function getNoteFormData(params) {
note_project_id: '',
target_type: noteableData.targetType,
target_id: noteableData.id,
+ return_discussion: true,
note: {
note,
position,
noteable_type: noteableType,
noteable_id: noteableData.id,
commit_id: '',
- type: DIFF_NOTE_TYPE,
+ type:
+ diffFile.diffRefs.startSha && diffFile.diffRefs.headSha
+ ? DIFF_NOTE_TYPE
+ : LEGACY_DIFF_NOTE_TYPE,
line_code: noteTargetLine.lineCode,
},
};
@@ -230,7 +235,16 @@ export function getDiffPositionByLineCode(diffFiles) {
const { lineCode, oldLine, newLine } = line;
if (lineCode) {
- acc[lineCode] = { baseSha, headSha, startSha, newPath, oldPath, oldLine, newLine };
+ acc[lineCode] = {
+ baseSha,
+ headSha,
+ startSha,
+ newPath,
+ oldPath,
+ oldLine,
+ newLine,
+ lineCode,
+ };
}
});
}
@@ -241,9 +255,15 @@ export function getDiffPositionByLineCode(diffFiles) {
// This method will check whether the discussion is still applicable
// to the diff line in question regarding different versions of the MR
-export function isDiscussionApplicableToLine(discussion, diffPosition) {
- const originalRefs = convertObjectPropsToCamelCase(discussion.original_position.formatter);
- const refs = convertObjectPropsToCamelCase(discussion.position.formatter);
+export function isDiscussionApplicableToLine({ discussion, diffPosition, latestDiff }) {
+ const { lineCode, ...diffPositionCopy } = diffPosition;
- return _.isEqual(refs, diffPosition) || _.isEqual(originalRefs, diffPosition);
+ if (discussion.original_position && discussion.position) {
+ const originalRefs = convertObjectPropsToCamelCase(discussion.original_position.formatter);
+ const refs = convertObjectPropsToCamelCase(discussion.position.formatter);
+
+ return _.isEqual(refs, diffPositionCopy) || _.isEqual(originalRefs, diffPositionCopy);
+ }
+
+ return latestDiff && discussion.active && lineCode === discussion.line_code;
}
diff --git a/app/assets/javascripts/dispatcher.js b/app/assets/javascripts/dispatcher.js
deleted file mode 100644
index a5af37e80b6..00000000000
--- a/app/assets/javascripts/dispatcher.js
+++ /dev/null
@@ -1,89 +0,0 @@
-/* eslint-disable consistent-return, no-new */
-
-import $ from 'jquery';
-import GfmAutoComplete from './gfm_auto_complete';
-import { convertPermissionToBoolean } from './lib/utils/common_utils';
-import GlFieldErrors from './gl_field_errors';
-import Shortcuts from './shortcuts';
-import SearchAutocomplete from './search_autocomplete';
-import performanceBar from './performance_bar';
-
-function initSearch() {
- // Only when search form is present
- if ($('.search').length) {
- return new SearchAutocomplete();
- }
-}
-
-function initFieldErrors() {
- $('.gl-show-field-errors').each((i, form) => {
- new GlFieldErrors(form);
- });
-}
-
-function initPageShortcuts(page) {
- const pagesWithCustomShortcuts = [
- 'projects:activity',
- 'projects:artifacts:browse',
- 'projects:artifacts:file',
- 'projects:blame:show',
- 'projects:blob:show',
- 'projects:commit:show',
- 'projects:commits:show',
- 'projects:find_file:show',
- 'projects:issues:edit',
- 'projects:issues:index',
- 'projects:issues:new',
- 'projects:issues:show',
- 'projects:merge_requests:creations:diffs',
- 'projects:merge_requests:creations:new',
- 'projects:merge_requests:edit',
- 'projects:merge_requests:index',
- 'projects:merge_requests:show',
- 'projects:network:show',
- 'projects:show',
- 'projects:tree:show',
- 'groups:show',
- ];
-
- if (pagesWithCustomShortcuts.indexOf(page) === -1) {
- new Shortcuts();
- }
-}
-
-function initGFMInput() {
- $('.js-gfm-input:not(.js-vue-textarea)').each((i, el) => {
- const gfm = new GfmAutoComplete(
- gl.GfmAutoComplete && gl.GfmAutoComplete.dataSources,
- );
- const enableGFM = convertPermissionToBoolean(
- el.dataset.supportsAutocomplete,
- );
- gfm.setup($(el), {
- emojis: true,
- members: enableGFM,
- issues: enableGFM,
- milestones: enableGFM,
- mergeRequests: enableGFM,
- labels: enableGFM,
- });
- });
-}
-
-function initPerformanceBar() {
- if (document.querySelector('#js-peek')) {
- performanceBar({ container: '#js-peek' });
- }
-}
-
-export default () => {
- initSearch();
- initFieldErrors();
-
- const page = $('body').attr('data-page');
- if (page) {
- initPageShortcuts(page);
- initGFMInput();
- initPerformanceBar();
- }
-};
diff --git a/app/assets/javascripts/dropzone_input.js b/app/assets/javascripts/dropzone_input.js
index ff969bb94a4..d2778bcdf1c 100644
--- a/app/assets/javascripts/dropzone_input.js
+++ b/app/assets/javascripts/dropzone_input.js
@@ -1,7 +1,7 @@
import $ from 'jquery';
import Dropzone from 'dropzone';
import _ from 'underscore';
-import './preview_markdown';
+import './behaviors/preview_markdown';
import csrf from './lib/utils/csrf';
import axios from './lib/utils/axios_utils';
diff --git a/app/assets/javascripts/environments/components/empty_state.vue b/app/assets/javascripts/environments/components/empty_state.vue
index 00e63c3467a..cf78f89981e 100644
--- a/app/assets/javascripts/environments/components/empty_state.vue
+++ b/app/assets/javascripts/environments/components/empty_state.vue
@@ -35,7 +35,7 @@ code gets deployed, such as staging or production.`) }}
<a
v-if="canCreateEnvironment"
:href="newPath"
- class="btn btn-create js-new-environment-button"
+ class="btn btn-success js-new-environment-button"
>
{{ s__("Environments|New environment") }}
</a>
diff --git a/app/assets/javascripts/environments/components/environments_app.vue b/app/assets/javascripts/environments/components/environments_app.vue
index 8efdfb8abe0..e2ecf426e64 100644
--- a/app/assets/javascripts/environments/components/environments_app.vue
+++ b/app/assets/javascripts/environments/components/environments_app.vue
@@ -107,7 +107,7 @@
>
<a
:href="newEnvironmentPath"
- class="btn btn-create"
+ class="btn btn-success"
>
{{ s__("Environments|New environment") }}
</a>
diff --git a/app/assets/javascripts/environments/components/environments_table.vue b/app/assets/javascripts/environments/components/environments_table.vue
index a9d9d768c06..16abafebbc0 100644
--- a/app/assets/javascripts/environments/components/environments_table.vue
+++ b/app/assets/javascripts/environments/components/environments_table.vue
@@ -83,10 +83,10 @@ export default {
:model="model">
<div
is="environment-item"
+ :key="`environment-item-${i}`"
:model="model"
:can-create-deployment="canCreateDeployment"
:can-read-environment="canReadEnvironment"
- :key="`environment-item-${i}`"
/>
<template
@@ -102,10 +102,10 @@ export default {
<div
is="environment-item"
v-for="(children, index) in model.children"
+ :key="`env-item-${i}-${index}`"
:model="children"
:can-create-deployment="canCreateDeployment"
:can-read-environment="canReadEnvironment"
- :key="`env-item-${i}-${index}`"
/>
<div :key="`sub-div-${i}`">
diff --git a/app/assets/javascripts/feature_highlight/feature_highlight.js b/app/assets/javascripts/feature_highlight/feature_highlight.js
index 2f27c9351bc..03dfa942d69 100644
--- a/app/assets/javascripts/feature_highlight/feature_highlight.js
+++ b/app/assets/javascripts/feature_highlight/feature_highlight.js
@@ -16,7 +16,7 @@ export function setupFeatureHighlightPopover(id, debounceTimeout = 300) {
const hideOnScroll = togglePopover.bind($selector, false);
$selector
- // Setup popover
+ // Set up popover
.data('content', $popoverContent.prop('outerHTML'))
.popover({
html: true,
diff --git a/app/assets/javascripts/filtered_search/admin_runners_filtered_search_token_keys.js b/app/assets/javascripts/filtered_search/admin_runners_filtered_search_token_keys.js
index 1f9c3f41e52..d7aa4ce597f 100644
--- a/app/assets/javascripts/filtered_search/admin_runners_filtered_search_token_keys.js
+++ b/app/assets/javascripts/filtered_search/admin_runners_filtered_search_token_keys.js
@@ -5,8 +5,15 @@ const tokenKeys = [{
type: 'string',
param: 'status',
symbol: '',
- icon: 'signal',
+ icon: 'messages',
tag: 'status',
+}, {
+ key: 'type',
+ type: 'string',
+ param: 'type',
+ symbol: '',
+ icon: 'cube',
+ tag: 'type',
}];
const AdminRunnersFilteredSearchTokenKeys = new FilteredSearchTokenKeys(tokenKeys);
diff --git a/app/assets/javascripts/filtered_search/components/recent_searches_dropdown_content.vue b/app/assets/javascripts/filtered_search/components/recent_searches_dropdown_content.vue
index a8eb8d94be3..21b5ccdb613 100644
--- a/app/assets/javascripts/filtered_search/components/recent_searches_dropdown_content.vue
+++ b/app/assets/javascripts/filtered_search/components/recent_searches_dropdown_content.vue
@@ -72,8 +72,8 @@ export default {
@click="onItemActivated(item.text)">
<span>
<span
- v-for="(token, index) in item.tokens"
- :key="`dropdown-token-${index}`"
+ v-for="(token, tokenIndex) in item.tokens"
+ :key="`dropdown-token-${tokenIndex}`"
class="filtered-search-history-dropdown-token"
>
<span class="name">{{ token.prefix }}</span>
diff --git a/app/assets/javascripts/filtered_search/dropdown_hint.js b/app/assets/javascripts/filtered_search/dropdown_hint.js
index 184b34b7b5e..8aecf9725e6 100644
--- a/app/assets/javascripts/filtered_search/dropdown_hint.js
+++ b/app/assets/javascripts/filtered_search/dropdown_hint.js
@@ -62,7 +62,7 @@ export default class DropdownHint extends FilteredSearchDropdown {
renderContent() {
const dropdownData = this.tokenKeys.get()
.map(tokenKey => ({
- icon: `fa-${tokenKey.icon}`,
+ icon: `${gon.sprite_icons}#${tokenKey.icon}`,
hint: tokenKey.key,
tag: `:${tokenKey.tag}`,
type: tokenKey.type,
diff --git a/app/assets/javascripts/filtered_search/filtered_search_dropdown_manager.js b/app/assets/javascripts/filtered_search/filtered_search_dropdown_manager.js
index a750647f8be..207616b9de2 100644
--- a/app/assets/javascripts/filtered_search/filtered_search_dropdown_manager.js
+++ b/app/assets/javascripts/filtered_search/filtered_search_dropdown_manager.js
@@ -96,6 +96,11 @@ export default class FilteredSearchDropdownManager {
gl: NullDropdown,
element: this.container.querySelector('#js-dropdown-admin-runner-status'),
},
+ type: {
+ reference: null,
+ gl: NullDropdown,
+ element: this.container.querySelector('#js-dropdown-admin-runner-type'),
+ },
};
supportedTokens.forEach((type) => {
diff --git a/app/assets/javascripts/filtered_search/issuable_filtered_search_token_keys.js b/app/assets/javascripts/filtered_search/issuable_filtered_search_token_keys.js
index cce2c07dc3e..cc7291c9f59 100644
--- a/app/assets/javascripts/filtered_search/issuable_filtered_search_token_keys.js
+++ b/app/assets/javascripts/filtered_search/issuable_filtered_search_token_keys.js
@@ -1,6 +1,6 @@
import FilteredSearchTokenKeys from './filtered_search_token_keys';
-const tokenKeys = [{
+export const tokenKeys = [{
key: 'author',
type: 'string',
param: 'username',
@@ -19,14 +19,14 @@ const tokenKeys = [{
type: 'string',
param: 'title',
symbol: '%',
- icon: 'clock-o',
+ icon: 'clock',
tag: '%milestone',
}, {
key: 'label',
type: 'array',
param: 'name[]',
symbol: '~',
- icon: 'tag',
+ icon: 'labels',
tag: '~label',
}];
@@ -37,19 +37,19 @@ if (gon.current_user_id) {
type: 'string',
param: 'emoji',
symbol: '',
- icon: 'thumbs-up',
+ icon: 'thumb-up',
tag: 'emoji',
});
}
-const alternativeTokenKeys = [{
+export const alternativeTokenKeys = [{
key: 'label',
type: 'string',
param: 'name',
symbol: '~',
}];
-const conditions = [{
+export const conditions = [{
url: 'assignee_id=0',
tokenKey: 'assignee',
value: 'none',
diff --git a/app/assets/javascripts/frequent_items/components/frequent_items_list_item.vue b/app/assets/javascripts/frequent_items/components/frequent_items_list_item.vue
index 1f1665ff7fe..2399ee15332 100644
--- a/app/assets/javascripts/frequent_items/components/frequent_items_list_item.vue
+++ b/app/assets/javascripts/frequent_items/components/frequent_items_list_item.vue
@@ -1,5 +1,5 @@
<script>
-/* eslint-disable vue/require-default-prop, vue/require-prop-types */
+/* eslint-disable vue/require-default-prop */
import Identicon from '../../vue_shared/components/identicon.vue';
export default {
diff --git a/app/assets/javascripts/gl_form.js b/app/assets/javascripts/gl_form.js
index c74de7ac34d..e672284a2d0 100644
--- a/app/assets/javascripts/gl_form.js
+++ b/app/assets/javascripts/gl_form.js
@@ -18,7 +18,7 @@ export default class GLForm {
});
// Before we start, we should clean up any previous data for this form
this.destroy();
- // Setup the form
+ // Set up the form
this.setupForm();
this.form.data('glForm', this);
}
diff --git a/app/assets/javascripts/groups/components/item_actions.vue b/app/assets/javascripts/groups/components/item_actions.vue
index 6e700b8bf8a..c1783d5ce25 100644
--- a/app/assets/javascripts/groups/components/item_actions.vue
+++ b/app/assets/javascripts/groups/components/item_actions.vue
@@ -46,8 +46,8 @@ export default {
<template>
<div class="controls">
<a
- v-tooltip
v-if="group.canEdit"
+ v-tooltip
:href="group.editPath"
:title="editBtnTitle"
:aria-label="editBtnTitle"
@@ -57,8 +57,8 @@ export default {
<icon name="settings"/>
</a>
<a
- v-tooltip
v-if="group.canLeave"
+ v-tooltip
:href="group.leavePath"
:title="leaveBtnTitle"
:aria-label="leaveBtnTitle"
diff --git a/app/assets/javascripts/ide/components/branches/search_list.vue b/app/assets/javascripts/ide/components/branches/search_list.vue
index bf0ff6e35ec..52ccc537c9d 100644
--- a/app/assets/javascripts/ide/components/branches/search_list.vue
+++ b/app/assets/javascripts/ide/components/branches/search_list.vue
@@ -60,8 +60,8 @@ export default {
<div class="position-relative">
<input
ref="searchInput"
- :placeholder="__('Search branches')"
v-model="search"
+ :placeholder="__('Search branches')"
type="search"
class="form-control dropdown-input-field"
@input="searchBranches"
diff --git a/app/assets/javascripts/ide/components/commit_sidebar/editor_header.vue b/app/assets/javascripts/ide/components/commit_sidebar/editor_header.vue
index c3ca147e850..3aca38399fb 100644
--- a/app/assets/javascripts/ide/components/commit_sidebar/editor_header.vue
+++ b/app/assets/javascripts/ide/components/commit_sidebar/editor_header.vue
@@ -52,6 +52,7 @@ export default {
</strong>
<changed-file-icon
:file="activeFile"
+ class="ml-0"
/>
<div class="ml-auto">
<button
diff --git a/app/assets/javascripts/ide/components/commit_sidebar/list.vue b/app/assets/javascripts/ide/components/commit_sidebar/list.vue
index 3fdd35ad228..3e3539e364b 100644
--- a/app/assets/javascripts/ide/components/commit_sidebar/list.vue
+++ b/app/assets/javascripts/ide/components/commit_sidebar/list.vue
@@ -113,8 +113,8 @@ export default {
</strong>
<div class="d-flex ml-auto">
<button
- v-tooltip
ref="actionBtn"
+ v-tooltip
:title="actionBtnText"
:aria-label="actionBtnText"
:disabled="!filesLength"
@@ -135,8 +135,8 @@ export default {
/>
</button>
<button
- v-tooltip
v-if="!stagedList"
+ v-tooltip
:title="__('Discard all changes')"
:aria-label="__('Discard all changes')"
:disabled="!filesLength"
diff --git a/app/assets/javascripts/ide/components/commit_sidebar/list_item.vue b/app/assets/javascripts/ide/components/commit_sidebar/list_item.vue
index 10c78a80302..ee0e72cd05f 100644
--- a/app/assets/javascripts/ide/components/commit_sidebar/list_item.vue
+++ b/app/assets/javascripts/ide/components/commit_sidebar/list_item.vue
@@ -120,10 +120,6 @@ export default {
:css-classes="iconClass"
/>
</div>
- <component
- :is="actionComponent"
- :path="file.path"
- />
</div>
</div>
</div>
diff --git a/app/assets/javascripts/ide/components/file_finder/index.vue b/app/assets/javascripts/ide/components/file_finder/index.vue
index 0ba33053717..760ed8654ee 100644
--- a/app/assets/javascripts/ide/components/file_finder/index.vue
+++ b/app/assets/javascripts/ide/components/file_finder/index.vue
@@ -174,8 +174,8 @@ export default {
<div class="dropdown-input">
<input
ref="searchInput"
- :placeholder="__('Search files')"
v-model="searchText"
+ :placeholder="__('Search files')"
type="search"
class="dropdown-input-field"
autocomplete="off"
diff --git a/app/assets/javascripts/ide/components/file_finder/item.vue b/app/assets/javascripts/ide/components/file_finder/item.vue
index f5252ce7706..a612739d641 100644
--- a/app/assets/javascripts/ide/components/file_finder/item.vue
+++ b/app/assets/javascripts/ide/components/file_finder/item.vue
@@ -78,10 +78,10 @@ export default {
class="diff-changed-file-name"
>
<span
- v-for="(char, index) in file.name.split('')"
- :key="index + char"
+ v-for="(char, charIndex) in file.name.split('')"
+ :key="charIndex + char"
:class="{
- highlighted: nameSearchTextOccurences.indexOf(index) >= 0,
+ highlighted: nameSearchTextOccurences.indexOf(charIndex) >= 0,
}"
v-text="char"
>
@@ -91,10 +91,10 @@ export default {
class="diff-changed-file-path prepend-top-5"
>
<span
- v-for="(char, index) in pathWithEllipsis.split('')"
- :key="index + char"
+ v-for="(char, charIndex) in pathWithEllipsis.split('')"
+ :key="charIndex + char"
:class="{
- highlighted: pathSearchTextOccurences.indexOf(index) >= 0,
+ highlighted: pathSearchTextOccurences.indexOf(charIndex) >= 0,
}"
v-text="char"
>
diff --git a/app/assets/javascripts/ide/components/file_row_extra.vue b/app/assets/javascripts/ide/components/file_row_extra.vue
new file mode 100644
index 00000000000..44a360ab909
--- /dev/null
+++ b/app/assets/javascripts/ide/components/file_row_extra.vue
@@ -0,0 +1,104 @@
+<script>
+import { mapGetters } from 'vuex';
+import { n__, __, sprintf } from '~/locale';
+import tooltip from '~/vue_shared/directives/tooltip';
+import Icon from '~/vue_shared/components/icon.vue';
+import NewDropdown from './new_dropdown/index.vue';
+import ChangedFileIcon from './changed_file_icon.vue';
+import MrFileIcon from './mr_file_icon.vue';
+
+export default {
+ name: 'FileRowExtra',
+ directives: {
+ tooltip,
+ },
+ components: {
+ Icon,
+ NewDropdown,
+ ChangedFileIcon,
+ MrFileIcon,
+ },
+ props: {
+ file: {
+ type: Object,
+ required: true,
+ },
+ mouseOver: {
+ type: Boolean,
+ required: true,
+ },
+ },
+ computed: {
+ ...mapGetters([
+ 'getChangesInFolder',
+ 'getUnstagedFilesCountForPath',
+ 'getStagedFilesCountForPath',
+ ]),
+ folderUnstagedCount() {
+ return this.getUnstagedFilesCountForPath(this.file.path);
+ },
+ folderStagedCount() {
+ return this.getStagedFilesCountForPath(this.file.path);
+ },
+ changesCount() {
+ return this.getChangesInFolder(this.file.path);
+ },
+ folderChangesTooltip() {
+ if (this.changesCount === 0) return undefined;
+
+ if (this.folderUnstagedCount > 0 && this.folderStagedCount === 0) {
+ return n__('%d unstaged change', '%d unstaged changes', this.folderUnstagedCount);
+ } else if (this.folderUnstagedCount === 0 && this.folderStagedCount > 0) {
+ return n__('%d staged change', '%d staged changes', this.folderStagedCount);
+ }
+
+ return sprintf(__('%{unstaged} unstaged and %{staged} staged changes'), {
+ unstaged: this.folderUnstagedCount,
+ staged: this.folderStagedCount,
+ });
+ },
+ showTreeChangesCount() {
+ return this.file.type === 'tree' && this.changesCount > 0 && !this.file.opened;
+ },
+ showChangedFileIcon() {
+ return this.file.changed || this.file.tempFile || this.file.staged;
+ },
+ },
+};
+</script>
+
+<template>
+ <div class="float-right ide-file-icon-holder">
+ <mr-file-icon
+ v-if="file.mrChange"
+ />
+ <span
+ v-if="showTreeChangesCount"
+ class="ide-tree-changes"
+ >
+ {{ changesCount }}
+ <icon
+ v-tooltip
+ :title="folderChangesTooltip"
+ :size="12"
+ data-container="body"
+ data-placement="right"
+ name="file-modified"
+ css-classes="prepend-left-5 ide-file-modified"
+ />
+ </span>
+ <changed-file-icon
+ v-else-if="showChangedFileIcon"
+ :file="file"
+ :show-tooltip="true"
+ :show-staged-icon="true"
+ :force-modified-icon="true"
+ />
+ <new-dropdown
+ :type="file.type"
+ :path="file.path"
+ :mouse-over="mouseOver"
+ class="prepend-left-8"
+ />
+ </div>
+</template>
diff --git a/app/assets/javascripts/ide/components/ide.vue b/app/assets/javascripts/ide/components/ide.vue
index a3add3b778f..ad6151e3bf6 100644
--- a/app/assets/javascripts/ide/components/ide.vue
+++ b/app/assets/javascripts/ide/components/ide.vue
@@ -1,4 +1,5 @@
<script>
+import Vue from 'vue';
import Mousetrap from 'mousetrap';
import { mapActions, mapState, mapGetters } from 'vuex';
import { __ } from '~/locale';
@@ -22,10 +23,16 @@ export default {
IdeStatusBar,
RepoEditor,
FindFile,
- RightPane,
ErrorMessage,
CommitEditorHeader,
},
+ props: {
+ rightPaneComponent: {
+ type: Vue.Component,
+ required: false,
+ default: () => RightPane,
+ },
+ },
computed: {
...mapState([
'openFiles',
@@ -143,7 +150,8 @@ export default {
</div>
</template>
</div>
- <right-pane
+ <component
+ :is="rightPaneComponent"
v-if="currentProjectId"
/>
</div>
diff --git a/app/assets/javascripts/ide/components/ide_side_bar.vue b/app/assets/javascripts/ide/components/ide_side_bar.vue
index 4771c58a11d..f99ff6d6da8 100644
--- a/app/assets/javascripts/ide/components/ide_side_bar.vue
+++ b/app/assets/javascripts/ide/components/ide_side_bar.vue
@@ -1,6 +1,6 @@
<script>
import { mapState, mapGetters } from 'vuex';
-import SkeletonLoadingContainer from '~/vue_shared/components/skeleton_loading_container.vue';
+import { SkeletonLoading } from '@gitlab-org/gitlab-ui';
import IdeTree from './ide_tree.vue';
import ResizablePanel from './resizable_panel.vue';
import ActivityBar from './activity_bar.vue';
@@ -13,7 +13,7 @@ import { activityBarViews } from '../constants';
export default {
components: {
- SkeletonLoadingContainer,
+ SkeletonLoading,
ResizablePanel,
ActivityBar,
CommitSection,
@@ -56,7 +56,7 @@ export default {
:key="n"
class="multi-file-loading-container"
>
- <skeleton-loading-container />
+ <skeleton-loading />
</div>
</div>
</template>
diff --git a/app/assets/javascripts/ide/components/ide_status_bar.vue b/app/assets/javascripts/ide/components/ide_status_bar.vue
index 715dc1bfb42..a04d09ef374 100644
--- a/app/assets/javascripts/ide/components/ide_status_bar.vue
+++ b/app/assets/javascripts/ide/components/ide_status_bar.vue
@@ -50,7 +50,9 @@ export default {
this.stopPipelinePolling();
},
methods: {
- ...mapActions(['setRightPane']),
+ ...mapActions('rightPane', {
+ openRightPane: 'open',
+ }),
...mapActions('pipelines', ['fetchLatestPipeline', 'stopPipelinePolling']),
startTimer() {
this.intervalId = setInterval(() => {
@@ -88,7 +90,7 @@ export default {
<button
type="button"
class="p-0 border-0 h-50"
- @click="setRightPane($options.rightSidebarViews.pipelines)"
+ @click="openRightPane($options.rightSidebarViews.pipelines)"
>
<ci-icon
v-tooltip
diff --git a/app/assets/javascripts/ide/components/ide_tree_list.vue b/app/assets/javascripts/ide/components/ide_tree_list.vue
index 00ae5ea2c15..cfe25084b42 100644
--- a/app/assets/javascripts/ide/components/ide_tree_list.vue
+++ b/app/assets/javascripts/ide/components/ide_tree_list.vue
@@ -1,16 +1,17 @@
<script>
import { mapActions, mapGetters, mapState } from 'vuex';
import Icon from '~/vue_shared/components/icon.vue';
-import SkeletonLoadingContainer from '~/vue_shared/components/skeleton_loading_container.vue';
-import RepoFile from './repo_file.vue';
+import { SkeletonLoading } from '@gitlab-org/gitlab-ui';
+import FileRow from '~/vue_shared/components/file_row.vue';
import NavDropdown from './nav_dropdown.vue';
+import FileRowExtra from './file_row_extra.vue';
export default {
components: {
Icon,
- RepoFile,
- SkeletonLoadingContainer,
+ SkeletonLoading,
NavDropdown,
+ FileRow,
},
props: {
viewerType: {
@@ -34,8 +35,9 @@ export default {
this.updateViewer(this.viewerType);
},
methods: {
- ...mapActions(['updateViewer']),
+ ...mapActions(['updateViewer', 'toggleTreeOpen']),
},
+ FileRowExtra,
};
</script>
@@ -49,7 +51,7 @@ export default {
:key="n"
class="multi-file-loading-container"
>
- <skeleton-loading-container />
+ <skeleton-loading />
</div>
</template>
<template v-else>
@@ -63,11 +65,13 @@ export default {
<div
class="ide-tree-body h-100"
>
- <repo-file
+ <file-row
v-for="file in currentTree.tree"
:key="file.key"
:file="file"
:level="0"
+ :extra-component="$options.FileRowExtra"
+ @toggleTreeOpen="toggleTreeOpen"
/>
</div>
</template>
diff --git a/app/assets/javascripts/ide/components/jobs/stage.vue b/app/assets/javascripts/ide/components/jobs/stage.vue
index 1c474acb4b2..ec168d36b9e 100644
--- a/app/assets/javascripts/ide/components/jobs/stage.vue
+++ b/app/assets/javascripts/ide/components/jobs/stage.vue
@@ -69,8 +69,8 @@ export default {
:size="24"
/>
<strong
- v-tooltip="showTooltip"
ref="stageTitle"
+ v-tooltip="showTooltip"
:title="showTooltip ? stage.name : null"
data-container="body"
class="prepend-left-8 ide-stage-title"
diff --git a/app/assets/javascripts/ide/components/panes/right.vue b/app/assets/javascripts/ide/components/panes/right.vue
index 79df225c432..bd07f372177 100644
--- a/app/assets/javascripts/ide/components/panes/right.vue
+++ b/app/assets/javascripts/ide/components/panes/right.vue
@@ -1,5 +1,7 @@
<script>
import { mapActions, mapState, mapGetters } from 'vuex';
+import _ from 'underscore';
+import { __ } from '~/locale';
import tooltip from '../../../vue_shared/directives/tooltip';
import Icon from '../../../vue_shared/components/icon.vue';
import { rightSidebarViews } from '../../constants';
@@ -21,28 +23,77 @@ export default {
MergeRequestInfo,
Clientside,
},
+ props: {
+ extensionTabs: {
+ type: Array,
+ required: false,
+ default: () => [],
+ },
+ },
computed: {
- ...mapState(['rightPane', 'currentMergeRequestId', 'clientsidePreviewEnabled']),
+ ...mapState(['currentMergeRequestId', 'clientsidePreviewEnabled']),
+ ...mapState('rightPane', ['isOpen', 'currentView']),
...mapGetters(['packageJson']),
- pipelinesActive() {
- return (
- this.rightPane === rightSidebarViews.pipelines ||
- this.rightPane === rightSidebarViews.jobsDetail
- );
- },
+ ...mapGetters('rightPane', ['isActiveView', 'isAliveView']),
showLivePreview() {
return this.packageJson && this.clientsidePreviewEnabled;
},
+ defaultTabs() {
+ return [
+ {
+ show: this.currentMergeRequestId,
+ title: __('Merge Request'),
+ views: [
+ rightSidebarViews.mergeRequestInfo,
+ ],
+ icon: 'text-description',
+ },
+ {
+ show: true,
+ title: __('Pipelines'),
+ views: [
+ rightSidebarViews.pipelines,
+ rightSidebarViews.jobsDetail,
+ ],
+ icon: 'rocket',
+ },
+ {
+ show: this.showLivePreview,
+ title: __('Live preview'),
+ views: [
+ rightSidebarViews.clientSidePreview,
+ ],
+ icon: 'live-preview',
+ },
+ ];
+ },
+ tabs() {
+ return this.defaultTabs
+ .concat(this.extensionTabs)
+ .filter(tab => tab.show);
+ },
+ tabViews() {
+ return _.flatten(this.tabs.map(tab => tab.views));
+ },
+ aliveTabViews() {
+ return this.tabViews.filter(view => this.isAliveView(view.name));
+ },
},
methods: {
- ...mapActions(['setRightPane']),
- clickTab(e, view) {
+ ...mapActions('rightPane', ['toggleOpen', 'open']),
+ clickTab(e, tab) {
e.target.blur();
- this.setRightPane(view);
+ if (this.isActiveTab(tab)) {
+ this.toggleOpen();
+ } else {
+ this.open(tab.views[0]);
+ }
+ },
+ isActiveTab(tab) {
+ return tab.views.some(view => this.isActiveView(view.name));
},
},
- rightSidebarViews,
};
</script>
@@ -51,77 +102,45 @@ export default {
class="multi-file-commit-panel ide-right-sidebar"
>
<resizable-panel
- v-if="rightPane"
+ v-show="isOpen"
:collapsible="false"
:initial-width="350"
:min-size="350"
- :class="`ide-right-sidebar-${rightPane}`"
+ :class="`ide-right-sidebar-${currentView}`"
side="right"
class="multi-file-commit-panel-inner"
>
- <component :is="rightPane" />
+ <div
+ v-for="tabView in aliveTabViews"
+ v-show="isActiveView(tabView.name)"
+ :key="tabView.name"
+ class="h-100"
+ >
+ <component :is="tabView.name" />
+ </div>
</resizable-panel>
<nav class="ide-activity-bar">
<ul class="list-unstyled">
<li
- v-if="currentMergeRequestId"
+ v-for="tab of tabs"
+ :key="tab.title"
>
<button
v-tooltip
- :title="__('Merge Request')"
- :aria-label="__('Merge Request')"
- :class="{
- active: rightPane === $options.rightSidebarViews.mergeRequestInfo
- }"
- data-container="body"
- data-placement="left"
- class="ide-sidebar-link is-right"
- type="button"
- @click="clickTab($event, $options.rightSidebarViews.mergeRequestInfo)"
- >
- <icon
- :size="16"
- name="text-description"
- />
- </button>
- </li>
- <li>
- <button
- v-tooltip
- :title="__('Pipelines')"
- :aria-label="__('Pipelines')"
- :class="{
- active: pipelinesActive
- }"
- data-container="body"
- data-placement="left"
- class="ide-sidebar-link is-right"
- type="button"
- @click="clickTab($event, $options.rightSidebarViews.pipelines)"
- >
- <icon
- :size="16"
- name="rocket"
- />
- </button>
- </li>
- <li v-if="showLivePreview">
- <button
- v-tooltip
- :title="__('Live preview')"
- :aria-label="__('Live preview')"
+ :title="tab.title"
+ :aria-label="tab.title"
:class="{
- active: rightPane === $options.rightSidebarViews.clientSidePreview
+ active: isActiveTab(tab) && isOpen
}"
data-container="body"
data-placement="left"
class="ide-sidebar-link is-right"
type="button"
- @click="clickTab($event, $options.rightSidebarViews.clientSidePreview)"
+ @click="clickTab($event, tab)"
>
<icon
:size="16"
- name="live-preview"
+ :name="tab.icon"
/>
</button>
</li>
diff --git a/app/assets/javascripts/ide/components/repo_editor.vue b/app/assets/javascripts/ide/components/repo_editor.vue
index d3a73e84cc7..b2599128213 100644
--- a/app/assets/javascripts/ide/components/repo_editor.vue
+++ b/app/assets/javascripts/ide/components/repo_editor.vue
@@ -22,12 +22,14 @@ export default {
},
},
computed: {
+ ...mapState('rightPane', {
+ rightPaneIsOpen: 'isOpen',
+ }),
...mapState([
'rightPanelCollapsed',
'viewer',
'panelResizing',
'currentActivityView',
- 'rightPane',
]),
...mapGetters([
'currentMergeRequest',
@@ -99,7 +101,7 @@ export default {
this.editor.updateDimensions();
}
},
- rightPane() {
+ rightPaneIsOpen() {
this.editor.updateDimensions();
},
},
diff --git a/app/assets/javascripts/ide/components/repo_file.vue b/app/assets/javascripts/ide/components/repo_file.vue
deleted file mode 100644
index 110eda83bb4..00000000000
--- a/app/assets/javascripts/ide/components/repo_file.vue
+++ /dev/null
@@ -1,227 +0,0 @@
-<script>
-import { mapActions, mapGetters } from 'vuex';
-import { n__, __, sprintf } from '~/locale';
-import tooltip from '~/vue_shared/directives/tooltip';
-import SkeletonLoadingContainer from '~/vue_shared/components/skeleton_loading_container.vue';
-import Icon from '~/vue_shared/components/icon.vue';
-import FileIcon from '~/vue_shared/components/file_icon.vue';
-import router from '../ide_router';
-import NewDropdown from './new_dropdown/index.vue';
-import FileStatusIcon from './repo_file_status_icon.vue';
-import ChangedFileIcon from './changed_file_icon.vue';
-import MrFileIcon from './mr_file_icon.vue';
-
-export default {
- name: 'RepoFile',
- directives: {
- tooltip,
- },
- components: {
- SkeletonLoadingContainer,
- NewDropdown,
- FileStatusIcon,
- FileIcon,
- ChangedFileIcon,
- MrFileIcon,
- Icon,
- },
- props: {
- file: {
- type: Object,
- required: true,
- },
- level: {
- type: Number,
- required: true,
- },
- },
- data() {
- return {
- mouseOver: false,
- };
- },
- computed: {
- ...mapGetters([
- 'getChangesInFolder',
- 'getUnstagedFilesCountForPath',
- 'getStagedFilesCountForPath',
- ]),
- folderUnstagedCount() {
- return this.getUnstagedFilesCountForPath(this.file.path);
- },
- folderStagedCount() {
- return this.getStagedFilesCountForPath(this.file.path);
- },
- changesCount() {
- return this.getChangesInFolder(this.file.path);
- },
- folderChangesTooltip() {
- if (this.changesCount === 0) return undefined;
-
- if (this.folderUnstagedCount > 0 && this.folderStagedCount === 0) {
- return n__('%d unstaged change', '%d unstaged changes', this.folderUnstagedCount);
- } else if (this.folderUnstagedCount === 0 && this.folderStagedCount > 0) {
- return n__('%d staged change', '%d staged changes', this.folderStagedCount);
- }
-
- return sprintf(__('%{unstaged} unstaged and %{staged} staged changes'), {
- unstaged: this.folderUnstagedCount,
- staged: this.folderStagedCount,
- });
- },
- isTree() {
- return this.file.type === 'tree';
- },
- isBlob() {
- return this.file.type === 'blob';
- },
- levelIndentation() {
- return {
- marginLeft: `${this.level * 16}px`,
- };
- },
- fileClass() {
- return {
- 'file-open': this.isBlob && this.file.opened,
- 'file-active': this.isBlob && this.file.active,
- folder: this.isTree,
- 'is-open': this.file.opened,
- };
- },
- showTreeChangesCount() {
- return this.isTree && this.changesCount > 0 && !this.file.opened;
- },
- showChangedFileIcon() {
- return this.file.changed || this.file.tempFile || this.file.staged;
- },
- },
- watch: {
- 'file.active': function fileActiveWatch(active) {
- if (this.file.type === 'blob' && active) {
- this.scrollIntoView();
- }
- },
- },
- mounted() {
- if (this.hasPathAtCurrentRoute()) {
- this.scrollIntoView(true);
- }
- },
- methods: {
- ...mapActions(['toggleTreeOpen']),
- clickFile() {
- // Manual Action if a tree is selected/opened
- if (this.isTree && this.hasUrlAtCurrentRoute()) {
- this.toggleTreeOpen(this.file.path);
- }
-
- router.push(`/project${this.file.url}`);
- },
- scrollIntoView(isInit = false) {
- const block = isInit && this.isTree ? 'center' : 'nearest';
-
- this.$el.scrollIntoView({
- behavior: 'smooth',
- block,
- });
- },
- hasPathAtCurrentRoute() {
- if (!this.$router || !this.$router.currentRoute) {
- return false;
- }
-
- // - strip route up to "/-/" and ending "/"
- const routePath = this.$router.currentRoute.path
- .replace(/^.*?[/]-[/]/g, '')
- .replace(/[/]$/g, '');
-
- // - strip ending "/"
- const filePath = this.file.path.replace(/[/]$/g, '');
-
- return filePath === routePath;
- },
- hasUrlAtCurrentRoute() {
- return this.$router.currentRoute.path === `/project${this.file.url}`;
- },
- toggleHover(over) {
- this.mouseOver = over;
- },
- },
-};
-</script>
-
-<template>
- <div>
- <div
- :class="fileClass"
- class="file"
- role="button"
- @click="clickFile"
- @mouseover="toggleHover(true)"
- @mouseout="toggleHover(false)"
- >
- <div
- class="file-name"
- >
- <span
- :style="levelIndentation"
- class="ide-file-name str-truncated"
- >
- <file-icon
- :file-name="file.name"
- :loading="file.loading"
- :folder="isTree"
- :opened="file.opened"
- :size="16"
- />
- {{ file.name }}
- <file-status-icon
- :file="file"
- />
- </span>
- <span class="float-right ide-file-icon-holder">
- <mr-file-icon
- v-if="file.mrChange"
- />
- <span
- v-if="showTreeChangesCount"
- class="ide-tree-changes"
- >
- {{ changesCount }}
- <icon
- v-tooltip
- :title="folderChangesTooltip"
- :size="12"
- data-container="body"
- data-placement="right"
- name="file-modified"
- css-classes="prepend-left-5 ide-file-modified"
- />
- </span>
- <changed-file-icon
- v-else-if="showChangedFileIcon"
- :file="file"
- :show-tooltip="true"
- :show-staged-icon="true"
- :force-modified-icon="true"
- class="float-right"
- />
- </span>
- <new-dropdown
- :type="file.type"
- :path="file.path"
- :mouse-over="mouseOver"
- class="float-right prepend-left-8"
- />
- </div>
- </div>
- <template v-if="file.opened">
- <repo-file
- v-for="childFile in file.tree"
- :key="childFile.key"
- :file="childFile"
- :level="level + 1"
- />
- </template>
- </div>
-</template>
diff --git a/app/assets/javascripts/ide/components/repo_file_status_icon.vue b/app/assets/javascripts/ide/components/repo_file_status_icon.vue
index 76a3333be50..97589e116c5 100644
--- a/app/assets/javascripts/ide/components/repo_file_status_icon.vue
+++ b/app/assets/javascripts/ide/components/repo_file_status_icon.vue
@@ -26,8 +26,8 @@ export default {
<template>
<span
- v-tooltip
v-if="file.file_lock"
+ v-tooltip
:title="lockTooltip"
data-container="body"
>
diff --git a/app/assets/javascripts/ide/components/repo_loading_file.vue b/app/assets/javascripts/ide/components/repo_loading_file.vue
deleted file mode 100644
index 7a5ede82253..00000000000
--- a/app/assets/javascripts/ide/components/repo_loading_file.vue
+++ /dev/null
@@ -1,42 +0,0 @@
-<script>
- import { mapState } from 'vuex';
- import skeletonLoadingContainer from '~/vue_shared/components/skeleton_loading_container.vue';
-
- export default {
- components: {
- skeletonLoadingContainer,
- },
- computed: {
- ...mapState([
- 'leftPanelCollapsed',
- ]),
- },
- };
-</script>
-
-<template>
- <tr
- class="loading-file"
- aria-label="Loading files"
- >
- <td class="multi-file-table-col-name">
- <skeleton-loading-container
- :small="true"
- />
- </td>
- <template v-if="!leftPanelCollapsed">
- <td class="d-none d-sm-none d-md-block">
- <skeleton-loading-container
- :small="true"
- />
- </td>
-
- <td class="d-none d-sm-block">
- <skeleton-loading-container
- :small="true"
- class="animation-container-right"
- />
- </td>
- </template>
- </tr>
-</template>
diff --git a/app/assets/javascripts/ide/constants.js b/app/assets/javascripts/ide/constants.js
index 8caa5b86a9b..3b201f006aa 100644
--- a/app/assets/javascripts/ide/constants.js
+++ b/app/assets/javascripts/ide/constants.js
@@ -29,10 +29,10 @@ export const diffModes = {
};
export const rightSidebarViews = {
- pipelines: 'pipelines-list',
- jobsDetail: 'jobs-detail',
- mergeRequestInfo: 'merge-request-info',
- clientSidePreview: 'clientside',
+ pipelines: { name: 'pipelines-list', keepAlive: true },
+ jobsDetail: { name: 'jobs-detail', keepAlive: false },
+ mergeRequestInfo: { name: 'merge-request-info', keepAlive: true },
+ clientSidePreview: { name: 'clientside', keepAlive: false },
};
export const stageKeys = {
diff --git a/app/assets/javascripts/ide/index.js b/app/assets/javascripts/ide/index.js
index 79e38ae911e..c0550116633 100644
--- a/app/assets/javascripts/ide/index.js
+++ b/app/assets/javascripts/ide/index.js
@@ -8,16 +8,28 @@ import { convertPermissionToBoolean } from '../lib/utils/common_utils';
Vue.use(Translate);
-export function initIde(el) {
+/**
+ * Initialize the IDE on the given element.
+ *
+ * @param {Element} el - The element that will contain the IDE.
+ * @param {Object} options - Extra options for the IDE (Used by EE).
+ * @param {(e:Element) => Object} options.extraInitialData -
+ * Function that returns extra properties to seed initial data.
+ * @param {Component} options.rootComponent -
+ * Component that overrides the root component.
+ */
+export function initIde(el, options = {}) {
if (!el) return null;
+ const {
+ extraInitialData = () => ({}),
+ rootComponent = ide,
+ } = options;
+
return new Vue({
el,
store,
router,
- components: {
- ide,
- },
created() {
this.setEmptyStateSvgs({
emptyStateSvgPath: el.dataset.emptyStateSvgPath,
@@ -32,13 +44,14 @@ export function initIde(el) {
});
this.setInitialData({
clientsidePreviewEnabled: convertPermissionToBoolean(el.dataset.clientsidePreviewEnabled),
+ ...extraInitialData(el),
});
},
methods: {
...mapActions(['setEmptyStateSvgs', 'setLinks', 'setInitialData']),
},
render(createElement) {
- return createElement('ide');
+ return createElement(rootComponent);
},
});
}
@@ -52,3 +65,18 @@ export function resetServiceWorkersPublicPath() {
const webpackAssetPath = `${relativeRootPath}/assets/webpack/`;
__webpack_public_path__ = webpackAssetPath; // eslint-disable-line camelcase
}
+
+/**
+ * Start the IDE.
+ *
+ * @param {Objects} options - Extra options for the IDE (Used by EE).
+ */
+export function startIde(options) {
+ document.addEventListener('DOMContentLoaded', () => {
+ const ideElement = document.getElementById('ide');
+ if (ideElement) {
+ resetServiceWorkersPublicPath();
+ initIde(ideElement, options);
+ }
+ });
+}
diff --git a/app/assets/javascripts/ide/stores/actions.js b/app/assets/javascripts/ide/stores/actions.js
index b8b64aead30..e10a132ab4b 100644
--- a/app/assets/javascripts/ide/stores/actions.js
+++ b/app/assets/javascripts/ide/stores/actions.js
@@ -184,10 +184,6 @@ export const burstUnusedSeal = ({ state, commit }) => {
}
};
-export const setRightPane = ({ commit }, view) => {
- commit(types.SET_RIGHT_PANE, view);
-};
-
export const setLinks = ({ commit }, links) => commit(types.SET_LINKS, links);
export const setErrorMessage = ({ commit }, errorMessage) =>
diff --git a/app/assets/javascripts/ide/stores/index.js b/app/assets/javascripts/ide/stores/index.js
index 877d88bb060..f1f544b52b2 100644
--- a/app/assets/javascripts/ide/stores/index.js
+++ b/app/assets/javascripts/ide/stores/index.js
@@ -9,6 +9,7 @@ import pipelines from './modules/pipelines';
import mergeRequests from './modules/merge_requests';
import branches from './modules/branches';
import fileTemplates from './modules/file_templates';
+import paneModule from './modules/pane';
Vue.use(Vuex);
@@ -24,6 +25,7 @@ export const createStore = () =>
mergeRequests,
branches,
fileTemplates: fileTemplates(),
+ rightPane: paneModule(),
},
});
diff --git a/app/assets/javascripts/ide/stores/modules/file_templates/actions.js b/app/assets/javascripts/ide/stores/modules/file_templates/actions.js
index dd53213ed18..cc9f6c8638c 100644
--- a/app/assets/javascripts/ide/stores/modules/file_templates/actions.js
+++ b/app/assets/javascripts/ide/stores/modules/file_templates/actions.js
@@ -1,5 +1,6 @@
import Api from '~/api';
import { __ } from '~/locale';
+import { normalizeHeaders } from '~/lib/utils/common_utils';
import * as types from './mutation_types';
import eventHub from '../../../eventhub';
@@ -22,13 +23,21 @@ export const receiveTemplateTypesError = ({ commit, dispatch }) => {
export const receiveTemplateTypesSuccess = ({ commit }, templates) =>
commit(types.RECEIVE_TEMPLATE_TYPES_SUCCESS, templates);
-export const fetchTemplateTypes = ({ dispatch, state }) => {
+export const fetchTemplateTypes = ({ dispatch, state }, page = 1) => {
if (!Object.keys(state.selectedTemplateType).length) return Promise.reject();
dispatch('requestTemplateTypes');
- return Api.templates(state.selectedTemplateType.key)
- .then(({ data }) => dispatch('receiveTemplateTypesSuccess', data))
+ return Api.templates(state.selectedTemplateType.key, { page })
+ .then(({ data, headers }) => {
+ const nextPage = parseInt(normalizeHeaders(headers)['X-NEXT-PAGE'], 10);
+
+ dispatch('receiveTemplateTypesSuccess', data);
+
+ if (nextPage) {
+ dispatch('fetchTemplateTypes', nextPage);
+ }
+ })
.catch(() => dispatch('receiveTemplateTypesError'));
};
diff --git a/app/assets/javascripts/ide/stores/modules/file_templates/mutations.js b/app/assets/javascripts/ide/stores/modules/file_templates/mutations.js
index 674782a28ca..d519c033769 100644
--- a/app/assets/javascripts/ide/stores/modules/file_templates/mutations.js
+++ b/app/assets/javascripts/ide/stores/modules/file_templates/mutations.js
@@ -9,7 +9,7 @@ export default {
},
[types.RECEIVE_TEMPLATE_TYPES_SUCCESS](state, templates) {
state.isLoading = false;
- state.templates = templates;
+ state.templates = state.templates.concat(templates);
},
[types.SET_SELECTED_TEMPLATE_TYPE](state, type) {
state.selectedTemplateType = type;
diff --git a/app/assets/javascripts/ide/stores/modules/pane/actions.js b/app/assets/javascripts/ide/stores/modules/pane/actions.js
new file mode 100644
index 00000000000..7f5d167a14f
--- /dev/null
+++ b/app/assets/javascripts/ide/stores/modules/pane/actions.js
@@ -0,0 +1,30 @@
+import * as types from './mutation_types';
+
+export const toggleOpen = ({ dispatch, state }, view) => {
+ if (state.isOpen) {
+ dispatch('close');
+ } else {
+ dispatch('open', view);
+ }
+};
+
+export const open = ({ commit }, view) => {
+ commit(types.SET_OPEN, true);
+
+ if (view) {
+ const { name, keepAlive } = view;
+
+ commit(types.SET_CURRENT_VIEW, name);
+
+ if (keepAlive) {
+ commit(types.KEEP_ALIVE_VIEW, name);
+ }
+ }
+};
+
+export const close = ({ commit }) => {
+ commit(types.SET_OPEN, false);
+};
+
+// prevent babel-plugin-rewire from generating an invalid default during karma tests
+export default () => {};
diff --git a/app/assets/javascripts/ide/stores/modules/pane/getters.js b/app/assets/javascripts/ide/stores/modules/pane/getters.js
new file mode 100644
index 00000000000..c346cf13689
--- /dev/null
+++ b/app/assets/javascripts/ide/stores/modules/pane/getters.js
@@ -0,0 +1,4 @@
+export const isActiveView = state => view => state.currentView === view;
+
+export const isAliveView = (state, getters) => view =>
+ state.keepAliveViews[view] || (state.isOpen && getters.isActiveView(view));
diff --git a/app/assets/javascripts/ide/stores/modules/pane/index.js b/app/assets/javascripts/ide/stores/modules/pane/index.js
new file mode 100644
index 00000000000..5f61cb732c8
--- /dev/null
+++ b/app/assets/javascripts/ide/stores/modules/pane/index.js
@@ -0,0 +1,12 @@
+import * as actions from './actions';
+import * as getters from './getters';
+import mutations from './mutations';
+import state from './state';
+
+export default () => ({
+ namespaced: true,
+ state: state(),
+ actions,
+ getters,
+ mutations,
+});
diff --git a/app/assets/javascripts/ide/stores/modules/pane/mutation_types.js b/app/assets/javascripts/ide/stores/modules/pane/mutation_types.js
new file mode 100644
index 00000000000..abdebc4d913
--- /dev/null
+++ b/app/assets/javascripts/ide/stores/modules/pane/mutation_types.js
@@ -0,0 +1,3 @@
+export const SET_OPEN = 'SET_OPEN';
+export const SET_CURRENT_VIEW = 'SET_CURRENT_VIEW';
+export const KEEP_ALIVE_VIEW = 'KEEP_ALIVE_VIEW';
diff --git a/app/assets/javascripts/ide/stores/modules/pane/mutations.js b/app/assets/javascripts/ide/stores/modules/pane/mutations.js
new file mode 100644
index 00000000000..c16484b4402
--- /dev/null
+++ b/app/assets/javascripts/ide/stores/modules/pane/mutations.js
@@ -0,0 +1,19 @@
+import * as types from './mutation_types';
+
+export default {
+ [types.SET_OPEN](state, isOpen) {
+ Object.assign(state, {
+ isOpen,
+ });
+ },
+ [types.SET_CURRENT_VIEW](state, currentView) {
+ Object.assign(state, {
+ currentView,
+ });
+ },
+ [types.KEEP_ALIVE_VIEW](state, viewName) {
+ Object.assign(state.keepAliveViews, {
+ [viewName]: true,
+ });
+ },
+};
diff --git a/app/assets/javascripts/ide/stores/modules/pane/state.js b/app/assets/javascripts/ide/stores/modules/pane/state.js
new file mode 100644
index 00000000000..353065b5735
--- /dev/null
+++ b/app/assets/javascripts/ide/stores/modules/pane/state.js
@@ -0,0 +1,5 @@
+export default () => ({
+ isOpen: false,
+ currentView: null,
+ keepAliveViews: {},
+});
diff --git a/app/assets/javascripts/ide/stores/modules/pipelines/actions.js b/app/assets/javascripts/ide/stores/modules/pipelines/actions.js
index 3e67b222e66..8fa86995ef0 100644
--- a/app/assets/javascripts/ide/stores/modules/pipelines/actions.js
+++ b/app/assets/javascripts/ide/stores/modules/pipelines/actions.js
@@ -113,7 +113,7 @@ export const toggleStageCollapsed = ({ commit }, stageId) =>
export const setDetailJob = ({ commit, dispatch }, job) => {
commit(types.SET_DETAIL_JOB, job);
- dispatch('setRightPane', job ? rightSidebarViews.jobsDetail : rightSidebarViews.pipelines, {
+ dispatch('rightPane/open', job ? rightSidebarViews.jobsDetail : rightSidebarViews.pipelines, {
root: true,
});
};
diff --git a/app/assets/javascripts/ide/stores/mutation_types.js b/app/assets/javascripts/ide/stores/mutation_types.js
index 5a7991d2fa7..a5f8098dc17 100644
--- a/app/assets/javascripts/ide/stores/mutation_types.js
+++ b/app/assets/javascripts/ide/stores/mutation_types.js
@@ -68,8 +68,6 @@ export const UPDATE_TEMP_FLAG = 'UPDATE_TEMP_FLAG';
export const TOGGLE_FILE_FINDER = 'TOGGLE_FILE_FINDER';
export const BURST_UNUSED_SEAL = 'BURST_UNUSED_SEAL';
-export const SET_RIGHT_PANE = 'SET_RIGHT_PANE';
-
export const CLEAR_PROJECTS = 'CLEAR_PROJECTS';
export const RESET_OPEN_FILES = 'RESET_OPEN_FILES';
diff --git a/app/assets/javascripts/ide/stores/mutations.js b/app/assets/javascripts/ide/stores/mutations.js
index 2c8535bda59..78cdfda74f0 100644
--- a/app/assets/javascripts/ide/stores/mutations.js
+++ b/app/assets/javascripts/ide/stores/mutations.js
@@ -166,11 +166,6 @@ export default {
unusedSeal: false,
});
},
- [types.SET_RIGHT_PANE](state, view) {
- Object.assign(state, {
- rightPane: state.rightPane === view ? null : view,
- });
- },
[types.SET_LINKS](state, links) {
Object.assign(state, { links });
},
diff --git a/app/assets/javascripts/ide/stores/state.js b/app/assets/javascripts/ide/stores/state.js
index 46b52fa00fc..d400b9831a9 100644
--- a/app/assets/javascripts/ide/stores/state.js
+++ b/app/assets/javascripts/ide/stores/state.js
@@ -23,7 +23,6 @@ export default () => ({
currentActivityView: activityBarViews.edit,
unusedSeal: true,
fileFindVisible: false,
- rightPane: null,
links: {},
errorMessage: null,
entryModal: {
diff --git a/app/assets/javascripts/issuable_bulk_update_actions.js b/app/assets/javascripts/issuable_bulk_update_actions.js
index 35eaf21a836..9e848699163 100644
--- a/app/assets/javascripts/issuable_bulk_update_actions.js
+++ b/app/assets/javascripts/issuable_bulk_update_actions.js
@@ -36,7 +36,7 @@ export default {
},
getSelectedIssues() {
- return this.issues.has('.selected_issue:checked');
+ return this.issues.has('.selected-issuable:checked');
},
getLabelsFromSelection() {
@@ -110,7 +110,7 @@ export default {
getOriginalCommonIds() {
const labelIds = [];
- this.getElement('.selected_issue:checked').each((i, el) => {
+ this.getElement('.selected-issuable:checked').each((i, el) => {
labelIds.push(this.getElement(`#${this.prefixId}${el.dataset.id}`).data('labels'));
});
return _.intersection.apply(this, labelIds);
@@ -119,7 +119,7 @@ export default {
// From issuable's initial bulk selection
getOriginalMarkedIds() {
const labelIds = [];
- this.getElement('.selected_issue:checked').each((i, el) => {
+ this.getElement('.selected-issuable:checked').each((i, el) => {
labelIds.push(this.getElement(`#${this.prefixId}${el.dataset.id}`).data('labels'));
});
return _.intersection.apply(this, labelIds);
@@ -132,7 +132,7 @@ export default {
let issuableLabels = [];
// Collect unique label IDs for all checked issues
- this.getElement('.selected_issue:checked').each((i, el) => {
+ this.getElement('.selected-issuable:checked').each((i, el) => {
issuableLabels = this.getElement(`#${this.prefixId}${el.dataset.id}`).data('labels');
issuableLabels.forEach((labelId) => {
// Store unique IDs
diff --git a/app/assets/javascripts/issuable_bulk_update_sidebar.js b/app/assets/javascripts/issuable_bulk_update_sidebar.js
index 2307c8e0d85..74150ce3a8b 100644
--- a/app/assets/javascripts/issuable_bulk_update_sidebar.js
+++ b/app/assets/javascripts/issuable_bulk_update_sidebar.js
@@ -30,7 +30,7 @@ export default class IssuableBulkUpdateSidebar {
this.$otherFilters = $('.issues-other-filters');
this.$checkAllContainer = $('.check-all-holder');
this.$issueChecks = $('.issue-check');
- this.$issuesList = $('.selected_issue');
+ this.$issuesList = $('.selected-issuable');
this.$issuableIdsInput = $('#update_issuable_ids');
}
@@ -55,7 +55,7 @@ export default class IssuableBulkUpdateSidebar {
}
updateFormState() {
- const noCheckedIssues = !$('.selected_issue:checked').length;
+ const noCheckedIssues = !$('.selected-issuable:checked').length;
this.toggleSubmitButtonDisabled(noCheckedIssues);
this.updateSelectedIssuableIds();
@@ -123,7 +123,7 @@ export default class IssuableBulkUpdateSidebar {
}
static getCheckedIssueIds() {
- const $checkedIssues = $('.selected_issue:checked');
+ const $checkedIssues = $('.selected-issuable:checked');
if ($checkedIssues.length > 0) {
return $.map($checkedIssues, value => $(value).data('id'));
diff --git a/app/assets/javascripts/issue_show/components/app.vue b/app/assets/javascripts/issue_show/components/app.vue
index ad928484952..c6ad3aa3e0d 100644
--- a/app/assets/javascripts/issue_show/components/app.vue
+++ b/app/assets/javascripts/issue_show/components/app.vue
@@ -293,6 +293,7 @@
:show-delete-button="showDeleteButton"
:can-attach-file="canAttachFile"
:enable-autocomplete="enableAutocomplete"
+ :issuable-type="issuableType"
/>
<recaptcha-modal
diff --git a/app/assets/javascripts/issue_show/components/edit_actions.vue b/app/assets/javascripts/issue_show/components/edit_actions.vue
index 597c6d69a81..bcf8686afcc 100644
--- a/app/assets/javascripts/issue_show/components/edit_actions.vue
+++ b/app/assets/javascripts/issue_show/components/edit_actions.vue
@@ -1,7 +1,13 @@
<script>
+ import { __, sprintf } from '~/locale';
import updateMixin from '../mixins/update';
import eventHub from '../event_hub';
+ const issuableTypes = {
+ issue: __('Issue'),
+ epic: __('Epic'),
+ };
+
export default {
mixins: [updateMixin],
props: {
@@ -18,6 +24,10 @@
required: false,
default: true,
},
+ issuableType: {
+ type: String,
+ required: true,
+ },
},
data() {
return {
@@ -37,8 +47,11 @@
eventHub.$emit('close.form');
},
deleteIssuable() {
+ const confirmMessage = sprintf(__('%{issuableType} will be removed! Are you sure?'), {
+ issuableType: issuableTypes[this.issuableType],
+ });
// eslint-disable-next-line no-alert
- if (window.confirm('Issue will be removed! Are you sure?')) {
+ if (window.confirm(confirmMessage)) {
this.deleteLoading = true;
eventHub.$emit('delete.issuable');
@@ -53,7 +66,7 @@
<button
:class="{ disabled: formState.updateLoading || !isSubmitEnabled }"
:disabled="formState.updateLoading || !isSubmitEnabled"
- class="btn btn-save float-left"
+ class="btn btn-success float-left"
type="submit"
@click.prevent="updateIssuable">
Save changes
diff --git a/app/assets/javascripts/issue_show/components/form.vue b/app/assets/javascripts/issue_show/components/form.vue
index e509bb52f7d..03d8d0ec67c 100644
--- a/app/assets/javascripts/issue_show/components/form.vue
+++ b/app/assets/javascripts/issue_show/components/form.vue
@@ -27,6 +27,10 @@
required: false,
default: () => [],
},
+ issuableType: {
+ type: String,
+ required: true,
+ },
markdownPreviewPath: {
type: String,
required: true,
@@ -110,6 +114,7 @@
:form-state="formState"
:can-destroy="canDestroy"
:show-delete-button="showDeleteButton"
+ :issuable-type="issuableType"
/>
</form>
</template>
diff --git a/app/assets/javascripts/issue_show/components/title.vue b/app/assets/javascripts/issue_show/components/title.vue
index b5e8e0ea44b..cf99e9a9cd8 100644
--- a/app/assets/javascripts/issue_show/components/title.vue
+++ b/app/assets/javascripts/issue_show/components/title.vue
@@ -76,8 +76,8 @@ export default {
>
</h2>
<button
- v-tooltip
v-if="showInlineEditButton && canUpdate"
+ v-tooltip
type="button"
class="btn btn-default btn-edit btn-svg js-issuable-edit"
title="Edit title and description"
diff --git a/app/assets/javascripts/job.js b/app/assets/javascripts/job.js
index d4f2a3ef7d3..0e71e705c13 100644
--- a/app/assets/javascripts/job.js
+++ b/app/assets/javascripts/job.js
@@ -6,7 +6,7 @@ import { visitUrl } from './lib/utils/url_utility';
import bp from './breakpoints';
import { numberToHumanSize } from './lib/utils/number_utils';
import { setCiStatusFavicon } from './lib/utils/common_utils';
-import { isScrolledToBottom, scrollDown } from './lib/utils/scroll_utils';
+import { isScrolledToBottom, scrollDown, scrollUp } from './lib/utils/scroll_utils';
import LogOutputBehaviours from './lib/utils/logoutput_behaviours';
export default class Job extends LogOutputBehaviours {
@@ -80,7 +80,7 @@ export default class Job extends LogOutputBehaviours {
}
scrollToTop() {
- $(document).scrollTop(0);
+ scrollUp();
this.hasBeenScrolled = true;
this.toggleScroll();
}
diff --git a/app/assets/javascripts/jobs/components/artifacts_block.vue b/app/assets/javascripts/jobs/components/artifacts_block.vue
index 525c5eec91a..d5866f9b9f1 100644
--- a/app/assets/javascripts/jobs/components/artifacts_block.vue
+++ b/app/assets/javascripts/jobs/components/artifacts_block.vue
@@ -1,40 +1,27 @@
<script>
- import TimeagoTooltiop from '~/vue_shared/components/time_ago_tooltip.vue';
+ import TimeagoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
+ import timeagoMixin from '~/vue_shared/mixins/timeago';
export default {
components: {
- TimeagoTooltiop,
+ TimeagoTooltip,
},
+ mixins: [
+ timeagoMixin,
+ ],
props: {
- // @build.artifacts_expired?
- haveArtifactsExpired: {
- type: Boolean,
+ artifact: {
+ type: Object,
required: true,
},
- // @build.has_expiring_artifacts?
- willArtifactsExpire: {
- type: Boolean,
- required: true,
- },
- expireAt: {
- type: String,
- required: false,
- default: null,
- },
- keepArtifactsPath: {
- type: String,
- required: false,
- default: null,
- },
- downloadArtifactsPath: {
- type: String,
- required: false,
- default: null,
+ },
+ computed: {
+ isExpired() {
+ return this.artifact.expired;
},
- browseArtifactsPath: {
- type: String,
- required: false,
- default: null,
+ // Only when the key is `false` we can render this block
+ willExpire() {
+ return this.artifact.expired === false;
},
},
};
@@ -46,21 +33,22 @@
</div>
<p
- v-if="haveArtifactsExpired"
+ v-if="isExpired"
class="js-artifacts-removed build-detail-row"
>
{{ s__('Job|The artifacts were removed') }}
</p>
+
<p
- v-else-if="willArtifactsExpire"
+ v-else-if="willExpire"
class="js-artifacts-will-be-removed build-detail-row"
>
- {{ s__('Job|The artifacts will be removed') }}
+ {{ s__('Job|The artifacts will be removed in') }}
</p>
- <timeago-tooltiop
- v-if="expireAt"
- :time="expireAt"
+ <timeago-tooltip
+ v-if="artifact.expire_at"
+ :time="artifact.expire_at"
/>
<div
@@ -68,8 +56,8 @@
role="group"
>
<a
- v-if="keepArtifactsPath"
- :href="keepArtifactsPath"
+ v-if="artifact.keep_path"
+ :href="artifact.keep_path"
class="js-keep-artifacts btn btn-sm btn-default"
data-method="post"
>
@@ -77,8 +65,8 @@
</a>
<a
- v-if="downloadArtifactsPath"
- :href="downloadArtifactsPath"
+ v-if="artifact.download_path"
+ :href="artifact.download_path"
class="js-download-artifacts btn btn-sm btn-default"
download
rel="nofollow"
@@ -87,8 +75,8 @@
</a>
<a
- v-if="browseArtifactsPath"
- :href="browseArtifactsPath"
+ v-if="artifact.browse_path"
+ :href="artifact.browse_path"
class="js-browse-artifacts btn btn-sm btn-default"
>
{{ s__('Job|Browse') }}
diff --git a/app/assets/javascripts/jobs/components/commit_block.vue b/app/assets/javascripts/jobs/components/commit_block.vue
index 7f485295513..39a4ff159e2 100644
--- a/app/assets/javascripts/jobs/components/commit_block.vue
+++ b/app/assets/javascripts/jobs/components/commit_block.vue
@@ -1,64 +1,56 @@
<script>
-import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
+ import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
-export default {
- components: {
- ClipboardButton,
- },
- props: {
- pipelineShortSha: {
- type: String,
- required: true,
+ export default {
+ components: {
+ ClipboardButton,
},
- pipelineShaPath: {
- type: String,
- required: true,
+ props: {
+ commit: {
+ type: Object,
+ required: true,
+ },
+ mergeRequest: {
+ type: Object,
+ required: false,
+ default: null,
+ },
+ isLastBlock: {
+ type: Boolean,
+ required: true,
+ },
},
- mergeRequestReference: {
- type: String,
- required: false,
- default: null,
- },
- mergeRequestPath: {
- type: String,
- required: false,
- default: null,
- },
- gitCommitTitlte: {
- type: String,
- required: true,
- },
- },
-};
+ };
</script>
<template>
- <div class="block">
+ <div
+ :class="{
+ 'block-last': isLastBlock,
+ block: !isLastBlock
+ }">
<p>
{{ __('Commit') }}
<a
- :href="pipelineShaPath"
+ :href="commit.commit_path"
class="js-commit-sha commit-sha link-commit"
- >
- {{ pipelineShortSha }}
- </a>
+ >{{ commit.short_id }}</a>
<clipboard-button
- :text="pipelineShortSha"
+ :text="commit.short_id"
:title="__('Copy commit SHA to clipboard')"
+ css-class="btn btn-clipboard btn-transparent"
/>
<a
- v-if="mergeRequestPath && mergeRequestReference"
- :href="mergeRequestPath"
+ v-if="mergeRequest"
+ :href="mergeRequest.path"
class="js-link-commit link-commit"
- >
- {{ mergeRequestReference }}
- </a>
+ >{{ mergeRequest.iid }}</a>
</p>
<p class="build-light-text append-bottom-0">
- {{ gitCommitTitlte }}
+ {{ commit.title }}
</p>
</div>
</template>
diff --git a/app/assets/javascripts/jobs/components/empty_state.vue b/app/assets/javascripts/jobs/components/empty_state.vue
index 4faf08387fb..ff45a5b05f8 100644
--- a/app/assets/javascripts/jobs/components/empty_state.vue
+++ b/app/assets/javascripts/jobs/components/empty_state.vue
@@ -25,7 +25,7 @@
validator(value) {
return (
value === null ||
- (Object.prototype.hasOwnProperty.call(value, 'link') &&
+ (Object.prototype.hasOwnProperty.call(value, 'path') &&
Object.prototype.hasOwnProperty.call(value, 'method') &&
Object.prototype.hasOwnProperty.call(value, 'title'))
);
@@ -63,7 +63,7 @@
class="text-center"
>
<a
- :href="action.link"
+ :href="action.path"
:data-method="action.method"
class="js-job-empty-state-action btn btn-primary"
>
diff --git a/app/assets/javascripts/jobs/components/erased_block.vue b/app/assets/javascripts/jobs/components/erased_block.vue
index d688eebfa95..3d6d9ba4387 100644
--- a/app/assets/javascripts/jobs/components/erased_block.vue
+++ b/app/assets/javascripts/jobs/components/erased_block.vue
@@ -1,39 +1,36 @@
<script>
-import TimeagoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
+ import _ from 'underscore';
+ import TimeagoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
-export default {
- components: {
- TimeagoTooltip,
- },
- props: {
- erasedByUser: {
- type: Boolean,
- required: true,
+ export default {
+ components: {
+ TimeagoTooltip,
},
- username: {
- type: String,
- required: false,
- default: null,
+ props: {
+ user: {
+ type: Object,
+ required: false,
+ default: () => ({}),
+ },
+ erasedAt: {
+ type: String,
+ required: true,
+ },
},
- linkToUser: {
- type: String,
- required: false,
- default: null,
+ computed: {
+ isErasedByUser() {
+ return !_.isEmpty(this.user);
+ },
},
- erasedAt: {
- type: String,
- required: true,
- },
- },
-};
+ };
</script>
<template>
<div class="prepend-top-default js-build-erased">
<div class="erased alert alert-warning">
- <template v-if="erasedByUser">
+ <template v-if="isErasedByUser">
{{ s__("Job|Job has been erased by") }}
- <a :href="linkToUser">
- {{ username }}
+ <a :href="user.web_url">
+ {{ user.username }}
</a>
</template>
<template v-else>
diff --git a/app/assets/javascripts/jobs/components/header.vue b/app/assets/javascripts/jobs/components/header.vue
index 3e49b04e44e..63324e68d68 100644
--- a/app/assets/javascripts/jobs/components/header.vue
+++ b/app/assets/javascripts/jobs/components/header.vue
@@ -57,7 +57,7 @@ export default {
actions.push({
label: 'New issue',
path: this.job.new_issue_path,
- cssClass: 'js-new-issue btn btn-new btn-inverted d-none d-md-block d-lg-block d-xl-block',
+ cssClass: 'js-new-issue btn btn-success btn-inverted d-none d-md-block d-lg-block d-xl-block',
type: 'link',
});
}
diff --git a/app/assets/javascripts/jobs/components/job_log.vue b/app/assets/javascripts/jobs/components/job_log.vue
index 3c4749d996b..b12e963b60c 100644
--- a/app/assets/javascripts/jobs/components/job_log.vue
+++ b/app/assets/javascripts/jobs/components/job_log.vue
@@ -6,7 +6,7 @@
type: String,
required: true,
},
- isReceivingBuildTrace: {
+ isComplete: {
type: Boolean,
required: true,
},
@@ -22,7 +22,7 @@
</code>
<div
- v-if="isReceivingBuildTrace"
+ v-if="isComplete"
class="js-log-animation build-loader-animation"
>
<div class="dot"></div>
diff --git a/app/assets/javascripts/jobs/components/job_log_controllers.vue b/app/assets/javascripts/jobs/components/job_log_controllers.vue
index 513851e376f..3e62ababea3 100644
--- a/app/assets/javascripts/jobs/components/job_log_controllers.vue
+++ b/app/assets/javascripts/jobs/components/job_log_controllers.vue
@@ -1,8 +1,9 @@
<script>
+ import { polyfillSticky } from '~/lib/utils/sticky';
import Icon from '~/vue_shared/components/icon.vue';
import tooltip from '~/vue_shared/directives/tooltip';
import { numberToHumanSize } from '~/lib/utils/number_utils';
- import { s__, sprintf } from '~/locale';
+ import { sprintf } from '~/locale';
export default {
components: {
@@ -12,44 +13,48 @@
tooltip,
},
props: {
- canEraseJob: {
- type: Boolean,
- required: true,
+ erasePath: {
+ type: String,
+ required: false,
+ default: null,
},
size: {
type: Number,
required: true,
},
- rawTracePath: {
+ rawPath: {
type: String,
required: false,
default: null,
},
- canScrollToTop: {
+ isScrollTopDisabled: {
+ type: Boolean,
+ required: true,
+ },
+ isScrollBottomDisabled: {
+ type: Boolean,
+ required: true,
+ },
+ isScrollingDown: {
type: Boolean,
required: true,
},
- canScrollToBottom: {
+ isTraceSizeVisible: {
type: Boolean,
required: true,
},
},
computed: {
jobLogSize() {
- return sprintf('Showing last %{startSpanTag} %{size} %{endSpanTag} of log -', {
- startSpanTag: '<span class="s-truncated-info-size truncated-info-size">',
- endSpanTag: '</span>',
+ return sprintf('Showing last %{size} of log -', {
size: numberToHumanSize(this.size),
});
},
},
+ mounted() {
+ polyfillSticky(this.$el);
+ },
methods: {
- handleEraseJobClick() {
- // eslint-disable-next-line no-alert
- if (window.confirm(s__('Job|Are you sure you want to erase this job?'))) {
- this.$emit('eraseJob');
- }
- },
handleScrollToTop() {
this.$emit('scrollJobLogTop');
},
@@ -57,48 +62,52 @@
this.$emit('scrollJobLogBottom');
},
},
+
};
</script>
<template>
<div class="top-bar">
<!-- truncate information -->
<div class="js-truncated-info truncated-info d-none d-sm-block float-left">
- <p v-html="jobLogSize"></p>
+ <template v-if="isTraceSizeVisible">
+ {{ jobLogSize }}
- <a
- v-if="rawTracePath"
- :href="rawTracePath"
- class="js-raw-link raw-link"
- >
- {{ s__("Job|Complete Raw") }}
- </a>
+ <a
+ v-if="rawPath"
+ :href="rawPath"
+ class="js-raw-link raw-link"
+ >
+ {{ s__("Job|Complete Raw") }}
+ </a>
+ </template>
</div>
<!-- eo truncate information -->
<div class="controllers float-right">
<!-- links -->
<a
+ v-if="rawPath"
v-tooltip
- v-if="rawTracePath"
:title="s__('Job|Show complete raw')"
- :href="rawTracePath"
+ :href="rawPath"
class="js-raw-link-controller controllers-buttons"
data-container="body"
>
<icon name="doc-text" />
</a>
- <button
+ <a
+ v-if="erasePath"
v-tooltip
- v-if="canEraseJob"
:title="s__('Job|Erase job log')"
- type="button"
+ :href="erasePath"
+ data-confirm="__('Are you sure you want to erase this build?')"
class="js-erase-link controllers-buttons"
data-container="body"
- @click="handleEraseJobClick"
+ data-method="post"
>
<icon name="remove" />
- </button>
+ </a>
<!-- eo links -->
<!-- scroll buttons -->
@@ -109,7 +118,7 @@
data-container="body"
>
<button
- :disabled="!canScrollToTop"
+ :disabled="isScrollTopDisabled"
type="button"
class="js-scroll-top btn-scroll btn-transparent btn-blank"
@click="handleScrollToTop"
@@ -125,9 +134,10 @@
data-container="body"
>
<button
- :disabled="!canScrollToBottom"
+ :disabled="isScrollBottomDisabled"
type="button"
class="js-scroll-bottom btn-scroll btn-transparent btn-blank"
+ :class="{ animate: isScrollingDown }"
@click="handleScrollToBottom"
>
<icon name="scroll_down"/>
diff --git a/app/assets/javascripts/jobs/components/jobs_container.vue b/app/assets/javascripts/jobs/components/jobs_container.vue
index b81109bdd06..93e2292ff84 100644
--- a/app/assets/javascripts/jobs/components/jobs_container.vue
+++ b/app/assets/javascripts/jobs/components/jobs_container.vue
@@ -25,9 +25,9 @@
class="build-job"
>
<a
- v-tooltip
v-for="job in jobs"
:key="job.id"
+ v-tooltip
:href="job.path"
:title="job.tooltip"
:class="{ active: job.active, retried: job.retried }"
diff --git a/app/assets/javascripts/jobs/components/sidebar_details_block.vue b/app/assets/javascripts/jobs/components/sidebar_details_block.vue
index 1210ccd038a..a591fcfb482 100644
--- a/app/assets/javascripts/jobs/components/sidebar_details_block.vue
+++ b/app/assets/javascripts/jobs/components/sidebar_details_block.vue
@@ -1,89 +1,113 @@
<script>
-import timeagoMixin from '~/vue_shared/mixins/timeago';
-import { timeIntervalInWords } from '~/lib/utils/datetime_utility';
-import Icon from '~/vue_shared/components/icon.vue';
-import DetailRow from './sidebar_detail_row.vue';
+ import _ from 'underscore';
+ import timeagoMixin from '~/vue_shared/mixins/timeago';
+ import { timeIntervalInWords } from '~/lib/utils/datetime_utility';
+ import Icon from '~/vue_shared/components/icon.vue';
+ import DetailRow from './sidebar_detail_row.vue';
+ import ArtifactsBlock from './artifacts_block.vue';
+ import TriggerBlock from './trigger_block.vue';
+ import CommitBlock from './commit_block.vue';
-export default {
- name: 'SidebarDetailsBlock',
- components: {
- DetailRow,
- Icon,
- },
- mixins: [timeagoMixin],
- props: {
- job: {
- type: Object,
- required: true,
+ export default {
+ name: 'SidebarDetailsBlock',
+ components: {
+ ArtifactsBlock,
+ CommitBlock,
+ DetailRow,
+ Icon,
+ TriggerBlock,
},
- isLoading: {
- type: Boolean,
- required: true,
+ mixins: [timeagoMixin],
+ props: {
+ job: {
+ type: Object,
+ required: true,
+ },
+ isLoading: {
+ type: Boolean,
+ required: true,
+ },
+ runnerHelpUrl: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ terminalPath: {
+ type: String,
+ required: false,
+ default: null,
+ },
},
- runnerHelpUrl: {
- type: String,
- required: false,
- default: '',
- },
- terminalPath: {
- type: String,
- required: false,
- default: null,
- },
- },
- computed: {
- shouldRenderContent() {
- return !this.isLoading && Object.keys(this.job).length > 0;
- },
- coverage() {
- return `${this.job.coverage}%`;
- },
- duration() {
- return timeIntervalInWords(this.job.duration);
- },
- queued() {
- return timeIntervalInWords(this.job.queued);
- },
- runnerId() {
- return `${this.job.runner.description} (#${this.job.runner.id})`;
- },
- retryButtonClass() {
- let className =
- 'js-retry-button float-right btn btn-retry d-none d-md-block d-lg-block d-xl-block';
- className +=
- this.job.status && this.job.recoverable ? ' btn-primary' : ' btn-inverted-secondary';
- return className;
- },
- hasTimeout() {
- return this.job.metadata != null && this.job.metadata.timeout_human_readable !== null;
- },
- timeout() {
- if (this.job.metadata == null) {
- return '';
- }
+ computed: {
+ shouldRenderContent() {
+ return !this.isLoading && Object.keys(this.job).length > 0;
+ },
+ coverage() {
+ return `${this.job.coverage}%`;
+ },
+ duration() {
+ return timeIntervalInWords(this.job.duration);
+ },
+ queued() {
+ return timeIntervalInWords(this.job.queued);
+ },
+ runnerId() {
+ return `${this.job.runner.description} (#${this.job.runner.id})`;
+ },
+ retryButtonClass() {
+ let className =
+ 'js-retry-button float-right btn btn-retry d-none d-md-block d-lg-block d-xl-block';
+ className +=
+ this.job.status && this.job.recoverable ? ' btn-primary' : ' btn-inverted-secondary';
+ return className;
+ },
+ hasTimeout() {
+ return this.job.metadata != null && this.job.metadata.timeout_human_readable !== null;
+ },
+ timeout() {
+ if (this.job.metadata == null) {
+ return '';
+ }
- let t = this.job.metadata.timeout_human_readable;
- if (this.job.metadata.timeout_source !== '') {
- t += ` (from ${this.job.metadata.timeout_source})`;
- }
+ let t = this.job.metadata.timeout_human_readable;
+ if (this.job.metadata.timeout_source !== '') {
+ t += ` (from ${this.job.metadata.timeout_source})`;
+ }
- return t;
- },
- renderBlock() {
- return (
- this.job.merge_request ||
- this.job.duration ||
- this.job.finished_data ||
- this.job.erased_at ||
- this.job.queued ||
- this.job.runner ||
- this.job.coverage ||
- this.job.tags.length ||
- this.job.cancel_path
- );
+ return t;
+ },
+ renderBlock() {
+ return (
+ this.job.merge_request ||
+ this.job.duration ||
+ this.job.finished_data ||
+ this.job.erased_at ||
+ this.job.queued ||
+ this.job.runner ||
+ this.job.coverage ||
+ this.job.tags.length ||
+ this.job.cancel_path
+ );
+ },
+ hasArtifact() {
+ return !_.isEmpty(this.job.artifact);
+ },
+ hasTriggers() {
+ return !_.isEmpty(this.job.trigger);
+ },
+ hasStages() {
+ return (
+ this.job &&
+ this.job.pipeline &&
+ this.job.pipeline.stages &&
+ this.job.pipeline.stages.length > 0
+ ) || false;
+ },
+ commit() {
+ return this.job.pipeline.commit || {};
+ },
},
- },
-};
+ };
</script>
<template>
<div>
@@ -130,7 +154,7 @@ export default {
<a
v-if="job.new_issue_path"
:href="job.new_issue_path"
- class="js-new-issue btn btn-new btn-inverted"
+ class="js-new-issue btn btn-success btn-inverted"
>
{{ __('New issue') }}
</a>
@@ -229,6 +253,19 @@ export default {
</a>
</div>
</div>
+ <artifacts-block
+ v-if="hasArtifact"
+ :artifact="job.artifact"
+ />
+ <trigger-block
+ v-if="hasTriggers"
+ :trigger="job.trigger"
+ />
+ <commit-block
+ :is-last-block="hasStages"
+ :commit="commit"
+ :merge-request="job.merge_request"
+ />
</template>
<gl-loading-icon
v-if="isLoading"
diff --git a/app/assets/javascripts/jobs/components/stuck_block.vue b/app/assets/javascripts/jobs/components/stuck_block.vue
index 18883fea950..a60643b2c65 100644
--- a/app/assets/javascripts/jobs/components/stuck_block.vue
+++ b/app/assets/javascripts/jobs/components/stuck_block.vue
@@ -24,14 +24,14 @@ export default {
<div class="bs-callout bs-callout-warning">
<p
v-if="hasNoRunnersForProject"
- class="js-stuck-no-runners"
+ class="js-stuck-no-runners append-bottom-0"
>
{{ s__(`Job|This job is stuck, because the project
doesn't have any runners online assigned to it.`) }}
</p>
<p
v-else-if="tags.length"
- class="js-stuck-with-tags"
+ class="js-stuck-with-tags append-bottom-0"
>
{{ s__(`This job is stuck, because you don't have
any active runners online with any of these tags assigned to them:`) }}
@@ -45,7 +45,7 @@ export default {
</p>
<p
v-else
- class="js-stuck-no-active-runner"
+ class="js-stuck-no-active-runner append-bottom-0"
>
{{ s__(`This job is stuck, because you don't
have any active runners that can run this job.`) }}
diff --git a/app/assets/javascripts/jobs/components/trigger_block.vue b/app/assets/javascripts/jobs/components/trigger_block.vue
index 8a88e5da6aa..d7b3c4fcb5b 100644
--- a/app/assets/javascripts/jobs/components/trigger_block.vue
+++ b/app/assets/javascripts/jobs/components/trigger_block.vue
@@ -1,16 +1,9 @@
<script>
export default {
props: {
- shortToken: {
- type: String,
- required: false,
- default: null,
- },
-
- variables: {
+ trigger: {
type: Object,
- required: false,
- default: () => ({}),
+ required: true,
},
},
data() {
@@ -20,7 +13,7 @@
},
computed: {
hasVariables() {
- return Object.keys(this.variables).length > 0;
+ return this.trigger.variables && this.trigger.variables.length > 0;
},
},
methods: {
@@ -38,17 +31,18 @@
</h4>
<p
- v-if="shortToken"
+ v-if="trigger.short_token"
class="js-short-token"
>
<span class="build-light-text">
{{ __('Token') }}
</span>
- {{ shortToken }}
+ {{ trigger.short_token }}
</p>
<p v-if="hasVariables">
<button
+ v-if="!areVariablesVisible"
type="button"
class="btn btn-default group js-reveal-variables"
@click="revealVariables"
@@ -63,20 +57,20 @@
class="js-build-variables trigger-build-variables"
>
<template
- v-for="(value, key) in variables"
+ v-for="variable in trigger.variables"
>
<dt
- :key="`${key}-variable`"
+ :key="`${variable.key}-variable`"
class="js-build-variable trigger-build-variable"
>
- {{ key }}
+ {{ variable.key }}
</dt>
<dd
- :key="`${key}-value`"
+ :key="`${variable.key}-value`"
class="js-build-value trigger-build-value"
>
- {{ value }}
+ {{ variable.value }}
</dd>
</template>
</dl>
diff --git a/app/assets/javascripts/jobs/job_details_bundle.js b/app/assets/javascripts/jobs/job_details_bundle.js
index a84324f14b2..0136ec4d194 100644
--- a/app/assets/javascripts/jobs/job_details_bundle.js
+++ b/app/assets/javascripts/jobs/job_details_bundle.js
@@ -1,34 +1,36 @@
+import { mapState } from 'vuex';
import Vue from 'vue';
-import JobMediator from './job_details_mediator';
-import jobHeader from './components/header.vue';
-import detailsBlock from './components/sidebar_details_block.vue';
+import Job from '../job';
+import JobHeader from './components/header.vue';
+import DetailsBlock from './components/sidebar_details_block.vue';
+import createStore from './store';
export default () => {
const { dataset } = document.getElementById('js-job-details-vue');
- const mediator = new JobMediator({ endpoint: dataset.endpoint });
- mediator.fetchJob();
+ // eslint-disable-next-line no-new
+ new Job();
+
+ const store = createStore();
+ store.dispatch('setJobEndpoint', dataset.endpoint);
+ store.dispatch('fetchJob');
// Header
// eslint-disable-next-line no-new
new Vue({
el: '#js-build-header-vue',
components: {
- jobHeader,
- },
- data() {
- return {
- mediator,
- };
+ JobHeader,
},
- mounted() {
- this.mediator.initBuildClass();
+ store,
+ computed: {
+ ...mapState(['job', 'isLoading']),
},
render(createElement) {
return createElement('job-header', {
props: {
- isLoading: this.mediator.state.isLoading,
- job: this.mediator.store.state.job,
+ isLoading: this.isLoading,
+ job: this.job,
},
});
},
@@ -41,18 +43,17 @@ export default () => {
new Vue({
el: detailsBlockElement,
components: {
- detailsBlock,
+ DetailsBlock,
},
- data() {
- return {
- mediator,
- };
+ store,
+ computed: {
+ ...mapState(['job', 'isLoading']),
},
render(createElement) {
return createElement('details-block', {
props: {
- isLoading: this.mediator.state.isLoading,
- job: this.mediator.store.state.job,
+ isLoading: this.isLoading,
+ job: this.job,
runnerHelpUrl: dataset.runnerHelpUrl,
terminalPath: detailsBlockDataset.terminalPath,
},
diff --git a/app/assets/javascripts/jobs/job_details_mediator.js b/app/assets/javascripts/jobs/job_details_mediator.js
deleted file mode 100644
index 89019da9d1e..00000000000
--- a/app/assets/javascripts/jobs/job_details_mediator.js
+++ /dev/null
@@ -1,67 +0,0 @@
-import Visibility from 'visibilityjs';
-import Flash from '../flash';
-import Poll from '../lib/utils/poll';
-import JobStore from './stores/job_store';
-import JobService from './services/job_service';
-import Job from '../job';
-import handleRevealVariables from '../build_variables';
-
-export default class JobMediator {
- constructor(options = {}) {
- this.options = options;
-
- this.store = new JobStore();
- this.service = new JobService(options.endpoint);
-
- this.state = {
- isLoading: false,
- };
- }
-
- initBuildClass() {
- this.build = new Job();
- handleRevealVariables();
- }
-
- fetchJob() {
- this.poll = new Poll({
- resource: this.service,
- method: 'getJob',
- successCallback: response => this.successCallback(response),
- errorCallback: () => this.errorCallback(),
- });
-
- if (!Visibility.hidden()) {
- this.state.isLoading = true;
- this.poll.makeRequest();
- } else {
- this.getJob();
- }
-
- Visibility.change(() => {
- if (!Visibility.hidden()) {
- this.poll.restart();
- } else {
- this.poll.stop();
- }
- });
- }
-
- getJob() {
- return this.service
- .getJob()
- .then(response => this.successCallback(response))
- .catch(() => this.errorCallback());
- }
-
- successCallback(response) {
- this.state.isLoading = false;
- return this.store.storeJob(response.data);
- }
-
- errorCallback() {
- this.state.isLoading = false;
-
- return new Flash('An error occurred while fetching the job.');
- }
-}
diff --git a/app/assets/javascripts/jobs/services/job_service.js b/app/assets/javascripts/jobs/services/job_service.js
deleted file mode 100644
index b746489c45c..00000000000
--- a/app/assets/javascripts/jobs/services/job_service.js
+++ /dev/null
@@ -1,11 +0,0 @@
-import axios from '../../lib/utils/axios_utils';
-
-export default class JobService {
- constructor(endpoint) {
- this.job = endpoint;
- }
-
- getJob() {
- return axios.get(this.job);
- }
-}
diff --git a/app/assets/javascripts/jobs/store/mutations.js b/app/assets/javascripts/jobs/store/mutations.js
index cd12ef87d40..c3f2359fa4d 100644
--- a/app/assets/javascripts/jobs/store/mutations.js
+++ b/app/assets/javascripts/jobs/store/mutations.js
@@ -1,6 +1,9 @@
import * as types from './mutation_types';
export default {
+ [types.SET_JOB_ENDPOINT](state, endpoint) {
+ state.jobEndpoint = endpoint;
+ },
[types.REQUEST_STATUS_FAVICON](state) {
state.fetchingStatusFavicon = true;
},
diff --git a/app/assets/javascripts/jobs/stores/job_store.js b/app/assets/javascripts/jobs/stores/job_store.js
deleted file mode 100644
index 766194b8387..00000000000
--- a/app/assets/javascripts/jobs/stores/job_store.js
+++ /dev/null
@@ -1,11 +0,0 @@
-export default class JobStore {
- constructor() {
- this.state = {
- job: {},
- };
- }
-
- storeJob(job = {}) {
- this.state.job = job;
- }
-}
diff --git a/app/assets/javascripts/labels_select.js b/app/assets/javascripts/labels_select.js
index 6499b919787..1c7bca78df3 100644
--- a/app/assets/javascripts/labels_select.js
+++ b/app/assets/javascripts/labels_select.js
@@ -449,11 +449,11 @@ export default class LabelsSelect {
}
bindEvents() {
- return $('body').on('change', '.selected_issue', this.onSelectCheckboxIssue);
+ return $('body').on('change', '.selected-issuable', this.onSelectCheckboxIssue);
}
// eslint-disable-next-line class-methods-use-this
onSelectCheckboxIssue() {
- if ($('.selected_issue:checked').length) {
+ if ($('.selected-issuable:checked').length) {
return;
}
return $('.issues-bulk-update .labels-filter .dropdown-toggle-text').text('Label');
diff --git a/app/assets/javascripts/lib/utils/common_utils.js b/app/assets/javascripts/lib/utils/common_utils.js
index 0849d97bc1a..30925940807 100644
--- a/app/assets/javascripts/lib/utils/common_utils.js
+++ b/app/assets/javascripts/lib/utils/common_utils.js
@@ -56,7 +56,8 @@ export const rstrip = val => {
return val;
};
-export const updateTooltipTitle = ($tooltipEl, newTitle) => $tooltipEl.attr('title', newTitle).tooltip('_fixTitle');
+export const updateTooltipTitle = ($tooltipEl, newTitle) =>
+ $tooltipEl.attr('title', newTitle).tooltip('_fixTitle');
export const disableButtonIfEmptyField = (fieldSelector, buttonSelector, eventName = 'input') => {
const field = $(fieldSelector);
@@ -86,6 +87,7 @@ export const handleLocationHash = () => {
const fixedTabs = document.querySelector('.js-tabs-affix');
const fixedDiffStats = document.querySelector('.js-diff-files-changed');
const fixedNav = document.querySelector('.navbar-gitlab');
+ const performanceBar = document.querySelector('#js-peek');
let adjustment = 0;
if (fixedNav) adjustment -= fixedNav.offsetHeight;
@@ -102,6 +104,10 @@ export const handleLocationHash = () => {
adjustment -= fixedDiffStats.offsetHeight;
}
+ if (performanceBar) {
+ adjustment -= performanceBar.offsetHeight;
+ }
+
window.scrollBy(0, adjustment);
};
@@ -131,21 +137,20 @@ export const parseUrlPathname = url => {
return parsedUrl.pathname.charAt(0) === '/' ? parsedUrl.pathname : `/${parsedUrl.pathname}`;
};
-const splitPath = (path = '') => path
- .replace(/^\?/, '')
- .split('&');
+const splitPath = (path = '') => path.replace(/^\?/, '').split('&');
-export const urlParamsToArray = (path = '') => splitPath(path)
- .filter(param => param.length > 0)
- .map(param => {
- const split = param.split('=');
- return [decodeURI(split[0]), split[1]].join('=');
- });
+export const urlParamsToArray = (path = '') =>
+ splitPath(path)
+ .filter(param => param.length > 0)
+ .map(param => {
+ const split = param.split('=');
+ return [decodeURI(split[0]), split[1]].join('=');
+ });
export const getUrlParamsArray = () => urlParamsToArray(window.location.search);
-export const urlParamsToObject = (path = '') => splitPath(path)
- .reduce((dataParam, filterParam) => {
+export const urlParamsToObject = (path = '') =>
+ splitPath(path).reduce((dataParam, filterParam) => {
if (filterParam === '') {
return dataParam;
}
@@ -216,7 +221,7 @@ export const getParameterByName = (name, urlToParse) => {
return decodeURIComponent(results[2].replace(/\+/g, ' '));
};
-const handleSelectedRange = (range) => {
+const handleSelectedRange = range => {
const container = range.commonAncestorContainer;
// add context to fragment if needed
if (container.tagName === 'OL') {
@@ -453,7 +458,7 @@ export const backOff = (fn, timeout = 60000) => {
export const createOverlayIcon = (iconPath, overlayPath) => {
const faviconImage = document.createElement('img');
- return new Promise((resolve) => {
+ return new Promise(resolve => {
faviconImage.onload = () => {
const size = 32;
@@ -464,13 +469,29 @@ export const createOverlayIcon = (iconPath, overlayPath) => {
const context = canvas.getContext('2d');
context.clearRect(0, 0, size, size);
context.drawImage(
- faviconImage, 0, 0, faviconImage.width, faviconImage.height, 0, 0, size, size,
+ faviconImage,
+ 0,
+ 0,
+ faviconImage.width,
+ faviconImage.height,
+ 0,
+ 0,
+ size,
+ size,
);
const overlayImage = document.createElement('img');
overlayImage.onload = () => {
context.drawImage(
- overlayImage, 0, 0, overlayImage.width, overlayImage.height, 0, 0, size, size,
+ overlayImage,
+ 0,
+ 0,
+ overlayImage.width,
+ overlayImage.height,
+ 0,
+ 0,
+ size,
+ size,
);
const faviconWithOverlayUrl = canvas.toDataURL();
@@ -483,17 +504,21 @@ export const createOverlayIcon = (iconPath, overlayPath) => {
});
};
-export const setFaviconOverlay = (overlayPath) => {
+export const setFaviconOverlay = overlayPath => {
const faviconEl = document.getElementById('favicon');
- if (!faviconEl) { return null; }
+ if (!faviconEl) {
+ return null;
+ }
const iconPath = faviconEl.getAttribute('data-original-href');
- return createOverlayIcon(iconPath, overlayPath).then(faviconWithOverlayUrl => faviconEl.setAttribute('href', faviconWithOverlayUrl));
+ return createOverlayIcon(iconPath, overlayPath).then(faviconWithOverlayUrl =>
+ faviconEl.setAttribute('href', faviconWithOverlayUrl),
+ );
};
-export const setFavicon = (faviconPath) => {
+export const setFavicon = faviconPath => {
const faviconEl = document.getElementById('favicon');
if (faviconEl && faviconPath) {
faviconEl.setAttribute('href', faviconPath);
@@ -518,7 +543,7 @@ export const setCiStatusFavicon = pageUrl =>
}
return resetFavicon();
})
- .catch((error) => {
+ .catch(error => {
resetFavicon();
throw error;
});
diff --git a/app/assets/javascripts/lib/utils/logoutput_behaviours.js b/app/assets/javascripts/lib/utils/logoutput_behaviours.js
index 1bf99d935ef..41b57025cc9 100644
--- a/app/assets/javascripts/lib/utils/logoutput_behaviours.js
+++ b/app/assets/javascripts/lib/utils/logoutput_behaviours.js
@@ -1,5 +1,11 @@
import $ from 'jquery';
-import { canScroll, isScrolledToBottom, toggleDisableButton } from './scroll_utils';
+import {
+ canScroll,
+ isScrolledToBottom,
+ isScrolledToTop,
+ isScrolledToMiddle,
+ toggleDisableButton,
+} from './scroll_utils';
export default class LogOutputBehaviours {
constructor() {
@@ -12,18 +18,13 @@ export default class LogOutputBehaviours {
}
toggleScroll() {
- const $document = $(document);
- const currentPosition = $document.scrollTop();
- const scrollHeight = $document.height();
-
- const windowHeight = $(window).height();
if (canScroll()) {
- if (currentPosition > 0 && scrollHeight - currentPosition !== windowHeight) {
+ if (isScrolledToMiddle()) {
// User is in the middle of the log
toggleDisableButton(this.$scrollTopBtn, false);
toggleDisableButton(this.$scrollBottomBtn, false);
- } else if (currentPosition === 0) {
+ } else if (isScrolledToTop()) {
// User is at Top of Log
toggleDisableButton(this.$scrollTopBtn, true);
diff --git a/app/assets/javascripts/shortcuts_dashboard_navigation.js b/app/assets/javascripts/lib/utils/navigation_utility.js
index 9f69f110d06..1579b225e44 100644
--- a/app/assets/javascripts/shortcuts_dashboard_navigation.js
+++ b/app/assets/javascripts/lib/utils/navigation_utility.js
@@ -1,4 +1,4 @@
-import { visitUrl } from './lib/utils/url_utility';
+import { visitUrl } from './url_utility';
/**
* Helper function that finds the href of the fiven selector and updates the location.
diff --git a/app/assets/javascripts/lib/utils/scroll_utils.js b/app/assets/javascripts/lib/utils/scroll_utils.js
index 9313b570863..b4da1e16f08 100644
--- a/app/assets/javascripts/lib/utils/scroll_utils.js
+++ b/app/assets/javascripts/lib/utils/scroll_utils.js
@@ -4,6 +4,7 @@ export const canScroll = () => $(document).height() > $(window).height();
/**
* Checks if the entire page is scrolled down all the way to the bottom
+ * @returns {Boolean}
*/
export const isScrolledToBottom = () => {
const $document = $(document);
@@ -16,11 +17,34 @@ export const isScrolledToBottom = () => {
return scrollHeight - currentPosition === windowHeight;
};
+/**
+ * Checks if page is scrolled to the top
+ * @returns {Boolean}
+ */
+export const isScrolledToTop = () => $(document).scrollTop() === 0;
+
export const scrollDown = () => {
const $document = $(document);
$document.scrollTop($document.height());
};
+export const scrollUp = () => {
+ $(document).scrollTop(0);
+};
+
+/**
+ * Checks if scroll position is in the middle of the page
+ * @returns {Boolean}
+ */
+export const isScrolledToMiddle = () => {
+ const $document = $(document);
+ const currentPosition = $document.scrollTop();
+ const scrollHeight = $document.height();
+ const windowHeight = $(window).height();
+
+ return currentPosition > 0 && scrollHeight - currentPosition !== windowHeight;
+};
+
export const toggleDisableButton = ($button, disable) => {
if (disable && $button.prop('disabled')) return;
$button.prop('disabled', disable);
diff --git a/app/assets/javascripts/main.js b/app/assets/javascripts/main.js
index c5a5f64abac..e8aac51a299 100644
--- a/app/assets/javascripts/main.js
+++ b/app/assets/javascripts/main.js
@@ -2,7 +2,6 @@
import jQuery from 'jquery';
import Cookies from 'js-cookie';
-import svg4everybody from 'svg4everybody';
// bootstrap webpack, common libs, polyfills, and behaviors
import './webpack';
@@ -25,11 +24,12 @@ import initLayoutNav from './layout_nav';
import './feature_highlight/feature_highlight_options';
import LazyLoader from './lazy_loader';
import initLogoAnimation from './logo';
-import './milestone_select';
import './frequent_items';
import initBreadcrumbs from './breadcrumb';
-import initDispatcher from './dispatcher';
import initUsagePingConsent from './usage_ping_consent';
+import initPerformanceBar from './performance_bar';
+import initSearchAutocomplete from './search_autocomplete';
+import GlFieldErrors from './gl_field_errors';
// expose jQuery as global (TODO: remove these)
window.jQuery = jQuery;
@@ -41,8 +41,6 @@ if (process.env.NODE_ENV !== 'production' && gon && gon.test_env) {
import(/* webpackMode: "eager" */ './test_utils/');
}
-svg4everybody();
-
document.addEventListener('beforeunload', () => {
// Unbind scroll events
$(document).off('scroll');
@@ -81,6 +79,9 @@ document.addEventListener('DOMContentLoaded', () => {
initLogoAnimation();
initUsagePingConsent();
+ if (document.querySelector('.search')) initSearchAutocomplete();
+ if (document.querySelector('#js-peek')) initPerformanceBar({ container: '#js-peek' });
+
// Set the default path for all cookies to GitLab's root directory
Cookies.defaults.path = gon.relative_url_root || '/';
@@ -270,5 +271,6 @@ document.addEventListener('DOMContentLoaded', () => {
});
}
- initDispatcher();
+ // initialize field errors
+ $('.gl-show-field-errors').each((i, form) => new GlFieldErrors(form));
});
diff --git a/app/assets/javascripts/merge_request_tabs.js b/app/assets/javascripts/merge_request_tabs.js
index 53d7504de35..763429d7242 100644
--- a/app/assets/javascripts/merge_request_tabs.js
+++ b/app/assets/javascripts/merge_request_tabs.js
@@ -115,8 +115,9 @@ export default class MergeRequestTabs {
this.mergeRequestTabs &&
this.mergeRequestTabs.querySelector(`a[data-action='${action}']`) &&
this.mergeRequestTabs.querySelector(`a[data-action='${action}']`).click
- )
+ ) {
this.mergeRequestTabs.querySelector(`a[data-action='${action}']`).click();
+ }
this.initAffix();
}
diff --git a/app/assets/javascripts/monitoring/components/dashboard.vue b/app/assets/javascripts/monitoring/components/dashboard.vue
index ae96ac3b80c..67338aa96c3 100644
--- a/app/assets/javascripts/monitoring/components/dashboard.vue
+++ b/app/assets/javascripts/monitoring/components/dashboard.vue
@@ -97,33 +97,45 @@ export default {
store: new MonitoringStore(),
state: 'gettingStarted',
showEmptyState: true,
- updateAspectRatio: false,
- updatedAspectRatios: 0,
hoverData: {},
- resizeThrottled: {},
+ elWidth: 0,
};
},
+ computed: {
+ forceRedraw() {
+ return this.elWidth;
+ },
+ },
created() {
this.service = new MonitoringService({
metricsEndpoint: this.metricsEndpoint,
deploymentEndpoint: this.deploymentEndpoint,
environmentsEndpoint: this.environmentsEndpoint,
});
- eventHub.$on('toggleAspectRatio', this.toggleAspectRatio);
+ this.mutationObserverConfig = {
+ attributes: true,
+ childList: false,
+ subtree: false,
+ };
eventHub.$on('hoverChanged', this.hoverChanged);
},
beforeDestroy() {
- eventHub.$off('toggleAspectRatio', this.toggleAspectRatio);
eventHub.$off('hoverChanged', this.hoverChanged);
window.removeEventListener('resize', this.resizeThrottled, false);
+ this.sidebarMutationObserver.disconnect();
},
mounted() {
- this.resizeThrottled = _.throttle(this.resize, 600);
+ this.resizeThrottled = _.debounce(this.resize, 100);
if (!this.hasMetrics) {
this.state = 'gettingStarted';
} else {
this.getGraphsData();
window.addEventListener('resize', this.resizeThrottled, false);
+
+ const sidebarEl = document.querySelector('.nav-sidebar');
+ // The sidebar listener
+ this.sidebarMutationObserver = new MutationObserver(this.resizeThrottled);
+ this.sidebarMutationObserver.observe(sidebarEl, this.mutationObserverConfig);
}
},
methods: {
@@ -153,14 +165,7 @@ export default {
});
},
resize() {
- this.updateAspectRatio = true;
- },
- toggleAspectRatio() {
- this.updatedAspectRatios += 1;
- if (this.store.getMetricsCount() === this.updatedAspectRatios) {
- this.updateAspectRatio = !this.updateAspectRatio;
- this.updatedAspectRatios = 0;
- }
+ this.elWidth = this.$el.clientWidth;
},
hoverChanged(data) {
this.hoverData = data;
@@ -172,6 +177,7 @@ export default {
<template>
<div
v-if="!showEmptyState"
+ :key="forceRedraw"
class="prometheus-graphs prepend-top-default"
>
<div class="environments d-flex align-items-center">
@@ -214,11 +220,10 @@ export default {
:show-panels="showPanels"
>
<graph
- v-for="(graphData, index) in groupData.metrics"
- :key="index"
+ v-for="(graphData, graphIndex) in groupData.metrics"
+ :key="graphIndex"
:graph-data="graphData"
:hover-data="hoverData"
- :update-aspect-ratio="updateAspectRatio"
:deployment-data="store.deploymentData"
:project-path="projectPath"
:tags-path="tagsPath"
diff --git a/app/assets/javascripts/monitoring/components/graph.vue b/app/assets/javascripts/monitoring/components/graph.vue
index a13f30e6079..ff44f51b8f8 100644
--- a/app/assets/javascripts/monitoring/components/graph.vue
+++ b/app/assets/javascripts/monitoring/components/graph.vue
@@ -32,10 +32,6 @@ export default {
type: Object,
required: true,
},
- updateAspectRatio: {
- type: Boolean,
- required: true,
- },
deploymentData: {
type: Array,
required: true,
@@ -110,15 +106,6 @@ export default {
},
},
watch: {
- updateAspectRatio() {
- if (this.updateAspectRatio) {
- this.graphHeight = 450;
- this.graphWidth = 600;
- this.measurements = measurements.large;
- this.draw();
- eventHub.$emit('toggleAspectRatio');
- }
- },
hoverData() {
this.positionFlag();
},
diff --git a/app/assets/javascripts/monitoring/components/graph/legend.vue b/app/assets/javascripts/monitoring/components/graph/legend.vue
index 3276f3a1ceb..ef18ae5c2c8 100644
--- a/app/assets/javascripts/monitoring/components/graph/legend.vue
+++ b/app/assets/javascripts/monitoring/components/graph/legend.vue
@@ -58,8 +58,8 @@ export default {
</td>
<template v-for="(track, trackIndex) in series.tracksLegend">
<track-line
- :track="track"
- :key="`track-line-${trackIndex}`"/>
+ :key="`track-line-${trackIndex}`"
+ :track="track"/>
<td :key="`track-info-${trackIndex}`">
<track-info
:track="track"
diff --git a/app/assets/javascripts/notebook/index.vue b/app/assets/javascripts/notebook/index.vue
index e2e3b08c77f..f241df9620d 100644
--- a/app/assets/javascripts/notebook/index.vue
+++ b/app/assets/javascripts/notebook/index.vue
@@ -51,10 +51,10 @@
<template>
<div v-if="hasNotebook">
<component
- v-for="(cell, index) in cells"
:is="cellType(cell.cell_type)"
- :cell="cell"
+ v-for="(cell, index) in cells"
:key="index"
+ :cell="cell"
:code-css-class="codeCssClass" />
</div>
</template>
diff --git a/app/assets/javascripts/notes.js b/app/assets/javascripts/notes.js
index 8b1d8f6055e..f301f093ef4 100644
--- a/app/assets/javascripts/notes.js
+++ b/app/assets/javascripts/notes.js
@@ -16,7 +16,7 @@ import 'vendor/jquery.atwho';
import AjaxCache from '~/lib/utils/ajax_cache';
import Vue from 'vue';
import syntaxHighlight from '~/syntax_highlight';
-import SkeletonLoadingContainer from '~/vue_shared/components/skeleton_loading_container.vue';
+import { SkeletonLoading } from '@gitlab-org/gitlab-ui';
import axios from './lib/utils/axios_utils';
import { getLocationHash } from './lib/utils/url_utility';
import Flash from './flash';
@@ -631,7 +631,7 @@ export default class Notes {
*
* deactivates the submit button when text is empty
* hides the preview button when text is empty
- * setup GFM auto complete
+ * set up GFM auto complete
* show the form
*/
setupNoteForm(form, enableGFM = defaultAutocompleteConfig) {
@@ -954,7 +954,7 @@ export default class Notes {
* Note: dataHolder must have the "discussionId" and "lineCode" data attributes set.
*/
setupDiscussionNoteForm(dataHolder, form) {
- // setup note target
+ // set up note target
let diffFileData = dataHolder.closest('.text-file');
if (diffFileData.length === 0) {
@@ -1036,7 +1036,7 @@ export default class Notes {
$diffFile[0].dispatchEvent(clickEvent);
- // Setup comment form
+ // Set up comment form
let newForm;
const $noteContainer = $link.closest('.diff-viewer').find('.note-container');
const $form = $noteContainer.find('> .discussion-form');
@@ -1293,10 +1293,10 @@ export default class Notes {
new Vue({
el,
components: {
- SkeletonLoadingContainer,
+ SkeletonLoading,
},
render(createElement) {
- return createElement('skeleton-loading-container');
+ return createElement('skeleton-loading');
},
});
}
diff --git a/app/assets/javascripts/notes/components/comment_form.vue b/app/assets/javascripts/notes/components/comment_form.vue
index 6612bc44e0b..7735133c470 100644
--- a/app/assets/javascripts/notes/components/comment_form.vue
+++ b/app/assets/javascripts/notes/components/comment_form.vue
@@ -374,7 +374,7 @@ js-gfm-input js-autosize markdown-area js-vue-textarea"
append-right-10 comment-type-dropdown js-comment-type-dropdown droplab-dropdown">
<button
:disabled="isSubmitButtonDisabled"
- class="btn btn-create comment-btn js-comment-button js-comment-submit-button"
+ class="btn btn-success comment-btn js-comment-button js-comment-submit-button"
type="submit"
@click.prevent="handleSave()">
{{ __(commentButtonTitle) }}
diff --git a/app/assets/javascripts/notes/components/diff_file_header.vue b/app/assets/javascripts/notes/components/diff_file_header.vue
index fc7b52be241..4fd93304a03 100644
--- a/app/assets/javascripts/notes/components/diff_file_header.vue
+++ b/app/assets/javascripts/notes/components/diff_file_header.vue
@@ -41,8 +41,8 @@ export default {
</div>
<template v-else>
<component
- ref="titleWrapper"
:is="titleTag"
+ ref="titleWrapper"
:href="diffFile.discussionPath"
>
<span v-html="diffFile.blobIcon"></span>
diff --git a/app/assets/javascripts/notes/components/diff_with_note.vue b/app/assets/javascripts/notes/components/diff_with_note.vue
index 802be022ba6..353aa790743 100644
--- a/app/assets/javascripts/notes/components/diff_with_note.vue
+++ b/app/assets/javascripts/notes/components/diff_with_note.vue
@@ -3,13 +3,13 @@ import { mapState, mapActions } from 'vuex';
import imageDiffHelper from '~/image_diff/helpers/index';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
import DiffFileHeader from '~/diffs/components/diff_file_header.vue';
-import SkeletonLoadingContainer from '~/vue_shared/components/skeleton_loading_container.vue';
+import { SkeletonLoading } from '@gitlab-org/gitlab-ui';
import { trimFirstCharOfLineContent } from '~/diffs/store/utils';
export default {
components: {
DiffFileHeader,
- SkeletonLoadingContainer,
+ SkeletonLoading,
},
props: {
discussion: {
@@ -142,7 +142,7 @@ export default {
class="line_content js-success-lazy-load"
>
<span></span>
- <skeleton-loading-container />
+ <skeleton-loading />
<span></span>
</td>
</tr>
diff --git a/app/assets/javascripts/notes/components/note_awards_list.vue b/app/assets/javascripts/notes/components/note_awards_list.vue
index 051b17e9aa9..c68860d98ae 100644
--- a/app/assets/javascripts/notes/components/note_awards_list.vue
+++ b/app/assets/javascripts/notes/components/note_awards_list.vue
@@ -182,9 +182,9 @@ export default {
<div class="note-awards">
<div class="awards js-awards-block">
<button
- v-tooltip
v-for="(awardList, awardName, index) in groupedAwards"
:key="index"
+ v-tooltip
:class="getAwardClassBindings(awardList)"
:title="awardTitle(awardList)"
class="btn award-control"
diff --git a/app/assets/javascripts/notes/components/note_form.vue b/app/assets/javascripts/notes/components/note_form.vue
index c41ed070383..2d47d55f33c 100644
--- a/app/assets/javascripts/notes/components/note_form.vue
+++ b/app/assets/javascripts/notes/components/note_form.vue
@@ -171,8 +171,8 @@ export default {
id="note_note"
ref="textarea"
slot="textarea"
- :data-supports-quick-actions="!isEditing"
v-model="updatedNoteBody"
+ :data-supports-quick-actions="!isEditing"
name="note[note]"
class="note-textarea js-gfm-input js-note-text
js-autosize markdown-area js-vue-issue-note-form js-vue-textarea"
@@ -188,7 +188,7 @@ js-autosize markdown-area js-vue-issue-note-form js-vue-textarea"
<button
:disabled="isDisabled"
type="button"
- class="js-vue-issue-save btn btn-save js-comment-button "
+ class="js-vue-issue-save btn btn-success js-comment-button "
@click="handleUpdate()">
{{ saveButtonTitle }}
</button>
diff --git a/app/assets/javascripts/notes/components/noteable_discussion.vue b/app/assets/javascripts/notes/components/noteable_discussion.vue
index afe86911230..6ede7562edf 100644
--- a/app/assets/javascripts/notes/components/noteable_discussion.vue
+++ b/app/assets/javascripts/notes/components/noteable_discussion.vue
@@ -348,10 +348,10 @@ Please check your network connection and try again.`;
<div class="discussion-notes">
<ul class="notes">
<component
- v-for="note in discussion.notes"
:is="componentName(note)"
- :note="componentData(note)"
+ v-for="note in discussion.notes"
:key="note.id"
+ :note="componentData(note)"
@handleDeleteNote="deleteNoteHandler"
/>
</ul>
diff --git a/app/assets/javascripts/notes/components/notes_app.vue b/app/assets/javascripts/notes/components/notes_app.vue
index 42c87fdf54a..d8e8efb982a 100644
--- a/app/assets/javascripts/notes/components/notes_app.vue
+++ b/app/assets/javascripts/notes/components/notes_app.vue
@@ -187,10 +187,10 @@ export default {
class="notes main-notes-list timeline"
>
<component
- v-for="discussion in allDiscussions"
:is="getComponentName(discussion)"
- v-bind="getComponentData(discussion)"
+ v-for="discussion in allDiscussions"
:key="discussion.id"
+ v-bind="getComponentData(discussion)"
/>
</ul>
diff --git a/app/assets/javascripts/notes/stores/actions.js b/app/assets/javascripts/notes/stores/actions.js
index 9a2ec15debd..320dfa47d5a 100644
--- a/app/assets/javascripts/notes/stores/actions.js
+++ b/app/assets/javascripts/notes/stores/actions.js
@@ -10,6 +10,7 @@ import service from '../services/notes_service';
import loadAwardsHandler from '../../awards_handler';
import sidebarTimeTrackingEventHub from '../../sidebar/event_hub';
import { isInViewport, scrollToElement } from '../../lib/utils/common_utils';
+import mrWidgetEventHub from '../../vue_merge_request_widget/event_hub';
let eTagPoll;
@@ -43,27 +44,17 @@ export const fetchDiscussions = ({ commit }, path) =>
commit(types.SET_INITIAL_DISCUSSIONS, discussions);
});
-export const refetchDiscussionById = ({ commit, state }, { path, discussionId }) =>
- new Promise(resolve => {
- service
- .fetchDiscussions(path)
- .then(res => res.json())
- .then(discussions => {
- const selectedDiscussion = discussions.find(discussion => discussion.id === discussionId);
- if (selectedDiscussion) {
- commit(types.UPDATE_DISCUSSION, selectedDiscussion);
- // We need to refetch as it is now the transformed one in state
- const discussion = utils.findNoteObjectById(state.discussions, discussionId);
-
- resolve(discussion);
- }
- })
- .catch(() => {});
- });
+export const updateDiscussion = ({ commit, state }, discussion) => {
+ commit(types.UPDATE_DISCUSSION, discussion);
-export const deleteNote = ({ commit }, note) =>
+ return utils.findNoteObjectById(state.discussions, discussion.id);
+};
+
+export const deleteNote = ({ commit, dispatch }, note) =>
service.deleteNote(note.path).then(() => {
commit(types.DELETE_NOTE, note);
+
+ dispatch('updateMergeRequestWidget');
});
export const updateNote = ({ commit }, { endpoint, note }) =>
@@ -84,20 +75,22 @@ export const replyToDiscussion = ({ commit }, { endpoint, data }) =>
return res;
});
-export const createNewNote = ({ commit }, { endpoint, data }) =>
+export const createNewNote = ({ commit, dispatch }, { endpoint, data }) =>
service
.createNewNote(endpoint, data)
.then(res => res.json())
.then(res => {
if (!res.errors) {
commit(types.ADD_NEW_NOTE, res);
+
+ dispatch('updateMergeRequestWidget');
}
return res;
});
export const removePlaceholderNotes = ({ commit }) => commit(types.REMOVE_PLACEHOLDER_NOTES);
-export const toggleResolveNote = ({ commit }, { endpoint, isResolved, discussion }) =>
+export const toggleResolveNote = ({ commit, dispatch }, { endpoint, isResolved, discussion }) =>
service
.toggleResolveNote(endpoint, isResolved)
.then(res => res.json())
@@ -105,6 +98,8 @@ export const toggleResolveNote = ({ commit }, { endpoint, isResolved, discussion
const mutationType = discussion ? types.UPDATE_DISCUSSION : types.UPDATE_NOTE;
commit(mutationType, res);
+
+ dispatch('updateMergeRequestWidget');
});
export const closeIssue = ({ commit, dispatch, state }) => {
@@ -333,5 +328,9 @@ export const fetchDiscussionDiffLines = ({ commit }, discussion) =>
});
});
+export const updateMergeRequestWidget = () => {
+ mrWidgetEventHub.$emit('mr.discussion.updated');
+};
+
// prevent babel-plugin-rewire from generating an invalid default during karma tests
export default () => {};
diff --git a/app/assets/javascripts/notes/stores/mutations.js b/app/assets/javascripts/notes/stores/mutations.js
index 16bb54be126..73e55705f39 100644
--- a/app/assets/javascripts/notes/stores/mutations.js
+++ b/app/assets/javascripts/notes/stores/mutations.js
@@ -4,7 +4,8 @@ import * as constants from '../constants';
import { isInMRPage } from '../../lib/utils/common_utils';
export default {
- [types.ADD_NEW_NOTE](state, note) {
+ [types.ADD_NEW_NOTE](state, data) {
+ const note = data.discussion ? data.discussion.notes[0] : data;
const { discussion_id, type } = note;
const [exists] = state.discussions.filter(n => n.id === note.discussion_id);
const isDiscussion = type === constants.DISCUSSION_NOTE || type === constants.DIFF_NOTE;
@@ -100,7 +101,10 @@ export default {
discussionsData.forEach(discussion => {
if (discussion.diff_file) {
- Object.assign(discussion, { fileHash: discussion.diff_file.file_hash });
+ Object.assign(discussion, {
+ fileHash: discussion.diff_file.file_hash,
+ truncated_diff_lines: discussion.truncated_diff_lines || [],
+ });
}
// To support legacy notes, should be very rare case.
diff --git a/app/assets/javascripts/notes/stores/utils.js b/app/assets/javascripts/notes/stores/utils.js
index 8ccbdb4c130..0e41ff03d67 100644
--- a/app/assets/javascripts/notes/stores/utils.js
+++ b/app/assets/javascripts/notes/stores/utils.js
@@ -27,7 +27,7 @@ export const getQuickActionText = note => {
export const reduceDiscussionsToLineCodes = selectedDiscussions =>
selectedDiscussions.reduce((acc, note) => {
- if (note.diff_discussion && note.line_code && note.resolvable) {
+ if (note.diff_discussion && note.line_code) {
// For context about line notes: there might be multiple notes with the same line code
const items = acc[note.line_code] || [];
items.push(note);
diff --git a/app/assets/javascripts/pages/admin/application_settings/index.js b/app/assets/javascripts/pages/admin/application_settings/index.js
index 069f8ce55d0..47bd70537f1 100644
--- a/app/assets/javascripts/pages/admin/application_settings/index.js
+++ b/app/assets/javascripts/pages/admin/application_settings/index.js
@@ -1,13 +1,8 @@
import initSettingsPanels from '~/settings_panels';
import projectSelect from '~/project_select';
-import UsagePingPayload from './usage_ping_payload';
document.addEventListener('DOMContentLoaded', () => {
// Initialize expandable settings panels
initSettingsPanels();
projectSelect();
- new UsagePingPayload(
- document.querySelector('.js-usage-ping-payload-trigger'),
- document.querySelector('.js-usage-ping-payload'),
- ).init();
});
diff --git a/app/assets/javascripts/pages/admin/application_settings/metrics_and_profiling/index.js b/app/assets/javascripts/pages/admin/application_settings/metrics_and_profiling/index.js
new file mode 100644
index 00000000000..c40503603be
--- /dev/null
+++ b/app/assets/javascripts/pages/admin/application_settings/metrics_and_profiling/index.js
@@ -0,0 +1,8 @@
+import UsagePingPayload from './../usage_ping_payload';
+
+document.addEventListener('DOMContentLoaded', () => {
+ new UsagePingPayload(
+ document.querySelector('.js-usage-ping-payload-trigger'),
+ document.querySelector('.js-usage-ping-payload'),
+ ).init();
+});
diff --git a/app/assets/javascripts/pages/admin/users/components/delete_user_modal.vue b/app/assets/javascripts/pages/admin/users/components/delete_user_modal.vue
index d6aa4bb95d2..8d5efcdcd96 100644
--- a/app/assets/javascripts/pages/admin/users/components/delete_user_modal.vue
+++ b/app/assets/javascripts/pages/admin/users/components/delete_user_modal.vue
@@ -155,10 +155,7 @@
/>
</form>
</template>
- <template
- slot="secondary-button"
- slot-scope="props"
- >
+ <template slot="secondary-button">
<button
:disabled="!canSubmit"
type="button"
diff --git a/app/assets/javascripts/pages/groups/boards/index.js b/app/assets/javascripts/pages/groups/boards/index.js
index 5cfe8723204..79c3be771d0 100644
--- a/app/assets/javascripts/pages/groups/boards/index.js
+++ b/app/assets/javascripts/pages/groups/boards/index.js
@@ -1,5 +1,5 @@
import UsersSelect from '~/users_select';
-import ShortcutsNavigation from '~/shortcuts_navigation';
+import ShortcutsNavigation from '~/behaviors/shortcuts/shortcuts_navigation';
import initBoards from '~/boards';
document.addEventListener('DOMContentLoaded', () => {
diff --git a/app/assets/javascripts/pages/groups/show/index.js b/app/assets/javascripts/pages/groups/show/index.js
index 5b8c2ae7e81..3a45fd70d02 100644
--- a/app/assets/javascripts/pages/groups/show/index.js
+++ b/app/assets/javascripts/pages/groups/show/index.js
@@ -6,7 +6,7 @@ import NewGroupChild from '~/groups/new_group_child';
import notificationsDropdown from '~/notifications_dropdown';
import NotificationsForm from '~/notifications_form';
import ProjectsList from '~/projects_list';
-import ShortcutsNavigation from '~/shortcuts_navigation';
+import ShortcutsNavigation from '~/behaviors/shortcuts/shortcuts_navigation';
import GroupTabs from './group_tabs';
document.addEventListener('DOMContentLoaded', () => {
diff --git a/app/assets/javascripts/pages/ide/index.js b/app/assets/javascripts/pages/ide/index.js
index efadf6967aa..d192df3561e 100644
--- a/app/assets/javascripts/pages/ide/index.js
+++ b/app/assets/javascripts/pages/ide/index.js
@@ -1,9 +1,3 @@
-import { initIde, resetServiceWorkersPublicPath } from '~/ide/index';
+import { startIde } from '~/ide/index';
-document.addEventListener('DOMContentLoaded', () => {
- const ideElement = document.getElementById('ide');
- if (ideElement) {
- resetServiceWorkersPublicPath();
- initIde(ideElement);
- }
-});
+startIde();
diff --git a/app/assets/javascripts/pages/projects/activity/index.js b/app/assets/javascripts/pages/projects/activity/index.js
index 5543ad82428..d39ea3d10bf 100644
--- a/app/assets/javascripts/pages/projects/activity/index.js
+++ b/app/assets/javascripts/pages/projects/activity/index.js
@@ -1,5 +1,5 @@
import Activities from '~/activities';
-import ShortcutsNavigation from '~/shortcuts_navigation';
+import ShortcutsNavigation from '~/behaviors/shortcuts/shortcuts_navigation';
document.addEventListener('DOMContentLoaded', () => {
new Activities(); // eslint-disable-line no-new
diff --git a/app/assets/javascripts/pages/projects/artifacts/browse/index.js b/app/assets/javascripts/pages/projects/artifacts/browse/index.js
index ea7458fe9b8..26dc90a56d7 100644
--- a/app/assets/javascripts/pages/projects/artifacts/browse/index.js
+++ b/app/assets/javascripts/pages/projects/artifacts/browse/index.js
@@ -1,5 +1,5 @@
import BuildArtifacts from '~/build_artifacts';
-import ShortcutsNavigation from '~/shortcuts_navigation';
+import ShortcutsNavigation from '~/behaviors/shortcuts/shortcuts_navigation';
document.addEventListener('DOMContentLoaded', () => {
new ShortcutsNavigation(); // eslint-disable-line no-new
diff --git a/app/assets/javascripts/pages/projects/artifacts/file/index.js b/app/assets/javascripts/pages/projects/artifacts/file/index.js
index 8484e5e9848..249900d6cb7 100644
--- a/app/assets/javascripts/pages/projects/artifacts/file/index.js
+++ b/app/assets/javascripts/pages/projects/artifacts/file/index.js
@@ -1,5 +1,5 @@
import BlobViewer from '~/blob/viewer/index';
-import ShortcutsNavigation from '~/shortcuts_navigation';
+import ShortcutsNavigation from '~/behaviors/shortcuts/shortcuts_navigation';
document.addEventListener('DOMContentLoaded', () => {
new ShortcutsNavigation(); // eslint-disable-line no-new
diff --git a/app/assets/javascripts/pages/projects/boards/index.js b/app/assets/javascripts/pages/projects/boards/index.js
index 5cfe8723204..79c3be771d0 100644
--- a/app/assets/javascripts/pages/projects/boards/index.js
+++ b/app/assets/javascripts/pages/projects/boards/index.js
@@ -1,5 +1,5 @@
import UsersSelect from '~/users_select';
-import ShortcutsNavigation from '~/shortcuts_navigation';
+import ShortcutsNavigation from '~/behaviors/shortcuts/shortcuts_navigation';
import initBoards from '~/boards';
document.addEventListener('DOMContentLoaded', () => {
diff --git a/app/assets/javascripts/pages/projects/commit/show/index.js b/app/assets/javascripts/pages/projects/commit/show/index.js
index 2e23cce11ce..f477424811d 100644
--- a/app/assets/javascripts/pages/projects/commit/show/index.js
+++ b/app/assets/javascripts/pages/projects/commit/show/index.js
@@ -3,7 +3,7 @@
import $ from 'jquery';
import Diff from '~/diff';
import ZenMode from '~/zen_mode';
-import ShortcutsNavigation from '~/shortcuts_navigation';
+import ShortcutsNavigation from '~/behaviors/shortcuts/shortcuts_navigation';
import MiniPipelineGraph from '~/mini_pipeline_graph_dropdown';
import initNotes from '~/init_notes';
import initChangesDropdown from '~/init_changes_dropdown';
diff --git a/app/assets/javascripts/pages/projects/commits/show/index.js b/app/assets/javascripts/pages/projects/commits/show/index.js
index 3682020579b..ad671ce9351 100644
--- a/app/assets/javascripts/pages/projects/commits/show/index.js
+++ b/app/assets/javascripts/pages/projects/commits/show/index.js
@@ -1,6 +1,6 @@
import CommitsList from '~/commits';
import GpgBadges from '~/gpg_badges';
-import ShortcutsNavigation from '~/shortcuts_navigation';
+import ShortcutsNavigation from '~/behaviors/shortcuts/shortcuts_navigation';
document.addEventListener('DOMContentLoaded', () => {
new CommitsList(document.querySelector('.js-project-commits-show').dataset.commitsLimit); // eslint-disable-line no-new
diff --git a/app/assets/javascripts/pages/projects/find_file/show/index.js b/app/assets/javascripts/pages/projects/find_file/show/index.js
index 24630c2aa05..388d7d7bdda 100644
--- a/app/assets/javascripts/pages/projects/find_file/show/index.js
+++ b/app/assets/javascripts/pages/projects/find_file/show/index.js
@@ -1,6 +1,6 @@
import $ from 'jquery';
import ProjectFindFile from '~/project_find_file';
-import ShortcutsFindFile from '~/shortcuts_find_file';
+import ShortcutsFindFile from '~/behaviors/shortcuts/shortcuts_find_file';
document.addEventListener('DOMContentLoaded', () => {
const findElement = document.querySelector('.js-file-finder');
diff --git a/app/assets/javascripts/pages/projects/index.js b/app/assets/javascripts/pages/projects/index.js
index 9c074b74c3b..5659e13981a 100644
--- a/app/assets/javascripts/pages/projects/index.js
+++ b/app/assets/javascripts/pages/projects/index.js
@@ -1,7 +1,7 @@
import initDismissableCallout from '~/dismissable_callout';
import initGkeDropdowns from '~/projects/gke_cluster_dropdowns';
import Project from './project';
-import ShortcutsNavigation from '../../shortcuts_navigation';
+import ShortcutsNavigation from '../../behaviors/shortcuts/shortcuts_navigation';
document.addEventListener('DOMContentLoaded', () => {
const { page } = document.body.dataset;
diff --git a/app/assets/javascripts/pages/projects/init_blob.js b/app/assets/javascripts/pages/projects/init_blob.js
index 56ab3fcdfcb..bc08ccf3584 100644
--- a/app/assets/javascripts/pages/projects/init_blob.js
+++ b/app/assets/javascripts/pages/projects/init_blob.js
@@ -1,7 +1,7 @@
import LineHighlighter from '~/line_highlighter';
import BlobLinePermalinkUpdater from '~/blob/blob_line_permalink_updater';
-import ShortcutsNavigation from '~/shortcuts_navigation';
-import ShortcutsBlob from '~/shortcuts_blob';
+import ShortcutsNavigation from '~/behaviors/shortcuts/shortcuts_navigation';
+import ShortcutsBlob from '~/behaviors/shortcuts/shortcuts_blob';
import BlobForkSuggestion from '~/blob/blob_fork_suggestion';
import initBlobBundle from '~/blob_edit/blob_bundle';
diff --git a/app/assets/javascripts/pages/projects/issues/form.js b/app/assets/javascripts/pages/projects/issues/form.js
index b2b8e5d2300..197bfa8a394 100644
--- a/app/assets/javascripts/pages/projects/issues/form.js
+++ b/app/assets/javascripts/pages/projects/issues/form.js
@@ -5,7 +5,7 @@ import GLForm from '~/gl_form';
import IssuableForm from '~/issuable_form';
import LabelsSelect from '~/labels_select';
import MilestoneSelect from '~/milestone_select';
-import ShortcutsNavigation from '~/shortcuts_navigation';
+import ShortcutsNavigation from '~/behaviors/shortcuts/shortcuts_navigation';
import IssuableTemplateSelectors from '~/templates/issuable_template_selectors';
export default () => {
diff --git a/app/assets/javascripts/pages/projects/issues/index/index.js b/app/assets/javascripts/pages/projects/issues/index/index.js
index 23edbdc5cad..a56c0bb6be8 100644
--- a/app/assets/javascripts/pages/projects/issues/index/index.js
+++ b/app/assets/javascripts/pages/projects/issues/index/index.js
@@ -1,7 +1,7 @@
/* eslint-disable no-new */
import IssuableIndex from '~/issuable_index';
-import ShortcutsNavigation from '~/shortcuts_navigation';
+import ShortcutsNavigation from '~/behaviors/shortcuts/shortcuts_navigation';
import UsersSelect from '~/users_select';
import initFilteredSearch from '~/pages/search/init_filtered_search';
import IssuableFilteredSearchTokenKeys from '~/filtered_search/issuable_filtered_search_token_keys';
diff --git a/app/assets/javascripts/pages/projects/issues/show.js b/app/assets/javascripts/pages/projects/issues/show.js
index 500fbd27340..74b3a515e84 100644
--- a/app/assets/javascripts/pages/projects/issues/show.js
+++ b/app/assets/javascripts/pages/projects/issues/show.js
@@ -1,6 +1,6 @@
import initIssuableSidebar from '~/init_issuable_sidebar';
import Issue from '~/issue';
-import ShortcutsIssuable from '~/shortcuts_issuable';
+import ShortcutsIssuable from '~/behaviors/shortcuts/shortcuts_issuable';
import ZenMode from '~/zen_mode';
import '~/notes/index';
import '~/issue_show/index';
diff --git a/app/assets/javascripts/pages/projects/merge_requests/index/index.js b/app/assets/javascripts/pages/projects/merge_requests/index/index.js
index 1fad0fb7297..3647048a872 100644
--- a/app/assets/javascripts/pages/projects/merge_requests/index/index.js
+++ b/app/assets/javascripts/pages/projects/merge_requests/index/index.js
@@ -1,5 +1,5 @@
import IssuableIndex from '~/issuable_index';
-import ShortcutsNavigation from '~/shortcuts_navigation';
+import ShortcutsNavigation from '~/behaviors/shortcuts/shortcuts_navigation';
import UsersSelect from '~/users_select';
import initFilteredSearch from '~/pages/search/init_filtered_search';
import IssuableFilteredSearchTokenKeys from '~/filtered_search/issuable_filtered_search_token_keys';
diff --git a/app/assets/javascripts/pages/projects/merge_requests/init_merge_request.js b/app/assets/javascripts/pages/projects/merge_requests/init_merge_request.js
index 3a3c21f2202..e3971618da5 100644
--- a/app/assets/javascripts/pages/projects/merge_requests/init_merge_request.js
+++ b/app/assets/javascripts/pages/projects/merge_requests/init_merge_request.js
@@ -2,7 +2,7 @@
import $ from 'jquery';
import Diff from '~/diff';
-import ShortcutsNavigation from '~/shortcuts_navigation';
+import ShortcutsNavigation from '~/behaviors/shortcuts/shortcuts_navigation';
import GLForm from '~/gl_form';
import IssuableForm from '~/issuable_form';
import LabelsSelect from '~/labels_select';
diff --git a/app/assets/javascripts/pages/projects/merge_requests/init_merge_request_show.js b/app/assets/javascripts/pages/projects/merge_requests/init_merge_request_show.js
index 26ead75cec4..7bfb83a2204 100644
--- a/app/assets/javascripts/pages/projects/merge_requests/init_merge_request_show.js
+++ b/app/assets/javascripts/pages/projects/merge_requests/init_merge_request_show.js
@@ -1,6 +1,6 @@
import ZenMode from '~/zen_mode';
import initIssuableSidebar from '~/init_issuable_sidebar';
-import ShortcutsIssuable from '~/shortcuts_issuable';
+import ShortcutsIssuable from '~/behaviors/shortcuts/shortcuts_issuable';
import { handleLocationHash } from '~/lib/utils/common_utils';
import howToMerge from '~/how_to_merge';
import initPipelines from '~/commit/pipelines/pipelines_bundle';
diff --git a/app/assets/javascripts/pages/projects/network/show/index.js b/app/assets/javascripts/pages/projects/network/show/index.js
index a0b14fed10f..9f05f63b742 100644
--- a/app/assets/javascripts/pages/projects/network/show/index.js
+++ b/app/assets/javascripts/pages/projects/network/show/index.js
@@ -1,5 +1,5 @@
import $ from 'jquery';
-import ShortcutsNetwork from '../../../../shortcuts_network';
+import ShortcutsNetwork from '~/behaviors/shortcuts/shortcuts_network';
import Network from '../network';
document.addEventListener('DOMContentLoaded', () => {
diff --git a/app/assets/javascripts/pages/projects/pipeline_schedules/shared/components/interval_pattern_input.vue b/app/assets/javascripts/pages/projects/pipeline_schedules/shared/components/interval_pattern_input.vue
index 0d05668b285..ef53d67e7cb 100644
--- a/app/assets/javascripts/pages/projects/pipeline_schedules/shared/components/interval_pattern_input.vue
+++ b/app/assets/javascripts/pages/projects/pipeline_schedules/shared/components/interval_pattern_input.vue
@@ -147,8 +147,8 @@
<div class="cron-interval-input-wrapper">
<input
id="schedule_cron"
- :placeholder="__('Define a custom pattern with cron syntax')"
v-model="cronInterval"
+ :placeholder="__('Define a custom pattern with cron syntax')"
:name="inputNameAttribute"
:disabled="!isEditable"
class="form-control inline cron-interval-input"
diff --git a/app/assets/javascripts/pages/projects/shared/permissions/components/settings_panel.vue b/app/assets/javascripts/pages/projects/shared/permissions/components/settings_panel.vue
index ae88b765abf..875f6928bed 100644
--- a/app/assets/javascripts/pages/projects/shared/permissions/components/settings_panel.vue
+++ b/app/assets/javascripts/pages/projects/shared/permissions/components/settings_panel.vue
@@ -240,8 +240,8 @@
help-text="Lightweight issue tracking system for this project"
>
<project-feature-setting
- :options="featureAccessLevelOptions"
v-model="issuesAccessLevel"
+ :options="featureAccessLevelOptions"
name="project[project_feature_attributes][issues_access_level]"
/>
</project-setting-row>
@@ -250,8 +250,8 @@
help-text="View and edit files in this project"
>
<project-feature-setting
- :options="featureAccessLevelOptions"
v-model="repositoryAccessLevel"
+ :options="featureAccessLevelOptions"
name="project[project_feature_attributes][repository_access_level]"
/>
</project-setting-row>
@@ -261,8 +261,8 @@
help-text="Submit changes to be merged upstream"
>
<project-feature-setting
- :options="repoFeatureAccessLevelOptions"
v-model="mergeRequestsAccessLevel"
+ :options="repoFeatureAccessLevelOptions"
:disabled-input="!repositoryEnabled"
name="project[project_feature_attributes][merge_requests_access_level]"
/>
@@ -272,8 +272,8 @@
help-text="Build, test, and deploy your changes"
>
<project-feature-setting
- :options="repoFeatureAccessLevelOptions"
v-model="buildsAccessLevel"
+ :options="repoFeatureAccessLevelOptions"
:disabled-input="!repositoryEnabled"
name="project[project_feature_attributes][builds_access_level]"
/>
@@ -308,8 +308,8 @@
help-text="Pages for project documentation"
>
<project-feature-setting
- :options="featureAccessLevelOptions"
v-model="wikiAccessLevel"
+ :options="featureAccessLevelOptions"
name="project[project_feature_attributes][wiki_access_level]"
/>
</project-setting-row>
@@ -318,8 +318,8 @@
help-text="Share code pastes with others out of Git repository"
>
<project-feature-setting
- :options="featureAccessLevelOptions"
v-model="snippetsAccessLevel"
+ :options="featureAccessLevelOptions"
name="project[project_feature_attributes][snippets_access_level]"
/>
</project-setting-row>
diff --git a/app/assets/javascripts/pages/projects/show/index.js b/app/assets/javascripts/pages/projects/show/index.js
index 0507f67843f..7302c1ab202 100644
--- a/app/assets/javascripts/pages/projects/show/index.js
+++ b/app/assets/javascripts/pages/projects/show/index.js
@@ -1,6 +1,6 @@
import $ from 'jquery';
import initBlob from '~/blob_edit/blob_bundle';
-import ShortcutsNavigation from '~/shortcuts_navigation';
+import ShortcutsNavigation from '~/behaviors/shortcuts/shortcuts_navigation';
import NotificationsForm from '~/notifications_form';
import UserCallout from '~/user_callout';
import TreeView from '~/tree';
diff --git a/app/assets/javascripts/pages/projects/tree/show/index.js b/app/assets/javascripts/pages/projects/tree/show/index.js
index 33d69d891d8..400aed35e32 100644
--- a/app/assets/javascripts/pages/projects/tree/show/index.js
+++ b/app/assets/javascripts/pages/projects/tree/show/index.js
@@ -4,7 +4,7 @@ import initBlob from '~/blob_edit/blob_bundle';
import commitPipelineStatus from '~/projects/tree/components/commit_pipeline_status_component.vue';
import GpgBadges from '~/gpg_badges';
import TreeView from '../../../../tree';
-import ShortcutsNavigation from '../../../../shortcuts_navigation';
+import ShortcutsNavigation from '../../../../behaviors/shortcuts/shortcuts_navigation';
import BlobViewer from '../../../../blob/viewer';
import NewCommitForm from '../../../../new_commit_form';
import { ajaxGet } from '../../../../lib/utils/common_utils';
diff --git a/app/assets/javascripts/pages/projects/wikis/index.js b/app/assets/javascripts/pages/projects/wikis/index.js
index b0a323a71cd..c2629090f01 100644
--- a/app/assets/javascripts/pages/projects/wikis/index.js
+++ b/app/assets/javascripts/pages/projects/wikis/index.js
@@ -2,8 +2,8 @@ import $ from 'jquery';
import Vue from 'vue';
import Translate from '~/vue_shared/translate';
import csrf from '~/lib/utils/csrf';
+import ShortcutsWiki from '~/behaviors/shortcuts/shortcuts_wiki';
import Wikis from './wikis';
-import ShortcutsWiki from '../../../shortcuts_wiki';
import ZenMode from '../../../zen_mode';
import GLForm from '../../../gl_form';
import deleteWikiModal from './components/delete_wiki_modal.vue';
diff --git a/app/assets/javascripts/performance_bar/components/performance_bar_app.vue b/app/assets/javascripts/performance_bar/components/performance_bar_app.vue
index 0fdb0a080cf..1522e2227e4 100644
--- a/app/assets/javascripts/performance_bar/components/performance_bar_app.vue
+++ b/app/assets/javascripts/performance_bar/components/performance_bar_app.vue
@@ -42,7 +42,7 @@ export default {
keys: ['feature', 'request'],
},
],
- simpleMetrics: ['redis', 'sidekiq'],
+ simpleMetrics: ['redis'],
data() {
return { currentRequestId: '' };
},
@@ -130,8 +130,8 @@ export default {
</div>
<simple-metric
v-for="metric in $options.simpleMetrics"
- :current-request="currentRequest"
:key="metric"
+ :current-request="currentRequest"
:metric="metric"
/>
<div
diff --git a/app/assets/javascripts/performance_bar/components/simple_metric.vue b/app/assets/javascripts/performance_bar/components/simple_metric.vue
index b654bc66249..760ea8fe1e6 100644
--- a/app/assets/javascripts/performance_bar/components/simple_metric.vue
+++ b/app/assets/javascripts/performance_bar/components/simple_metric.vue
@@ -1,16 +1,29 @@
<script>
-export default {
- props: {
- currentRequest: {
- type: Object,
- required: true,
+ export default {
+ props: {
+ currentRequest: {
+ type: Object,
+ required: true,
+ },
+ metric: {
+ type: String,
+ required: true,
+ },
},
- metric: {
- type: String,
- required: true,
+ computed: {
+ duration() {
+ return (
+ this.currentRequest.details[this.metric] &&
+ this.currentRequest.details[this.metric].duration
+ );
+ },
+ calls() {
+ return (
+ this.currentRequest.details[this.metric] && this.currentRequest.details[this.metric].calls
+ );
+ },
},
- },
-};
+ };
</script>
<template>
<div
@@ -21,9 +34,9 @@ export default {
v-if="currentRequest.details"
class="bold"
>
- {{ currentRequest.details[metric].duration }}
+ {{ duration }}
/
- {{ currentRequest.details[metric].calls }}
+ {{ calls }}
</span>
{{ metric }}
</div>
diff --git a/app/assets/javascripts/pipelines/components/graph/graph_component.vue b/app/assets/javascripts/pipelines/components/graph/graph_component.vue
index e27f195c9b0..9b4ba0c1a9a 100644
--- a/app/assets/javascripts/pipelines/components/graph/graph_component.vue
+++ b/app/assets/javascripts/pipelines/components/graph/graph_component.vue
@@ -68,9 +68,9 @@ export default {
class="stage-column-list">
<stage-column-component
v-for="(stage, index) in graph"
+ :key="stage.name"
:title="capitalizeStageName(stage.name)"
:jobs="stage.groups"
- :key="stage.name"
:stage-connector-class="stageConnectorClass(index, stage)"
:is-first-column="isFirstColumn(index)"
@refreshPipelineGraph="refreshPipelineGraph"
diff --git a/app/assets/javascripts/pipelines/components/graph/job_component.vue b/app/assets/javascripts/pipelines/components/graph/job_component.vue
index 9ac16b7e541..a1504592bbc 100644
--- a/app/assets/javascripts/pipelines/components/graph/job_component.vue
+++ b/app/assets/javascripts/pipelines/components/graph/job_component.vue
@@ -98,8 +98,8 @@ export default {
<template>
<div class="ci-job-component">
<a
- v-tooltip
v-if="status.has_details"
+ v-tooltip
:href="status.details_path"
:title="tooltipText"
:class="cssClassJobName"
@@ -115,8 +115,8 @@ export default {
</a>
<div
- v-tooltip
v-else
+ v-tooltip
:title="tooltipText"
:class="cssClassJobName"
class="js-job-component-tooltip non-details-job-component"
diff --git a/app/assets/javascripts/pipelines/components/graph/stage_column_component.vue b/app/assets/javascripts/pipelines/components/graph/stage_column_component.vue
index e7b2de52f76..567ea119343 100644
--- a/app/assets/javascripts/pipelines/components/graph/stage_column_component.vue
+++ b/app/assets/javascripts/pipelines/components/graph/stage_column_component.vue
@@ -62,9 +62,9 @@ export default {
<ul>
<li
v-for="(job, index) in jobs"
+ :id="jobId(job)"
:key="job.id"
:class="buildConnnectorClass(index)"
- :id="jobId(job)"
class="build"
>
diff --git a/app/assets/javascripts/pipelines/components/nav_controls.vue b/app/assets/javascripts/pipelines/components/nav_controls.vue
index 9501afb7493..efb80d3a3c0 100644
--- a/app/assets/javascripts/pipelines/components/nav_controls.vue
+++ b/app/assets/javascripts/pipelines/components/nav_controls.vue
@@ -43,7 +43,7 @@ export default {
<a
v-if="newPipelinePath"
:href="newPipelinePath"
- class="btn btn-create js-run-pipeline"
+ class="btn btn-success js-run-pipeline"
>
{{ s__('Pipelines|Run Pipeline') }}
</a>
diff --git a/app/assets/javascripts/pipelines/components/pipeline_url.vue b/app/assets/javascripts/pipelines/components/pipeline_url.vue
index 75db1e9ae7c..40df07650c9 100644
--- a/app/assets/javascripts/pipelines/components/pipeline_url.vue
+++ b/app/assets/javascripts/pipelines/components/pipeline_url.vue
@@ -67,29 +67,29 @@ export default {
</span>
<div class="label-container">
<span
- v-tooltip
v-if="pipeline.flags.latest"
+ v-tooltip
class="js-pipeline-url-latest badge badge-success"
title="Latest pipeline for this branch">
latest
</span>
<span
- v-tooltip
v-if="pipeline.flags.yaml_errors"
+ v-tooltip
:title="pipeline.yaml_errors"
class="js-pipeline-url-yaml badge badge-danger">
yaml invalid
</span>
<span
- v-tooltip
v-if="pipeline.flags.failure_reason"
+ v-tooltip
:title="pipeline.failure_reason"
class="js-pipeline-url-failure badge badge-danger">
error
</span>
<a
- v-popover="popoverOptions"
v-if="pipeline.flags.auto_devops"
+ v-popover="popoverOptions"
tabindex="0"
class="js-pipeline-url-autodevops badge badge-info autodevops-badge"
role="button">
diff --git a/app/assets/javascripts/pipelines/components/stage.vue b/app/assets/javascripts/pipelines/components/stage.vue
index 3e13bad9a0b..47c15b1a9c4 100644
--- a/app/assets/javascripts/pipelines/components/stage.vue
+++ b/app/assets/javascripts/pipelines/components/stage.vue
@@ -155,9 +155,9 @@ export default {
<template>
<div class="dropdown">
<button
- v-tooltip
id="stageDropdown"
ref="dropdown"
+ v-tooltip
:class="triggerButtonClass"
:title="stage.title"
class="mini-pipeline-graph-dropdown-toggle js-builds-dropdown-button"
diff --git a/app/assets/javascripts/registry/components/collapsible_container.vue b/app/assets/javascripts/registry/components/collapsible_container.vue
index d4c4d779d44..d9bf41924d1 100644
--- a/app/assets/javascripts/registry/components/collapsible_container.vue
+++ b/app/assets/javascripts/registry/components/collapsible_container.vue
@@ -88,8 +88,8 @@
<div class="controls d-none d-sm-block float-right">
<button
- v-tooltip
v-if="repo.canDelete"
+ v-tooltip
:title="s__('ContainerRegistry|Remove repository')"
:aria-label="s__('ContainerRegistry|Remove repository')"
type="button"
diff --git a/app/assets/javascripts/registry/components/table_registry.vue b/app/assets/javascripts/registry/components/table_registry.vue
index 9f4973c3490..fafb35bd69a 100644
--- a/app/assets/javascripts/registry/components/table_registry.vue
+++ b/app/assets/javascripts/registry/components/table_registry.vue
@@ -118,8 +118,8 @@
<td class="content">
<button
- v-tooltip
v-if="item.canDelete"
+ v-tooltip
:title="s__('ContainerRegistry|Remove tag')"
:aria-label="s__('ContainerRegistry|Remove tag')"
type="button"
diff --git a/app/assets/javascripts/reports/components/grouped_test_reports_app.vue b/app/assets/javascripts/reports/components/grouped_test_reports_app.vue
index 7b37f4e9a97..fb8c6402d02 100644
--- a/app/assets/javascripts/reports/components/grouped_test_reports_app.vue
+++ b/app/assets/javascripts/reports/components/grouped_test_reports_app.vue
@@ -92,16 +92,16 @@
v-for="(report, i) in reports"
>
<summary-row
+ :key="`summary-row-${i}`"
:summary="reportText(report)"
:status-icon="getReportIcon(report)"
- :key="`summary-row-${i}`"
/>
<issues-list
v-if="shouldRenderIssuesList(report)"
+ :key="`issues-list-${i}`"
:unresolved-issues="report.existing_failures"
:new-issues="report.new_failures"
:resolved-issues="report.resolved_failures"
- :key="`issues-list-${i}`"
:component="$options.componentNames.TestIssueBody"
class="report-block-group-list"
/>
diff --git a/app/assets/javascripts/reports/components/report_issues.vue b/app/assets/javascripts/reports/components/report_issues.vue
index c553a374f66..a2a03945ae3 100644
--- a/app/assets/javascripts/reports/components/report_issues.vue
+++ b/app/assets/javascripts/reports/components/report_issues.vue
@@ -37,8 +37,8 @@ export default {
<ul class="report-block-list">
<li
v-for="(issue, index) in issues"
- :class="{ 'is-dismissed': issue.isDismissed }"
:key="index"
+ :class="{ 'is-dismissed': issue.isDismissed }"
class="report-block-list-issue"
>
<issue-status-icon
@@ -47,8 +47,8 @@ export default {
/>
<component
- v-if="component"
:is="component"
+ v-if="component"
:issue="issue"
:status="issue.status || status"
:is-new="isNew"
diff --git a/app/assets/javascripts/search_autocomplete.js b/app/assets/javascripts/search_autocomplete.js
index aec09b8bc0a..50dd3c12382 100644
--- a/app/assets/javascripts/search_autocomplete.js
+++ b/app/assets/javascripts/search_autocomplete.js
@@ -68,7 +68,7 @@ function setSearchOptions() {
}
}
-export default class SearchAutocomplete {
+export class SearchAutocomplete {
constructor({ wrap, optsEl, autocompletePath, projectId, projectRef } = {}) {
setSearchOptions();
this.bindEventContext();
@@ -499,3 +499,7 @@ export default class SearchAutocomplete {
this.dropdownMenu.toggleClass('fade-out', !this.isScrolledUp());
}
}
+
+export default function initSearchAutocomplete(opts) {
+ return new SearchAutocomplete(opts);
+}
diff --git a/app/assets/javascripts/sidebar/components/time_tracking/time_tracker.vue b/app/assets/javascripts/sidebar/components/time_tracking/time_tracker.vue
index ca3b9338c29..2ee3e1f322e 100644
--- a/app/assets/javascripts/sidebar/components/time_tracking/time_tracker.vue
+++ b/app/assets/javascripts/sidebar/components/time_tracking/time_tracker.vue
@@ -19,19 +19,23 @@ export default {
TimeTrackingHelpState,
},
props: {
+ // eslint-disable-next-line vue/prop-name-casing
time_estimate: {
type: Number,
required: true,
},
+ // eslint-disable-next-line vue/prop-name-casing
time_spent: {
type: Number,
required: true,
},
+ // eslint-disable-next-line vue/prop-name-casing
human_time_estimate: {
type: String,
required: false,
default: '',
},
+ // eslint-disable-next-line vue/prop-name-casing
human_time_spent: {
type: String,
required: false,
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 d530ab2767b..70518ad73e8 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/deployment.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/deployment.vue
@@ -106,8 +106,8 @@ export default {
</tooltip-on-truncate>
</template>
<span
- v-tooltip
v-if="hasDeploymentTime"
+ v-tooltip
:title="deployment.deployed_at_formatted"
class="js-deploy-time"
>
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 4c3f8dff3c4..acfdab3a015 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
@@ -28,11 +28,17 @@ export default {
return this.mr.divergedCommitsCount > 0;
},
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);
+ 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
@@ -45,17 +51,24 @@ export default {
},
webIdePath() {
if (this.mr.canPushToSourceBranch) {
- return mergeUrlParams({
- target_project: this.mr.sourceProjectFullPath !== this.mr.targetProjectFullPath ?
- this.mr.targetProjectFullPath : '',
- }, webIDEUrl(`/${this.mr.sourceProjectFullPath}/merge_requests/${this.mr.iid}`));
+ return mergeUrlParams(
+ {
+ target_project:
+ this.mr.sourceProjectFullPath !== this.mr.targetProjectFullPath
+ ? this.mr.targetProjectFullPath
+ : '',
+ },
+ webIDEUrl(`/${this.mr.sourceProjectFullPath}/merge_requests/${this.mr.iid}`),
+ );
}
return null;
},
ideButtonTitle() {
return !this.mr.canPushToSourceBranch
- ? s__('mrWidget|You are not allowed to edit this project directly. Please fork to make changes.')
+ ? s__(
+ 'mrWidget|You are not allowed to edit this project directly. Please fork to make changes.',
+ )
: '';
},
},
@@ -104,37 +117,34 @@ export default {
<div
v-if="mr.isOpen"
- class="branch-actions"
+ class="branch-actions d-flex"
>
- <span
+ <a
+ v-if="!mr.sourceBranchRemoved"
v-tooltip
+ :href="webIdePath"
:title="ideButtonTitle"
+ :class="{ disabled: !mr.canPushToSourceBranch }"
+ class="btn btn-default js-web-ide d-none d-md-inline-block append-right-8"
data-placement="bottom"
tabindex="0"
+ role="button"
>
- <a
- v-if="!mr.sourceBranchRemoved"
- :href="webIdePath"
- :class="{ disabled: !mr.canPushToSourceBranch }"
- class="btn btn-default inline js-web-ide d-none d-md-inline-block"
- role="button"
- >
- {{ s__("mrWidget|Open in Web IDE") }}
- </a>
- </span>
+ {{ s__("mrWidget|Open in Web IDE") }}
+ </a>
<button
:disabled="mr.sourceBranchRemoved"
data-target="#modal_merge_info"
data-toggle="modal"
- class="btn btn-default inline js-check-out-branch"
+ class="btn btn-default js-check-out-branch append-right-default"
type="button"
>
{{ s__("mrWidget|Check out branch") }}
</button>
- <span class="dropdown prepend-left-10">
+ <span class="dropdown">
<button
type="button"
- class="btn inline dropdown-toggle"
+ class="btn dropdown-toggle"
data-toggle="dropdown"
aria-label="Download as"
aria-haspopup="true"
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merged.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merged.vue
index 2f2394371ef..8184ef33022 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merged.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merged.vue
@@ -114,8 +114,8 @@
:date-readable="mr.metrics.readableMergedAt"
/>
<a
- v-tooltip
v-if="mr.canRevertInCurrentMR"
+ v-tooltip
:title="revertTitle"
class="btn btn-close btn-sm"
href="#modal-revert-commit"
@@ -125,8 +125,8 @@
{{ revertLabel }}
</a>
<a
- v-tooltip
v-else-if="mr.revertInForkPath"
+ v-tooltip
:href="mr.revertInForkPath"
:title="revertTitle"
class="btn btn-close btn-sm"
@@ -135,8 +135,8 @@
{{ revertLabel }}
</a>
<a
- v-tooltip
v-if="mr.canCherryPickInCurrentMR"
+ v-tooltip
:title="cherryPickTitle"
class="btn btn-default btn-sm"
href="#modal-cherry-pick-commit"
@@ -146,8 +146,8 @@
{{ cherryPickLabel }}
</a>
<a
- v-tooltip
v-else-if="mr.cherryPickInForkPath"
+ v-tooltip
:href="mr.cherryPickInForkPath"
:title="cherryPickTitle"
class="btn btn-default btn-sm"
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_squash_before_merge.js b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_squash_before_merge.js
deleted file mode 100644
index bf8628d18a6..00000000000
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_squash_before_merge.js
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
-The squash-before-merge button is EE only, but it's located right in the middle
-of the readyToMerge state component template.
-
-If we didn't declare this component in CE, we'd need to maintain a separate copy
-of the readyToMergeState template in EE, which is pretty big and likely to change.
-
-Instead, in CE, we declare the component, but it's hidden and is configured to do nothing.
-In EE, the configuration extends this object to add a functioning squash-before-merge
-button.
-*/
-
-export default {
- template: '',
-};
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/nothing_to_merge.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/nothing_to_merge.vue
index 086dbabe77e..e73b7e410d5 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/nothing_to_merge.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/nothing_to_merge.vue
@@ -37,7 +37,7 @@ export default {
<a
v-if="mr.newBlobPath"
:href="mr.newBlobPath"
- class="btn btn-inverted btn-save">
+ class="btn btn-inverted btn-success">
Create file
</a>
</div>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue
index a5ca7b719a1..c8ad2aa30a6 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue
@@ -6,7 +6,7 @@ import MergeRequest from '../../../merge_request';
import Flash from '../../../flash';
import statusIcon from '../mr_widget_status_icon.vue';
import eventHub from '../../event_hub';
-import SquashBeforeMerge from './mr_widget_squash_before_merge.vue';
+import SquashBeforeMerge from './squash_before_merge.vue';
export default {
name: 'ReadyToMerge',
@@ -255,7 +255,7 @@ export default {
data-toggle="dropdown"
aria-label="Select merge moment">
<i
- class="fa fa-chevron-down"
+ class="fa fa-chevron-down qa-merge-moment-dropdown"
aria-hidden="true"
></i>
</button>
@@ -265,7 +265,7 @@ export default {
role="menu">
<li>
<a
- class="merge_when_pipeline_succeeds"
+ class="merge_when_pipeline_succeeds qa-merge-when-pipeline-succeeds-option"
href="#"
@click.prevent="handleMergeButtonClick(true)">
<span class="media">
@@ -279,7 +279,7 @@ export default {
</li>
<li>
<a
- class="accept-merge-request"
+ class="accept-merge-request qa-merge-immediately-option"
href="#"
@click.prevent="handleMergeButtonClick(false, true)">
<span class="media">
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_squash_before_merge.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/squash_before_merge.vue
index 25c1044fe2b..25ad329e196 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_squash_before_merge.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/squash_before_merge.vue
@@ -37,8 +37,8 @@ export default {
<div class="accept-control inline">
<label class="merge-param-checkbox">
<input
- :disabled="isMergeButtonDisabled"
v-model="squashBeforeMerge"
+ :disabled="isMergeButtonDisabled"
type="checkbox"
name="squash"
class="qa-squash-checkbox"
diff --git a/app/assets/javascripts/vue_merge_request_widget/dependencies.js b/app/assets/javascripts/vue_merge_request_widget/dependencies.js
index 15097fa2a3f..a23496c6bf5 100644
--- a/app/assets/javascripts/vue_merge_request_widget/dependencies.js
+++ b/app/assets/javascripts/vue_merge_request_widget/dependencies.js
@@ -40,7 +40,7 @@ export { default as MRWidgetService } from './services/mr_widget_service';
export { default as eventHub } from './event_hub';
export { default as getStateKey } from './stores/get_state_key';
export { default as stateMaps } from './stores/state_maps';
-export { default as SquashBeforeMerge } from './components/states/mr_widget_squash_before_merge.vue';
+export { default as SquashBeforeMerge } from './components/states/squash_before_merge.vue';
export { default as notify } from '../lib/utils/notify';
export { default as SourceBranchRemovalStatus } from './components/source_branch_removal_status.vue';
diff --git a/app/assets/javascripts/vue_merge_request_widget/index.js b/app/assets/javascripts/vue_merge_request_widget/index.js
index 69a9132a2da..cc6e620f365 100644
--- a/app/assets/javascripts/vue_merge_request_widget/index.js
+++ b/app/assets/javascripts/vue_merge_request_widget/index.js
@@ -1,7 +1,4 @@
-import {
- Vue,
- mrWidgetOptions,
-} from './dependencies';
+import { Vue, mrWidgetOptions } from './dependencies';
import Translate from '../vue_shared/translate';
Vue.use(Translate);
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 dc6be025f11..0e445a29de4 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
@@ -107,10 +107,16 @@ export default {
created() {
this.initPolling();
this.bindEventHubListeners();
+ eventHub.$on('mr.discussion.updated', this.checkStatus);
},
mounted() {
this.handleMounted();
},
+ beforeDestroy() {
+ eventHub.$off('mr.discussion.updated', this.checkStatus);
+ this.pollingInterval.destroy();
+ this.deploymentsInterval.destroy();
+ },
methods: {
createService(store) {
const endpoints = {
diff --git a/app/assets/javascripts/vue_shared/components/bar_chart.vue b/app/assets/javascripts/vue_shared/components/bar_chart.vue
index 3ced4eb691a..33af7a7f1df 100644
--- a/app/assets/javascripts/vue_shared/components/bar_chart.vue
+++ b/app/assets/javascripts/vue_shared/components/bar_chart.vue
@@ -291,8 +291,8 @@ export default {
<template
v-for="(data, index) in graphData">
<rect
- v-tooltip
:key="index"
+ v-tooltip
:width="xScale.bandwidth()"
:x="xScale(data.name)"
:y="yScale(data.value)"
diff --git a/app/assets/javascripts/vue_shared/components/content_viewer/viewers/markdown_viewer.vue b/app/assets/javascripts/vue_shared/components/content_viewer/viewers/markdown_viewer.vue
index a10deb93f0f..807e049caf6 100644
--- a/app/assets/javascripts/vue_shared/components/content_viewer/viewers/markdown_viewer.vue
+++ b/app/assets/javascripts/vue_shared/components/content_viewer/viewers/markdown_viewer.vue
@@ -2,14 +2,14 @@
import axios from '~/lib/utils/axios_utils';
import { __ } from '~/locale';
import $ from 'jquery';
-import SkeletonLoadingContainer from '~/vue_shared/components/skeleton_loading_container.vue';
+import { SkeletonLoading } from '@gitlab-org/gitlab-ui';
const { CancelToken } = axios;
let axiosSource;
export default {
components: {
- SkeletonLoadingContainer,
+ SkeletonLoading,
},
props: {
content: {
@@ -81,7 +81,7 @@ export default {
<div
ref="markdown-preview"
class="md md-previewer">
- <skeleton-loading-container v-if="isLoading" />
+ <skeleton-loading v-if="isLoading" />
<div
v-else
v-html="previewContent">
diff --git a/app/assets/javascripts/vue_shared/components/diff_viewer/diff_viewer.vue b/app/assets/javascripts/vue_shared/components/diff_viewer/diff_viewer.vue
index d3cbe3c7e74..cfc5343217c 100644
--- a/app/assets/javascripts/vue_shared/components/diff_viewer/diff_viewer.vue
+++ b/app/assets/javascripts/vue_shared/components/diff_viewer/diff_viewer.vue
@@ -46,7 +46,7 @@ export default {
}
},
basePath() {
- // We might get the project path from rails with the relative url already setup
+ // We might get the project path from rails with the relative url already set up
return this.projectPath.indexOf('/') === 0 ? '' : `${gon.relative_url_root}/`;
},
fullOldPath() {
diff --git a/app/assets/javascripts/vue_shared/components/file_row.vue b/app/assets/javascripts/vue_shared/components/file_row.vue
new file mode 100644
index 00000000000..c797ad62a5d
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/file_row.vue
@@ -0,0 +1,210 @@
+<script>
+import Icon from '~/vue_shared/components/icon.vue';
+import FileIcon from '~/vue_shared/components/file_icon.vue';
+
+export default {
+ name: 'FileRow',
+ components: {
+ FileIcon,
+ Icon,
+ },
+ props: {
+ file: {
+ type: Object,
+ required: true,
+ },
+ level: {
+ type: Number,
+ required: true,
+ },
+ extraComponent: {
+ type: Object,
+ required: false,
+ default: null,
+ },
+ },
+ data() {
+ return {
+ mouseOver: false,
+ };
+ },
+ computed: {
+ isTree() {
+ return this.file.type === 'tree';
+ },
+ isBlob() {
+ return this.file.type === 'blob';
+ },
+ levelIndentation() {
+ return {
+ marginLeft: `${this.level * 16}px`,
+ };
+ },
+ fileClass() {
+ return {
+ 'file-open': this.isBlob && this.file.opened,
+ 'is-active': this.isBlob && this.file.active,
+ folder: this.isTree,
+ 'is-open': this.file.opened,
+ };
+ },
+ },
+ watch: {
+ 'file.active': function fileActiveWatch(active) {
+ if (this.file.type === 'blob' && active) {
+ this.scrollIntoView();
+ }
+ },
+ },
+ mounted() {
+ if (this.hasPathAtCurrentRoute()) {
+ this.scrollIntoView(true);
+ }
+ },
+ methods: {
+ toggleTreeOpen(path) {
+ this.$emit('toggleTreeOpen', path);
+ },
+ clickFile() {
+ // Manual Action if a tree is selected/opened
+ if (this.isTree && this.hasUrlAtCurrentRoute()) {
+ this.toggleTreeOpen(this.file.path);
+ }
+
+ if (this.$router) this.$router.push(`/project${this.file.url}`);
+ },
+ scrollIntoView(isInit = false) {
+ const block = isInit && this.isTree ? 'center' : 'nearest';
+
+ this.$el.scrollIntoView({
+ behavior: 'smooth',
+ block,
+ });
+ },
+ hasPathAtCurrentRoute() {
+ if (!this.$router || !this.$router.currentRoute) {
+ return false;
+ }
+
+ // - strip route up to "/-/" and ending "/"
+ const routePath = this.$router.currentRoute.path
+ .replace(/^.*?[/]-[/]/g, '')
+ .replace(/[/]$/g, '');
+
+ // - strip ending "/"
+ const filePath = this.file.path.replace(/[/]$/g, '');
+
+ return filePath === routePath;
+ },
+ hasUrlAtCurrentRoute() {
+ if (!this.$router || !this.$router.currentRoute) return true;
+
+ return this.$router.currentRoute.path === `/project${this.file.url}`;
+ },
+ toggleHover(over) {
+ this.mouseOver = over;
+ },
+ },
+};
+</script>
+
+<template>
+ <div>
+ <div
+ :class="fileClass"
+ class="file-row"
+ role="button"
+ @click="clickFile"
+ @mouseover="toggleHover(true)"
+ @mouseout="toggleHover(false)"
+ >
+ <div
+ class="file-row-name-container"
+ >
+ <span
+ :style="levelIndentation"
+ class="file-row-name str-truncated"
+ >
+ <file-icon
+ :file-name="file.name"
+ :loading="file.loading"
+ :folder="isTree"
+ :opened="file.opened"
+ :size="16"
+ />
+ {{ file.name }}
+ </span>
+ <component
+ :is="extraComponent"
+ v-if="extraComponent"
+ :file="file"
+ :mouse-over="mouseOver"
+ />
+ </div>
+ </div>
+ <template v-if="file.opened">
+ <file-row
+ v-for="childFile in file.tree"
+ :key="childFile.key"
+ :file="childFile"
+ :level="level + 1"
+ :extra-component="extraComponent"
+ @toggleTreeOpen="toggleTreeOpen"
+ />
+ </template>
+ </div>
+</template>
+
+<style>
+.file-row {
+ display: flex;
+ align-items: center;
+ height: 32px;
+ padding: 4px 8px;
+ margin-left: -8px;
+ margin-right: -8px;
+ border-radius: 3px;
+ text-align: left;
+ cursor: pointer;
+}
+
+.file-row:hover,
+.file-row:focus {
+ background: #f2f2f2;
+}
+
+.file-row:active {
+ background: #dfdfdf;
+}
+
+.file-row.is-active {
+ background: #f2f2f2;
+}
+
+.file-row-name-container {
+ display: flex;
+ width: 100%;
+ align-items: center;
+ overflow: visible;
+}
+
+.file-row-name {
+ display: inline-block;
+ flex: 1;
+ max-width: inherit;
+ height: 18px;
+ line-height: 16px;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.file-row-name svg {
+ margin-right: 2px;
+ vertical-align: middle;
+}
+
+.file-row-name .loading-container {
+ display: inline-block;
+ margin-right: 4px;
+}
+</style>
diff --git a/app/assets/javascripts/vue_shared/components/header_ci_component.vue b/app/assets/javascripts/vue_shared/components/header_ci_component.vue
index 18f5ce53bb1..b371b6adf7e 100644
--- a/app/assets/javascripts/vue_shared/components/header_ci_component.vue
+++ b/app/assets/javascripts/vue_shared/components/header_ci_component.vue
@@ -126,18 +126,18 @@ export default {
>
<a
v-if="action.type === 'link'"
+ :key="i"
:href="action.path"
:class="action.cssClass"
- :key="i"
>
{{ action.label }}
</a>
<a
v-else-if="action.type === 'ujs-link'"
+ :key="i"
:href="action.path"
:class="action.cssClass"
- :key="i"
data-method="post"
rel="nofollow"
>
@@ -146,9 +146,9 @@ export default {
<button
v-else-if="action.type === 'button'"
+ :key="i"
:disabled="action.isLoading"
:class="action.cssClass"
- :key="i"
type="button"
@click="onClickAction(action)"
>
diff --git a/app/assets/javascripts/vue_shared/components/markdown/toolbar.vue b/app/assets/javascripts/vue_shared/components/markdown/toolbar.vue
index d63318f3da6..c45dafa9807 100644
--- a/app/assets/javascripts/vue_shared/components/markdown/toolbar.vue
+++ b/app/assets/javascripts/vue_shared/components/markdown/toolbar.vue
@@ -1,5 +1,10 @@
<script>
+ import { Link } from '@gitlab-org/gitlab-ui';
+
export default {
+ components: {
+ 'gl-link': Link,
+ },
props: {
markdownDocsPath: {
type: String,
@@ -28,30 +33,30 @@
<div class="comment-toolbar clearfix">
<div class="toolbar-text">
<template v-if="!hasQuickActionsDocsPath && markdownDocsPath">
- <a
+ <gl-link
:href="markdownDocsPath"
target="_blank"
tabindex="-1"
>
Markdown is supported
- </a>
+ </gl-link>
</template>
<template v-if="hasQuickActionsDocsPath && markdownDocsPath">
- <a
+ <gl-link
:href="markdownDocsPath"
target="_blank"
tabindex="-1"
>
Markdown
- </a>
+ </gl-link>
and
- <a
+ <gl-link
:href="quickActionsDocsPath"
target="_blank"
tabindex="-1"
>
quick actions
- </a>
+ </gl-link>
are supported
</template>
</div>
diff --git a/app/assets/javascripts/vue_shared/components/notes/skeleton_note.vue b/app/assets/javascripts/vue_shared/components/notes/skeleton_note.vue
index 2eb6c20b2c0..1d9c9220469 100644
--- a/app/assets/javascripts/vue_shared/components/notes/skeleton_note.vue
+++ b/app/assets/javascripts/vue_shared/components/notes/skeleton_note.vue
@@ -1,3 +1,14 @@
+<script>
+import { SkeletonLoading } from '@gitlab-org/gitlab-ui';
+
+export default {
+ name: 'SkeletonNote',
+ components: {
+ SkeletonLoading,
+ },
+};
+</script>
+
<template>
<li class="timeline-entry note">
<div class="timeline-entry-inner">
@@ -6,20 +17,9 @@
<div class="timeline-content">
<div class="note-header"></div>
<div class="note-body">
- <skeleton-loading-container />
+ <skeleton-loading />
</div>
</div>
</div>
</li>
</template>
-
-<script>
-import skeletonLoadingContainer from '~/vue_shared/components/skeleton_loading_container.vue';
-
-export default {
- name: 'SkeletonNote',
- components: {
- skeletonLoadingContainer,
- },
-};
-</script>
diff --git a/app/assets/javascripts/vue_shared/components/skeleton_loading_container.vue b/app/assets/javascripts/vue_shared/components/skeleton_loading_container.vue
deleted file mode 100644
index 4a5ffbe5d5a..00000000000
--- a/app/assets/javascripts/vue_shared/components/skeleton_loading_container.vue
+++ /dev/null
@@ -1,37 +0,0 @@
-<script>
- export default {
- props: {
- small: {
- type: Boolean,
- required: false,
- default: false,
- },
- lines: {
- type: Number,
- required: false,
- default: 3,
- },
- },
- computed: {
- lineClasses() {
- return new Array(this.lines).fill().map((_, i) => `skeleton-line-${i + 1}`);
- },
- },
- };
-</script>
-
-<template>
- <div
- :class="{
- 'animation-container-small': small,
- }"
- class="animation-container"
- >
- <div
- v-for="(css, index) in lineClasses"
- :key="index"
- :class="css"
- >
- </div>
- </div>
-</template>
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 78fde463507..cd3ee544344 100644
--- a/app/assets/javascripts/vue_shared/components/stacked_progress_bar.vue
+++ b/app/assets/javascripts/vue_shared/components/stacked_progress_bar.vue
@@ -99,8 +99,8 @@ export default {
{{ __("Not available") }}
</span>
<span
- v-tooltip
v-if="successPercent"
+ v-tooltip
:title="successTooltip"
:style="successBarStyle"
class="status-green"
@@ -109,8 +109,8 @@ export default {
{{ successPercent }}%
</span>
<span
- v-tooltip
v-if="neutralPercent"
+ v-tooltip
:title="neutralTooltip"
:style="neutralBarStyle"
class="status-neutral"
@@ -119,8 +119,8 @@ export default {
{{ neutralPercent }}%
</span>
<span
- v-tooltip
v-if="failurePercent"
+ v-tooltip
:title="failureTooltip"
:style="failureBarStyle"
class="status-red"
diff --git a/app/assets/javascripts/vue_shared/components/tooltip_on_truncate.vue b/app/assets/javascripts/vue_shared/components/tooltip_on_truncate.vue
index 125826da6c3..d5b58574123 100644
--- a/app/assets/javascripts/vue_shared/components/tooltip_on_truncate.vue
+++ b/app/assets/javascripts/vue_shared/components/tooltip_on_truncate.vue
@@ -51,8 +51,8 @@ export default {
<template>
<span
- v-tooltip
v-if="showTooltip"
+ v-tooltip
:title="title"
:data-placement="placement"
class="js-show-tooltip"
diff --git a/app/assets/javascripts/vue_shared/components/user_avatar/user_avatar_link.vue b/app/assets/javascripts/vue_shared/components/user_avatar/user_avatar_link.vue
index 01c36fec41a..08e102e57c3 100644
--- a/app/assets/javascripts/vue_shared/components/user_avatar/user_avatar_link.vue
+++ b/app/assets/javascripts/vue_shared/components/user_avatar/user_avatar_link.vue
@@ -94,8 +94,8 @@ export default {
:tooltip-text="avatarTooltipText"
:tooltip-placement="tooltipPlacement"
/><span
- v-tooltip
v-if="shouldShowUsername"
+ v-tooltip
:title="tooltipText"
:tooltip-placement="tooltipPlacement"
>{{ username }}</span>
diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss
index f2950308019..ffe65ce780e 100644
--- a/app/assets/stylesheets/application.scss
+++ b/app/assets/stylesheets/application.scss
@@ -5,7 +5,6 @@
*= require jquery.atwho
*= require select2
*= require_self
- *= require dropzone/basic
*= require cropper.css
*/
@@ -18,6 +17,7 @@
*/
@import "../../../node_modules/pikaday/scss/pikaday";
+@import "../../../node_modules/dropzone/dist/basic.css";
/*
* GitLab UI framework
diff --git a/app/assets/stylesheets/bootstrap_migration.scss b/app/assets/stylesheets/bootstrap_migration.scss
index c91f5e279ea..af73954bd2e 100644
--- a/app/assets/stylesheets/bootstrap_migration.scss
+++ b/app/assets/stylesheets/bootstrap_migration.scss
@@ -93,7 +93,6 @@ hr {
}
.form-group.row .col-form-label {
- padding-top: 0;
// Bootstrap 4 aligns labels to the left
// for horizontal forms
@include media-breakpoint-up(md) {
diff --git a/app/assets/stylesheets/framework/buttons.scss b/app/assets/stylesheets/framework/buttons.scss
index ab62ca07573..686ce0c63a4 100644
--- a/app/assets/stylesheets/framework/buttons.scss
+++ b/app/assets/stylesheets/framework/buttons.scss
@@ -147,18 +147,12 @@
}
&.btn-success,
- &.btn-new,
- &.btn-create,
- &.btn-save,
&.btn-register {
@include btn-green;
}
&.btn-inverted {
- &.btn-success,
- &.btn-new,
- &.btn-create,
- &.btn-save {
+ &.btn-success {
@include btn-outline($white-light, $green-600, $green-500, $green-500, $white-light, $green-600, $green-600, $green-700);
}
diff --git a/app/assets/stylesheets/framework/common.scss b/app/assets/stylesheets/framework/common.scss
index 28dda65091d..3c9505a21d6 100644
--- a/app/assets/stylesheets/framework/common.scss
+++ b/app/assets/stylesheets/framework/common.scss
@@ -324,6 +324,16 @@ img.emoji {
word-wrap: break-word;
}
+.checkbox-icon-inline-wrapper {
+ .checkbox {
+ display: inline;
+
+ label {
+ display: inline;
+ }
+ }
+}
+
/** COMMON CLASSES **/
.prepend-top-0 { margin-top: 0; }
.prepend-top-2 { margin-top: 2px; }
diff --git a/app/assets/stylesheets/framework/filters.scss b/app/assets/stylesheets/framework/filters.scss
index e9b074236cc..d5693a5d1a1 100644
--- a/app/assets/stylesheets/framework/filters.scss
+++ b/app/assets/stylesheets/framework/filters.scss
@@ -389,9 +389,8 @@
.btn {
text-overflow: ellipsis;
- .fa {
- width: 15px;
- line-height: $line-height-base;
+ svg {
+ margin-right: $gl-padding-8;
}
.dropdown-label-box {
diff --git a/app/assets/stylesheets/framework/lists.scss b/app/assets/stylesheets/framework/lists.scss
index fdc0454d837..d9d4a210f5f 100644
--- a/app/assets/stylesheets/framework/lists.scss
+++ b/app/assets/stylesheets/framework/lists.scss
@@ -111,6 +111,7 @@ ul.content-list {
border-color: $white-normal;
font-size: $gl-font-size;
color: $gl-text-color;
+ word-break: break-word;
&.no-description {
.title {
diff --git a/app/assets/stylesheets/framework/responsive_tables.scss b/app/assets/stylesheets/framework/responsive_tables.scss
index 764bebd82c6..29a9c076cdf 100644
--- a/app/assets/stylesheets/framework/responsive_tables.scss
+++ b/app/assets/stylesheets/framework/responsive_tables.scss
@@ -39,7 +39,7 @@
.table-section {
white-space: nowrap;
- $section-widths: 10 15 20 25 30 40 50 100;
+ $section-widths: 5 10 15 20 25 30 40 50 60 100;
@each $width in $section-widths {
&.section-#{$width} {
flex: 0 0 #{$width + '%'};
diff --git a/app/assets/stylesheets/framework/snippets.scss b/app/assets/stylesheets/framework/snippets.scss
index 7152ef9bcfd..36ab38f1c9d 100644
--- a/app/assets/stylesheets/framework/snippets.scss
+++ b/app/assets/stylesheets/framework/snippets.scss
@@ -45,7 +45,7 @@
}
}
-.snippet-scope-menu .btn-new {
+.snippet-scope-menu .btn-success {
margin-top: 15px;
}
diff --git a/app/assets/stylesheets/framework/typography.scss b/app/assets/stylesheets/framework/typography.scss
index 0c1b8b92de3..6d891e21556 100644
--- a/app/assets/stylesheets/framework/typography.scss
+++ b/app/assets/stylesheets/framework/typography.scss
@@ -286,7 +286,7 @@ body {
}
.page-title {
- margin-top: $gl-padding;
+ margin: #{2 * $grid-size} 0;
line-height: 1.3;
font-size: 1.25em;
font-weight: $gl-font-weight-bold;
diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss
index f66782ab882..837016db67b 100644
--- a/app/assets/stylesheets/framework/variables.scss
+++ b/app/assets/stylesheets/framework/variables.scss
@@ -55,7 +55,7 @@ $blue-50: #f6fafe;
$blue-100: #e4f0fb;
$blue-200: #b8d6f4;
$blue-300: #73afea;
-$blue-400: #2e87e0;
+$blue-400: #418cd8;
$blue-500: #1f78d1;
$blue-600: #1b69b6;
$blue-700: #17599c;
@@ -67,7 +67,7 @@ $orange-50: #fffaf4;
$orange-100: #fff1de;
$orange-200: #fed69f;
$orange-300: #fdbc60;
-$orange-400: #fca121;
+$orange-400: #fca429;
$orange-500: #fc9403;
$orange-600: #de7e00;
$orange-700: #c26700;
@@ -78,7 +78,7 @@ $orange-950: #592800;
$red-50: #fef6f5;
$red-100: #fbe5e1;
$red-200: #f2b4a9;
-$red-300: #e67664;
+$red-300: #ea8271;
$red-400: #e05842;
$red-500: #db3b21;
$red-600: #c0341d;
diff --git a/app/assets/stylesheets/page_bundles/ide.scss b/app/assets/stylesheets/page_bundles/ide.scss
index 45df8391f9a..65f0a0d18e2 100644
--- a/app/assets/stylesheets/page_bundles/ide.scss
+++ b/app/assets/stylesheets/page_bundles/ide.scss
@@ -53,83 +53,9 @@ $ide-commit-header-height: 48px;
flex: 1;
min-height: 0; // firefox fix
- .file {
- height: 32px;
- cursor: pointer;
-
- &.file-active {
- background: $theme-gray-100;
- }
-
- .ide-file-name {
- flex: 1;
- white-space: nowrap;
- text-overflow: ellipsis;
- max-width: inherit;
- line-height: 16px;
- display: inline-block;
- height: 18px;
-
- svg {
- vertical-align: middle;
- margin-right: 2px;
- }
-
- .loading-container {
- margin-right: 4px;
- display: inline-block;
- }
- }
-
- .ide-file-icon-holder {
- display: flex;
- align-items: center;
- color: $theme-gray-700;
- }
-
- .ide-file-changed-icon {
- margin-left: auto;
-
- > svg {
- display: block;
- }
- }
-
- .ide-new-btn {
- display: none;
-
- .btn {
- padding: 2px 5px;
- }
- }
-
- &:hover,
- &:focus {
- .ide-new-btn {
- display: block;
- }
- }
-
- .folder-icon {
- fill: $gl-text-color-secondary;
- }
- }
-
a {
color: $gl-text-color;
}
-
- th {
- position: sticky;
- top: 0;
- }
-}
-
-.file-name {
- display: flex;
- overflow: visible;
- align-items: center;
- width: 100%;
}
.multi-file-loading-container {
@@ -625,8 +551,7 @@ $ide-commit-header-height: 48px;
}
}
-.multi-file-commit-list-path,
-.ide-file-list .file {
+.multi-file-commit-list-path {
display: flex;
align-items: center;
margin-left: -$grid-size;
@@ -634,28 +559,14 @@ $ide-commit-header-height: 48px;
padding: $grid-size / 2 $grid-size;
border-radius: $border-radius-default;
text-align: left;
-
- &:hover,
- &:focus {
- background: $theme-gray-100;
- }
-
- &:active {
- background: $theme-gray-200;
- }
-}
-
-.multi-file-commit-list-path {
cursor: pointer;
height: $ide-commit-row-height;
padding-right: 0;
- &.is-active {
- background-color: $white-normal;
- }
-
&:hover,
&:focus {
+ background: $theme-gray-100;
+
outline: 0;
.multi-file-discard-btn {
@@ -665,6 +576,14 @@ $ide-commit-header-height: 48px;
}
}
+ &:active {
+ background: $theme-gray-200;
+ }
+
+ &.is-active {
+ background-color: $white-normal;
+ }
+
svg {
min-width: 16px;
vertical-align: middle;
@@ -1398,9 +1317,17 @@ $ide-commit-header-height: 48px;
}
}
-.ide-new-btn .dropdown.show .ide-entry-dropdown-toggle {
- color: $white-normal;
- background-color: $blue-500;
+.ide-new-btn {
+ display: none;
+
+ .btn {
+ padding: 2px 5px;
+ }
+
+ .dropdown.show .ide-entry-dropdown-toggle {
+ color: $white-normal;
+ background-color: $blue-500;
+ }
}
.ide-preview-header {
@@ -1465,3 +1392,28 @@ $ide-commit-header-height: 48px;
width: $ide-commit-row-height;
height: $ide-commit-row-height;
}
+
+.ide-file-icon-holder {
+ display: flex;
+ align-items: center;
+ color: $theme-gray-700;
+}
+
+.ide-file-changed-icon {
+ margin-left: auto;
+
+ > svg {
+ display: block;
+ }
+}
+
+.file-row:hover,
+.file-row:focus {
+ .ide-new-btn {
+ display: block;
+ }
+
+ .folder-icon {
+ fill: $gl-text-color-secondary;
+ }
+}
diff --git a/app/assets/stylesheets/pages/xterm.scss b/app/assets/stylesheets/page_bundles/xterm.scss
index 7d40c61da26..7f040ac9b96 100644
--- a/app/assets/stylesheets/pages/xterm.scss
+++ b/app/assets/stylesheets/page_bundles/xterm.scss
@@ -1,3 +1,5 @@
+@import 'framework/variables';
+
.build-page {
// color codes are based on http://en.wikipedia.org/wiki/File:Xterm_256color_chart.svg
// see also: https://gist.github.com/jasonm23/2868981
diff --git a/app/assets/stylesheets/pages/boards.scss b/app/assets/stylesheets/pages/boards.scss
index 69d7de886b4..b3c5c693824 100644
--- a/app/assets/stylesheets/pages/boards.scss
+++ b/app/assets/stylesheets/pages/boards.scss
@@ -136,15 +136,23 @@
right: 0;
bottom: 0;
left: 0;
+
+ button {
+ display: none;
+ }
}
.board-title {
padding: 0;
border-bottom: 0;
+ justify-content: center;
> span {
+ width: 100%;
+ margin-top: -12px;
display: block;
- transform: rotate(90deg) translate(35px, 10px);
+ transform: rotate(90deg) translate(35px, 0);
+ overflow: initial;
}
}
@@ -265,7 +273,7 @@
margin-bottom: 0;
padding: 5px;
list-style: none;
- overflow-y: scroll;
+ overflow-y: auto;
overflow-x: hidden;
}
diff --git a/app/assets/stylesheets/pages/clusters.scss b/app/assets/stylesheets/pages/clusters.scss
index 0f22fe21143..71a3fd544f2 100644
--- a/app/assets/stylesheets/pages/clusters.scss
+++ b/app/assets/stylesheets/pages/clusters.scss
@@ -4,9 +4,60 @@
}
}
-.cluster-applications-table {
- // Wait for the Vue to kick-in and render the applications block
- min-height: 628px;
+.cluster-application-row {
+ background: $gray-lighter;
+
+ &.cluster-application-installed {
+ background: none;
+ }
+
+ .settings-message {
+ padding: $gl-vert-padding $gl-padding-8;
+ }
+}
+
+@media (min-width: map-get($grid-breakpoints, md)) {
+ .cluster-application-list {
+ border: 1px solid $border-color;
+ border-radius: $border-radius-default;
+ }
+
+ .cluster-application-row {
+ border-bottom: 1px solid $border-color;
+ padding: $gl-padding;
+ }
+}
+
+.cluster-application-logo {
+ border: 3px solid $white-light;
+ box-shadow: 0 0 0 1px $gray-normal;
+
+ &.avatar:hover {
+ border-color: $white-light;
+ }
+}
+
+.cluster-application-warning {
+ font-weight: bold;
+ text-align: center;
+ padding: $gl-padding;
+ border-bottom: 1px solid $white-normal;
+
+ .svg-container {
+ display: inline-block;
+ vertical-align: middle;
+ margin-right: $gl-padding-8;
+ width: 40px;
+ height: 40px;
+ }
+}
+
+.cluster-application-description {
+ flex: 1;
+}
+
+.cluster-application-disabled {
+ opacity: 0.5;
}
.clusters-dropdown-menu {
diff --git a/app/assets/stylesheets/pages/groups.scss b/app/assets/stylesheets/pages/groups.scss
index 394c99268be..fe792a53b44 100644
--- a/app/assets/stylesheets/pages/groups.scss
+++ b/app/assets/stylesheets/pages/groups.scss
@@ -106,7 +106,7 @@
&,
.dropdown,
.dropdown .dropdown-toggle,
- .btn-new {
+ .btn-success {
display: block;
}
@@ -118,7 +118,7 @@
.group-filter-form,
.dropdown .dropdown-toggle,
- .btn-new {
+ .btn-success {
width: 100%;
}
diff --git a/app/assets/stylesheets/pages/issuable.scss b/app/assets/stylesheets/pages/issuable.scss
index 57539212e0c..62a9f97caa9 100644
--- a/app/assets/stylesheets/pages/issuable.scss
+++ b/app/assets/stylesheets/pages/issuable.scss
@@ -726,13 +726,13 @@
display: flex;
}
- .issue-info-container {
+ .issuable-info-container {
-webkit-flex: 1;
flex: 1;
display: flex;
padding-right: $gl-padding;
- .issue-main-info {
+ .issuable-main-info {
flex: 1 auto;
margin-right: 10px;
}
@@ -768,7 +768,7 @@
margin-bottom: 10px;
min-width: 15px;
- .selected_issue {
+ .selected-issuable {
vertical-align: text-top;
}
}
@@ -800,7 +800,7 @@
}
.issuable-list li,
-.issue-info-container .controls {
+.issuable-info-container .controls {
.avatar-counter {
display: inline-block;
vertical-align: middle;
diff --git a/app/assets/stylesheets/pages/members.scss b/app/assets/stylesheets/pages/members.scss
index 5fdb2b4a90a..99609a96976 100644
--- a/app/assets/stylesheets/pages/members.scss
+++ b/app/assets/stylesheets/pages/members.scss
@@ -4,7 +4,7 @@
}
.users-project-form {
- .btn-create {
+ .btn-success {
margin-right: 10px;
}
}
diff --git a/app/assets/stylesheets/pages/merge_requests.scss b/app/assets/stylesheets/pages/merge_requests.scss
index 9d46c2cf4fa..97b131687d3 100644
--- a/app/assets/stylesheets/pages/merge_requests.scss
+++ b/app/assets/stylesheets/pages/merge_requests.scss
@@ -460,7 +460,7 @@
display: -webkit-flex;
display: flex;
- .issue-info-container {
+ .issuable-info-container {
-webkit-flex: 1;
flex: 1;
}
diff --git a/app/assets/stylesheets/pages/note_form.scss b/app/assets/stylesheets/pages/note_form.scss
index ac7b701c2e2..4268e194ed7 100644
--- a/app/assets/stylesheets/pages/note_form.scss
+++ b/app/assets/stylesheets/pages/note_form.scss
@@ -2,7 +2,7 @@
* Note Form
*/
.comment-btn {
- @extend .btn-create;
+ @extend .btn-success;
}
.diff-file .diff-content {
diff --git a/app/assets/stylesheets/pages/profile.scss b/app/assets/stylesheets/pages/profile.scss
index 17f34319050..caa839c32a5 100644
--- a/app/assets/stylesheets/pages/profile.scss
+++ b/app/assets/stylesheets/pages/profile.scss
@@ -279,6 +279,10 @@ table.u2f-registrations {
}
}
+.codes {
+ padding-top: 14px;
+}
+
.oauth-application-show {
.scope-name {
font-weight: $gl-font-weight-bold;
diff --git a/app/assets/stylesheets/pages/search.scss b/app/assets/stylesheets/pages/search.scss
index 77119aea9e2..04151b1cd59 100644
--- a/app/assets/stylesheets/pages/search.scss
+++ b/app/assets/stylesheets/pages/search.scss
@@ -218,7 +218,7 @@ input[type='checkbox']:hover {
}
.btn-search,
- .btn-new {
+ .btn-success {
width: 100%;
margin-top: 5px;
diff --git a/app/controllers/abuse_reports_controller.rb b/app/controllers/abuse_reports_controller.rb
index 51547ed7eaf..68e14f0c2e5 100644
--- a/app/controllers/abuse_reports_controller.rb
+++ b/app/controllers/abuse_reports_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class AbuseReportsController < ApplicationController
before_action :set_user, only: [:new]
diff --git a/app/controllers/admin/abuse_reports_controller.rb b/app/controllers/admin/abuse_reports_controller.rb
index 68a49f0749f..d5537023b26 100644
--- a/app/controllers/admin/abuse_reports_controller.rb
+++ b/app/controllers/admin/abuse_reports_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Admin::AbuseReportsController < Admin::ApplicationController
# rubocop: disable CodeReuse/ActiveRecord
def index
diff --git a/app/controllers/admin/appearances_controller.rb b/app/controllers/admin/appearances_controller.rb
index 9aaec905734..fdd3b4126ff 100644
--- a/app/controllers/admin/appearances_controller.rb
+++ b/app/controllers/admin/appearances_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Admin::AppearancesController < Admin::ApplicationController
before_action :set_appearance, except: :create
diff --git a/app/controllers/admin/application_controller.rb b/app/controllers/admin/application_controller.rb
index a4648b33cfa..ef182b981f1 100644
--- a/app/controllers/admin/application_controller.rb
+++ b/app/controllers/admin/application_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
# Provides a base class for Admin controllers to subclass
#
# Automatically sets the layout and ensures an administrator is logged in
diff --git a/app/controllers/admin/application_settings_controller.rb b/app/controllers/admin/application_settings_controller.rb
index 869213d61f1..b7c758a42ed 100644
--- a/app/controllers/admin/application_settings_controller.rb
+++ b/app/controllers/admin/application_settings_controller.rb
@@ -1,9 +1,39 @@
+# frozen_string_literal: true
+
class Admin::ApplicationSettingsController < Admin::ApplicationController
+ include InternalRedirect
before_action :set_application_setting
def show
end
+ def integrations
+ end
+
+ def repository
+ end
+
+ def templates
+ end
+
+ def ci_cd
+ end
+
+ def reporting
+ end
+
+ def metrics_and_profiling
+ end
+
+ def network
+ end
+
+ def geo
+ end
+
+ def preferences
+ end
+
def update
successful = ApplicationSettings::UpdateService
.new(@application_setting, current_user, application_setting_params)
@@ -13,10 +43,12 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
session[:ask_for_usage_stats_consent] = current_user.requires_usage_stats_consent?
end
+ redirect_path = referer_path(request) || admin_application_settings_path
+
respond_to do |format|
if successful
format.json { head :ok }
- format.html { redirect_to admin_application_settings_path, notice: 'Application settings saved successfully' }
+ format.html { redirect_to redirect_path, notice: 'Application settings saved successfully' }
else
format.json { head :bad_request }
format.html { render :show }
@@ -96,8 +128,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
disabled_oauth_sign_in_sources: [],
import_sources: [],
repository_storages: [],
- restricted_visibility_levels: [],
- sidekiq_throttling_queues: []
+ restricted_visibility_levels: []
]
end
end
diff --git a/app/controllers/admin/applications_controller.rb b/app/controllers/admin/applications_controller.rb
index daa21d1be93..00d2cc01192 100644
--- a/app/controllers/admin/applications_controller.rb
+++ b/app/controllers/admin/applications_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Admin::ApplicationsController < Admin::ApplicationController
include OauthApplications
diff --git a/app/controllers/admin/background_jobs_controller.rb b/app/controllers/admin/background_jobs_controller.rb
index 5f90ad7137d..7701f2e645b 100644
--- a/app/controllers/admin/background_jobs_controller.rb
+++ b/app/controllers/admin/background_jobs_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Admin::BackgroundJobsController < Admin::ApplicationController
def show
ps_output, _ = Gitlab::Popen.popen(%W(ps ww -U #{Gitlab.config.gitlab.user} -o pid,pcpu,pmem,stat,start,command))
diff --git a/app/controllers/admin/broadcast_messages_controller.rb b/app/controllers/admin/broadcast_messages_controller.rb
index b2fbbfc3e64..a91d9a534cd 100644
--- a/app/controllers/admin/broadcast_messages_controller.rb
+++ b/app/controllers/admin/broadcast_messages_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Admin::BroadcastMessagesController < Admin::ApplicationController
include BroadcastMessagesHelper
diff --git a/app/controllers/admin/dashboard_controller.rb b/app/controllers/admin/dashboard_controller.rb
index 5dc3e6c2990..b5fb5511638 100644
--- a/app/controllers/admin/dashboard_controller.rb
+++ b/app/controllers/admin/dashboard_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Admin::DashboardController < Admin::ApplicationController
include CountHelper
diff --git a/app/controllers/admin/deploy_keys_controller.rb b/app/controllers/admin/deploy_keys_controller.rb
index 5c2025c1988..49ce275ad14 100644
--- a/app/controllers/admin/deploy_keys_controller.rb
+++ b/app/controllers/admin/deploy_keys_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Admin::DeployKeysController < Admin::ApplicationController
before_action :deploy_keys, only: [:index]
before_action :deploy_key, only: [:destroy, :edit, :update]
diff --git a/app/controllers/admin/gitaly_servers_controller.rb b/app/controllers/admin/gitaly_servers_controller.rb
index 11c4dfe3d8d..0a5566bfe70 100644
--- a/app/controllers/admin/gitaly_servers_controller.rb
+++ b/app/controllers/admin/gitaly_servers_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Admin::GitalyServersController < Admin::ApplicationController
def index
@gitaly_servers = Gitaly::Server.all
diff --git a/app/controllers/admin/groups_controller.rb b/app/controllers/admin/groups_controller.rb
index 2a47f01c6ad..46e85e1424f 100644
--- a/app/controllers/admin/groups_controller.rb
+++ b/app/controllers/admin/groups_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Admin::GroupsController < Admin::ApplicationController
include MembersPresentation
diff --git a/app/controllers/admin/health_check_controller.rb b/app/controllers/admin/health_check_controller.rb
index 61247b280b3..44864f9c7d0 100644
--- a/app/controllers/admin/health_check_controller.rb
+++ b/app/controllers/admin/health_check_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Admin::HealthCheckController < Admin::ApplicationController
def show
@errors = HealthCheck::Utils.process_checks(['standard'])
diff --git a/app/controllers/admin/hook_logs_controller.rb b/app/controllers/admin/hook_logs_controller.rb
index 3017f96c26f..8301b3aa880 100644
--- a/app/controllers/admin/hook_logs_controller.rb
+++ b/app/controllers/admin/hook_logs_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Admin::HookLogsController < Admin::ApplicationController
include HooksExecution
diff --git a/app/controllers/admin/hooks_controller.rb b/app/controllers/admin/hooks_controller.rb
index a98c355c7ba..d0abdec50ae 100644
--- a/app/controllers/admin/hooks_controller.rb
+++ b/app/controllers/admin/hooks_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Admin::HooksController < Admin::ApplicationController
include HooksExecution
diff --git a/app/controllers/admin/identities_controller.rb b/app/controllers/admin/identities_controller.rb
index 57ad7389a23..b51c2f678ca 100644
--- a/app/controllers/admin/identities_controller.rb
+++ b/app/controllers/admin/identities_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Admin::IdentitiesController < Admin::ApplicationController
before_action :user
before_action :identity, except: [:index, :new, :create]
diff --git a/app/controllers/admin/impersonation_tokens_controller.rb b/app/controllers/admin/impersonation_tokens_controller.rb
index 9ebba88ef16..f5825ecb19a 100644
--- a/app/controllers/admin/impersonation_tokens_controller.rb
+++ b/app/controllers/admin/impersonation_tokens_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Admin::ImpersonationTokensController < Admin::ApplicationController
before_action :user
diff --git a/app/controllers/admin/impersonations_controller.rb b/app/controllers/admin/impersonations_controller.rb
index d2f947d2c66..08d7e3b4fa2 100644
--- a/app/controllers/admin/impersonations_controller.rb
+++ b/app/controllers/admin/impersonations_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Admin::ImpersonationsController < Admin::ApplicationController
skip_before_action :authenticate_admin!
before_action :authenticate_impersonator!
diff --git a/app/controllers/admin/jobs_controller.rb b/app/controllers/admin/jobs_controller.rb
index 788693c62c4..0c1afdc3d3b 100644
--- a/app/controllers/admin/jobs_controller.rb
+++ b/app/controllers/admin/jobs_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Admin::JobsController < Admin::ApplicationController
# rubocop: disable CodeReuse/ActiveRecord
def index
diff --git a/app/controllers/admin/keys_controller.rb b/app/controllers/admin/keys_controller.rb
index 0400a3b2f3b..4e9262ccc96 100644
--- a/app/controllers/admin/keys_controller.rb
+++ b/app/controllers/admin/keys_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Admin::KeysController < Admin::ApplicationController
before_action :user, only: [:show, :destroy]
diff --git a/app/controllers/admin/labels_controller.rb b/app/controllers/admin/labels_controller.rb
index 7eb8f758807..aa5eae7a474 100644
--- a/app/controllers/admin/labels_controller.rb
+++ b/app/controllers/admin/labels_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Admin::LabelsController < Admin::ApplicationController
before_action :set_label, only: [:show, :edit, :update, :destroy]
diff --git a/app/controllers/admin/logs_controller.rb b/app/controllers/admin/logs_controller.rb
index 7248edb64e1..06b0e6a15a3 100644
--- a/app/controllers/admin/logs_controller.rb
+++ b/app/controllers/admin/logs_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Admin::LogsController < Admin::ApplicationController
before_action :loggers
diff --git a/app/controllers/admin/projects_controller.rb b/app/controllers/admin/projects_controller.rb
index 5cb08c9787b..550f29a58d2 100644
--- a/app/controllers/admin/projects_controller.rb
+++ b/app/controllers/admin/projects_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Admin::ProjectsController < Admin::ApplicationController
include MembersPresentation
diff --git a/app/controllers/admin/requests_profiles_controller.rb b/app/controllers/admin/requests_profiles_controller.rb
index a478176e138..64d74ae4231 100644
--- a/app/controllers/admin/requests_profiles_controller.rb
+++ b/app/controllers/admin/requests_profiles_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Admin::RequestsProfilesController < Admin::ApplicationController
def index
@profile_token = Gitlab::RequestProfiler.profile_token
diff --git a/app/controllers/admin/runner_projects_controller.rb b/app/controllers/admin/runner_projects_controller.rb
index 51d5799cd89..774ce04d079 100644
--- a/app/controllers/admin/runner_projects_controller.rb
+++ b/app/controllers/admin/runner_projects_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Admin::RunnerProjectsController < Admin::ApplicationController
before_action :project, only: [:create]
diff --git a/app/controllers/admin/runners_controller.rb b/app/controllers/admin/runners_controller.rb
index 911603bac17..0b6ff491c66 100644
--- a/app/controllers/admin/runners_controller.rb
+++ b/app/controllers/admin/runners_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Admin::RunnersController < Admin::ApplicationController
before_action :runner, except: :index
diff --git a/app/controllers/admin/spam_logs_controller.rb b/app/controllers/admin/spam_logs_controller.rb
index 8df35d25303..18d22c95b61 100644
--- a/app/controllers/admin/spam_logs_controller.rb
+++ b/app/controllers/admin/spam_logs_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Admin::SpamLogsController < Admin::ApplicationController
# rubocop: disable CodeReuse/ActiveRecord
def index
diff --git a/app/controllers/admin/system_info_controller.rb b/app/controllers/admin/system_info_controller.rb
index 99039724521..244fc2b31bb 100644
--- a/app/controllers/admin/system_info_controller.rb
+++ b/app/controllers/admin/system_info_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Admin::SystemInfoController < Admin::ApplicationController
EXCLUDED_MOUNT_OPTIONS = [
'nobrowse',
diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb
index 85bdc85c55b..b783c0e2a6f 100644
--- a/app/controllers/admin/users_controller.rb
+++ b/app/controllers/admin/users_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Admin::UsersController < Admin::ApplicationController
before_action :user, except: [:index, :new, :create]
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index 7e2b2cf3ad3..b87034d10b6 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'gon'
require 'fogbugz'
@@ -10,6 +12,7 @@ class ApplicationController < ActionController::Base
include WorkhorseHelper
include EnforcesTwoFactorAuthentication
include WithPerformanceBar
+ include InvalidUTF8ErrorHandler
before_action :authenticate_sessionless_user!
before_action :authenticate_user!
@@ -270,9 +273,10 @@ class ApplicationController < ActionController::Base
end
def event_filter
- # Split using comma to maintain backward compatibility Ex/ "filter1,filter2"
- filters = cookies['event_filter'].split(',')[0] if cookies['event_filter'].present?
- @event_filter ||= EventFilter.new(filters)
+ @event_filter ||=
+ EventFilter.new(params[:event_filter].presence || cookies[:event_filter]).tap do |new_event_filter|
+ cookies[:event_filter] = new_event_filter.filter
+ end
end
# JSON for infinite scroll via Pager object
diff --git a/app/controllers/autocomplete_controller.rb b/app/controllers/autocomplete_controller.rb
index 9e30b982b06..3766b64a091 100644
--- a/app/controllers/autocomplete_controller.rb
+++ b/app/controllers/autocomplete_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class AutocompleteController < ApplicationController
skip_before_action :authenticate_user!, only: [:users, :award_emojis]
diff --git a/app/controllers/boards/application_controller.rb b/app/controllers/boards/application_controller.rb
index b2675025fc0..eab908ba5ed 100644
--- a/app/controllers/boards/application_controller.rb
+++ b/app/controllers/boards/application_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Boards
class ApplicationController < ::ApplicationController
respond_to :json
diff --git a/app/controllers/boards/issues_controller.rb b/app/controllers/boards/issues_controller.rb
index 071906f1e91..4f3d737e3ce 100644
--- a/app/controllers/boards/issues_controller.rb
+++ b/app/controllers/boards/issues_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Boards
class IssuesController < Boards::ApplicationController
include BoardsResponses
diff --git a/app/controllers/boards/lists_controller.rb b/app/controllers/boards/lists_controller.rb
index e8b5934f2a9..ccd02144671 100644
--- a/app/controllers/boards/lists_controller.rb
+++ b/app/controllers/boards/lists_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Boards
class ListsController < Boards::ApplicationController
include BoardsResponses
diff --git a/app/controllers/ci/lints_controller.rb b/app/controllers/ci/lints_controller.rb
index 738a6a5173e..99ce24bd435 100644
--- a/app/controllers/ci/lints_controller.rb
+++ b/app/controllers/ci/lints_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Ci
class LintsController < ::ApplicationController
before_action :authenticate_user!
diff --git a/app/controllers/concerns/accepts_pending_invitations.rb b/app/controllers/concerns/accepts_pending_invitations.rb
index 6e8aef52b52..cb66c1a055d 100644
--- a/app/controllers/concerns/accepts_pending_invitations.rb
+++ b/app/controllers/concerns/accepts_pending_invitations.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module AcceptsPendingInvitations
extend ActiveSupport::Concern
diff --git a/app/controllers/concerns/authenticates_with_two_factor.rb b/app/controllers/concerns/authenticates_with_two_factor.rb
index 961f121548b..5507328f8ae 100644
--- a/app/controllers/concerns/authenticates_with_two_factor.rb
+++ b/app/controllers/concerns/authenticates_with_two_factor.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
# == AuthenticatesWithTwoFactor
#
# Controller concern to handle two-factor authentication
diff --git a/app/controllers/concerns/boards_responses.rb b/app/controllers/concerns/boards_responses.rb
index da830ec2cb1..b7e4f9b81f1 100644
--- a/app/controllers/concerns/boards_responses.rb
+++ b/app/controllers/concerns/boards_responses.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module BoardsResponses
include Gitlab::Utils::StrongMemoize
diff --git a/app/controllers/concerns/checks_collaboration.rb b/app/controllers/concerns/checks_collaboration.rb
index 81367663a06..1fa82f7dcd4 100644
--- a/app/controllers/concerns/checks_collaboration.rb
+++ b/app/controllers/concerns/checks_collaboration.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module ChecksCollaboration
def can_collaborate_with_project?(project, ref: nil)
return true if can?(current_user, :push_code, project)
diff --git a/app/controllers/concerns/continue_params.rb b/app/controllers/concerns/continue_params.rb
index 8b7355974df..f0e6adf4dec 100644
--- a/app/controllers/concerns/continue_params.rb
+++ b/app/controllers/concerns/continue_params.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module ContinueParams
include InternalRedirect
extend ActiveSupport::Concern
diff --git a/app/controllers/concerns/controller_with_cross_project_access_check.rb b/app/controllers/concerns/controller_with_cross_project_access_check.rb
index a45c3384578..3f72f092683 100644
--- a/app/controllers/concerns/controller_with_cross_project_access_check.rb
+++ b/app/controllers/concerns/controller_with_cross_project_access_check.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module ControllerWithCrossProjectAccessCheck
extend ActiveSupport::Concern
diff --git a/app/controllers/concerns/creates_commit.rb b/app/controllers/concerns/creates_commit.rb
index 709c8aaf337..b3777fd2b0f 100644
--- a/app/controllers/concerns/creates_commit.rb
+++ b/app/controllers/concerns/creates_commit.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module CreatesCommit
extend ActiveSupport::Concern
include Gitlab::Utils::StrongMemoize
@@ -65,7 +67,7 @@ module CreatesCommit
flash[:notice] = nil
else
target = different_project? ? "project" : "branch"
- flash[:notice] << " You can now submit a merge request to get this change into the original #{target}."
+ flash[:notice] = flash[:notice] + " You can now submit a merge request to get this change into the original #{target}."
end
end
end
diff --git a/app/controllers/concerns/cycle_analytics_params.rb b/app/controllers/concerns/cycle_analytics_params.rb
index 1ab107168c0..c1ef848e1e7 100644
--- a/app/controllers/concerns/cycle_analytics_params.rb
+++ b/app/controllers/concerns/cycle_analytics_params.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module CycleAnalyticsParams
extend ActiveSupport::Concern
diff --git a/app/controllers/concerns/diff_for_path.rb b/app/controllers/concerns/diff_for_path.rb
index d5388c4cd20..6be7a2a18a2 100644
--- a/app/controllers/concerns/diff_for_path.rb
+++ b/app/controllers/concerns/diff_for_path.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module DiffForPath
extend ActiveSupport::Concern
diff --git a/app/controllers/concerns/enforces_two_factor_authentication.rb b/app/controllers/concerns/enforces_two_factor_authentication.rb
index 69e5cbed343..71bdef8ce03 100644
--- a/app/controllers/concerns/enforces_two_factor_authentication.rb
+++ b/app/controllers/concerns/enforces_two_factor_authentication.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
# == EnforcesTwoFactorAuthentication
#
# Controller concern to enforce two-factor authentication requirements
diff --git a/app/controllers/concerns/group_tree.rb b/app/controllers/concerns/group_tree.rb
index c363cad0ffa..4f56346832c 100644
--- a/app/controllers/concerns/group_tree.rb
+++ b/app/controllers/concerns/group_tree.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module GroupTree
# rubocop:disable Gitlab/ModuleWithInstanceVariables
# rubocop: disable CodeReuse/ActiveRecord
diff --git a/app/controllers/concerns/hooks_execution.rb b/app/controllers/concerns/hooks_execution.rb
index a22e46b4860..e8add1f4055 100644
--- a/app/controllers/concerns/hooks_execution.rb
+++ b/app/controllers/concerns/hooks_execution.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module HooksExecution
extend ActiveSupport::Concern
diff --git a/app/controllers/concerns/internal_redirect.rb b/app/controllers/concerns/internal_redirect.rb
index 10b9852e329..6785e6972d0 100644
--- a/app/controllers/concerns/internal_redirect.rb
+++ b/app/controllers/concerns/internal_redirect.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module InternalRedirect
extend ActiveSupport::Concern
@@ -36,4 +38,10 @@ module InternalRedirect
path_with_query = [uri.path, uri.query].compact.join('?')
[path_with_query, uri.fragment].compact.join("#")
end
+
+ def referer_path(request)
+ return unless request.referer.presence
+
+ URI(request.referer).path
+ end
end
diff --git a/app/controllers/concerns/invalid_utf8_error_handler.rb b/app/controllers/concerns/invalid_utf8_error_handler.rb
new file mode 100644
index 00000000000..44c6d6b0da0
--- /dev/null
+++ b/app/controllers/concerns/invalid_utf8_error_handler.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+module InvalidUTF8ErrorHandler
+ extend ActiveSupport::Concern
+
+ included do
+ rescue_from ArgumentError, with: :handle_invalid_utf8
+ end
+
+ private
+
+ def handle_invalid_utf8(error)
+ if error.message == "invalid byte sequence in UTF-8"
+ render_412
+ else
+ raise(error)
+ end
+ end
+
+ def render_412
+ respond_to do |format|
+ format.html { render "errors/precondition_failed", layout: "errors", status: 412 }
+ format.js { render json: { error: 'Invalid UTF-8' }, status: :precondition_failed, content_type: 'application/json' }
+ format.any { head :precondition_failed }
+ end
+ end
+end
diff --git a/app/controllers/concerns/issuable_actions.rb b/app/controllers/concerns/issuable_actions.rb
index e723107bd7f..07e01e903ea 100644
--- a/app/controllers/concerns/issuable_actions.rb
+++ b/app/controllers/concerns/issuable_actions.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module IssuableActions
extend ActiveSupport::Concern
diff --git a/app/controllers/concerns/issuable_collections.rb b/app/controllers/concerns/issuable_collections.rb
index d29154d5c60..5217b4be928 100644
--- a/app/controllers/concerns/issuable_collections.rb
+++ b/app/controllers/concerns/issuable_collections.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module IssuableCollections
extend ActiveSupport::Concern
include CookiesHelper
diff --git a/app/controllers/concerns/issues_action.rb b/app/controllers/concerns/issues_action.rb
index 9d58656773d..a75590457d6 100644
--- a/app/controllers/concerns/issues_action.rb
+++ b/app/controllers/concerns/issues_action.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module IssuesAction
extend ActiveSupport::Concern
include IssuableCollections
diff --git a/app/controllers/concerns/issues_calendar.rb b/app/controllers/concerns/issues_calendar.rb
index 76e1d1ff4e8..1fdfde4c869 100644
--- a/app/controllers/concerns/issues_calendar.rb
+++ b/app/controllers/concerns/issues_calendar.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module IssuesCalendar
extend ActiveSupport::Concern
diff --git a/app/controllers/concerns/lfs_request.rb b/app/controllers/concerns/lfs_request.rb
index 4584ff782a3..9576eb14fdd 100644
--- a/app/controllers/concerns/lfs_request.rb
+++ b/app/controllers/concerns/lfs_request.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
# This concern assumes:
# - a `#project` accessor
# - a `#user` accessor
diff --git a/app/controllers/concerns/members_presentation.rb b/app/controllers/concerns/members_presentation.rb
index e146e7574aa..c6c3598a976 100644
--- a/app/controllers/concerns/members_presentation.rb
+++ b/app/controllers/concerns/members_presentation.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module MembersPresentation
extend ActiveSupport::Concern
diff --git a/app/controllers/concerns/membership_actions.rb b/app/controllers/concerns/membership_actions.rb
index 94a352c0bcc..ca713192c9e 100644
--- a/app/controllers/concerns/membership_actions.rb
+++ b/app/controllers/concerns/membership_actions.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module MembershipActions
include MembersPresentation
extend ActiveSupport::Concern
diff --git a/app/controllers/concerns/merge_requests_action.rb b/app/controllers/concerns/merge_requests_action.rb
index b70db99b157..285f2c3a8a0 100644
--- a/app/controllers/concerns/merge_requests_action.rb
+++ b/app/controllers/concerns/merge_requests_action.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module MergeRequestsAction
extend ActiveSupport::Concern
include IssuableCollections
diff --git a/app/controllers/concerns/milestone_actions.rb b/app/controllers/concerns/milestone_actions.rb
index d92cf8b4894..eccbe35577b 100644
--- a/app/controllers/concerns/milestone_actions.rb
+++ b/app/controllers/concerns/milestone_actions.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module MilestoneActions
extend ActiveSupport::Concern
diff --git a/app/controllers/concerns/notes_actions.rb b/app/controllers/concerns/notes_actions.rb
index b63f2eb85f0..3a45d6205ab 100644
--- a/app/controllers/concerns/notes_actions.rb
+++ b/app/controllers/concerns/notes_actions.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module NotesActions
include RendersNotes
include Gitlab::Utils::StrongMemoize
@@ -41,12 +43,26 @@ module NotesActions
@note = Notes::CreateService.new(note_project, current_user, create_params).execute
- if @note.is_a?(Note)
- prepare_notes_for_rendering([@note], noteable)
- end
-
respond_to do |format|
- format.json { render json: note_json(@note) }
+ format.json do
+ json = {
+ commands_changes: @note.commands_changes
+ }
+
+ if @note.persisted? && return_discussion?
+ json[:valid] = true
+
+ discussion = @note.discussion
+ prepare_notes_for_rendering(discussion.notes)
+ json[:discussion] = discussion_serializer.represent(discussion, context: self)
+ else
+ prepare_notes_for_rendering([@note])
+
+ json.merge!(note_json(@note))
+ end
+
+ render json: json
+ end
format.html { redirect_back_or_default }
end
end
@@ -55,10 +71,7 @@ module NotesActions
# rubocop:disable Gitlab/ModuleWithInstanceVariables
def update
@note = Notes::UpdateService.new(project, current_user, note_params).execute(note)
-
- if @note.is_a?(Note)
- prepare_notes_for_rendering([@note])
- end
+ prepare_notes_for_rendering([@note])
respond_to do |format|
format.json { render json: note_json(@note) }
@@ -89,14 +102,17 @@ module NotesActions
end
def note_json(note)
- attrs = {
- commands_changes: note.commands_changes
- }
+ attrs = {}
if note.persisted?
attrs[:valid] = true
- if use_note_serializer?
+ if return_discussion?
+ discussion = note.discussion
+ prepare_notes_for_rendering(discussion.notes)
+
+ attrs[:discussion] = discussion_serializer.represent(discussion, context: self)
+ elsif use_note_serializer?
attrs.merge!(note_serializer.represent(note))
else
attrs.merge!(
@@ -216,6 +232,10 @@ module NotesActions
ProjectNoteSerializer.new(project: project, noteable: noteable, current_user: current_user)
end
+ def discussion_serializer
+ DiscussionSerializer.new(project: project, noteable: noteable, current_user: current_user, note_entity: ProjectNoteEntity)
+ end
+
def note_project
strong_memoize(:note_project) do
next nil unless project
@@ -235,6 +255,10 @@ module NotesActions
end
end
+ def return_discussion?
+ Gitlab::Utils.to_boolean(params[:return_discussion])
+ end
+
def use_note_serializer?
return false if params['html']
diff --git a/app/controllers/concerns/oauth_applications.rb b/app/controllers/concerns/oauth_applications.rb
index f0a68f23566..d97e22df472 100644
--- a/app/controllers/concerns/oauth_applications.rb
+++ b/app/controllers/concerns/oauth_applications.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module OauthApplications
extend ActiveSupport::Concern
diff --git a/app/controllers/concerns/params_backward_compatibility.rb b/app/controllers/concerns/params_backward_compatibility.rb
index b0e3d9c7b34..c972d6e3161 100644
--- a/app/controllers/concerns/params_backward_compatibility.rb
+++ b/app/controllers/concerns/params_backward_compatibility.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module ParamsBackwardCompatibility
private
diff --git a/app/controllers/concerns/preview_markdown.rb b/app/controllers/concerns/preview_markdown.rb
index 99123fcb3b0..c61b9fabe9e 100644
--- a/app/controllers/concerns/preview_markdown.rb
+++ b/app/controllers/concerns/preview_markdown.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module PreviewMarkdown
extend ActiveSupport::Concern
diff --git a/app/controllers/concerns/renders_blob.rb b/app/controllers/concerns/renders_blob.rb
index ba7adcfea86..b8026c7a01d 100644
--- a/app/controllers/concerns/renders_blob.rb
+++ b/app/controllers/concerns/renders_blob.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module RendersBlob
extend ActiveSupport::Concern
diff --git a/app/controllers/concerns/renders_commits.rb b/app/controllers/concerns/renders_commits.rb
index b1c9b1e532f..f48e0586211 100644
--- a/app/controllers/concerns/renders_commits.rb
+++ b/app/controllers/concerns/renders_commits.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module RendersCommits
def limited_commits(commits)
if commits.size > MergeRequestDiff::COMMITS_SAFE_SIZE
diff --git a/app/controllers/concerns/renders_member_access.rb b/app/controllers/concerns/renders_member_access.rb
index c5b77dacb26..955ac1a1bc8 100644
--- a/app/controllers/concerns/renders_member_access.rb
+++ b/app/controllers/concerns/renders_member_access.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module RendersMemberAccess
def prepare_groups_for_rendering(groups)
preload_max_member_access_for_collection(Group, groups)
diff --git a/app/controllers/concerns/renders_notes.rb b/app/controllers/concerns/renders_notes.rb
index c5f23e33424..ce36da6b715 100644
--- a/app/controllers/concerns/renders_notes.rb
+++ b/app/controllers/concerns/renders_notes.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module RendersNotes
# rubocop:disable Gitlab/ModuleWithInstanceVariables
def prepare_notes_for_rendering(notes, noteable = nil)
diff --git a/app/controllers/concerns/repository_settings_redirect.rb b/app/controllers/concerns/repository_settings_redirect.rb
index f3db3cd563b..0f18735c29e 100644
--- a/app/controllers/concerns/repository_settings_redirect.rb
+++ b/app/controllers/concerns/repository_settings_redirect.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module RepositorySettingsRedirect
extend ActiveSupport::Concern
diff --git a/app/controllers/concerns/requires_whitelisted_monitoring_client.rb b/app/controllers/concerns/requires_whitelisted_monitoring_client.rb
index 88d1b34bb06..426f224d26b 100644
--- a/app/controllers/concerns/requires_whitelisted_monitoring_client.rb
+++ b/app/controllers/concerns/requires_whitelisted_monitoring_client.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module RequiresWhitelistedMonitoringClient
extend ActiveSupport::Concern
diff --git a/app/controllers/concerns/routable_actions.rb b/app/controllers/concerns/routable_actions.rb
index 0931bdf4c04..88939b002b2 100644
--- a/app/controllers/concerns/routable_actions.rb
+++ b/app/controllers/concerns/routable_actions.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module RoutableActions
extend ActiveSupport::Concern
diff --git a/app/controllers/concerns/send_file_upload.rb b/app/controllers/concerns/send_file_upload.rb
index 382ec91f771..0bb7b7efed0 100644
--- a/app/controllers/concerns/send_file_upload.rb
+++ b/app/controllers/concerns/send_file_upload.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module SendFileUpload
def send_upload(file_upload, send_params: {}, redirect_params: {}, attachment: nil, disposition: 'attachment')
if attachment
diff --git a/app/controllers/concerns/service_params.rb b/app/controllers/concerns/service_params.rb
index c1acb50b76c..8bd93a349ef 100644
--- a/app/controllers/concerns/service_params.rb
+++ b/app/controllers/concerns/service_params.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module ServiceParams
extend ActiveSupport::Concern
diff --git a/app/controllers/concerns/snippets_actions.rb b/app/controllers/concerns/snippets_actions.rb
index 120614739aa..8c22490700c 100644
--- a/app/controllers/concerns/snippets_actions.rb
+++ b/app/controllers/concerns/snippets_actions.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module SnippetsActions
extend ActiveSupport::Concern
diff --git a/app/controllers/concerns/spammable_actions.rb b/app/controllers/concerns/spammable_actions.rb
index 922aa58a00f..c3a1b12af84 100644
--- a/app/controllers/concerns/spammable_actions.rb
+++ b/app/controllers/concerns/spammable_actions.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module SpammableActions
extend ActiveSupport::Concern
diff --git a/app/controllers/concerns/todos_actions.rb b/app/controllers/concerns/todos_actions.rb
index c0acdb3498d..78b65f7961b 100644
--- a/app/controllers/concerns/todos_actions.rb
+++ b/app/controllers/concerns/todos_actions.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module TodosActions
extend ActiveSupport::Concern
diff --git a/app/controllers/concerns/toggle_award_emoji.rb b/app/controllers/concerns/toggle_award_emoji.rb
index ae0b815f85e..97b343f8b1a 100644
--- a/app/controllers/concerns/toggle_award_emoji.rb
+++ b/app/controllers/concerns/toggle_award_emoji.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module ToggleAwardEmoji
extend ActiveSupport::Concern
diff --git a/app/controllers/concerns/toggle_subscription_action.rb b/app/controllers/concerns/toggle_subscription_action.rb
index 776583579e8..e613bfaeef2 100644
--- a/app/controllers/concerns/toggle_subscription_action.rb
+++ b/app/controllers/concerns/toggle_subscription_action.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module ToggleSubscriptionAction
extend ActiveSupport::Concern
diff --git a/app/controllers/concerns/uploads_actions.rb b/app/controllers/concerns/uploads_actions.rb
index 56772df21d7..7a1c7abfb8f 100644
--- a/app/controllers/concerns/uploads_actions.rb
+++ b/app/controllers/concerns/uploads_actions.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module UploadsActions
extend ActiveSupport::Concern
diff --git a/app/controllers/concerns/with_performance_bar.rb b/app/controllers/concerns/with_performance_bar.rb
index 6a8b1a4de7b..77c3d476ac6 100644
--- a/app/controllers/concerns/with_performance_bar.rb
+++ b/app/controllers/concerns/with_performance_bar.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module WithPerformanceBar
extend ActiveSupport::Concern
@@ -8,11 +10,7 @@ module WithPerformanceBar
def peek_enabled?
return false unless Gitlab::PerformanceBar.enabled?(current_user)
- if RequestStore.active?
- RequestStore.fetch(:peek_enabled) { cookie_or_default_value }
- else
- cookie_or_default_value
- end
+ Gitlab::SafeRequestStore.fetch(:peek_enabled) { cookie_or_default_value }
end
private
diff --git a/app/controllers/concerns/workhorse_request.rb b/app/controllers/concerns/workhorse_request.rb
index 43c0f1b173c..028f10e866a 100644
--- a/app/controllers/concerns/workhorse_request.rb
+++ b/app/controllers/concerns/workhorse_request.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module WorkhorseRequest
extend ActiveSupport::Concern
diff --git a/app/controllers/confirmations_controller.rb b/app/controllers/confirmations_controller.rb
index 7bc46a6ccc0..2c4aab67448 100644
--- a/app/controllers/confirmations_controller.rb
+++ b/app/controllers/confirmations_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class ConfirmationsController < Devise::ConfirmationsController
include AcceptsPendingInvitations
@@ -20,7 +22,7 @@ class ConfirmationsController < Devise::ConfirmationsController
after_sign_in(resource)
else
Gitlab::AppLogger.info("Email Confirmed: username=#{resource.username} email=#{resource.email} ip=#{request.remote_ip}")
- flash[:notice] += " Please sign in."
+ flash[:notice] = flash[:notice] + " Please sign in."
new_session_path(:user, anchor: 'login-pane')
end
end
diff --git a/app/controllers/dashboard/application_controller.rb b/app/controllers/dashboard/application_controller.rb
index 9fb5c525425..cee0753a021 100644
--- a/app/controllers/dashboard/application_controller.rb
+++ b/app/controllers/dashboard/application_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Dashboard::ApplicationController < ApplicationController
include ControllerWithCrossProjectAccessCheck
diff --git a/app/controllers/dashboard/groups_controller.rb b/app/controllers/dashboard/groups_controller.rb
index 79f563bef86..f82cde8e10a 100644
--- a/app/controllers/dashboard/groups_controller.rb
+++ b/app/controllers/dashboard/groups_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Dashboard::GroupsController < Dashboard::ApplicationController
include GroupTree
diff --git a/app/controllers/dashboard/labels_controller.rb b/app/controllers/dashboard/labels_controller.rb
index 9dcb3a0eb6d..89d87c2d5c8 100644
--- a/app/controllers/dashboard/labels_controller.rb
+++ b/app/controllers/dashboard/labels_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Dashboard::LabelsController < Dashboard::ApplicationController
def index
respond_to do |format|
diff --git a/app/controllers/dashboard/milestones_controller.rb b/app/controllers/dashboard/milestones_controller.rb
index 78f7f6d4e23..6e17bc212e4 100644
--- a/app/controllers/dashboard/milestones_controller.rb
+++ b/app/controllers/dashboard/milestones_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Dashboard::MilestonesController < Dashboard::ApplicationController
include MilestoneActions
diff --git a/app/controllers/dashboard/projects_controller.rb b/app/controllers/dashboard/projects_controller.rb
index e8f796f17ca..e9686ed8d06 100644
--- a/app/controllers/dashboard/projects_controller.rb
+++ b/app/controllers/dashboard/projects_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Dashboard::ProjectsController < Dashboard::ApplicationController
include ParamsBackwardCompatibility
include RendersMemberAccess
diff --git a/app/controllers/dashboard/snippets_controller.rb b/app/controllers/dashboard/snippets_controller.rb
index 0ba97e4fd59..161c22046f9 100644
--- a/app/controllers/dashboard/snippets_controller.rb
+++ b/app/controllers/dashboard/snippets_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Dashboard::SnippetsController < Dashboard::ApplicationController
skip_cross_project_access_check :index
diff --git a/app/controllers/dashboard/todos_controller.rb b/app/controllers/dashboard/todos_controller.rb
index 231a23427f7..b82caf30a91 100644
--- a/app/controllers/dashboard/todos_controller.rb
+++ b/app/controllers/dashboard/todos_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Dashboard::TodosController < Dashboard::ApplicationController
include ActionView::Helpers::NumberHelper
diff --git a/app/controllers/dashboard_controller.rb b/app/controllers/dashboard_controller.rb
index ff133001b84..c032fb2efb5 100644
--- a/app/controllers/dashboard_controller.rb
+++ b/app/controllers/dashboard_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class DashboardController < Dashboard::ApplicationController
include IssuesAction
include MergeRequestsAction
@@ -38,7 +40,7 @@ class DashboardController < Dashboard::ApplicationController
end
@events = EventCollection
- .new(projects, offset: params[:offset].to_i, filter: @event_filter)
+ .new(projects, offset: params[:offset].to_i, filter: event_filter)
.to_a
Events::RenderService.new(current_user).execute(@events)
diff --git a/app/controllers/explore/application_controller.rb b/app/controllers/explore/application_controller.rb
index baf54520b9c..8eee3742d89 100644
--- a/app/controllers/explore/application_controller.rb
+++ b/app/controllers/explore/application_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Explore::ApplicationController < ApplicationController
skip_before_action :authenticate_user!
diff --git a/app/controllers/explore/groups_controller.rb b/app/controllers/explore/groups_controller.rb
index fa0a0f68fbc..67db797b80a 100644
--- a/app/controllers/explore/groups_controller.rb
+++ b/app/controllers/explore/groups_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Explore::GroupsController < Explore::ApplicationController
include GroupTree
diff --git a/app/controllers/explore/projects_controller.rb b/app/controllers/explore/projects_controller.rb
index 03a2ee07fea..7ecbc32cf4e 100644
--- a/app/controllers/explore/projects_controller.rb
+++ b/app/controllers/explore/projects_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Explore::ProjectsController < Explore::ApplicationController
include ParamsBackwardCompatibility
include RendersMemberAccess
diff --git a/app/controllers/explore/snippets_controller.rb b/app/controllers/explore/snippets_controller.rb
index d3f0e033068..76ed142c939 100644
--- a/app/controllers/explore/snippets_controller.rb
+++ b/app/controllers/explore/snippets_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Explore::SnippetsController < Explore::ApplicationController
def index
@snippets = SnippetsFinder.new(current_user).execute
diff --git a/app/controllers/google_api/authorizations_controller.rb b/app/controllers/google_api/authorizations_controller.rb
index 5551057ff55..dd9f5af61b3 100644
--- a/app/controllers/google_api/authorizations_controller.rb
+++ b/app/controllers/google_api/authorizations_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module GoogleApi
class AuthorizationsController < ApplicationController
def callback
diff --git a/app/controllers/graphql_controller.rb b/app/controllers/graphql_controller.rb
index 0a1cf169aca..a1ec144410b 100644
--- a/app/controllers/graphql_controller.rb
+++ b/app/controllers/graphql_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class GraphqlController < ApplicationController
# Unauthenticated users have access to the API for public data
skip_before_action :authenticate_user!
diff --git a/app/controllers/groups/application_controller.rb b/app/controllers/groups/application_controller.rb
index 62213561898..5f92333c2c3 100644
--- a/app/controllers/groups/application_controller.rb
+++ b/app/controllers/groups/application_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Groups::ApplicationController < ApplicationController
include RoutableActions
include ControllerWithCrossProjectAccessCheck
diff --git a/app/controllers/groups/avatars_controller.rb b/app/controllers/groups/avatars_controller.rb
index 35a61b359c8..8e4dc2bb6e9 100644
--- a/app/controllers/groups/avatars_controller.rb
+++ b/app/controllers/groups/avatars_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Groups::AvatarsController < Groups::ApplicationController
before_action :authorize_admin_group!
diff --git a/app/controllers/groups/boards_controller.rb b/app/controllers/groups/boards_controller.rb
index e892d1f8dbf..8d259b4052e 100644
--- a/app/controllers/groups/boards_controller.rb
+++ b/app/controllers/groups/boards_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Groups::BoardsController < Groups::ApplicationController
include BoardsResponses
diff --git a/app/controllers/groups/children_controller.rb b/app/controllers/groups/children_controller.rb
index 0e8125d6113..d549f793ad7 100644
--- a/app/controllers/groups/children_controller.rb
+++ b/app/controllers/groups/children_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Groups
class ChildrenController < Groups::ApplicationController
before_action :group
diff --git a/app/controllers/groups/group_members_controller.rb b/app/controllers/groups/group_members_controller.rb
index 7dc51f4c357..0bc082246a1 100644
--- a/app/controllers/groups/group_members_controller.rb
+++ b/app/controllers/groups/group_members_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Groups::GroupMembersController < Groups::ApplicationController
include MembershipActions
include MembersPresentation
diff --git a/app/controllers/groups/labels_controller.rb b/app/controllers/groups/labels_controller.rb
index 059cf160fa2..cb9ab35de85 100644
--- a/app/controllers/groups/labels_controller.rb
+++ b/app/controllers/groups/labels_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Groups::LabelsController < Groups::ApplicationController
include ToggleSubscriptionAction
@@ -10,10 +12,7 @@ class Groups::LabelsController < Groups::ApplicationController
def index
respond_to do |format|
format.html do
- @labels = @group.labels
- .optionally_search(params[:search])
- .order_by(sort)
- .page(params[:page])
+ @labels = GroupLabelsFinder.new(@group, params.merge(sort: sort)).execute
end
format.json do
render json: LabelSerializer.new.represent_appearance(available_labels)
diff --git a/app/controllers/groups/milestones_controller.rb b/app/controllers/groups/milestones_controller.rb
index 6bdc0f79ef2..a7cee426cf1 100644
--- a/app/controllers/groups/milestones_controller.rb
+++ b/app/controllers/groups/milestones_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Groups::MilestonesController < Groups::ApplicationController
include MilestoneActions
diff --git a/app/controllers/groups/runners_controller.rb b/app/controllers/groups/runners_controller.rb
index 1036b4e6ed3..dd8fbf7a029 100644
--- a/app/controllers/groups/runners_controller.rb
+++ b/app/controllers/groups/runners_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Groups::RunnersController < Groups::ApplicationController
# Proper policies should be implemented per
# https://gitlab.com/gitlab-org/gitlab-ce/issues/45894
diff --git a/app/controllers/groups/settings/ci_cd_controller.rb b/app/controllers/groups/settings/ci_cd_controller.rb
index 4bf6a2a3ad1..6d9a225b771 100644
--- a/app/controllers/groups/settings/ci_cd_controller.rb
+++ b/app/controllers/groups/settings/ci_cd_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Groups
module Settings
class CiCdController < Groups::ApplicationController
diff --git a/app/controllers/groups/shared_projects_controller.rb b/app/controllers/groups/shared_projects_controller.rb
index 7dec1f5f402..30b7bfc70ae 100644
--- a/app/controllers/groups/shared_projects_controller.rb
+++ b/app/controllers/groups/shared_projects_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Groups
class SharedProjectsController < Groups::ApplicationController
respond_to :json
diff --git a/app/controllers/groups/uploads_controller.rb b/app/controllers/groups/uploads_controller.rb
index 74760194a1f..7e5cdae0ce3 100644
--- a/app/controllers/groups/uploads_controller.rb
+++ b/app/controllers/groups/uploads_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Groups::UploadsController < Groups::ApplicationController
include UploadsActions
include WorkhorseRequest
diff --git a/app/controllers/groups/variables_controller.rb b/app/controllers/groups/variables_controller.rb
index 4d8a20de017..4f641de0357 100644
--- a/app/controllers/groups/variables_controller.rb
+++ b/app/controllers/groups/variables_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Groups
class VariablesController < Groups::ApplicationController
before_action :authorize_admin_build!
diff --git a/app/controllers/groups_controller.rb b/app/controllers/groups_controller.rb
index 8b46eedae79..062c8c4e9e1 100644
--- a/app/controllers/groups_controller.rb
+++ b/app/controllers/groups_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class GroupsController < Groups::ApplicationController
include API::Helpers::RelatedResourcesHelpers
include IssuesAction
diff --git a/app/controllers/health_check_controller.rb b/app/controllers/health_check_controller.rb
index c3d18991fd4..a2abed7ba4e 100644
--- a/app/controllers/health_check_controller.rb
+++ b/app/controllers/health_check_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class HealthCheckController < HealthCheck::HealthCheckController
include RequiresWhitelistedMonitoringClient
end
diff --git a/app/controllers/health_controller.rb b/app/controllers/health_controller.rb
index 3fedd5bfb29..ab4bc911e17 100644
--- a/app/controllers/health_controller.rb
+++ b/app/controllers/health_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class HealthController < ActionController::Base
protect_from_forgery with: :exception, except: :storage_check, prepend: true
include RequiresWhitelistedMonitoringClient
diff --git a/app/controllers/help_controller.rb b/app/controllers/help_controller.rb
index a394521698c..e5a1fc9d6ff 100644
--- a/app/controllers/help_controller.rb
+++ b/app/controllers/help_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class HelpController < ApplicationController
skip_before_action :authenticate_user!
diff --git a/app/controllers/ide_controller.rb b/app/controllers/ide_controller.rb
index 96bb2237d90..eeeebe430a7 100644
--- a/app/controllers/ide_controller.rb
+++ b/app/controllers/ide_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class IdeController < ApplicationController
layout 'fullscreen'
diff --git a/app/controllers/import/base_controller.rb b/app/controllers/import/base_controller.rb
index 14b8c6e4137..042b6b1264f 100644
--- a/app/controllers/import/base_controller.rb
+++ b/app/controllers/import/base_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Import::BaseController < ApplicationController
private
diff --git a/app/controllers/import/bitbucket_controller.rb b/app/controllers/import/bitbucket_controller.rb
index f885e04b198..1b30b4dda36 100644
--- a/app/controllers/import/bitbucket_controller.rb
+++ b/app/controllers/import/bitbucket_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Import::BitbucketController < Import::BaseController
before_action :verify_bitbucket_import_enabled
before_action :bitbucket_auth, except: :callback
diff --git a/app/controllers/import/fogbugz_controller.rb b/app/controllers/import/fogbugz_controller.rb
index df96d181153..5a439e6de78 100644
--- a/app/controllers/import/fogbugz_controller.rb
+++ b/app/controllers/import/fogbugz_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Import::FogbugzController < Import::BaseController
before_action :verify_fogbugz_import_enabled
before_action :user_map, only: [:new_user_map, :create_user_map]
diff --git a/app/controllers/import/gitea_controller.rb b/app/controllers/import/gitea_controller.rb
index fbd851c64a7..382c684a408 100644
--- a/app/controllers/import/gitea_controller.rb
+++ b/app/controllers/import/gitea_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Import::GiteaController < Import::GithubController
def new
if session[access_token_key].present? && session[host_key].present?
diff --git a/app/controllers/import/github_controller.rb b/app/controllers/import/github_controller.rb
index f8b43b4fde5..1dfa814cdd5 100644
--- a/app/controllers/import/github_controller.rb
+++ b/app/controllers/import/github_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Import::GithubController < Import::BaseController
before_action :verify_import_enabled
before_action :provider_auth, only: [:status, :jobs, :create]
diff --git a/app/controllers/import/gitlab_controller.rb b/app/controllers/import/gitlab_controller.rb
index bdc402b0a77..498de0b07b8 100644
--- a/app/controllers/import/gitlab_controller.rb
+++ b/app/controllers/import/gitlab_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Import::GitlabController < Import::BaseController
MAX_PROJECT_PAGES = 15
PER_PAGE_PROJECTS = 100
diff --git a/app/controllers/import/gitlab_projects_controller.rb b/app/controllers/import/gitlab_projects_controller.rb
index f22df992fe9..354fba5d204 100644
--- a/app/controllers/import/gitlab_projects_controller.rb
+++ b/app/controllers/import/gitlab_projects_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Import::GitlabProjectsController < Import::BaseController
before_action :whitelist_query_limiting, only: [:create]
before_action :verify_gitlab_project_import_enabled
@@ -11,7 +13,7 @@ class Import::GitlabProjectsController < Import::BaseController
def create
unless file_is_valid?
- return redirect_back_or_default(options: { alert: "You need to upload a GitLab project export archive." })
+ return redirect_back_or_default(options: { alert: "You need to upload a GitLab project export archive (ending in .gz)." })
end
@project = ::Projects::GitlabProjectsImportService.new(current_user, project_params).execute
@@ -29,7 +31,11 @@ class Import::GitlabProjectsController < Import::BaseController
private
def file_is_valid?
- project_params[:file] && project_params[:file].respond_to?(:read)
+ return false unless project_params[:file] && project_params[:file].respond_to?(:read)
+
+ filename = project_params[:file].original_filename
+
+ ImportExportUploader::EXTENSION_WHITELIST.include?(File.extname(filename).delete('.'))
end
def verify_gitlab_project_import_enabled
diff --git a/app/controllers/import/google_code_controller.rb b/app/controllers/import/google_code_controller.rb
index e9387d0ad14..331f06c3dd6 100644
--- a/app/controllers/import/google_code_controller.rb
+++ b/app/controllers/import/google_code_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Import::GoogleCodeController < Import::BaseController
before_action :verify_google_code_import_enabled
before_action :user_map, only: [:new_user_map, :create_user_map]
diff --git a/app/controllers/import/manifest_controller.rb b/app/controllers/import/manifest_controller.rb
index 4ed9dca2475..320cd45b925 100644
--- a/app/controllers/import/manifest_controller.rb
+++ b/app/controllers/import/manifest_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Import::ManifestController < Import::BaseController
before_action :whitelist_query_limiting, only: [:create]
before_action :verify_import_enabled
diff --git a/app/controllers/invites_controller.rb b/app/controllers/invites_controller.rb
index 025d8270b7c..315d1375e02 100644
--- a/app/controllers/invites_controller.rb
+++ b/app/controllers/invites_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class InvitesController < ApplicationController
before_action :member
skip_before_action :authenticate_user!, only: :decline
@@ -50,9 +52,9 @@ class InvitesController < ApplicationController
def authenticate_user!
return if current_user
- notice = "To accept this invitation, sign in"
- notice << " or create an account" if Gitlab::CurrentSettings.allow_signup?
- notice << "."
+ notice = ["To accept this invitation, sign in"]
+ notice << "or create an account" if Gitlab::CurrentSettings.allow_signup?
+ notice = notice.join(' ') + "."
store_location_for :user, request.fullpath
redirect_to new_user_session_path, notice: notice
diff --git a/app/controllers/jwt_controller.rb b/app/controllers/jwt_controller.rb
index d172aee5436..f9008a5b67e 100644
--- a/app/controllers/jwt_controller.rb
+++ b/app/controllers/jwt_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class JwtController < ApplicationController
skip_before_action :authenticate_user!
skip_before_action :verify_authenticity_token
diff --git a/app/controllers/koding_controller.rb b/app/controllers/koding_controller.rb
index 745abf3c0f5..72aa9d4f17f 100644
--- a/app/controllers/koding_controller.rb
+++ b/app/controllers/koding_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class KodingController < ApplicationController
before_action :check_integration!
layout 'koding'
diff --git a/app/controllers/ldap/omniauth_callbacks_controller.rb b/app/controllers/ldap/omniauth_callbacks_controller.rb
index fb24edb8602..5e872804448 100644
--- a/app/controllers/ldap/omniauth_callbacks_controller.rb
+++ b/app/controllers/ldap/omniauth_callbacks_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Ldap::OmniauthCallbacksController < OmniauthCallbacksController
extend ::Gitlab::Utils::Override
diff --git a/app/controllers/metrics_controller.rb b/app/controllers/metrics_controller.rb
index 0400ffcfee5..7353be478e1 100644
--- a/app/controllers/metrics_controller.rb
+++ b/app/controllers/metrics_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class MetricsController < ActionController::Base
include RequiresWhitelistedMonitoringClient
diff --git a/app/controllers/notification_settings_controller.rb b/app/controllers/notification_settings_controller.rb
index 461f26561f1..84dce74ace8 100644
--- a/app/controllers/notification_settings_controller.rb
+++ b/app/controllers/notification_settings_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class NotificationSettingsController < ApplicationController
before_action :authenticate_user!
diff --git a/app/controllers/oauth/applications_controller.rb b/app/controllers/oauth/applications_controller.rb
index a1fe02dc852..b50f140dc80 100644
--- a/app/controllers/oauth/applications_controller.rb
+++ b/app/controllers/oauth/applications_controller.rb
@@ -1,10 +1,12 @@
+# frozen_string_literal: true
+
class Oauth::ApplicationsController < Doorkeeper::ApplicationsController
include Gitlab::GonHelper
include Gitlab::Allowable
include PageLayoutHelper
include OauthApplications
- before_action :verify_user_oauth_applications_enabled
+ before_action :verify_user_oauth_applications_enabled, except: :index
before_action :authenticate_user!
before_action :add_gon_variables
before_action :load_scopes, only: [:index, :create, :edit]
diff --git a/app/controllers/oauth/authorizations_controller.rb b/app/controllers/oauth/authorizations_controller.rb
index 05190103767..894a6a431e3 100644
--- a/app/controllers/oauth/authorizations_controller.rb
+++ b/app/controllers/oauth/authorizations_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Oauth::AuthorizationsController < Doorkeeper::AuthorizationsController
layout 'profile'
diff --git a/app/controllers/oauth/authorized_applications_controller.rb b/app/controllers/oauth/authorized_applications_controller.rb
index 656107d2b26..a59ade559b3 100644
--- a/app/controllers/oauth/authorized_applications_controller.rb
+++ b/app/controllers/oauth/authorized_applications_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Oauth::AuthorizedApplicationsController < Doorkeeper::AuthorizedApplicationsController
include PageLayoutHelper
diff --git a/app/controllers/omniauth_callbacks_controller.rb b/app/controllers/omniauth_callbacks_controller.rb
index 1547d4b5972..30be50d4595 100644
--- a/app/controllers/omniauth_callbacks_controller.rb
+++ b/app/controllers/omniauth_callbacks_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class OmniauthCallbacksController < Devise::OmniauthCallbacksController
include AuthenticatesWithTwoFactor
include Devise::Controllers::Rememberable
@@ -135,14 +137,13 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController
def handle_signup_error
label = Gitlab::Auth::OAuth::Provider.label_for(oauth['provider'])
- message = "Signing in using your #{label} account without a pre-existing GitLab account is not allowed."
+ message = ["Signing in using your #{label} account without a pre-existing GitLab account is not allowed."]
if Gitlab::CurrentSettings.allow_signup?
- message << " Create a GitLab account first, and then connect it to your #{label} account."
+ message << "Create a GitLab account first, and then connect it to your #{label} account."
end
- flash[:notice] = message
-
+ flash[:notice] = message.join(' ')
redirect_to new_user_session_path
end
diff --git a/app/controllers/passwords_controller.rb b/app/controllers/passwords_controller.rb
index a1bcf206b65..2912a22411e 100644
--- a/app/controllers/passwords_controller.rb
+++ b/app/controllers/passwords_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class PasswordsController < Devise::PasswordsController
skip_before_action :require_no_authentication, only: [:edit, :update]
diff --git a/app/controllers/profiles/accounts_controller.rb b/app/controllers/profiles/accounts_controller.rb
index fd9cb9fca3e..cb3180f4196 100644
--- a/app/controllers/profiles/accounts_controller.rb
+++ b/app/controllers/profiles/accounts_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Profiles::AccountsController < Profiles::ApplicationController
include AuthHelper
diff --git a/app/controllers/profiles/active_sessions_controller.rb b/app/controllers/profiles/active_sessions_controller.rb
index f1e77d68acd..efe7ede5efa 100644
--- a/app/controllers/profiles/active_sessions_controller.rb
+++ b/app/controllers/profiles/active_sessions_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Profiles::ActiveSessionsController < Profiles::ApplicationController
def index
@sessions = ActiveSession.list(current_user)
diff --git a/app/controllers/profiles/application_controller.rb b/app/controllers/profiles/application_controller.rb
index c8be288b9a0..52b046ef64f 100644
--- a/app/controllers/profiles/application_controller.rb
+++ b/app/controllers/profiles/application_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Profiles::ApplicationController < ApplicationController
layout 'profile'
end
diff --git a/app/controllers/profiles/avatars_controller.rb b/app/controllers/profiles/avatars_controller.rb
index 4f030ded80f..3378a09628c 100644
--- a/app/controllers/profiles/avatars_controller.rb
+++ b/app/controllers/profiles/avatars_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Profiles::AvatarsController < Profiles::ApplicationController
def destroy
@user = current_user
diff --git a/app/controllers/profiles/chat_names_controller.rb b/app/controllers/profiles/chat_names_controller.rb
index a186c5f36a8..2e78b9e6dc7 100644
--- a/app/controllers/profiles/chat_names_controller.rb
+++ b/app/controllers/profiles/chat_names_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Profiles::ChatNamesController < Profiles::ApplicationController
before_action :chat_name_token, only: [:new]
before_action :chat_name_params, only: [:new, :create, :deny]
diff --git a/app/controllers/profiles/emails_controller.rb b/app/controllers/profiles/emails_controller.rb
index a39824ec9c8..503eda250b4 100644
--- a/app/controllers/profiles/emails_controller.rb
+++ b/app/controllers/profiles/emails_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Profiles::EmailsController < Profiles::ApplicationController
before_action :find_email, only: [:destroy, :resend_confirmation_instructions]
diff --git a/app/controllers/profiles/gpg_keys_controller.rb b/app/controllers/profiles/gpg_keys_controller.rb
index c32507756e8..8c34a66c374 100644
--- a/app/controllers/profiles/gpg_keys_controller.rb
+++ b/app/controllers/profiles/gpg_keys_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Profiles::GpgKeysController < Profiles::ApplicationController
before_action :set_gpg_key, only: [:destroy, :revoke]
diff --git a/app/controllers/profiles/keys_controller.rb b/app/controllers/profiles/keys_controller.rb
index 6035258667e..01801c31327 100644
--- a/app/controllers/profiles/keys_controller.rb
+++ b/app/controllers/profiles/keys_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Profiles::KeysController < Profiles::ApplicationController
skip_before_action :authenticate_user!, only: [:get_keys]
diff --git a/app/controllers/profiles/notifications_controller.rb b/app/controllers/profiles/notifications_controller.rb
index 00bd2040b9a..b719b70c56e 100644
--- a/app/controllers/profiles/notifications_controller.rb
+++ b/app/controllers/profiles/notifications_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Profiles::NotificationsController < Profiles::ApplicationController
# rubocop: disable CodeReuse/ActiveRecord
def show
diff --git a/app/controllers/profiles/passwords_controller.rb b/app/controllers/profiles/passwords_controller.rb
index b8ccc6e3c99..a0391d677c4 100644
--- a/app/controllers/profiles/passwords_controller.rb
+++ b/app/controllers/profiles/passwords_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Profiles::PasswordsController < Profiles::ApplicationController
skip_before_action :check_password_expiration, only: [:new, :create]
skip_before_action :check_two_factor_requirement, only: [:new, :create]
diff --git a/app/controllers/profiles/personal_access_tokens_controller.rb b/app/controllers/profiles/personal_access_tokens_controller.rb
index b357741e3fb..4b6ec2697b7 100644
--- a/app/controllers/profiles/personal_access_tokens_controller.rb
+++ b/app/controllers/profiles/personal_access_tokens_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Profiles::PersonalAccessTokensController < Profiles::ApplicationController
def index
set_index_vars
diff --git a/app/controllers/profiles/preferences_controller.rb b/app/controllers/profiles/preferences_controller.rb
index ed0f98179eb..37ac11dc6a1 100644
--- a/app/controllers/profiles/preferences_controller.rb
+++ b/app/controllers/profiles/preferences_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Profiles::PreferencesController < Profiles::ApplicationController
before_action :user
diff --git a/app/controllers/profiles/two_factor_auths_controller.rb b/app/controllers/profiles/two_factor_auths_controller.rb
index 29ff18a1219..ba94196b2f9 100644
--- a/app/controllers/profiles/two_factor_auths_controller.rb
+++ b/app/controllers/profiles/two_factor_auths_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Profiles::TwoFactorAuthsController < Profiles::ApplicationController
skip_before_action :check_two_factor_requirement
@@ -30,7 +32,7 @@ class Profiles::TwoFactorAuthsController < Profiles::ApplicationController
unless two_factor_grace_period_expired?
grace_period_deadline = current_user.otp_grace_period_started_at + two_factor_grace_period.hours
- flash.now[:alert] << " You need to do this before #{l(grace_period_deadline)}."
+ flash.now[:alert] = flash.now[:alert] + " You need to do this before #{l(grace_period_deadline)}."
end
end
diff --git a/app/controllers/profiles/u2f_registrations_controller.rb b/app/controllers/profiles/u2f_registrations_controller.rb
index e3d7737f44a..e6a154fb6aa 100644
--- a/app/controllers/profiles/u2f_registrations_controller.rb
+++ b/app/controllers/profiles/u2f_registrations_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Profiles::U2fRegistrationsController < Profiles::ApplicationController
def destroy
u2f_registration = current_user.u2f_registrations.find(params[:id])
diff --git a/app/controllers/profiles_controller.rb b/app/controllers/profiles_controller.rb
index a43d47797f1..15248d2d08f 100644
--- a/app/controllers/profiles_controller.rb
+++ b/app/controllers/profiles_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class ProfilesController < Profiles::ApplicationController
include ActionView::Helpers::SanitizeHelper
diff --git a/app/controllers/projects/application_controller.rb b/app/controllers/projects/application_controller.rb
index 695ffd90a85..a2bdcaefa9b 100644
--- a/app/controllers/projects/application_controller.rb
+++ b/app/controllers/projects/application_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Projects::ApplicationController < ApplicationController
include CookiesHelper
include RoutableActions
diff --git a/app/controllers/projects/artifacts_controller.rb b/app/controllers/projects/artifacts_controller.rb
index 3e8ffa485dd..bd110d646e5 100644
--- a/app/controllers/projects/artifacts_controller.rb
+++ b/app/controllers/projects/artifacts_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Projects::ArtifactsController < Projects::ApplicationController
include ExtractsPath
include RendersBlob
diff --git a/app/controllers/projects/autocomplete_sources_controller.rb b/app/controllers/projects/autocomplete_sources_controller.rb
index a8f73ed5cb0..7c93cf36862 100644
--- a/app/controllers/projects/autocomplete_sources_controller.rb
+++ b/app/controllers/projects/autocomplete_sources_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Projects::AutocompleteSourcesController < Projects::ApplicationController
before_action :load_autocomplete_service, except: [:members]
diff --git a/app/controllers/projects/avatars_controller.rb b/app/controllers/projects/avatars_controller.rb
index 878c82cd183..1c385c0e15a 100644
--- a/app/controllers/projects/avatars_controller.rb
+++ b/app/controllers/projects/avatars_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Projects::AvatarsController < Projects::ApplicationController
include SendsBlob
diff --git a/app/controllers/projects/badges_controller.rb b/app/controllers/projects/badges_controller.rb
index 06ba73d8e8d..c24bf211760 100644
--- a/app/controllers/projects/badges_controller.rb
+++ b/app/controllers/projects/badges_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Projects::BadgesController < Projects::ApplicationController
layout 'project_settings'
before_action :authorize_admin_project!, only: [:index]
diff --git a/app/controllers/projects/blame_controller.rb b/app/controllers/projects/blame_controller.rb
index 6461eeac11c..9076bdb9f04 100644
--- a/app/controllers/projects/blame_controller.rb
+++ b/app/controllers/projects/blame_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
# Controller for viewing a file's blame
class Projects::BlameController < Projects::ApplicationController
include ExtractsPath
diff --git a/app/controllers/projects/blob_controller.rb b/app/controllers/projects/blob_controller.rb
index bfe4e7f934f..92d26a13da9 100644
--- a/app/controllers/projects/blob_controller.rb
+++ b/app/controllers/projects/blob_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
# Controller for viewing a file's blame
class Projects::BlobController < Projects::ApplicationController
include ExtractsPath
diff --git a/app/controllers/projects/boards_controller.rb b/app/controllers/projects/boards_controller.rb
index e7354a9e1f7..77b818347c7 100644
--- a/app/controllers/projects/boards_controller.rb
+++ b/app/controllers/projects/boards_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Projects::BoardsController < Projects::ApplicationController
include BoardsResponses
include IssuableCollections
diff --git a/app/controllers/projects/branches_controller.rb b/app/controllers/projects/branches_controller.rb
index d14795e787b..b7750f4517b 100644
--- a/app/controllers/projects/branches_controller.rb
+++ b/app/controllers/projects/branches_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Projects::BranchesController < Projects::ApplicationController
include ActionView::Helpers::SanitizeHelper
include SortingHelper
diff --git a/app/controllers/projects/build_artifacts_controller.rb b/app/controllers/projects/build_artifacts_controller.rb
index 9e99a84fac7..46449a4aae9 100644
--- a/app/controllers/projects/build_artifacts_controller.rb
+++ b/app/controllers/projects/build_artifacts_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Projects::BuildArtifactsController < Projects::ApplicationController
include ExtractsPath
include RendersBlob
diff --git a/app/controllers/projects/builds_controller.rb b/app/controllers/projects/builds_controller.rb
index 230b072dcea..6b3d70cb720 100644
--- a/app/controllers/projects/builds_controller.rb
+++ b/app/controllers/projects/builds_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Projects::BuildsController < Projects::ApplicationController
before_action :authorize_read_build!
diff --git a/app/controllers/projects/ci/lints_controller.rb b/app/controllers/projects/ci/lints_controller.rb
index a2185572a20..2090af0a111 100644
--- a/app/controllers/projects/ci/lints_controller.rb
+++ b/app/controllers/projects/ci/lints_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Projects::Ci::LintsController < Projects::ApplicationController
before_action :authorize_create_pipeline!
diff --git a/app/controllers/projects/clusters/applications_controller.rb b/app/controllers/projects/clusters/applications_controller.rb
index 8c9df51981a..c356f8d2987 100644
--- a/app/controllers/projects/clusters/applications_controller.rb
+++ b/app/controllers/projects/clusters/applications_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Projects::Clusters::ApplicationsController < Projects::ApplicationController
before_action :cluster
before_action :application_class, only: [:create]
diff --git a/app/controllers/projects/clusters_controller.rb b/app/controllers/projects/clusters_controller.rb
index b4fd09c06e5..bcdbf48bb35 100644
--- a/app/controllers/projects/clusters_controller.rb
+++ b/app/controllers/projects/clusters_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Projects::ClustersController < Projects::ApplicationController
before_action :cluster, except: [:index, :new, :create_gcp, :create_user]
before_action :authorize_read_cluster!
@@ -141,7 +143,8 @@ class Projects::ClustersController < Projects::ApplicationController
:gcp_project_id,
:zone,
:num_nodes,
- :machine_type
+ :machine_type,
+ :legacy_abac
]).merge(
provider_type: :gcp,
platform_type: :kubernetes
diff --git a/app/controllers/projects/commit_controller.rb b/app/controllers/projects/commit_controller.rb
index 81f375875b2..00b63f55710 100644
--- a/app/controllers/projects/commit_controller.rb
+++ b/app/controllers/projects/commit_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
# Controller for a specific Commit
#
# Not to be confused with CommitsController, plural.
diff --git a/app/controllers/projects/commits_controller.rb b/app/controllers/projects/commits_controller.rb
index cd9c9aa30f1..84a2a461da7 100644
--- a/app/controllers/projects/commits_controller.rb
+++ b/app/controllers/projects/commits_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require "base64"
class Projects::CommitsController < Projects::ApplicationController
diff --git a/app/controllers/projects/compare_controller.rb b/app/controllers/projects/compare_controller.rb
index cca77903250..c2df7b34f90 100644
--- a/app/controllers/projects/compare_controller.rb
+++ b/app/controllers/projects/compare_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'addressable/uri'
class Projects::CompareController < Projects::ApplicationController
diff --git a/app/controllers/projects/cycle_analytics/events_controller.rb b/app/controllers/projects/cycle_analytics/events_controller.rb
index 26f3c114108..fb43356ff10 100644
--- a/app/controllers/projects/cycle_analytics/events_controller.rb
+++ b/app/controllers/projects/cycle_analytics/events_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Projects
module CycleAnalytics
class EventsController < Projects::ApplicationController
diff --git a/app/controllers/projects/cycle_analytics_controller.rb b/app/controllers/projects/cycle_analytics_controller.rb
index d1b8fd80c4e..8c071496ba9 100644
--- a/app/controllers/projects/cycle_analytics_controller.rb
+++ b/app/controllers/projects/cycle_analytics_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Projects::CycleAnalyticsController < Projects::ApplicationController
include ActionView::Helpers::DateHelper
include ActionView::Helpers::TextHelper
diff --git a/app/controllers/projects/deploy_keys_controller.rb b/app/controllers/projects/deploy_keys_controller.rb
index 2555139cd2c..92ef10a9ef5 100644
--- a/app/controllers/projects/deploy_keys_controller.rb
+++ b/app/controllers/projects/deploy_keys_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Projects::DeployKeysController < Projects::ApplicationController
include RepositorySettingsRedirect
respond_to :html
diff --git a/app/controllers/projects/deploy_tokens_controller.rb b/app/controllers/projects/deploy_tokens_controller.rb
index 83abda64fe0..830b1f4fe4a 100644
--- a/app/controllers/projects/deploy_tokens_controller.rb
+++ b/app/controllers/projects/deploy_tokens_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Projects::DeployTokensController < Projects::ApplicationController
before_action :authorize_admin_project!
diff --git a/app/controllers/projects/deployments_controller.rb b/app/controllers/projects/deployments_controller.rb
index 5a2da7274d1..0a009477d61 100644
--- a/app/controllers/projects/deployments_controller.rb
+++ b/app/controllers/projects/deployments_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Projects::DeploymentsController < Projects::ApplicationController
before_action :authorize_read_environment!
before_action :authorize_read_deployment!
diff --git a/app/controllers/projects/discussions_controller.rb b/app/controllers/projects/discussions_controller.rb
index efdddb24290..b62606067c0 100644
--- a/app/controllers/projects/discussions_controller.rb
+++ b/app/controllers/projects/discussions_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Projects::DiscussionsController < Projects::ApplicationController
include NotesHelper
include RendersNotes
diff --git a/app/controllers/projects/environments_controller.rb b/app/controllers/projects/environments_controller.rb
index be22950286e..de10783df1a 100644
--- a/app/controllers/projects/environments_controller.rb
+++ b/app/controllers/projects/environments_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Projects::EnvironmentsController < Projects::ApplicationController
layout 'project'
before_action :authorize_read_environment!
diff --git a/app/controllers/projects/find_file_controller.rb b/app/controllers/projects/find_file_controller.rb
index cf53ad0a670..c026e9ff332 100644
--- a/app/controllers/projects/find_file_controller.rb
+++ b/app/controllers/projects/find_file_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
# Controller for viewing a repository's file structure
class Projects::FindFileController < Projects::ApplicationController
include ExtractsPath
diff --git a/app/controllers/projects/forks_controller.rb b/app/controllers/projects/forks_controller.rb
index b709edc8f10..7a1700a206a 100644
--- a/app/controllers/projects/forks_controller.rb
+++ b/app/controllers/projects/forks_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Projects::ForksController < Projects::ApplicationController
include ContinueParams
diff --git a/app/controllers/projects/git_http_client_controller.rb b/app/controllers/projects/git_http_client_controller.rb
index a52814e6e52..d439db97252 100644
--- a/app/controllers/projects/git_http_client_controller.rb
+++ b/app/controllers/projects/git_http_client_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
# This file should be identical in GitLab Community Edition and Enterprise Edition
class Projects::GitHttpClientController < Projects::ApplicationController
diff --git a/app/controllers/projects/git_http_controller.rb b/app/controllers/projects/git_http_controller.rb
index 1dcf837f78e..be708835e30 100644
--- a/app/controllers/projects/git_http_controller.rb
+++ b/app/controllers/projects/git_http_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Projects::GitHttpController < Projects::GitHttpClientController
include WorkhorseRequest
diff --git a/app/controllers/projects/graphs_controller.rb b/app/controllers/projects/graphs_controller.rb
index 475d4c86294..925b6ed9bfd 100644
--- a/app/controllers/projects/graphs_controller.rb
+++ b/app/controllers/projects/graphs_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Projects::GraphsController < Projects::ApplicationController
include ExtractsPath
diff --git a/app/controllers/projects/group_links_controller.rb b/app/controllers/projects/group_links_controller.rb
index bc5f38f3c2b..7c713c19762 100644
--- a/app/controllers/projects/group_links_controller.rb
+++ b/app/controllers/projects/group_links_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Projects::GroupLinksController < Projects::ApplicationController
layout 'project_settings'
before_action :authorize_admin_project!
diff --git a/app/controllers/projects/hook_logs_controller.rb b/app/controllers/projects/hook_logs_controller.rb
index 745e89fc843..a7afc3d77a5 100644
--- a/app/controllers/projects/hook_logs_controller.rb
+++ b/app/controllers/projects/hook_logs_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Projects::HookLogsController < Projects::ApplicationController
include HooksExecution
diff --git a/app/controllers/projects/hooks_controller.rb b/app/controllers/projects/hooks_controller.rb
index bbf8c7d5cbc..bc84418b79f 100644
--- a/app/controllers/projects/hooks_controller.rb
+++ b/app/controllers/projects/hooks_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Projects::HooksController < Projects::ApplicationController
include HooksExecution
diff --git a/app/controllers/projects/imports_controller.rb b/app/controllers/projects/imports_controller.rb
index 49aa32119ef..e55065c5817 100644
--- a/app/controllers/projects/imports_controller.rb
+++ b/app/controllers/projects/imports_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Projects::ImportsController < Projects::ApplicationController
include ContinueParams
diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb
index 632e498e4ba..4e859de6fde 100644
--- a/app/controllers/projects/issues_controller.rb
+++ b/app/controllers/projects/issues_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Projects::IssuesController < Projects::ApplicationController
include RendersNotes
include ToggleSubscriptionAction
diff --git a/app/controllers/projects/jobs_controller.rb b/app/controllers/projects/jobs_controller.rb
index 62b74e84c2c..3f85e442be9 100644
--- a/app/controllers/projects/jobs_controller.rb
+++ b/app/controllers/projects/jobs_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Projects::JobsController < Projects::ApplicationController
include SendFileUpload
diff --git a/app/controllers/projects/labels_controller.rb b/app/controllers/projects/labels_controller.rb
index 1fd4f0721a7..a0ce3b08d9f 100644
--- a/app/controllers/projects/labels_controller.rb
+++ b/app/controllers/projects/labels_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Projects::LabelsController < Projects::ApplicationController
include ToggleSubscriptionAction
@@ -138,12 +140,7 @@ class Projects::LabelsController < Projects::ApplicationController
end
def flash_notice_for(label, group)
- notice = ''.html_safe
- notice << label.title
- notice << ' promoted to '
- notice << view_context.link_to('<u>group label</u>'.html_safe, group_labels_path(group))
- notice << '.'
- notice
+ ''.html_safe + "#{label.title} promoted to " + view_context.link_to('<u>group label</u>'.html_safe, group_labels_path(group)) + '.'
end
protected
diff --git a/app/controllers/projects/lfs_api_controller.rb b/app/controllers/projects/lfs_api_controller.rb
index 6d6f88c1075..be40077d389 100644
--- a/app/controllers/projects/lfs_api_controller.rb
+++ b/app/controllers/projects/lfs_api_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Projects::LfsApiController < Projects::GitHttpClientController
include LfsRequest
diff --git a/app/controllers/projects/lfs_locks_api_controller.rb b/app/controllers/projects/lfs_locks_api_controller.rb
index 3fff0fd69ae..fc67cd72faa 100644
--- a/app/controllers/projects/lfs_locks_api_controller.rb
+++ b/app/controllers/projects/lfs_locks_api_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Projects::LfsLocksApiController < Projects::GitHttpClientController
include LfsRequest
diff --git a/app/controllers/projects/lfs_storage_controller.rb b/app/controllers/projects/lfs_storage_controller.rb
index 930d9a05c50..babeee48ef3 100644
--- a/app/controllers/projects/lfs_storage_controller.rb
+++ b/app/controllers/projects/lfs_storage_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Projects::LfsStorageController < Projects::GitHttpClientController
include LfsRequest
include WorkhorseRequest
diff --git a/app/controllers/projects/mattermosts_controller.rb b/app/controllers/projects/mattermosts_controller.rb
index 0f6add3e287..085b1bc1498 100644
--- a/app/controllers/projects/mattermosts_controller.rb
+++ b/app/controllers/projects/mattermosts_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Projects::MattermostsController < Projects::ApplicationController
include TriggersHelper
include ActionView::Helpers::AssetUrlHelper
diff --git a/app/controllers/projects/merge_requests/application_controller.rb b/app/controllers/projects/merge_requests/application_controller.rb
index aa2008722ec..368ee89ff5c 100644
--- a/app/controllers/projects/merge_requests/application_controller.rb
+++ b/app/controllers/projects/merge_requests/application_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Projects::MergeRequests::ApplicationController < Projects::ApplicationController
before_action :check_merge_requests_available!
before_action :merge_request
diff --git a/app/controllers/projects/merge_requests/conflicts_controller.rb b/app/controllers/projects/merge_requests/conflicts_controller.rb
index 366524b0783..ac1969adc6e 100644
--- a/app/controllers/projects/merge_requests/conflicts_controller.rb
+++ b/app/controllers/projects/merge_requests/conflicts_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Projects::MergeRequests::ConflictsController < Projects::MergeRequests::ApplicationController
include IssuableActions
diff --git a/app/controllers/projects/merge_requests/creations_controller.rb b/app/controllers/projects/merge_requests/creations_controller.rb
index 2ccb3896857..86583adc6a4 100644
--- a/app/controllers/projects/merge_requests/creations_controller.rb
+++ b/app/controllers/projects/merge_requests/creations_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Projects::MergeRequests::CreationsController < Projects::MergeRequests::ApplicationController
include DiffForPath
include DiffHelper
diff --git a/app/controllers/projects/merge_requests/diffs_controller.rb b/app/controllers/projects/merge_requests/diffs_controller.rb
index 666e65b6c5e..25d2c11b7db 100644
--- a/app/controllers/projects/merge_requests/diffs_controller.rb
+++ b/app/controllers/projects/merge_requests/diffs_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Projects::MergeRequests::DiffsController < Projects::MergeRequests::ApplicationController
include DiffForPath
include DiffHelper
@@ -23,7 +25,7 @@ class Projects::MergeRequests::DiffsController < Projects::MergeRequests::Applic
@diffs.write_cache
- render json: DiffsSerializer.new(current_user: current_user).represent(@diffs, additional_attributes)
+ render json: DiffsSerializer.new(current_user: current_user, project: @merge_request.project).represent(@diffs, additional_attributes)
end
def define_diff_vars
diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb
index 75a85fafa3f..dfb69de650b 100644
--- a/app/controllers/projects/merge_requests_controller.rb
+++ b/app/controllers/projects/merge_requests_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationController
include ToggleSubscriptionAction
include IssuableActions
diff --git a/app/controllers/projects/milestones_controller.rb b/app/controllers/projects/milestones_controller.rb
index e2c05171cd6..20998c97730 100644
--- a/app/controllers/projects/milestones_controller.rb
+++ b/app/controllers/projects/milestones_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Projects::MilestonesController < Projects::ApplicationController
include Gitlab::Utils::StrongMemoize
include MilestoneActions
@@ -91,12 +93,7 @@ class Projects::MilestonesController < Projects::ApplicationController
end
def flash_notice_for(milestone, group)
- notice = ''.html_safe
- notice << milestone.title
- notice << ' promoted to '
- notice << view_context.link_to('<u>group milestone</u>'.html_safe, group_milestone_path(group, milestone.iid))
- notice << '.'
- notice
+ ''.html_safe + "#{milestone.title} promoted to " + view_context.link_to('<u>group milestone</u>'.html_safe, group_milestone_path(group, milestone.iid)) + '.'
end
def destroy
diff --git a/app/controllers/projects/mirrors_controller.rb b/app/controllers/projects/mirrors_controller.rb
index 3739608e4c0..78d5faf2326 100644
--- a/app/controllers/projects/mirrors_controller.rb
+++ b/app/controllers/projects/mirrors_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Projects::MirrorsController < Projects::ApplicationController
include RepositorySettingsRedirect
diff --git a/app/controllers/projects/network_controller.rb b/app/controllers/projects/network_controller.rb
index 35fec229db7..ad2466a8588 100644
--- a/app/controllers/projects/network_controller.rb
+++ b/app/controllers/projects/network_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Projects::NetworkController < Projects::ApplicationController
include ExtractsPath
include ApplicationHelper
diff --git a/app/controllers/projects/notes_controller.rb b/app/controllers/projects/notes_controller.rb
index 21e2145b73b..4bac763d000 100644
--- a/app/controllers/projects/notes_controller.rb
+++ b/app/controllers/projects/notes_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Projects::NotesController < Projects::ApplicationController
include RendersNotes
include NotesActions
diff --git a/app/controllers/projects/pages_controller.rb b/app/controllers/projects/pages_controller.rb
index e1eba4f8327..c1ad6707c97 100644
--- a/app/controllers/projects/pages_controller.rb
+++ b/app/controllers/projects/pages_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Projects::PagesController < Projects::ApplicationController
layout 'project_settings'
diff --git a/app/controllers/projects/pages_domains_controller.rb b/app/controllers/projects/pages_domains_controller.rb
index c29b3c953a6..439ec9b1731 100644
--- a/app/controllers/projects/pages_domains_controller.rb
+++ b/app/controllers/projects/pages_domains_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Projects::PagesDomainsController < Projects::ApplicationController
layout 'project_settings'
diff --git a/app/controllers/projects/pipeline_schedules_controller.rb b/app/controllers/projects/pipeline_schedules_controller.rb
index d8adeffd0b2..acf56f0eb6a 100644
--- a/app/controllers/projects/pipeline_schedules_controller.rb
+++ b/app/controllers/projects/pipeline_schedules_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Projects::PipelineSchedulesController < Projects::ApplicationController
before_action :schedule, except: [:index, :new, :create]
diff --git a/app/controllers/projects/pipelines_controller.rb b/app/controllers/projects/pipelines_controller.rb
index 2cc721dfeec..53b29d4146e 100644
--- a/app/controllers/projects/pipelines_controller.rb
+++ b/app/controllers/projects/pipelines_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Projects::PipelinesController < Projects::ApplicationController
before_action :whitelist_query_limiting, only: [:create, :retry]
before_action :pipeline, except: [:index, :new, :create, :charts]
@@ -96,7 +98,7 @@ class Projects::PipelinesController < Projects::ApplicationController
render json: StageSerializer
.new(project: @project, current_user: @current_user)
- .represent(@stage, details: true)
+ .represent(@stage, details: true, retried: params[:retried])
end
# TODO: This endpoint is used by mini-pipeline-graph
diff --git a/app/controllers/projects/pipelines_settings_controller.rb b/app/controllers/projects/pipelines_settings_controller.rb
index 73c613b26f3..192e6d38f36 100644
--- a/app/controllers/projects/pipelines_settings_controller.rb
+++ b/app/controllers/projects/pipelines_settings_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Projects::PipelinesSettingsController < Projects::ApplicationController
before_action :authorize_admin_pipeline!
diff --git a/app/controllers/projects/project_members_controller.rb b/app/controllers/projects/project_members_controller.rb
index 08d5e377941..8938cfbad54 100644
--- a/app/controllers/projects/project_members_controller.rb
+++ b/app/controllers/projects/project_members_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Projects::ProjectMembersController < Projects::ApplicationController
include MembershipActions
include MembersPresentation
diff --git a/app/controllers/projects/prometheus/metrics_controller.rb b/app/controllers/projects/prometheus/metrics_controller.rb
index c6b6243b553..3a9f9aab4a5 100644
--- a/app/controllers/projects/prometheus/metrics_controller.rb
+++ b/app/controllers/projects/prometheus/metrics_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Projects
module Prometheus
class MetricsController < Projects::ApplicationController
diff --git a/app/controllers/projects/protected_branches_controller.rb b/app/controllers/projects/protected_branches_controller.rb
index 64954ac9a42..a860be83e95 100644
--- a/app/controllers/projects/protected_branches_controller.rb
+++ b/app/controllers/projects/protected_branches_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Projects::ProtectedBranchesController < Projects::ProtectedRefsController
protected
diff --git a/app/controllers/projects/protected_refs_controller.rb b/app/controllers/projects/protected_refs_controller.rb
index cc62ce2f11b..3a3a29ddd0d 100644
--- a/app/controllers/projects/protected_refs_controller.rb
+++ b/app/controllers/projects/protected_refs_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Projects::ProtectedRefsController < Projects::ApplicationController
include RepositorySettingsRedirect
diff --git a/app/controllers/projects/protected_tags_controller.rb b/app/controllers/projects/protected_tags_controller.rb
index 198c938ff35..01cedba95ac 100644
--- a/app/controllers/projects/protected_tags_controller.rb
+++ b/app/controllers/projects/protected_tags_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Projects::ProtectedTagsController < Projects::ProtectedRefsController
protected
diff --git a/app/controllers/projects/raw_controller.rb b/app/controllers/projects/raw_controller.rb
index 91cf35bc70b..1dd5d1ff2e8 100644
--- a/app/controllers/projects/raw_controller.rb
+++ b/app/controllers/projects/raw_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
# Controller for viewing a file's raw
class Projects::RawController < Projects::ApplicationController
include ExtractsPath
diff --git a/app/controllers/projects/refs_controller.rb b/app/controllers/projects/refs_controller.rb
index 0fed7f6576c..b97fbe19bbf 100644
--- a/app/controllers/projects/refs_controller.rb
+++ b/app/controllers/projects/refs_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Projects::RefsController < Projects::ApplicationController
include ExtractsPath
include TreeHelper
diff --git a/app/controllers/projects/registry/application_controller.rb b/app/controllers/projects/registry/application_controller.rb
index a56f9c58726..2f891d78c91 100644
--- a/app/controllers/projects/registry/application_controller.rb
+++ b/app/controllers/projects/registry/application_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Projects
module Registry
class ApplicationController < Projects::ApplicationController
diff --git a/app/controllers/projects/registry/repositories_controller.rb b/app/controllers/projects/registry/repositories_controller.rb
index ef0433795f4..6d60117c37d 100644
--- a/app/controllers/projects/registry/repositories_controller.rb
+++ b/app/controllers/projects/registry/repositories_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Projects
module Registry
class RepositoriesController < ::Projects::Registry::ApplicationController
diff --git a/app/controllers/projects/registry/tags_controller.rb b/app/controllers/projects/registry/tags_controller.rb
index e602aa3f393..567d750caae 100644
--- a/app/controllers/projects/registry/tags_controller.rb
+++ b/app/controllers/projects/registry/tags_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Projects
module Registry
class TagsController < ::Projects::Registry::ApplicationController
diff --git a/app/controllers/projects/releases_controller.rb b/app/controllers/projects/releases_controller.rb
index caf400ecd92..55827075896 100644
--- a/app/controllers/projects/releases_controller.rb
+++ b/app/controllers/projects/releases_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Projects::ReleasesController < Projects::ApplicationController
# Authorize
before_action :require_non_empty_project
diff --git a/app/controllers/projects/repositories_controller.rb b/app/controllers/projects/repositories_controller.rb
index ecb2ece7532..4eeaeb860ee 100644
--- a/app/controllers/projects/repositories_controller.rb
+++ b/app/controllers/projects/repositories_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Projects::RepositoriesController < Projects::ApplicationController
include ExtractsPath
diff --git a/app/controllers/projects/runner_projects_controller.rb b/app/controllers/projects/runner_projects_controller.rb
index c098c82081e..cbeb32fd610 100644
--- a/app/controllers/projects/runner_projects_controller.rb
+++ b/app/controllers/projects/runner_projects_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Projects::RunnerProjectsController < Projects::ApplicationController
before_action :authorize_admin_build!
diff --git a/app/controllers/projects/runners_controller.rb b/app/controllers/projects/runners_controller.rb
index d118cec977c..91f40b90aa8 100644
--- a/app/controllers/projects/runners_controller.rb
+++ b/app/controllers/projects/runners_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Projects::RunnersController < Projects::ApplicationController
before_action :authorize_admin_build!
before_action :runner, only: [:edit, :update, :destroy, :pause, :resume, :show]
diff --git a/app/controllers/projects/services_controller.rb b/app/controllers/projects/services_controller.rb
index d55046047ae..f1c9d0d0f77 100644
--- a/app/controllers/projects/services_controller.rb
+++ b/app/controllers/projects/services_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Projects::ServicesController < Projects::ApplicationController
include ServiceParams
diff --git a/app/controllers/projects/settings/ci_cd_controller.rb b/app/controllers/projects/settings/ci_cd_controller.rb
index 322ec096ffb..a2d1b7866c2 100644
--- a/app/controllers/projects/settings/ci_cd_controller.rb
+++ b/app/controllers/projects/settings/ci_cd_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Projects
module Settings
class CiCdController < Projects::ApplicationController
diff --git a/app/controllers/projects/settings/integrations_controller.rb b/app/controllers/projects/settings/integrations_controller.rb
index d9fecfecc40..388fcb32c35 100644
--- a/app/controllers/projects/settings/integrations_controller.rb
+++ b/app/controllers/projects/settings/integrations_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Projects
module Settings
class IntegrationsController < Projects::ApplicationController
diff --git a/app/controllers/projects/settings/repository_controller.rb b/app/controllers/projects/settings/repository_controller.rb
index ccd481b4dbd..6d83d24cdb8 100644
--- a/app/controllers/projects/settings/repository_controller.rb
+++ b/app/controllers/projects/settings/repository_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Projects
module Settings
class RepositoryController < Projects::ApplicationController
@@ -12,10 +14,10 @@ module Projects
@new_deploy_token = DeployTokens::CreateService.new(@project, current_user, deploy_token_params).execute
if @new_deploy_token.persisted?
- flash.now[:notice] = s_('DeployTokens|Your new project deploy token has been created.')
+ flash[:notice] = s_('DeployTokens|Your new project deploy token has been created.')
end
- render_show
+ redirect_to action: :show
end
private
diff --git a/app/controllers/projects/snippets_controller.rb b/app/controllers/projects/snippets_controller.rb
index 7c03d8ce827..a44acb12bdf 100644
--- a/app/controllers/projects/snippets_controller.rb
+++ b/app/controllers/projects/snippets_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Projects::SnippetsController < Projects::ApplicationController
include RendersNotes
include ToggleAwardEmoji
diff --git a/app/controllers/projects/tags_controller.rb b/app/controllers/projects/tags_controller.rb
index 74bba97987f..c8442ff3592 100644
--- a/app/controllers/projects/tags_controller.rb
+++ b/app/controllers/projects/tags_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Projects::TagsController < Projects::ApplicationController
include SortingHelper
diff --git a/app/controllers/projects/templates_controller.rb b/app/controllers/projects/templates_controller.rb
index 52d6fb82093..7ceea4e5b96 100644
--- a/app/controllers/projects/templates_controller.rb
+++ b/app/controllers/projects/templates_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Projects::TemplatesController < Projects::ApplicationController
before_action :authenticate_user!, :get_template_class
diff --git a/app/controllers/projects/todos_controller.rb b/app/controllers/projects/todos_controller.rb
index 93fb9da6510..0b11ee9edc0 100644
--- a/app/controllers/projects/todos_controller.rb
+++ b/app/controllers/projects/todos_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Projects::TodosController < Projects::ApplicationController
include Gitlab::Utils::StrongMemoize
include TodosActions
diff --git a/app/controllers/projects/tree_controller.rb b/app/controllers/projects/tree_controller.rb
index ee9b5458282..3fe300dcfc0 100644
--- a/app/controllers/projects/tree_controller.rb
+++ b/app/controllers/projects/tree_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
# Controller for viewing a repository's file structure
class Projects::TreeController < Projects::ApplicationController
include ExtractsPath
diff --git a/app/controllers/projects/triggers_controller.rb b/app/controllers/projects/triggers_controller.rb
index cb12b707087..f5fdfb8accc 100644
--- a/app/controllers/projects/triggers_controller.rb
+++ b/app/controllers/projects/triggers_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Projects::TriggersController < Projects::ApplicationController
before_action :authorize_admin_build!
before_action :authorize_manage_trigger!, except: [:index, :create]
diff --git a/app/controllers/projects/uploads_controller.rb b/app/controllers/projects/uploads_controller.rb
index 7a85046164c..4ffcc2ac805 100644
--- a/app/controllers/projects/uploads_controller.rb
+++ b/app/controllers/projects/uploads_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Projects::UploadsController < Projects::ApplicationController
include UploadsActions
include WorkhorseRequest
diff --git a/app/controllers/projects/variables_controller.rb b/app/controllers/projects/variables_controller.rb
index bf09ea7e4d8..bb658bfcc19 100644
--- a/app/controllers/projects/variables_controller.rb
+++ b/app/controllers/projects/variables_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Projects::VariablesController < Projects::ApplicationController
before_action :authorize_admin_build!
diff --git a/app/controllers/projects/wikis_controller.rb b/app/controllers/projects/wikis_controller.rb
index da7aeb26a75..8c6d87a421f 100644
--- a/app/controllers/projects/wikis_controller.rb
+++ b/app/controllers/projects/wikis_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Projects::WikisController < Projects::ApplicationController
include PreviewMarkdown
include Gitlab::Utils::StrongMemoize
diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb
index e2f9d501c4b..7352c5e9bec 100644
--- a/app/controllers/projects_controller.rb
+++ b/app/controllers/projects_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class ProjectsController < Projects::ApplicationController
include API::Helpers::RelatedResourcesHelpers
include IssuableCollections
@@ -196,7 +198,7 @@ class ProjectsController < Projects::ApplicationController
def download_export
if @project.export_file_exists?
- send_upload(@project.export_file)
+ send_upload(@project.export_file, attachment: @project.export_file.filename)
else
redirect_to(
edit_project_path(@project, anchor: 'js-export-project'),
diff --git a/app/controllers/registrations_controller.rb b/app/controllers/registrations_controller.rb
index e6d6965036e..8b8d87524a8 100644
--- a/app/controllers/registrations_controller.rb
+++ b/app/controllers/registrations_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class RegistrationsController < Devise::RegistrationsController
include Recaptcha::Verify
include AcceptsPendingInvitations
diff --git a/app/controllers/root_controller.rb b/app/controllers/root_controller.rb
index 651b82f04f4..ebf70f25bda 100644
--- a/app/controllers/root_controller.rb
+++ b/app/controllers/root_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
# RootController
#
# This controller exists solely to handle requests to `root_url`. When a user is
diff --git a/app/controllers/search_controller.rb b/app/controllers/search_controller.rb
index a928758f325..1b22907c10f 100644
--- a/app/controllers/search_controller.rb
+++ b/app/controllers/search_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class SearchController < ApplicationController
include ControllerWithCrossProjectAccessCheck
include SearchHelper
diff --git a/app/controllers/sent_notifications_controller.rb b/app/controllers/sent_notifications_controller.rb
index 93a71103a09..2b76921ebd8 100644
--- a/app/controllers/sent_notifications_controller.rb
+++ b/app/controllers/sent_notifications_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class SentNotificationsController < ApplicationController
skip_before_action :authenticate_user!
diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb
index 9f2e66dea90..643eb75c83c 100644
--- a/app/controllers/sessions_controller.rb
+++ b/app/controllers/sessions_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class SessionsController < Devise::SessionsController
include InternalRedirect
include AuthenticatesWithTwoFactor
diff --git a/app/controllers/sherlock/application_controller.rb b/app/controllers/sherlock/application_controller.rb
index 6bdd3568a78..c048254d348 100644
--- a/app/controllers/sherlock/application_controller.rb
+++ b/app/controllers/sherlock/application_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Sherlock
class ApplicationController < ::ApplicationController
before_action :find_transaction
diff --git a/app/controllers/sherlock/file_samples_controller.rb b/app/controllers/sherlock/file_samples_controller.rb
index 0c3bc100106..900446bb75a 100644
--- a/app/controllers/sherlock/file_samples_controller.rb
+++ b/app/controllers/sherlock/file_samples_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Sherlock
class FileSamplesController < Sherlock::ApplicationController
def show
diff --git a/app/controllers/sherlock/queries_controller.rb b/app/controllers/sherlock/queries_controller.rb
index 63b26aab1a4..49a25c682b5 100644
--- a/app/controllers/sherlock/queries_controller.rb
+++ b/app/controllers/sherlock/queries_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Sherlock
class QueriesController < Sherlock::ApplicationController
def show
diff --git a/app/controllers/sherlock/transactions_controller.rb b/app/controllers/sherlock/transactions_controller.rb
index ae4953c3259..46e382e594e 100644
--- a/app/controllers/sherlock/transactions_controller.rb
+++ b/app/controllers/sherlock/transactions_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Sherlock
class TransactionsController < Sherlock::ApplicationController
def index
diff --git a/app/controllers/snippets/notes_controller.rb b/app/controllers/snippets/notes_controller.rb
index e992afc0026..091bcb1253d 100644
--- a/app/controllers/snippets/notes_controller.rb
+++ b/app/controllers/snippets/notes_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class Snippets::NotesController < ApplicationController
include NotesActions
include ToggleAwardEmoji
diff --git a/app/controllers/snippets_controller.rb b/app/controllers/snippets_controller.rb
index 19d865900e9..694c3a59e2b 100644
--- a/app/controllers/snippets_controller.rb
+++ b/app/controllers/snippets_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class SnippetsController < ApplicationController
include RendersNotes
include ToggleAwardEmoji
diff --git a/app/controllers/uploads_controller.rb b/app/controllers/uploads_controller.rb
index 3d227b0a955..fa5d84633b5 100644
--- a/app/controllers/uploads_controller.rb
+++ b/app/controllers/uploads_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class UploadsController < ApplicationController
include UploadsActions
diff --git a/app/controllers/user_callouts_controller.rb b/app/controllers/user_callouts_controller.rb
index b8d2deba93b..ebf1dd8ca02 100644
--- a/app/controllers/user_callouts_controller.rb
+++ b/app/controllers/user_callouts_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class UserCalloutsController < ApplicationController
def create
if ensure_callout.persisted?
diff --git a/app/controllers/users/terms_controller.rb b/app/controllers/users/terms_controller.rb
index 1b1560a2a00..3c16d934b4d 100644
--- a/app/controllers/users/terms_controller.rb
+++ b/app/controllers/users/terms_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Users
class TermsController < ApplicationController
include InternalRedirect
diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb
index 2f65f4a7403..e509098d778 100644
--- a/app/controllers/users_controller.rb
+++ b/app/controllers/users_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class UsersController < ApplicationController
include RoutableActions
include RendersMemberAccess
diff --git a/app/finders/admin/runners_finder.rb b/app/finders/admin/runners_finder.rb
index 3c2d7ee7d76..fbb1cfc5c66 100644
--- a/app/finders/admin/runners_finder.rb
+++ b/app/finders/admin/runners_finder.rb
@@ -10,6 +10,7 @@ class Admin::RunnersFinder < UnionFinder
def execute
search!
filter_by_status!
+ filter_by_runner_type!
sort!
paginate!
@@ -36,10 +37,11 @@ class Admin::RunnersFinder < UnionFinder
end
def filter_by_status!
- status = @params[:status_status]
- if status.present? && Ci::Runner::AVAILABLE_STATUSES.include?(status)
- @runners = @runners.public_send(status) # rubocop:disable GitlabSecurity/PublicSend
- end
+ filter_by!(:status_status, Ci::Runner::AVAILABLE_STATUSES)
+ end
+
+ def filter_by_runner_type!
+ filter_by!(:type_type, Ci::Runner::AVAILABLE_TYPES)
end
def sort!
@@ -49,4 +51,12 @@ class Admin::RunnersFinder < UnionFinder
def paginate!
@runners = @runners.page(@params[:page]).per(NUMBER_OF_RUNNERS_PER_PAGE)
end
+
+ def filter_by!(scope_name, available_scopes)
+ scope = @params[scope_name]
+
+ if scope.present? && available_scopes.include?(scope)
+ @runners = @runners.public_send(scope) # rubocop:disable GitlabSecurity/PublicSend
+ end
+ end
end
diff --git a/app/finders/group_labels_finder.rb b/app/finders/group_labels_finder.rb
new file mode 100644
index 00000000000..903023033ed
--- /dev/null
+++ b/app/finders/group_labels_finder.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+class GroupLabelsFinder
+ attr_reader :group, :params
+
+ def initialize(group, params = {})
+ @group = group
+ @params = params
+ end
+
+ def execute
+ group.labels
+ .optionally_search(params[:search])
+ .order_by(params[:sort])
+ .page(params[:page])
+ end
+end
diff --git a/app/finders/members_finder.rb b/app/finders/members_finder.rb
index 48777838d60..f90a7868102 100644
--- a/app/finders/members_finder.rb
+++ b/app/finders/members_finder.rb
@@ -18,7 +18,7 @@ class MembersFinder
group_members = GroupMembersFinder.new(group).execute(include_descendants: include_descendants) # rubocop: disable CodeReuse/Finder
group_members = group_members.non_invite
- union = Gitlab::SQL::Union.new([project_members, group_members], remove_duplicates: false)
+ union = Gitlab::SQL::Union.new([project_members, group_members], remove_duplicates: false) # rubocop: disable Gitlab/Union
sql = distinct_on(union)
diff --git a/app/finders/snippets_finder.rb b/app/finders/snippets_finder.rb
index 715dffb972f..3528e4228b2 100644
--- a/app/finders/snippets_finder.rb
+++ b/app/finders/snippets_finder.rb
@@ -89,9 +89,7 @@ class SnippetsFinder < UnionFinder
# We use a UNION here instead of OR clauses since this results in better
# performance.
- union = Gitlab::SQL::Union.new([authorized_projects.select('projects.id'), visible_projects.select('projects.id')])
-
- Project.from("(#{union.to_sql}) AS #{Project.table_name}")
+ Project.from_union([authorized_projects, visible_projects])
end
# rubocop: enable CodeReuse/ActiveRecord
diff --git a/app/finders/todos_finder.rb b/app/finders/todos_finder.rb
index 0d9f16fdce7..74baf79e4f2 100644
--- a/app/finders/todos_finder.rb
+++ b/app/finders/todos_finder.rb
@@ -164,16 +164,13 @@ class TodosFinder
# rubocop: disable CodeReuse/ActiveRecord
def by_group(items)
- if group?
- groups = group.self_and_descendants
- project_todos = items.where(project_id: Project.where(group: groups).select(:id))
- group_todos = items.where(group_id: groups.select(:id))
+ return items unless group?
- union = Gitlab::SQL::Union.new([project_todos, group_todos])
- items = Todo.from("(#{union.to_sql}) #{Todo.table_name}")
- end
+ groups = group.self_and_descendants
+ project_todos = items.where(project_id: Project.where(group: groups).select(:id))
+ group_todos = items.where(group_id: groups.select(:id))
- items
+ Todo.from_union([project_todos, group_todos])
end
# rubocop: enable CodeReuse/ActiveRecord
diff --git a/app/finders/union_finder.rb b/app/finders/union_finder.rb
index 798c3eba0f3..c3b02f7e52f 100644
--- a/app/finders/union_finder.rb
+++ b/app/finders/union_finder.rb
@@ -1,15 +1,15 @@
# frozen_string_literal: true
class UnionFinder
- # rubocop: disable CodeReuse/ActiveRecord
def find_union(segments, klass)
- if segments.length > 1
- union = Gitlab::SQL::Union.new(segments.map { |s| s.select(:id) })
+ unless klass < FromUnion
+ raise TypeError, "#{klass.inspect} must include the FromUnion module"
+ end
- klass.where("#{klass.table_name}.id IN (#{union.to_sql})")
+ if segments.length > 1
+ klass.from_union(segments)
else
segments.first
end
end
- # rubocop: enable CodeReuse/ActiveRecord
end
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index bb401b03709..32fc8e5e9ce 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -7,13 +7,21 @@ module ApplicationHelper
# See https://docs.gitlab.com/ee/development/ee_features.html#code-in-app-views
# rubocop: disable CodeReuse/ActiveRecord
def render_if_exists(partial, locals = {})
- render(partial, locals) if lookup_context.exists?(partial, [], true)
+ render(partial, locals) if partial_exists?(partial)
+ end
+
+ def partial_exists?(partial)
+ lookup_context.exists?(partial, [], true)
+ end
+
+ def template_exists?(template)
+ lookup_context.exists?(template, [], false)
end
# rubocop: enable CodeReuse/ActiveRecord
# Check if a particular controller is the current one
#
- # args - One or more controller names to check
+ # args - One or more controller names to check (using path notation when inside namespaces)
#
# Examples
#
@@ -21,6 +29,11 @@ module ApplicationHelper
# current_controller?(:tree) # => true
# current_controller?(:commits) # => false
# current_controller?(:commits, :tree) # => true
+ #
+ # # On Admin::ApplicationController
+ # current_controller?(:application) # => true
+ # current_controller?('admin/application') # => true
+ # current_controller?('gitlab/application') # => false
def current_controller?(*args)
args.any? do |v|
v.to_s.downcase == controller.controller_name || v.to_s.downcase == controller.controller_path
diff --git a/app/helpers/application_settings_helper.rb b/app/helpers/application_settings_helper.rb
index 3ebf0162cb6..c9a5431d18e 100644
--- a/app/helpers/application_settings_helper.rb
+++ b/app/helpers/application_settings_helper.rb
@@ -108,10 +108,6 @@ module ApplicationSettingsHelper
options_for_select(options, selected)
end
- def sidekiq_queue_options_for_select
- options_for_select(Sidekiq::Queue.all.map(&:name), @application_setting.sidekiq_throttling_queues)
- end
-
def circuitbreaker_failure_count_help_text
health_link = link_to(s_('AdminHealthPageLink|health page'), admin_health_check_path)
api_link = link_to(s_('CircuitBreakerApiLink|circuitbreaker api'), help_page_path("api/repository_storage_health"))
@@ -234,9 +230,6 @@ module ApplicationSettingsHelper
:session_expire_delay,
:shared_runners_enabled,
:shared_runners_text,
- :sidekiq_throttling_enabled,
- :sidekiq_throttling_factor,
- :sidekiq_throttling_queues,
:sign_in_text,
:signup_enabled,
:terminal_max_session_time,
@@ -264,4 +257,8 @@ module ApplicationSettingsHelper
:web_ide_clientside_preview_enabled
]
end
+
+ def expanded_by_default?
+ Rails.env.test?
+ end
end
diff --git a/app/helpers/avatars_helper.rb b/app/helpers/avatars_helper.rb
index 321811a3ca3..7fc4c1a023f 100644
--- a/app/helpers/avatars_helper.rb
+++ b/app/helpers/avatars_helper.rb
@@ -1,12 +1,12 @@
# frozen_string_literal: true
module AvatarsHelper
- def project_icon(project_id, options = {})
- source_icon(Project, project_id, options)
+ def project_icon(project, options = {})
+ source_icon(project, options)
end
- def group_icon(group_id, options = {})
- source_icon(Group, group_id, options)
+ def group_icon(group, options = {})
+ source_icon(group, options)
end
# Takes both user and email and returns the avatar_icon by
@@ -110,16 +110,11 @@ module AvatarsHelper
private
- def source_icon(klass, source_id, options = {})
- source =
- if source_id.respond_to?(:avatar_url)
- source_id
- else
- klass.find_by_full_path(source_id)
- end
+ def source_icon(source, options = {})
+ avatar_url = source.try(:avatar_url)
- if source.avatar_url
- image_tag source.avatar_url, options
+ if avatar_url
+ image_tag avatar_url, options
else
source_identicon(source, options)
end
diff --git a/app/helpers/ci_status_helper.rb b/app/helpers/ci_status_helper.rb
index f8d36dce45d..136772e1ec3 100644
--- a/app/helpers/ci_status_helper.rb
+++ b/app/helpers/ci_status_helper.rb
@@ -123,11 +123,6 @@ module CiStatusHelper
render_status_with_link('pipeline', pipeline.status, path, tooltip_placement: tooltip_placement)
end
- def no_runners_for_project?(project)
- project.runners.blank? &&
- Ci::Runner.instance_type.blank?
- end
-
def render_status_with_link(type, status, path = nil, tooltip_placement: 'left', cssclass: '', container: 'body', icon_size: 16)
klass = "ci-status-link ci-status-icon-#{status.dasherize} #{cssclass}"
title = "#{type.titleize}: #{ci_label_for_status(status)}"
diff --git a/app/helpers/services_helper.rb b/app/helpers/services_helper.rb
index 8b554e1aaa9..d4b50b7ecfb 100644
--- a/app/helpers/services_helper.rb
+++ b/app/helpers/services_helper.rb
@@ -32,7 +32,7 @@ module ServicesHelper
end
def service_save_button(service)
- button_tag(class: 'btn btn-save', type: 'submit', disabled: service.deprecated?) do
+ button_tag(class: 'btn btn-success', type: 'submit', disabled: service.deprecated?) do
icon('spinner spin', class: 'hidden js-btn-spinner') +
content_tag(:span, 'Save changes', class: 'js-btn-label')
end
diff --git a/app/helpers/sorting_helper.rb b/app/helpers/sorting_helper.rb
index 0c59bdd6abb..53bd43d4861 100644
--- a/app/helpers/sorting_helper.rb
+++ b/app/helpers/sorting_helper.rb
@@ -35,7 +35,8 @@ module SortingHelper
sort_value_name => sort_title_name,
sort_value_oldest_activity => sort_title_oldest_activity,
sort_value_oldest_created => sort_title_oldest_created,
- sort_value_recently_created => sort_title_recently_created
+ sort_value_recently_created => sort_title_recently_created,
+ sort_value_most_stars => sort_title_most_stars
}
if current_controller?('admin/projects')
@@ -246,6 +247,10 @@ module SortingHelper
s_('SortOptions|Last Contact')
end
+ def sort_title_most_stars
+ s_('SortOptions|Most stars')
+ end
+
# Values.
def sort_value_access_level_asc
'access_level_asc'
@@ -370,4 +375,8 @@ module SortingHelper
def sort_value_contacted_date
'contacted_asc'
end
+
+ def sort_value_most_stars
+ 'stars_desc'
+ end
end
diff --git a/app/helpers/tab_helper.rb b/app/helpers/tab_helper.rb
index e310fda51d7..d91f0f78db7 100644
--- a/app/helpers/tab_helper.rb
+++ b/app/helpers/tab_helper.rb
@@ -8,7 +8,7 @@ module TabHelper
# element is the value passed to the block.
#
# options - The options hash used to determine if the element is "active" (default: {})
- # :controller - One or more controller names to check (optional).
+ # :controller - One or more controller names to check, use path notation when namespaced (optional).
# :action - One or more action names to check (optional).
# :path - A shorthand path, such as 'dashboard#index', to check (optional).
# :html_options - Extra options to be passed to the list element (optional).
@@ -42,6 +42,20 @@ module TabHelper
# nav_link(controller: :tree, html_options: {class: 'home'}) { "Hello" }
# # => '<li class="home active">Hello</li>'
#
+ # # For namespaced controllers like Admin::AppearancesController#show
+ #
+ # # Controller and namespace matches
+ # nav_link(controller: 'admin/appearances') { "Hello" }
+ # # => '<li class="active">Hello</li>'
+ #
+ # # Controller and namespace matches but action doesn't
+ # nav_link(controller: 'admin/appearances', action: :edit) { "Hello" }
+ # # => '<li>Hello</li>'
+ #
+ # # Shorthand path with namespace
+ # nav_link(path: 'admin/appearances#show') { "Hello"}
+ # # => '<li class="active">Hello</li>'
+ #
# Returns a list item element String
def nav_link(options = {}, &block)
klass = active_nav_link?(options) ? 'active' : ''
diff --git a/app/mailers/previews/notify_preview.rb b/app/mailers/previews/notify_preview.rb
index c133f4e6dbb..2f5b5483e9d 100644
--- a/app/mailers/previews/notify_preview.rb
+++ b/app/mailers/previews/notify_preview.rb
@@ -9,7 +9,7 @@ class NotifyPreview < ActionMailer::Preview
In this notification email, we expect to see:
- The note contents (that's what you're looking at)
- - A link to view this note on Gitlab
+ - A link to view this note on GitLab
- An explanation for why the user is receiving this notification
MD
@@ -26,7 +26,7 @@ class NotifyPreview < ActionMailer::Preview
- A line saying who started this discussion
- The note contents (that's what you're looking at)
- - A link to view this discussion on Gitlab
+ - A link to view this discussion on GitLab
- An explanation for why the user is receiving this notification
MD
@@ -44,7 +44,7 @@ class NotifyPreview < ActionMailer::Preview
- A line saying who started this discussion and on what file
- The diff
- The note contents (that's what you're looking at)
- - A link to view this discussion on Gitlab
+ - A link to view this discussion on GitLab
- An explanation for why the user is receiving this notification
MD
diff --git a/app/models/ability.rb b/app/models/ability.rb
index a853106e5bd..1466407d0d1 100644
--- a/app/models/ability.rb
+++ b/app/models/ability.rb
@@ -74,7 +74,7 @@ class Ability
end
def policy_for(user, subject = :global)
- cache = RequestStore.active? ? RequestStore : {}
+ cache = Gitlab::SafeRequestStore.active? ? Gitlab::SafeRequestStore : {}
DeclarativePolicy.policy_for(user, subject, cache: cache)
end
diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb
index 645adddb000..5f835a8da75 100644
--- a/app/models/application_setting.rb
+++ b/app/models/application_setting.rb
@@ -26,7 +26,6 @@ class ApplicationSetting < ActiveRecord::Base
serialize :domain_whitelist, Array # rubocop:disable Cop/ActiveRecordSerialize
serialize :domain_blacklist, Array # rubocop:disable Cop/ActiveRecordSerialize
serialize :repository_storages # rubocop:disable Cop/ActiveRecordSerialize
- serialize :sidekiq_throttling_queues, Array # rubocop:disable Cop/ActiveRecordSerialize
cache_markdown_field :sign_in_text
cache_markdown_field :help_page_text
@@ -131,15 +130,6 @@ class ApplicationSetting < ActiveRecord::Base
presence: { message: 'Domain blacklist cannot be empty if Blacklist is enabled.' },
if: :domain_blacklist_enabled?
- validates :sidekiq_throttling_factor,
- numericality: { greater_than: 0, less_than: 1 },
- presence: { message: 'Throttling factor cannot be empty if Sidekiq Throttling is enabled.' },
- if: :sidekiq_throttling_enabled?
-
- validates :sidekiq_throttling_queues,
- presence: { message: 'Queues to throttle cannot be empty if Sidekiq Throttling is enabled.' },
- if: :sidekiq_throttling_enabled?
-
validates :housekeeping_incremental_repack_period,
presence: true,
numericality: { only_integer: true, greater_than: 0 }
@@ -282,7 +272,6 @@ class ApplicationSetting < ActiveRecord::Base
send_user_confirmation_email: false,
shared_runners_enabled: Settings.gitlab_ci['shared_runners_enabled'],
shared_runners_text: nil,
- sidekiq_throttling_enabled: false,
sign_in_text: nil,
signup_enabled: Settings.gitlab['signup_enabled'],
terminal_max_session_time: 0,
@@ -328,10 +317,6 @@ class ApplicationSetting < ActiveRecord::Base
::Gitlab::Database.cached_column_exists?(:application_settings, :help_page_support_url)
end
- def sidekiq_throttling_column_exists?
- ::Gitlab::Database.cached_column_exists?(:application_settings, :sidekiq_throttling_enabled)
- end
-
def disabled_oauth_sign_in_sources=(sources)
sources = (sources || []).map(&:to_s) & Devise.omniauth_providers.map(&:to_s)
super(sources)
@@ -411,12 +396,6 @@ class ApplicationSetting < ActiveRecord::Base
ensure_health_check_access_token!
end
- def sidekiq_throttling_enabled?
- return false unless sidekiq_throttling_column_exists?
-
- sidekiq_throttling_enabled
- end
-
def usage_ping_can_be_configured?
Settings.gitlab.usage_ping_enabled
end
diff --git a/app/models/badge.rb b/app/models/badge.rb
index 7e3b6b659e4..f016654206b 100644
--- a/app/models/badge.rb
+++ b/app/models/badge.rb
@@ -1,6 +1,8 @@
# frozen_string_literal: true
class Badge < ActiveRecord::Base
+ include FromUnion
+
# This structure sets the placeholders that the urls
# can have. This hash also sets which action to ask when
# the placeholder is found.
diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb
index ab738c2fad8..3dadb95443a 100644
--- a/app/models/ci/build.rb
+++ b/app/models/ci/build.rb
@@ -68,8 +68,12 @@ module Ci
'', Ci::JobArtifact.select(1).where('ci_builds.id = ci_job_artifacts.job_id').archive)
end
+ scope :with_existing_job_artifacts, ->(query) do
+ where('EXISTS (?)', ::Ci::JobArtifact.select(1).where('ci_builds.id = ci_job_artifacts.job_id').merge(query))
+ end
+
scope :with_archived_trace, ->() do
- where('EXISTS (?)', Ci::JobArtifact.select(1).where('ci_builds.id = ci_job_artifacts.job_id').trace)
+ with_existing_job_artifacts(Ci::JobArtifact.trace)
end
scope :without_archived_trace, ->() do
@@ -77,10 +81,12 @@ module Ci
end
scope :with_test_reports, ->() do
- includes(:job_artifacts_junit) # Prevent N+1 problem when iterating each ci_job_artifact row
- .where('EXISTS (?)', Ci::JobArtifact.select(1).where('ci_builds.id = ci_job_artifacts.job_id').test_reports)
+ with_existing_job_artifacts(Ci::JobArtifact.test_reports)
+ .eager_load_job_artifacts
end
+ scope :eager_load_job_artifacts, -> { includes(:job_artifacts) }
+
scope :with_artifacts_stored_locally, -> { with_artifacts_archive.where(artifacts_file_store: [nil, LegacyArtifactUploader::Store::LOCAL]) }
scope :with_archived_trace_stored_locally, -> { with_archived_trace.where(artifacts_file_store: [nil, LegacyArtifactUploader::Store::LOCAL]) }
scope :with_artifacts_not_expired, ->() { with_artifacts_archive.where('artifacts_expire_at IS NULL OR artifacts_expire_at > ?', Time.now) }
@@ -404,8 +410,8 @@ module Ci
trace.exist?
end
- def has_test_reports?
- job_artifacts.test_reports.any?
+ def has_job_artifacts?
+ job_artifacts.any?
end
def has_old_trace?
@@ -469,28 +475,23 @@ module Ci
end
end
- def erase_artifacts!
- remove_artifacts_file!
- remove_artifacts_metadata!
- save
- end
-
- def erase_test_reports!
- # TODO: Use fast_destroy_all in the context of https://gitlab.com/gitlab-org/gitlab-ce/issues/35240
- job_artifacts_junit&.destroy
+ # and use that for `ExpireBuildInstanceArtifactsWorker`?
+ def erase_erasable_artifacts!
+ job_artifacts.erasable.destroy_all # rubocop: disable DestroyAll
+ erase_old_artifacts!
end
def erase(opts = {})
return false unless erasable?
- erase_artifacts!
- erase_test_reports!
+ job_artifacts.destroy_all # rubocop: disable DestroyAll
+ erase_old_artifacts!
erase_trace!
update_erased!(opts[:erased_by])
end
def erasable?
- complete? && (artifacts? || has_test_reports? || has_trace?)
+ complete? && (artifacts? || has_job_artifacts? || has_trace?)
end
def erased?
@@ -648,22 +649,57 @@ module Ci
def collect_test_reports!(test_reports)
test_reports.get_suite(group_name).tap do |test_suite|
- each_test_report do |file_type, blob|
- Gitlab::Ci::Parsers.fabricate!(file_type).parse!(blob, test_suite)
+ each_report(Ci::JobArtifact::TEST_REPORT_FILE_TYPES) do |file_type, blob|
+ Gitlab::Ci::Parsers::Test.fabricate!(file_type).parse!(blob, test_suite)
end
end
end
+ # Virtual deployment status depending on the environment status.
+ def deployment_status
+ return nil unless starts_environment?
+
+ if success?
+ return successful_deployment_status
+ elsif complete? && !success?
+ return :failed
+ end
+
+ :creating
+ end
+
private
- def each_test_report
- Ci::JobArtifact::TEST_REPORT_FILE_TYPES.each do |file_type|
- public_send("job_artifacts_#{file_type}").each_blob do |blob| # rubocop:disable GitlabSecurity/PublicSend
- yield file_type, blob
+ def erase_old_artifacts!
+ # TODO: To be removed once we get rid of
+ remove_artifacts_file!
+ remove_artifacts_metadata!
+ save
+ end
+
+ def successful_deployment_status
+ if success? && last_deployment&.last?
+ return :last
+ elsif success? && last_deployment.present?
+ return :out_of_date
+ end
+
+ :creating
+ end
+
+ def each_report(report_types)
+ job_artifacts_for_types(report_types).each do |report_artifact|
+ report_artifact.each_blob do |blob|
+ yield report_artifact.file_type, blob
end
end
end
+ def job_artifacts_for_types(report_types)
+ # Use select to leverage cached associations and avoid N+1 queries
+ job_artifacts.select { |artifact| artifact.file_type.in?(report_types) }
+ end
+
def update_artifacts_size
self.artifacts_size = legacy_artifacts_file&.size
end
diff --git a/app/models/ci/job_artifact.rb b/app/models/ci/job_artifact.rb
index 93fc1b145b2..259d85e2fe5 100644
--- a/app/models/ci/job_artifact.rb
+++ b/app/models/ci/job_artifact.rb
@@ -9,8 +9,28 @@ module Ci
NotSupportedAdapterError = Class.new(StandardError)
TEST_REPORT_FILE_TYPES = %w[junit].freeze
- DEFAULT_FILE_NAMES = { junit: 'junit.xml' }.freeze
- TYPE_AND_FORMAT_PAIRS = { archive: :zip, metadata: :gzip, trace: :raw, junit: :gzip }.freeze
+ NON_ERASABLE_FILE_TYPES = %w[trace].freeze
+ DEFAULT_FILE_NAMES = {
+ archive: nil,
+ metadata: nil,
+ trace: nil,
+ junit: 'junit.xml',
+ sast: 'gl-sast-report.json',
+ dependency_scanning: 'gl-dependency-scanning-report.json',
+ container_scanning: 'gl-container-scanning-report.json',
+ dast: 'gl-dast-report.json'
+ }.freeze
+
+ TYPE_AND_FORMAT_PAIRS = {
+ archive: :zip,
+ metadata: :gzip,
+ trace: :raw,
+ junit: :gzip,
+ sast: :gzip,
+ dependency_scanning: :gzip,
+ container_scanning: :gzip,
+ dast: :gzip
+ }.freeze
belongs_to :project
belongs_to :job, class_name: "Ci::Build", foreign_key: :job_id
@@ -27,8 +47,18 @@ module Ci
scope :with_files_stored_locally, -> { where(file_store: [nil, ::JobArtifactUploader::Store::LOCAL]) }
+ scope :with_file_types, -> (file_types) do
+ types = self.file_types.select { |file_type| file_types.include?(file_type) }.values
+
+ where(file_type: types)
+ end
+
scope :test_reports, -> do
- types = self.file_types.select { |file_type| TEST_REPORT_FILE_TYPES.include?(file_type) }.values
+ with_file_types(TEST_REPORT_FILE_TYPES)
+ end
+
+ scope :erasable, -> do
+ types = self.file_types.reject { |file_type| NON_ERASABLE_FILE_TYPES.include?(file_type) }.values
where(file_type: types)
end
@@ -39,7 +69,11 @@ module Ci
archive: 1,
metadata: 2,
trace: 3,
- junit: 4
+ junit: 4,
+ sast: 5, ## EE-specific
+ dependency_scanning: 6, ## EE-specific
+ container_scanning: 7, ## EE-specific
+ dast: 8 ## EE-specific
}
enum file_format: {
diff --git a/app/models/ci/runner.rb b/app/models/ci/runner.rb
index eabb41c29d7..31330d0682e 100644
--- a/app/models/ci/runner.rb
+++ b/app/models/ci/runner.rb
@@ -7,13 +7,26 @@ module Ci
include IgnorableColumn
include RedisCacheable
include ChronicDurationAttribute
+ include FromUnion
+
+ enum access_level: {
+ not_protected: 0,
+ ref_protected: 1
+ }
+
+ enum runner_type: {
+ instance_type: 1,
+ group_type: 2,
+ project_type: 3
+ }
RUNNER_QUEUE_EXPIRY_TIME = 60.minutes
ONLINE_CONTACT_TIMEOUT = 1.hour
UPDATE_DB_RUNNER_INFO_EVERY = 40.minutes
- AVAILABLE_TYPES = %w[specific shared].freeze
+ AVAILABLE_TYPES_LEGACY = %w[specific shared].freeze
+ AVAILABLE_TYPES = runner_types.keys.freeze
AVAILABLE_STATUSES = %w[active paused online offline].freeze
- AVAILABLE_SCOPES = (AVAILABLE_TYPES + AVAILABLE_STATUSES).freeze
+ AVAILABLE_SCOPES = (AVAILABLE_TYPES_LEGACY + AVAILABLE_TYPES + AVAILABLE_STATUSES).freeze
FORM_EDITABLE = %i[description tag_list active run_untagged locked access_level maximum_timeout_human_readable].freeze
ignore_column :is_shared
@@ -57,18 +70,26 @@ module Ci
}
scope :owned_or_instance_wide, -> (project_id) do
- union = Gitlab::SQL::Union.new(
- [belonging_to_project(project_id), belonging_to_parent_group_of_project(project_id), instance_type],
+ from_union(
+ [
+ belonging_to_project(project_id),
+ belonging_to_parent_group_of_project(project_id),
+ instance_type
+ ],
remove_duplicates: false
)
- from("(#{union.to_sql}) ci_runners")
end
scope :assignable_for, ->(project) do
# FIXME: That `to_sql` is needed to workaround a weird Rails bug.
# Without that, placeholders would miss one and couldn't match.
+ #
+ # We use "unscoped" here so that any current Ci::Runner filters don't
+ # apply to the inner query, which is not necessary.
+ exclude_runners = unscoped { project.runners.select(:id) }.to_sql
+
where(locked: false)
- .where.not("ci_runners.id IN (#{project.runners.select(:id).to_sql})")
+ .where.not("ci_runners.id IN (#{exclude_runners})")
.project_type
end
@@ -88,17 +109,6 @@ module Ci
after_destroy :cleanup_runner_queue
- enum access_level: {
- not_protected: 0,
- ref_protected: 1
- }
-
- enum runner_type: {
- instance_type: 1,
- group_type: 2,
- project_type: 3
- }
-
cached_attr_reader :version, :revision, :platform, :architecture, :ip_address, :contacted_at
chronic_duration_attr :maximum_timeout_human_readable, :maximum_timeout
diff --git a/app/models/clusters/applications/jupyter.rb b/app/models/clusters/applications/jupyter.rb
index 3d84eeed5a8..7be6a14f585 100644
--- a/app/models/clusters/applications/jupyter.rb
+++ b/app/models/clusters/applications/jupyter.rb
@@ -73,6 +73,11 @@ module Clusters
"clientSecret" => oauth_application.secret,
"callbackUrl" => callback_url
}
+ },
+ "singleuser" => {
+ "extraEnv" => {
+ "GITLAB_CLUSTER_ID" => cluster.id
+ }
}
}
end
diff --git a/app/models/concerns/bulk_member_access_load.rb b/app/models/concerns/bulk_member_access_load.rb
index c4346d5dd17..041ed3755e0 100644
--- a/app/models/concerns/bulk_member_access_load.rb
+++ b/app/models/concerns/bulk_member_access_load.rb
@@ -16,9 +16,9 @@ module BulkMemberAccessLoad
key = max_member_access_for_resource_key(resource_klass, memoization_index)
access = {}
- if RequestStore.active?
- RequestStore.store[key] ||= {}
- access = RequestStore.store[key]
+ if Gitlab::SafeRequestStore.active?
+ Gitlab::SafeRequestStore[key] ||= {}
+ access = Gitlab::SafeRequestStore[key]
end
# Look up only the IDs we need
diff --git a/app/models/concerns/cacheable_attributes.rb b/app/models/concerns/cacheable_attributes.rb
index 62b78c3611c..f8034be8376 100644
--- a/app/models/concerns/cacheable_attributes.rb
+++ b/app/models/concerns/cacheable_attributes.rb
@@ -27,11 +27,7 @@ module CacheableAttributes
end
def cached
- if RequestStore.active?
- RequestStore[:"#{name}_cached_attributes"] ||= retrieve_from_cache
- else
- retrieve_from_cache
- end
+ Gitlab::SafeRequestStore[:"#{name}_cached_attributes"] ||= retrieve_from_cache
end
def retrieve_from_cache
diff --git a/app/models/concerns/from_union.rb b/app/models/concerns/from_union.rb
new file mode 100644
index 00000000000..9b8595b1211
--- /dev/null
+++ b/app/models/concerns/from_union.rb
@@ -0,0 +1,51 @@
+# frozen_string_literal: true
+
+module FromUnion
+ extend ActiveSupport::Concern
+
+ class_methods do
+ # Produces a query that uses a FROM to select data using a UNION.
+ #
+ # Using a FROM for a UNION has in the past lead to better query plans. As
+ # such, we generally recommend this pattern instead of using a WHERE IN.
+ #
+ # Example:
+ # users = User.from_union([User.where(id: 1), User.where(id: 2)])
+ #
+ # This would produce the following SQL query:
+ #
+ # SELECT *
+ # FROM (
+ # SELECT *
+ # FROM users
+ # WHERE id = 1
+ #
+ # UNION
+ #
+ # SELECT *
+ # FROM users
+ # WHERE id = 2
+ # ) users;
+ #
+ # members - An Array of ActiveRecord::Relation objects to use in the UNION.
+ #
+ # remove_duplicates - A boolean indicating if duplicate entries should be
+ # removed. Defaults to true.
+ #
+ # alias_as - The alias to use for the sub query. Defaults to the name of the
+ # table of the current model.
+ # rubocop: disable Gitlab/Union
+ def from_union(members, remove_duplicates: true, alias_as: table_name)
+ union = Gitlab::SQL::Union
+ .new(members, remove_duplicates: remove_duplicates)
+ .to_sql
+
+ # This pattern is necessary as a bug in Rails 4 can cause the use of
+ # `from("string here").includes(:foo)` to break ActiveRecord. This is
+ # fixed in https://github.com/rails/rails/pull/25374, which is released as
+ # part of Rails 5.
+ from([Arel.sql("(#{union}) #{alias_as}")])
+ end
+ # rubocop: enable Gitlab/Union
+ end
+end
diff --git a/app/models/concerns/mentionable.rb b/app/models/concerns/mentionable.rb
index 393607e82c4..298d0d42d90 100644
--- a/app/models/concerns/mentionable.rb
+++ b/app/models/concerns/mentionable.rb
@@ -61,7 +61,7 @@ module Mentionable
cache_key: [self, attr],
author: author,
skip_project_check: skip_project_check?
- )
+ ).merge(mentionable_params)
extractor.analyze(text, options)
end
@@ -86,12 +86,11 @@ module Mentionable
return [] unless matches_cross_reference_regex?
refs = all_references(current_user)
- refs = (refs.issues + refs.merge_requests + refs.commits)
# We're using this method instead of Array diffing because that requires
# both of the object's `hash` values to be the same, which may not be the
# case for otherwise identical Commit objects.
- refs.reject { |ref| ref == local_reference }
+ extracted_mentionables(refs).reject { |ref| ref == local_reference }
end
# Uses regex to quickly determine if mentionables might be referenced
@@ -134,6 +133,10 @@ module Mentionable
private
+ def extracted_mentionables(refs)
+ refs.issues + refs.merge_requests + refs.commits
+ end
+
# Returns a Hash of changed mentionable fields
#
# Preference is given to the `changes` Hash, but falls back to
@@ -161,4 +164,8 @@ module Mentionable
def skip_project_check?
false
end
+
+ def mentionable_params
+ {}
+ end
end
diff --git a/app/models/concerns/mentionable/reference_regexes.rb b/app/models/concerns/mentionable/reference_regexes.rb
index f6fd28bac33..fe8fbb71184 100644
--- a/app/models/concerns/mentionable/reference_regexes.rb
+++ b/app/models/concerns/mentionable/reference_regexes.rb
@@ -5,13 +5,19 @@ module Mentionable
def self.reference_pattern(link_patterns, issue_pattern)
Regexp.union(link_patterns,
issue_pattern,
- Commit.reference_pattern,
- MergeRequest.reference_pattern)
+ *other_patterns)
+ end
+
+ def self.other_patterns
+ [
+ Commit.reference_pattern,
+ MergeRequest.reference_pattern
+ ]
end
DEFAULT_PATTERN = begin
issue_pattern = Issue.reference_pattern
- link_patterns = Regexp.union([Issue, Commit, MergeRequest].map(&:link_reference_pattern))
+ link_patterns = Regexp.union([Issue, Commit, MergeRequest, Epic].map(&:link_reference_pattern).compact)
reference_pattern(link_patterns, issue_pattern)
end
diff --git a/app/models/concerns/protected_ref_access.rb b/app/models/concerns/protected_ref_access.rb
index efa666fb3f2..583751ea6ac 100644
--- a/app/models/concerns/protected_ref_access.rb
+++ b/app/models/concerns/protected_ref_access.rb
@@ -3,18 +3,22 @@
module ProtectedRefAccess
extend ActiveSupport::Concern
- ALLOWED_ACCESS_LEVELS = [
- Gitlab::Access::MAINTAINER,
- Gitlab::Access::DEVELOPER,
- Gitlab::Access::NO_ACCESS
- ].freeze
-
HUMAN_ACCESS_LEVELS = {
Gitlab::Access::MAINTAINER => "Maintainers".freeze,
Gitlab::Access::DEVELOPER => "Developers + Maintainers".freeze,
Gitlab::Access::NO_ACCESS => "No one".freeze
}.freeze
+ class_methods do
+ def allowed_access_levels
+ [
+ Gitlab::Access::MAINTAINER,
+ Gitlab::Access::DEVELOPER,
+ Gitlab::Access::NO_ACCESS
+ ]
+ end
+ end
+
included do
scope :master, -> { maintainer } # @deprecated
scope :maintainer, -> { where(access_level: Gitlab::Access::MAINTAINER) }
@@ -26,7 +30,7 @@ module ProtectedRefAccess
scope :for_group, -> { where.not(group_id: nil) }
validates :access_level, presence: true, if: :role?, inclusion: {
- in: ALLOWED_ACCESS_LEVELS
+ in: self.allowed_access_levels
}
end
diff --git a/app/models/container_repository.rb b/app/models/container_repository.rb
index 93ca3a5daf4..2c08a8e1acf 100644
--- a/app/models/container_repository.rb
+++ b/app/models/container_repository.rb
@@ -8,8 +8,6 @@ class ContainerRepository < ActiveRecord::Base
delegate :client, to: :registry
- before_destroy :delete_tags!
-
# rubocop: disable CodeReuse/ServiceClass
def registry
@registry ||= begin
diff --git a/app/models/dashboard_group_milestone.rb b/app/models/dashboard_group_milestone.rb
index 067e14dda1c..32e8104125c 100644
--- a/app/models/dashboard_group_milestone.rb
+++ b/app/models/dashboard_group_milestone.rb
@@ -13,7 +13,11 @@ class DashboardGroupMilestone < GlobalMilestone
end
def self.build_collection(groups)
- MilestonesFinder.new(group_ids: groups.select(:id)).execute.map { |m| new(m) } # rubocop: disable CodeReuse/Finder
+ Milestone.of_groups(groups.select(:id))
+ .reorder_by_due_date_asc
+ .order_by_name_asc
+ .active
+ .map { |m| new(m) }
end
override :group_milestone?
diff --git a/app/models/deploy_key.rb b/app/models/deploy_key.rb
index fd5d7726fb6..db501b4b506 100644
--- a/app/models/deploy_key.rb
+++ b/app/models/deploy_key.rb
@@ -18,7 +18,7 @@ class DeployKey < Key
end
def orphaned?
- self.deploy_keys_projects.length == 0
+ self.deploy_keys_projects.empty?
end
def almost_orphaned?
diff --git a/app/models/diff_note.rb b/app/models/diff_note.rb
index 716cf6574d3..047d353b4b5 100644
--- a/app/models/diff_note.rb
+++ b/app/models/diff_note.rb
@@ -131,7 +131,7 @@ class DiffNote < Note
# As an extra benefit, the returned `diff_file` already
# has `highlighted_diff_lines` data set from Redis on
# `Diff::FileCollection::MergeRequestDiff`.
- noteable.diffs(paths: original_position.paths, expanded: true).diff_files.first
+ noteable.diffs(original_position.diff_options).diff_files.first
else
original_position.diff_file(self.project.repository)
end
diff --git a/app/models/epic.rb b/app/models/epic.rb
index f027993376c..ccd10593434 100644
--- a/app/models/epic.rb
+++ b/app/models/epic.rb
@@ -3,6 +3,10 @@
# Placeholder class for model that is implemented in EE
# It reserves '&' as a reference prefix, but the table does not exists in CE
class Epic < ActiveRecord::Base
+ def self.link_reference_pattern
+ nil
+ end
+
def self.reference_prefix
'&'
end
diff --git a/app/models/event.rb b/app/models/event.rb
index 041dac6941b..596155a9525 100644
--- a/app/models/event.rb
+++ b/app/models/event.rb
@@ -3,6 +3,7 @@
class Event < ActiveRecord::Base
include Sortable
include IgnorableColumn
+ include FromUnion
default_scope { reorder(nil) }
CREATED = 1
diff --git a/app/models/group.rb b/app/models/group.rb
index 024e77188b8..62af20d2142 100644
--- a/app/models/group.rb
+++ b/app/models/group.rb
@@ -304,14 +304,12 @@ class Group < Namespace
# 3. They belong to a sub-group or project in such sub-group
# 4. They belong to an ancestor group
def direct_and_indirect_users
- union = Gitlab::SQL::Union.new([
+ User.from_union([
User
.where(id: direct_and_indirect_members.select(:user_id))
.reorder(nil),
project_users_with_descendants
])
-
- User.from("(#{union.to_sql}) #{User.table_name}")
end
# Returns all users that are members of projects
diff --git a/app/models/label.rb b/app/models/label.rb
index 8dc7ded53ad..9ef57a05b3e 100644
--- a/app/models/label.rb
+++ b/app/models/label.rb
@@ -7,6 +7,7 @@ class Label < ActiveRecord::Base
include Gitlab::SQL::Pattern
include OptionallySearch
include Sortable
+ include FromUnion
# Represents a "No Label" state used for filtering Issues and Merge
# Requests that have no label assigned.
diff --git a/app/models/legacy_diff_note.rb b/app/models/legacy_diff_note.rb
index 20f9b18e4ca..00dec6bb92b 100644
--- a/app/models/legacy_diff_note.rb
+++ b/app/models/legacy_diff_note.rb
@@ -20,11 +20,7 @@ class LegacyDiffNote < Note
end
def project_repository
- if RequestStore.active?
- RequestStore.fetch("project:#{project_id}:repository") { self.project.repository }
- else
- self.project.repository
- end
+ Gitlab::SafeRequestStore.fetch("project:#{project_id}:repository") { self.project.repository }
end
def diff_file_hash
diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb
index e19bf62dcd0..dd5d494997d 100644
--- a/app/models/merge_request.rb
+++ b/app/models/merge_request.rb
@@ -14,6 +14,7 @@ class MergeRequest < ActiveRecord::Base
include Gitlab::Utils::StrongMemoize
include LabelEventable
include ReactiveCaching
+ include FromUnion
self.reactive_cache_key = ->(model) { [model.project.id, model.iid] }
self.reactive_cache_refresh_interval = 10.minutes
@@ -237,11 +238,10 @@ class MergeRequest < ActiveRecord::Base
def self.in_projects(relation)
# unscoping unnecessary conditions that'll be applied
# when executing `where("merge_requests.id IN (#{union.to_sql})")`
- source = unscoped.where(source_project_id: relation).select(:id)
- target = unscoped.where(target_project_id: relation).select(:id)
- union = Gitlab::SQL::Union.new([source, target])
+ source = unscoped.where(source_project_id: relation)
+ target = unscoped.where(target_project_id: relation)
- where("merge_requests.id IN (#{union.to_sql})") # rubocop:disable GitlabSecurity/SqlInjection
+ from_union([source, target])
end
# This is used after project import, to reset the IDs to the correct
@@ -740,11 +740,8 @@ class MergeRequest < ActiveRecord::Base
# compared to using OR statements. We're using UNION ALL since the queries
# used won't produce any duplicates (e.g. a note for a commit can't also be
# a note for an MR).
- union = Gitlab::SQL::Union
- .new([notes, commit_notes], remove_duplicates: false)
- .to_sql
-
- Note.from("(#{union}) #{Note.table_name}")
+ Note
+ .from_union([notes, commit_notes], remove_duplicates: false)
.includes(:noteable)
end
diff --git a/app/models/milestone.rb b/app/models/milestone.rb
index cb1def1b422..892a680f221 100644
--- a/app/models/milestone.rb
+++ b/app/models/milestone.rb
@@ -46,6 +46,9 @@ class Milestone < ActiveRecord::Base
where(conditions.reduce(:or))
end
+ scope :order_by_name_asc, -> { order(Arel::Nodes::Ascending.new(arel_table[:title].lower)) }
+ scope :reorder_by_due_date_asc, -> { reorder(Gitlab::Database.nulls_last_order('due_date', 'ASC')) }
+
validates :group, presence: true, unless: :project
validates :project, presence: true, unless: :group
@@ -149,7 +152,7 @@ class Milestone < ActiveRecord::Base
sorted =
case method.to_s
when 'due_date_asc'
- reorder(Gitlab::Database.nulls_last_order('due_date', 'ASC'))
+ reorder_by_due_date_asc
when 'due_date_desc'
reorder(Gitlab::Database.nulls_last_order('due_date', 'DESC'))
when 'name_asc'
diff --git a/app/models/namespace.rb b/app/models/namespace.rb
index 76920c3c039..c54be778d1b 100644
--- a/app/models/namespace.rb
+++ b/app/models/namespace.rb
@@ -11,6 +11,7 @@ class Namespace < ActiveRecord::Base
include Gitlab::SQL::Pattern
include IgnorableColumn
include FeatureGate
+ include FromUnion
ignore_column :deleted_at
@@ -147,8 +148,8 @@ class Namespace < ActiveRecord::Base
def find_fork_of(project)
return nil unless project.fork_network
- if RequestStore.active?
- forks_in_namespace = RequestStore.fetch("namespaces:#{id}:forked_projects") do
+ if Gitlab::SafeRequestStore.active?
+ forks_in_namespace = Gitlab::SafeRequestStore.fetch("namespaces:#{id}:forked_projects") do
Hash.new do |found_forks, project|
found_forks[project] = project.fork_network.find_forks_in(projects).first
end
diff --git a/app/models/network/commit.rb b/app/models/network/commit.rb
index 6c5a4c56377..1b2369aab18 100644
--- a/app/models/network/commit.rb
+++ b/app/models/network/commit.rb
@@ -18,7 +18,7 @@ module Network
end
def space
- if @spaces.size > 0
+ if @spaces.present?
@spaces.first
else
0
diff --git a/app/models/network/graph.rb b/app/models/network/graph.rb
index 1431dfefc55..6da3bb7bfb7 100644
--- a/app/models/network/graph.rb
+++ b/app/models/network/graph.rb
@@ -81,7 +81,7 @@ module Network
skip = 0
while offset == -1
tmp_commits = find_commits(skip)
- if tmp_commits.size > 0
+ if tmp_commits.present?
index = tmp_commits.index do |c|
c.id == @commit.id
end
@@ -218,7 +218,7 @@ module Network
def get_space_base(leaves)
space_base = 1
parents = leaves.last.parents(@map)
- if parents.size > 0
+ if parents.present?
if parents.first.space > 0
space_base = parents.first.space
end
diff --git a/app/models/note.rb b/app/models/note.rb
index 4429c1dcb07..bea02d69b65 100644
--- a/app/models/note.rb
+++ b/app/models/note.rb
@@ -17,6 +17,7 @@ class Note < ActiveRecord::Base
include Editable
include Gitlab::SQL::Pattern
include ThrottledTouch
+ include FromUnion
module SpecialRole
FIRST_TIME_CONTRIBUTOR = :first_time_contributor
diff --git a/app/models/project.rb b/app/models/project.rb
index c37915e111f..503fbc30768 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -29,6 +29,7 @@ class Project < ActiveRecord::Base
include BatchDestroyDependentAssociations
include FeatureGate
include OptionallySearch
+ include FromUnion
extend Gitlab::Cache::RequestCache
extend Gitlab::ConfigHelper
@@ -85,7 +86,7 @@ class Project < ActiveRecord::Base
after_create :create_project_feature, unless: :project_feature
after_create -> { SiteStatistic.track(STATISTICS_ATTRIBUTE) }
- before_destroy :untrack_site_statistics
+ before_destroy -> { SiteStatistic.untrack(STATISTICS_ATTRIBUTE) }
after_create :create_ci_cd_settings,
unless: :ci_cd_settings,
@@ -110,7 +111,7 @@ class Project < ActiveRecord::Base
after_create :ensure_storage_path_exists
after_save :ensure_storage_path_exists, if: :namespace_id_changed?
- acts_as_taggable
+ acts_as_ordered_taggable
attr_accessor :old_path_with_namespace
attr_accessor :template_name
@@ -330,7 +331,7 @@ class Project < ActiveRecord::Base
# last_activity_at is throttled every minute, but last_repository_updated_at is updated with every push
scope :sorted_by_activity, -> { reorder("GREATEST(COALESCE(last_activity_at, '1970-01-01'), COALESCE(last_repository_updated_at, '1970-01-01')) DESC") }
- scope :sorted_by_stars, -> { reorder('projects.star_count DESC') }
+ scope :sorted_by_stars, -> { reorder(star_count: :desc) }
scope :in_namespace, ->(namespace_ids) { where(namespace_id: namespace_ids) }
scope :personal, ->(user) { where(namespace_id: user.namespace_id) }
@@ -480,6 +481,8 @@ class Project < ActiveRecord::Base
reorder(last_activity_at: :desc)
when 'latest_activity_asc'
reorder(last_activity_at: :asc)
+ when 'stars_desc'
+ sorted_by_stars
else
order_by(method)
end
@@ -1493,8 +1496,7 @@ class Project < ActiveRecord::Base
end
def all_runners
- union = Gitlab::SQL::Union.new([runners, group_runners, shared_runners])
- Ci::Runner.from("(#{union.to_sql}) ci_runners")
+ Ci::Runner.from_union([runners, group_runners, shared_runners])
end
def active_runners
@@ -2022,12 +2024,10 @@ class Project < ActiveRecord::Base
def badges
return project_badges unless group
- group_badges_rel = GroupBadge.where(group: group.self_and_ancestors)
-
- union = Gitlab::SQL::Union.new([project_badges.select(:id),
- group_badges_rel.select(:id)])
-
- Badge.where("id IN (#{union.to_sql})") # rubocop:disable GitlabSecurity/SqlInjection
+ Badge.from_union([
+ project_badges,
+ GroupBadge.where(group: group.self_and_ancestors)
+ ])
end
def merge_requests_allowing_push_to_user(user)
@@ -2078,12 +2078,6 @@ class Project < ActiveRecord::Base
auto_cancel_pending_pipelines == 'enabled'
end
- # Update the default branch querying the remote to determine its HEAD
- def update_root_ref(remote_name)
- root_ref = repository.find_remote_root_ref(remote_name)
- change_head(root_ref) if root_ref.present? && root_ref != default_branch
- end
-
private
# rubocop: disable CodeReuse/ServiceClass
@@ -2116,11 +2110,6 @@ 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
-
# rubocop: disable CodeReuse/ServiceClass
def execute_rename_repository_hooks!(full_path_before)
# When we import a project overwriting the original project, there
@@ -2272,11 +2261,7 @@ class Project < ActiveRecord::Base
end
end
- if RequestStore.active?
- RequestStore.fetch("project-#{id}:branch-#{branch_name}:user-#{user.id}:branch_allows_collaboration") do
- check_access.call
- end
- else
+ Gitlab::SafeRequestStore.fetch("project-#{id}:branch-#{branch_name}:user-#{user.id}:branch_allows_collaboration") do
check_access.call
end
end
diff --git a/app/models/project_authorization.rb b/app/models/project_authorization.rb
index 746bb4584c9..2c590008db2 100644
--- a/app/models/project_authorization.rb
+++ b/app/models/project_authorization.rb
@@ -1,6 +1,8 @@
# frozen_string_literal: true
class ProjectAuthorization < ActiveRecord::Base
+ include FromUnion
+
belongs_to :user
belongs_to :project
@@ -8,9 +10,9 @@ class ProjectAuthorization < ActiveRecord::Base
validates :access_level, inclusion: { in: Gitlab::Access.all_values }, presence: true
validates :user, uniqueness: { scope: [:project, :access_level] }, presence: true
- def self.select_from_union(union)
- select(['project_id', 'MAX(access_level) AS access_level'])
- .from("(#{union.to_sql}) #{ProjectAuthorization.table_name}")
+ def self.select_from_union(relations)
+ from_union(relations)
+ .select(['project_id', 'MAX(access_level) AS access_level'])
.group(:project_id)
end
diff --git a/app/models/project_feature.rb b/app/models/project_feature.rb
index d74cb2506ba..4a0324e8b5c 100644
--- a/app/models/project_feature.rb
+++ b/app/models/project_feature.rb
@@ -21,7 +21,6 @@ class ProjectFeature < ActiveRecord::Base
ENABLED = 20
FEATURES = %i(issues merge_requests wiki snippets builds repository).freeze
- STATISTICS_ATTRIBUTE = 'wikis_count'.freeze
class << self
def access_level_attribute(feature)
@@ -55,9 +54,6 @@ class ProjectFeature < ActiveRecord::Base
default_value_for :wiki_access_level, value: ENABLED, allows_nil: false
default_value_for :repository_access_level, value: ENABLED, allows_nil: false
- after_create ->(model) { SiteStatistic.track(STATISTICS_ATTRIBUTE) if model.wiki_enabled? }
- after_update :update_site_statistics
-
def feature_available?(feature, user)
get_permission(user, access_level(feature))
end
@@ -82,30 +78,8 @@ class ProjectFeature < ActiveRecord::Base
issues_access_level > DISABLED
end
- # This is a workaround for the removal hooks not been triggered when removing a Project.
- #
- # ProjectFeature is removed using database cascade index rule.
- # This method is called by Project model when deletion starts.
- def untrack_statistics_for_deletion!
- return unless wiki_enabled?
-
- SiteStatistic.untrack(STATISTICS_ATTRIBUTE)
- end
-
private
- def update_site_statistics
- return unless wiki_access_level_changed?
-
- if self.wiki_access_level_was == DISABLED
- # possible new states are PRIVATE / ENABLED, both should be tracked
- SiteStatistic.track(STATISTICS_ATTRIBUTE)
- elsif self.wiki_access_level == DISABLED
- # old state was either PRIVATE / ENABLED, only untrack if new state is DISABLED
- SiteStatistic.untrack(STATISTICS_ATTRIBUTE)
- end
- end
-
# Validates builds and merge requests access level
# which cannot be higher than repository access level
def repository_children_level
diff --git a/app/models/project_services/asana_service.rb b/app/models/project_services/asana_service.rb
index 568f870c2db..cc5f1207653 100644
--- a/app/models/project_services/asana_service.rb
+++ b/app/models/project_services/asana_service.rb
@@ -65,7 +65,7 @@ http://app.asana.com/-/account_api'
# check the branch restriction is poplulated and branch is not included
branch = Gitlab::Git.ref_name(data[:ref])
branch_restriction = restrict_to_branch.to_s
- if branch_restriction.length > 0 && branch_restriction.index(branch).nil?
+ if branch_restriction.present? && branch_restriction.index(branch).nil?
return
end
diff --git a/app/models/project_services/chat_message/merge_message.rb b/app/models/project_services/chat_message/merge_message.rb
index 58631e09538..6b7a35aaa75 100644
--- a/app/models/project_services/chat_message/merge_message.rb
+++ b/app/models/project_services/chat_message/merge_message.rb
@@ -26,7 +26,7 @@ module ChatMessage
def activity
{
- title: "Merge Request #{state} by #{user_combined_name}",
+ title: "Merge Request #{state_or_action_text} by #{user_combined_name}",
subtitle: "in #{project_link}",
text: merge_request_link,
image: user_avatar
@@ -48,7 +48,7 @@ module ChatMessage
end
def merge_request_message
- "#{user_combined_name} #{state} #{merge_request_link} in #{project_link}: #{title}"
+ "#{user_combined_name} #{state_or_action_text} #{merge_request_link} in #{project_link}"
end
def merge_request_link
@@ -62,5 +62,10 @@ module ChatMessage
def merge_request_url
"#{project_url}/merge_requests/#{merge_request_iid}"
end
+
+ # overridden in EE
+ def state_or_action_text
+ state
+ end
end
end
diff --git a/app/models/project_wiki.rb b/app/models/project_wiki.rb
index f4b3421f04b..559e4f99294 100644
--- a/app/models/project_wiki.rb
+++ b/app/models/project_wiki.rb
@@ -80,7 +80,7 @@ class ProjectWiki
pages(limit: 1).empty?
end
- # Returns an Array of Gitlab WikiPage instances or an
+ # Returns an Array of GitLab WikiPage instances or an
# empty Array if this Wiki has no pages.
def pages(limit: 0)
wiki.pages(limit: limit).map { |page| WikiPage.new(self, page, true) }
@@ -184,11 +184,12 @@ class ProjectWiki
def commit_details(action, message = nil, title = nil)
commit_message = message || default_message(action, title)
+ git_user = Gitlab::Git::User.from_gitlab(@user)
Gitlab::Git::Wiki::CommitDetails.new(@user.id,
- @user.username,
- @user.name,
- @user.email,
+ git_user.username,
+ git_user.name,
+ git_user.email,
commit_message)
end
diff --git a/app/models/repository.rb b/app/models/repository.rb
index ad65881ff43..a3a3ce179fc 100644
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -24,7 +24,6 @@ class Repository
delegate :ref_name_for_sha, to: :raw_repository
delegate :bundle_to_disk, to: :raw_repository
- delegate :find_remote_root_ref, to: :raw_repository
CreateTreeError = Class.new(StandardError)
@@ -511,7 +510,7 @@ class Repository
raw_repository.exists?
end
- cache_method :exists?
+ cache_method_asymmetrically :exists?
# We don't need to cache the output of this method because both exists? and
# has_visible_content? are already memoized and cached. There's no guarantee
@@ -613,7 +612,7 @@ class Repository
Licensee::License.new(license_key)
end
- cache_method :license, memoize_only: true
+ memoize_method :license
def gitignore
file_on_head(:gitignore)
@@ -669,6 +668,14 @@ class Repository
end
end
+ def list_last_commits_for_tree(sha, path, offset: 0, limit: 25)
+ commits = raw_repository.list_last_commits_for_tree(sha, path, offset: offset, limit: limit)
+
+ commits.each do |path, commit|
+ commits[path] = ::Commit.new(commit, @project)
+ end
+ end
+
def last_commit_for_path(sha, path)
commit = raw_repository.last_commit_for_path(sha, path)
::Commit.new(commit, @project) if commit
@@ -1030,6 +1037,10 @@ class Repository
@cache ||= Gitlab::RepositoryCache.new(self)
end
+ def request_store_cache
+ @request_store_cache ||= Gitlab::RepositoryCache.new(self, backend: Gitlab::SafeRequestStore)
+ end
+
def tags_sorted_by_committed_date
tags.sort_by do |tag|
# Annotated tags can point to any object (e.g. a blob), but generally
diff --git a/app/models/site_statistic.rb b/app/models/site_statistic.rb
index 48324570f0b..3a7912ed53a 100644
--- a/app/models/site_statistic.rb
+++ b/app/models/site_statistic.rb
@@ -4,7 +4,7 @@ class SiteStatistic < ActiveRecord::Base
# prevents the creation of multiple rows
default_value_for :id, 1
- COUNTER_ATTRIBUTES = %w(repositories_count wikis_count).freeze
+ COUNTER_ATTRIBUTES = %w(repositories_count).freeze
REQUIRED_SCHEMA_VERSION = 20180629153018
# Tracks specific attribute
diff --git a/app/models/snippet.rb b/app/models/snippet.rb
index 5b394e3fa79..e9533ee7c77 100644
--- a/app/models/snippet.rb
+++ b/app/models/snippet.rb
@@ -12,6 +12,7 @@ class Snippet < ActiveRecord::Base
include Spammable
include Editable
include Gitlab::SQL::Pattern
+ include FromUnion
cache_markdown_field :title, pipeline: :single_line
cache_markdown_field :description
diff --git a/app/models/todo.rb b/app/models/todo.rb
index 48d92ad04b3..265fb932f7c 100644
--- a/app/models/todo.rb
+++ b/app/models/todo.rb
@@ -2,6 +2,7 @@
class Todo < ActiveRecord::Base
include Sortable
+ include FromUnion
ASSIGNED = 1
MENTIONED = 2
diff --git a/app/models/user.rb b/app/models/user.rb
index d68108a8e8e..eeac87e2e52 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -20,6 +20,7 @@ class User < ActiveRecord::Base
include BlocksJsonSerialization
include WithUploads
include OptionallySearch
+ include FromUnion
DEFAULT_NOTIFICATION_LEVEL = :participating
@@ -286,11 +287,9 @@ class User < ActiveRecord::Base
# user_id - The ID of the user to include.
def self.union_with_user(user_id = nil)
if user_id.present?
- union = Gitlab::SQL::Union.new([all, User.unscoped.where(id: user_id)])
-
# We use "unscoped" here so that any inner conditions are not repeated for
# the outer query, which would be redundant.
- User.unscoped.from("(#{union.to_sql}) #{User.table_name}")
+ User.unscoped.from_union([all, User.unscoped.where(id: user_id)])
else
all
end
@@ -354,9 +353,8 @@ class User < ActiveRecord::Base
emails = joins(:emails).where(emails: { email: email })
emails = emails.confirmed if confirmed
- union = Gitlab::SQL::Union.new([users, emails])
- from("(#{union.to_sql}) #{table_name}")
+ from_union([users, emails])
end
def filter(filter_name)
@@ -635,7 +633,7 @@ class User < ActiveRecord::Base
# possibility of the commit_email column not existing.
def commit_email
- return unless has_attribute?(:commit_email)
+ return self.email unless has_attribute?(:commit_email)
# The commit email is the same as the primary email if undefined
super.presence || self.email
@@ -676,10 +674,10 @@ class User < ActiveRecord::Base
# Returns the groups a user has access to, either through a membership or a project authorization
def authorized_groups
- union = Gitlab::SQL::Union
- .new([groups.select(:id), authorized_projects.select(:namespace_id)])
-
- Group.where("namespaces.id IN (#{union.to_sql})") # rubocop:disable GitlabSecurity/SqlInjection
+ Group.from_union([
+ groups,
+ authorized_projects.joins(:namespace).select('namespaces.*')
+ ])
end
# Returns the groups a user is a member of, either directly or through a parent group
@@ -744,7 +742,15 @@ class User < ActiveRecord::Base
end
def owned_projects
- @owned_projects ||= Project.from("(#{owned_projects_union.to_sql}) AS projects")
+ @owned_projects ||= Project.from_union(
+ [
+ Project.where(namespace: namespace),
+ Project.joins(:project_authorizations)
+ .where("projects.namespace_id <> ?", namespace.id)
+ .where(project_authorizations: { user_id: id, access_level: Gitlab::Access::OWNER })
+ ],
+ remove_duplicates: false
+ )
end
# Returns projects which user can admin issues on (for example to move an issue to that project).
@@ -1138,17 +1144,17 @@ class User < ActiveRecord::Base
def ci_owned_runners
@ci_owned_runners ||= begin
- project_runner_ids = Ci::RunnerProject
+ project_runners = Ci::RunnerProject
.where(project: authorized_projects(Gitlab::Access::MAINTAINER))
- .select(:runner_id)
+ .joins(:runner)
+ .select('ci_runners.*')
- group_runner_ids = Ci::RunnerNamespace
+ group_runners = Ci::RunnerNamespace
.where(namespace_id: owned_or_maintainers_groups.select(:id))
- .select(:runner_id)
+ .joins(:runner)
+ .select('ci_runners.*')
- union = Gitlab::SQL::Union.new([project_runner_ids, group_runner_ids])
-
- Ci::Runner.where("ci_runners.id IN (#{union.to_sql})") # rubocop:disable GitlabSecurity/SqlInjection
+ Ci::Runner.from_union([project_runners, group_runners])
end
end
@@ -1176,13 +1182,13 @@ class User < ActiveRecord::Base
def assigned_open_merge_requests_count(force: false)
Rails.cache.fetch(['users', id, 'assigned_open_merge_requests_count'], force: force, expires_in: 20.minutes) do
- MergeRequestsFinder.new(self, assignee_id: self.id, state: 'opened').execute.count
+ MergeRequestsFinder.new(self, assignee_id: self.id, state: 'opened', non_archived: true).execute.count
end
end
def assigned_open_issues_count(force: false)
Rails.cache.fetch(['users', id, 'assigned_open_issues_count'], force: force, expires_in: 20.minutes) do
- IssuesFinder.new(self, assignee_id: self.id, state: 'opened').execute.count
+ IssuesFinder.new(self, assignee_id: self.id, state: 'opened', non_archived: true).execute.count
end
end
@@ -1380,15 +1386,6 @@ class User < ActiveRecord::Base
Gitlab::CurrentSettings.usage_stats_set_by_user_id == self.id
end
- def owned_projects_union
- Gitlab::SQL::Union.new([
- Project.where(namespace: namespace),
- Project.joins(:project_authorizations)
- .where("projects.namespace_id <> ?", namespace.id)
- .where(project_authorizations: { user_id: id, access_level: Gitlab::Access::OWNER })
- ], remove_duplicates: false)
- end
-
# Added according to https://github.com/plataformatec/devise/blob/7df57d5081f9884849ca15e4fde179ef164a575f/README.md#activejob-integration
def send_devise_notification(notification, *args)
return true unless can?(:receive_notifications)
diff --git a/app/models/wiki_page.rb b/app/models/wiki_page.rb
index 33790afc35e..102907a8bd3 100644
--- a/app/models/wiki_page.rb
+++ b/app/models/wiki_page.rb
@@ -51,7 +51,7 @@ class WikiPage
validates :title, presence: true
validates :content, presence: true
- # The Gitlab ProjectWiki instance.
+ # The GitLab ProjectWiki instance.
attr_reader :wiki
# The raw Gitlab::Git::WikiPage instance.
@@ -127,7 +127,7 @@ class WikiPage
version.try(:message)
end
- # The Gitlab Commit instance for this page.
+ # The GitLab Commit instance for this page.
def version
return nil unless persisted?
diff --git a/app/serializers/build_details_entity.rb b/app/serializers/build_details_entity.rb
index 6f8194d9856..c85b1790e73 100644
--- a/app/serializers/build_details_entity.rb
+++ b/app/serializers/build_details_entity.rb
@@ -1,12 +1,27 @@
# frozen_string_literal: true
class BuildDetailsEntity < JobEntity
+ include EnvironmentHelper
+ include RequestAwareEntity
+ include CiStatusHelper
+
expose :coverage, :erased_at, :duration
expose :tag_list, as: :tags
+ expose :has_trace?, as: :has_trace
expose :user, using: UserEntity
expose :runner, using: RunnerEntity
expose :pipeline, using: PipelineEntity
+ expose :deployment_status, if: -> (*) { build.has_environment? } do
+ expose :deployment_status, as: :status
+
+ expose :icon do |build|
+ ci_label_for_status(build.status)
+ end
+
+ expose :persisted_environment, as: :environment, with: EnvironmentEntity
+ end
+
expose :metadata, using: BuildMetadataEntity
expose :artifact, if: -> (*) { can?(current_user, :read_build, build) } do
@@ -65,6 +80,20 @@ class BuildDetailsEntity < JobEntity
expose :trigger_variables, as: :variables, using: TriggerVariableEntity
end
+ expose :runners do
+ expose :online do |build|
+ build.any_runners_online?
+ end
+
+ expose :available do |build|
+ project.any_runners?
+ end
+
+ expose :settings_path, if: -> (*) { can_admin_build? } do |build|
+ project_runners_path(project)
+ end
+ end
+
private
def build_failed_issue_options
@@ -83,4 +112,8 @@ class BuildDetailsEntity < JobEntity
def can_create_build_terminal?
can?(current_user, :create_build_terminal, build) && build.has_terminal?
end
+
+ def can_admin_build?
+ can?(request.current_user, :admin_build, project)
+ end
end
diff --git a/app/serializers/commit_entity.rb b/app/serializers/commit_entity.rb
index ce76659fa46..396e95a03c8 100644
--- a/app/serializers/commit_entity.rb
+++ b/app/serializers/commit_entity.rb
@@ -1,6 +1,7 @@
# frozen_string_literal: true
class CommitEntity < API::Entities::Commit
+ include MarkupHelper
include RequestAwareEntity
expose :author, using: UserEntity
@@ -9,11 +10,19 @@ class CommitEntity < API::Entities::Commit
GravatarService.new.execute(commit.author_email) # rubocop: disable CodeReuse/ServiceClass
end
- expose :commit_url do |commit|
- project_commit_url(request.project, commit)
+ expose :commit_url do |commit, options|
+ project_commit_url(request.project, commit, params: options.fetch(:commit_url_params, {}))
end
- expose :commit_path do |commit|
- project_commit_path(request.project, commit)
+ expose :commit_path do |commit, options|
+ project_commit_path(request.project, commit, params: options.fetch(:commit_url_params, {}))
+ end
+
+ expose :description_html, if: { type: :full } do |commit|
+ markdown_field(commit, :description)
+ end
+
+ expose :title_html, if: { type: :full } do |commit|
+ markdown_field(commit, :title)
end
end
diff --git a/app/serializers/diffs_entity.rb b/app/serializers/diffs_entity.rb
index 878cc5290bd..00dc55fc004 100644
--- a/app/serializers/diffs_entity.rb
+++ b/app/serializers/diffs_entity.rb
@@ -15,8 +15,11 @@ class DiffsEntity < Grape::Entity
merge_request&.target_branch
end
- expose :commit do |diffs|
- options[:commit]
+ expose :commit do |diffs, options|
+ CommitEntity.represent options[:commit], options.merge(
+ type: :full,
+ commit_url_params: { merge_request_iid: merge_request&.iid }
+ )
end
expose :merge_request_diff, using: MergeRequestDiffEntity do |diffs|
diff --git a/app/serializers/runner_entity.rb b/app/serializers/runner_entity.rb
index 04ec80e0efa..97e5b336a35 100644
--- a/app/serializers/runner_entity.rb
+++ b/app/serializers/runner_entity.rb
@@ -5,8 +5,7 @@ class RunnerEntity < Grape::Entity
expose :id, :description
- expose :edit_path,
- if: -> (*) { can?(request.current_user, :admin_build, project) && runner.project_type? } do |runner|
+ expose :edit_path, if: -> (*) { can_edit_runner? } do |runner|
edit_project_runner_path(project, runner)
end
@@ -17,4 +16,8 @@ class RunnerEntity < Grape::Entity
def project
request.project
end
+
+ def can_edit_runner?
+ can?(request.current_user, :update_runner, runner) && runner.project_type?
+ end
end
diff --git a/app/serializers/stage_entity.rb b/app/serializers/stage_entity.rb
index ca8fa7e7877..029dd3d0684 100644
--- a/app/serializers/stage_entity.rb
+++ b/app/serializers/stage_entity.rb
@@ -19,6 +19,12 @@ class StageEntity < Grape::Entity
latest_statuses
end
+ expose :retried,
+ if: -> (_, opts) { opts[:retried] },
+ with: JobEntity do |stage|
+ retried_statuses
+ end
+
expose :detailed_status, as: :status, with: DetailedStatusEntity
expose :path do |stage|
@@ -48,9 +54,19 @@ class StageEntity < Grape::Entity
@grouped_statuses ||= stage.statuses.latest_ordered.group_by(&:status)
end
+ def grouped_retried_statuses
+ @grouped_retried_statuses ||= stage.statuses.retried_ordered.group_by(&:status)
+ end
+
def latest_statuses
HasStatus::ORDERED_STATUSES.map do |ordered_status|
grouped_statuses.fetch(ordered_status, [])
end.flatten
end
+
+ def retried_statuses
+ HasStatus::ORDERED_STATUSES.map do |ordered_status|
+ grouped_retried_statuses.fetch(ordered_status, [])
+ end.flatten
+ end
end
diff --git a/app/services/boards/create_service.rb b/app/services/boards/create_service.rb
index 4caf5ffa3cb..1b796cef3e2 100644
--- a/app/services/boards/create_service.rb
+++ b/app/services/boards/create_service.rb
@@ -9,7 +9,7 @@ module Boards
private
def can_create_board?
- parent.boards.size == 0
+ parent.boards.empty?
end
def create_board!
diff --git a/app/services/boards/issues/list_service.rb b/app/services/boards/issues/list_service.rb
index 4e352f2dc63..0b69661bbd0 100644
--- a/app/services/boards/issues/list_service.rb
+++ b/app/services/boards/issues/list_service.rb
@@ -56,6 +56,7 @@ module Boards
set_parent
set_state
set_scope
+ set_non_archived
params
end
@@ -76,6 +77,10 @@ module Boards
params[:include_subgroups] = board.group_board?
end
+ def set_non_archived
+ params[:non_archived] = parent.is_a?(Group)
+ end
+
# rubocop: disable CodeReuse/ActiveRecord
def board_label_ids
@board_label_ids ||= board.lists.movable.pluck(:label_id)
diff --git a/app/services/ci/fetch_kubernetes_token_service.rb b/app/services/ci/fetch_kubernetes_token_service.rb
deleted file mode 100644
index 15eda56cac6..00000000000
--- a/app/services/ci/fetch_kubernetes_token_service.rb
+++ /dev/null
@@ -1,75 +0,0 @@
-# frozen_string_literal: true
-
-##
-# TODO:
-# Almost components in this class were copied from app/models/project_services/kubernetes_service.rb
-# We should dry up those classes not to repeat the same code.
-# Maybe we should have a special facility (e.g. lib/kubernetes_api) to maintain all Kubernetes API caller.
-module Ci
- class FetchKubernetesTokenService
- attr_reader :api_url, :ca_pem, :username, :password
-
- def initialize(api_url, ca_pem, username, password)
- @api_url = api_url
- @ca_pem = ca_pem
- @username = username
- @password = password
- end
-
- def execute
- read_secrets.each do |secret|
- name = secret.dig('metadata', 'name')
- if /default-token/ =~ name
- token_base64 = secret.dig('data', 'token')
- return Base64.decode64(token_base64) if token_base64
- end
- end
-
- nil
- end
-
- private
-
- def read_secrets
- kubeclient = build_kubeclient!
-
- kubeclient.get_secrets.as_json
- rescue Kubeclient::HttpError => err
- raise err unless err.error_code == 404
-
- []
- end
-
- def build_kubeclient!(api_path: 'api', api_version: 'v1')
- raise "Incomplete settings" unless api_url && username && password
-
- ::Kubeclient::Client.new(
- join_api_url(api_path),
- api_version,
- auth_options: { username: username, password: password },
- ssl_options: kubeclient_ssl_options,
- http_proxy_uri: ENV['http_proxy']
- )
- end
-
- def join_api_url(api_path)
- url = URI.parse(api_url)
- prefix = url.path.sub(%r{/+\z}, '')
-
- url.path = [prefix, api_path].join("/")
-
- url.to_s
- end
-
- def kubeclient_ssl_options
- opts = { verify_ssl: OpenSSL::SSL::VERIFY_PEER }
-
- if ca_pem.present?
- opts[:cert_store] = OpenSSL::X509::Store.new
- opts[:cert_store].add_cert(OpenSSL::X509::Certificate.new(ca_pem))
- end
-
- opts
- end
- end
-end
diff --git a/app/services/clusters/gcp/finalize_creation_service.rb b/app/services/clusters/gcp/finalize_creation_service.rb
index 264419501dc..3ae0a4a19d0 100644
--- a/app/services/clusters/gcp/finalize_creation_service.rb
+++ b/app/services/clusters/gcp/finalize_creation_service.rb
@@ -9,17 +9,24 @@ module Clusters
@provider = provider
configure_provider
+ create_gitlab_service_account!
configure_kubernetes
cluster.save!
rescue Google::Apis::ServerError, Google::Apis::ClientError, Google::Apis::AuthorizationError => e
provider.make_errored!("Failed to request to CloudPlatform; #{e.message}")
+ rescue Kubeclient::HttpError => e
+ provider.make_errored!("Failed to run Kubeclient: #{e.message}")
rescue ActiveRecord::RecordInvalid => e
provider.make_errored!("Failed to configure Google Kubernetes Engine Cluster: #{e.message}")
end
private
+ def create_gitlab_service_account!
+ Clusters::Gcp::Kubernetes::CreateServiceAccountService.new(kube_client, rbac: create_rbac_cluster?).execute
+ end
+
def configure_provider
provider.endpoint = gke_cluster.endpoint
provider.status_event = :make_created
@@ -32,15 +39,54 @@ module Clusters
ca_cert: Base64.decode64(gke_cluster.master_auth.cluster_ca_certificate),
username: gke_cluster.master_auth.username,
password: gke_cluster.master_auth.password,
+ authorization_type: authorization_type,
token: request_kubernetes_token)
end
def request_kubernetes_token
- Ci::FetchKubernetesTokenService.new(
+ Clusters::Gcp::Kubernetes::FetchKubernetesTokenService.new(kube_client).execute
+ end
+
+ def authorization_type
+ create_rbac_cluster? ? 'rbac' : 'abac'
+ end
+
+ def create_rbac_cluster?
+ !provider.legacy_abac?
+ end
+
+ def kube_client
+ @kube_client ||= build_kube_client!(
'https://' + gke_cluster.endpoint,
Base64.decode64(gke_cluster.master_auth.cluster_ca_certificate),
gke_cluster.master_auth.username,
- gke_cluster.master_auth.password).execute
+ gke_cluster.master_auth.password,
+ api_groups: ['api', 'apis/rbac.authorization.k8s.io']
+ )
+ end
+
+ def build_kube_client!(api_url, ca_pem, username, password, api_groups: ['api'], api_version: 'v1')
+ raise "Incomplete settings" unless api_url && username && password
+
+ Gitlab::Kubernetes::KubeClient.new(
+ api_url,
+ api_groups,
+ api_version,
+ auth_options: { username: username, password: password },
+ ssl_options: kubeclient_ssl_options(ca_pem),
+ http_proxy_uri: ENV['http_proxy']
+ )
+ end
+
+ def kubeclient_ssl_options(ca_pem)
+ opts = { verify_ssl: OpenSSL::SSL::VERIFY_PEER }
+
+ if ca_pem.present?
+ opts[:cert_store] = OpenSSL::X509::Store.new
+ opts[:cert_store].add_cert(OpenSSL::X509::Certificate.new(ca_pem))
+ end
+
+ opts
end
def gke_cluster
diff --git a/app/services/clusters/gcp/kubernetes.rb b/app/services/clusters/gcp/kubernetes.rb
new file mode 100644
index 00000000000..d014d73b3e8
--- /dev/null
+++ b/app/services/clusters/gcp/kubernetes.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+module Clusters
+ module Gcp
+ module Kubernetes
+ SERVICE_ACCOUNT_NAME = 'gitlab'
+ SERVICE_ACCOUNT_NAMESPACE = 'default'
+ SERVICE_ACCOUNT_TOKEN_NAME = 'gitlab-token'
+ CLUSTER_ROLE_BINDING_NAME = 'gitlab-admin'
+ CLUSTER_ROLE_NAME = 'cluster-admin'
+ end
+ end
+end
diff --git a/app/services/clusters/gcp/kubernetes/create_service_account_service.rb b/app/services/clusters/gcp/kubernetes/create_service_account_service.rb
new file mode 100644
index 00000000000..d17744591e6
--- /dev/null
+++ b/app/services/clusters/gcp/kubernetes/create_service_account_service.rb
@@ -0,0 +1,51 @@
+# frozen_string_literal: true
+
+module Clusters
+ module Gcp
+ module Kubernetes
+ class CreateServiceAccountService
+ attr_reader :kubeclient, :rbac
+
+ def initialize(kubeclient, rbac:)
+ @kubeclient = kubeclient
+ @rbac = rbac
+ end
+
+ def execute
+ kubeclient.create_service_account(service_account_resource)
+ kubeclient.create_secret(service_account_token_resource)
+ kubeclient.create_cluster_role_binding(cluster_role_binding_resource) if rbac
+ end
+
+ private
+
+ def service_account_resource
+ Gitlab::Kubernetes::ServiceAccount.new(service_account_name, service_account_namespace).generate
+ end
+
+ def service_account_token_resource
+ Gitlab::Kubernetes::ServiceAccountToken.new(
+ SERVICE_ACCOUNT_TOKEN_NAME, service_account_name, service_account_namespace).generate
+ end
+
+ def cluster_role_binding_resource
+ subjects = [{ kind: 'ServiceAccount', name: service_account_name, namespace: service_account_namespace }]
+
+ Gitlab::Kubernetes::ClusterRoleBinding.new(
+ CLUSTER_ROLE_BINDING_NAME,
+ CLUSTER_ROLE_NAME,
+ subjects
+ ).generate
+ end
+
+ def service_account_name
+ SERVICE_ACCOUNT_NAME
+ end
+
+ def service_account_namespace
+ SERVICE_ACCOUNT_NAMESPACE
+ end
+ end
+ end
+ end
+end
diff --git a/app/services/clusters/gcp/kubernetes/fetch_kubernetes_token_service.rb b/app/services/clusters/gcp/kubernetes/fetch_kubernetes_token_service.rb
new file mode 100644
index 00000000000..9e09345c8dc
--- /dev/null
+++ b/app/services/clusters/gcp/kubernetes/fetch_kubernetes_token_service.rb
@@ -0,0 +1,30 @@
+# frozen_string_literal: true
+
+module Clusters
+ module Gcp
+ module Kubernetes
+ class FetchKubernetesTokenService
+ attr_reader :kubeclient
+
+ def initialize(kubeclient)
+ @kubeclient = kubeclient
+ end
+
+ def execute
+ token_base64 = get_secret&.dig('data', 'token')
+ Base64.decode64(token_base64) if token_base64
+ end
+
+ private
+
+ def get_secret
+ kubeclient.get_secret(SERVICE_ACCOUNT_TOKEN_NAME, SERVICE_ACCOUNT_NAMESPACE).as_json
+ rescue Kubeclient::HttpError => err
+ raise err unless err.error_code == 404
+
+ nil
+ end
+ end
+ end
+ end
+end
diff --git a/app/services/clusters/gcp/provision_service.rb b/app/services/clusters/gcp/provision_service.rb
index ab1bf9c64f6..80040511ec2 100644
--- a/app/services/clusters/gcp/provision_service.rb
+++ b/app/services/clusters/gcp/provision_service.rb
@@ -27,7 +27,9 @@ module Clusters
provider.zone,
provider.cluster.name,
provider.num_nodes,
- machine_type: provider.machine_type)
+ machine_type: provider.machine_type,
+ legacy_abac: provider.legacy_abac
+ )
unless operation.status == 'PENDING' || operation.status == 'RUNNING'
return provider.make_errored!("Operation status is unexpected; #{operation.status_message}")
diff --git a/app/services/files/base_service.rb b/app/services/files/base_service.rb
index fc7b236f7da..39e614d6569 100644
--- a/app/services/files/base_service.rb
+++ b/app/services/files/base_service.rb
@@ -7,8 +7,10 @@ module Files
def initialize(*args)
super
- @author_email = params[:author_email] || current_user&.email
- @author_name = params[:author_name] || current_user&.name
+ git_user = Gitlab::Git::User.from_gitlab(current_user) if current_user.present?
+
+ @author_email = params[:author_email] || git_user&.email
+ @author_name = params[:author_name] || git_user&.name
@commit_message = params[:commit_message]
@last_commit_sha = params[:last_commit_sha]
diff --git a/app/services/files/multi_service.rb b/app/services/files/multi_service.rb
index 08088f8c592..c9d3ee31d82 100644
--- a/app/services/files/multi_service.rb
+++ b/app/services/files/multi_service.rb
@@ -2,7 +2,7 @@
module Files
class MultiService < Files::BaseService
- UPDATE_FILE_ACTIONS = %w(update move delete).freeze
+ UPDATE_FILE_ACTIONS = %w(update move delete chmod).freeze
def create_commit!
transformer = Lfs::FileTransformer.new(project, @branch_name)
diff --git a/app/services/labels/transfer_service.rb b/app/services/labels/transfer_service.rb
index aec0282b31b..52360f775dc 100644
--- a/app/services/labels/transfer_service.rb
+++ b/app/services/labels/transfer_service.rb
@@ -34,13 +34,13 @@ module Labels
# rubocop: disable CodeReuse/ActiveRecord
def labels_to_transfer
- label_ids = []
- label_ids << group_labels_applied_to_issues.select(:id)
- label_ids << group_labels_applied_to_merge_requests.select(:id)
-
- union = Gitlab::SQL::Union.new(label_ids)
-
- Label.where("labels.id IN (#{union.to_sql})").reorder(nil).uniq # rubocop:disable GitlabSecurity/SqlInjection
+ Label
+ .from_union([
+ group_labels_applied_to_issues,
+ group_labels_applied_to_merge_requests
+ ])
+ .reorder(nil)
+ .uniq
end
# rubocop: enable CodeReuse/ActiveRecord
diff --git a/app/services/merge_requests/reload_diffs_service.rb b/app/services/merge_requests/reload_diffs_service.rb
index c350b14d12b..b4d48fe92ad 100644
--- a/app/services/merge_requests/reload_diffs_service.rb
+++ b/app/services/merge_requests/reload_diffs_service.rb
@@ -31,7 +31,7 @@ module MergeRequests
def clear_cache(new_diff)
# Executing the iteration we cache highlighted diffs for each diff file of
# MergeRequestDiff.
- new_diff.diffs_collection.write_cache
+ cacheable_collection(new_diff).write_cache
# Remove cache for all diffs on this MR. Do not use the association on the
# model, as that will interfere with other actions happening when
@@ -39,9 +39,15 @@ module MergeRequests
MergeRequestDiff.where(merge_request: merge_request).each do |merge_request_diff|
next if merge_request_diff == new_diff
- merge_request_diff.diffs_collection.clear_cache
+ cacheable_collection(merge_request_diff).clear_cache
end
end
# rubocop: enable CodeReuse/ActiveRecord
+
+ def cacheable_collection(diff)
+ # There are scenarios where we don't need to request Diff Stats.
+ # Mainly when clearing / writing diff caches.
+ diff.diffs(include_stats: false)
+ end
end
end
diff --git a/app/services/notes/build_service.rb b/app/services/notes/build_service.rb
index df5fe65de3c..7b92fe6fe14 100644
--- a/app/services/notes/build_service.rb
+++ b/app/services/notes/build_service.rb
@@ -3,6 +3,7 @@
module Notes
class BuildService < ::BaseService
def execute
+ should_resolve = false
in_reply_to_discussion_id = params.delete(:in_reply_to_discussion_id)
if in_reply_to_discussion_id.present?
@@ -15,12 +16,17 @@ module Notes
end
params.merge!(discussion.reply_attributes)
+ should_resolve = discussion.resolved?
end
note = Note.new(params)
note.project = project
note.author = current_user
+ if should_resolve
+ note.resolve_without_save(current_user)
+ end
+
note
end
diff --git a/app/services/projects/container_repository/destroy_service.rb b/app/services/projects/container_repository/destroy_service.rb
index a8e7eab6068..1f5af7970d6 100644
--- a/app/services/projects/container_repository/destroy_service.rb
+++ b/app/services/projects/container_repository/destroy_service.rb
@@ -6,6 +6,8 @@ module Projects
def execute(container_repository)
return false unless can?(current_user, :update_container_image, project)
+ # Delete tags outside of the transaction to avoid hitting an idle-in-transaction timeout
+ container_repository.delete_tags!
container_repository.destroy
end
end
diff --git a/app/services/projects/destroy_service.rb b/app/services/projects/destroy_service.rb
index 5090ebf8f51..210571b6b4e 100644
--- a/app/services/projects/destroy_service.rb
+++ b/app/services/projects/destroy_service.rb
@@ -133,11 +133,11 @@ module Projects
end
def attempt_destroy_transaction(project)
- Project.transaction do
- unless remove_legacy_registry_tags
- raise_error('Failed to remove some tags in project container registry. Please try again or contact administrator.')
- end
+ unless remove_registry_tags
+ raise_error('Failed to remove some tags in project container registry. Please try again or contact administrator.')
+ end
+ Project.transaction do
log_destroy_event
trash_repositories!
@@ -156,6 +156,17 @@ module Projects
log_info("Attempting to destroy #{project.full_path} (#{project.id})")
end
+ def remove_registry_tags
+ return false unless remove_legacy_registry_tags
+
+ project.container_repositories.find_each do |container_repository|
+ service = Projects::ContainerRepository::DestroyService.new(project, current_user)
+ service.execute(container_repository)
+ end
+
+ true
+ end
+
##
# This method makes sure that we correctly remove registry tags
# for legacy image repository (when repository path equals project path).
diff --git a/app/services/projects/update_remote_mirror_service.rb b/app/services/projects/update_remote_mirror_service.rb
index 85b9eb02803..9d0877d1ab2 100644
--- a/app/services/projects/update_remote_mirror_service.rb
+++ b/app/services/projects/update_remote_mirror_service.rb
@@ -12,7 +12,6 @@ module Projects
begin
remote_mirror.ensure_remote!
repository.fetch_remote(remote_mirror.remote_name, no_tags: true)
- project.update_root_ref(remote_mirror.remote_name)
opts = {}
if remote_mirror.only_protected_branches?
diff --git a/app/services/quick_actions/interpret_service.rb b/app/services/quick_actions/interpret_service.rb
index 02d68c3add3..8933bef29ee 100644
--- a/app/services/quick_actions/interpret_service.rb
+++ b/app/services/quick_actions/interpret_service.rb
@@ -126,18 +126,16 @@ module QuickActions
parse_params do |assignee_param|
extract_users(assignee_param)
end
- # rubocop: disable CodeReuse/ActiveRecord
command :assign do |users|
next if users.empty?
- @updates[:assignee_ids] =
- if issuable.allows_multiple_assignees?
- issuable.assignees.pluck(:id) + users.map(&:id)
- else
- [users.first.id]
- end
+ if issuable.allows_multiple_assignees?
+ @updates[:assignee_ids] ||= issuable.assignees.map(&:id)
+ @updates[:assignee_ids] += users.map(&:id)
+ else
+ @updates[:assignee_ids] = [users.first.id]
+ end
end
- # rubocop: enable CodeReuse/ActiveRecord
desc do
if issuable.allows_multiple_assignees?
@@ -164,16 +162,14 @@ module QuickActions
# When multiple users are assigned, all will be unassigned if multiple assignees are no longer allowed
extract_users(unassign_param) if issuable.allows_multiple_assignees?
end
- # rubocop: disable CodeReuse/ActiveRecord
command :unassign do |users = nil|
- @updates[:assignee_ids] =
- if users&.any?
- issuable.assignees.pluck(:id) - users.map(&:id)
- else
- []
- end
+ if issuable.allows_multiple_assignees? && users&.any?
+ @updates[:assignee_ids] ||= issuable.assignees.map(&:id)
+ @updates[:assignee_ids] -= users.map(&:id)
+ else
+ @updates[:assignee_ids] = []
+ end
end
- # rubocop: enable CodeReuse/ActiveRecord
desc 'Set milestone'
explanation do |milestone|
@@ -290,8 +286,7 @@ module QuickActions
end
params '#issue | !merge_request'
condition do
- issuable.persisted? &&
- current_user.can?(:"update_#{issuable.to_ability_name}", issuable)
+ current_user.can?(:"update_#{issuable.to_ability_name}", issuable)
end
parse_params do |issuable_param|
extract_references(issuable_param, :issue).first ||
diff --git a/app/validators/url_validator.rb b/app/validators/url_validator.rb
index faaf1283078..216acf79cbd 100644
--- a/app/validators/url_validator.rb
+++ b/app/validators/url_validator.rb
@@ -41,12 +41,13 @@ class UrlValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
@record = record
- if value.present?
- value.strip!
- else
+ unless value.present?
record.errors.add(attribute, 'must be a valid URL')
+ return
end
+ value = strip_value!(record, attribute, value)
+
Gitlab::UrlBlocker.validate!(value, blocker_args)
rescue Gitlab::UrlBlocker::BlockedUrlError => e
record.errors.add(attribute, "is blocked: #{e.message}")
@@ -54,6 +55,13 @@ class UrlValidator < ActiveModel::EachValidator
private
+ def strip_value!(record, attribute, value)
+ new_value = value.strip
+ return value if new_value == value
+
+ record.public_send("#{attribute}=", new_value) # rubocop:disable GitlabSecurity/PublicSend
+ end
+
def default_options
# By default the validator doesn't block any url based on the ip address
{
diff --git a/app/views/abuse_reports/new.html.haml b/app/views/abuse_reports/new.html.haml
index 278ad210543..391115a67b5 100644
--- a/app/views/abuse_reports/new.html.haml
+++ b/app/views/abuse_reports/new.html.haml
@@ -19,4 +19,4 @@
Explain the problem with this user. If appropriate, provide a link to the relevant issue or comment.
.form-actions
- = f.submit "Send report", class: "btn btn-create"
+ = f.submit "Send report", class: "btn btn-success"
diff --git a/app/views/admin/appearances/_form.html.haml b/app/views/admin/appearances/_form.html.haml
index a0861870ba4..cb67079853e 100644
--- a/app/views/admin/appearances/_form.html.haml
+++ b/app/views/admin/appearances/_form.html.haml
@@ -5,7 +5,7 @@
%legend
Navigation bar:
.form-group.row
- = f.label :header_logo, 'Header logo', class: 'col-sm-2 col-form-label'
+ = f.label :header_logo, 'Header logo', class: 'col-sm-2 col-form-label pt-0'
.col-sm-10
- if @appearance.header_logo?
= image_tag @appearance.header_logo_url, class: 'appearance-light-logo-preview'
@@ -22,7 +22,7 @@
%legend
Favicon:
.form-group.row
- = f.label :favicon, 'Favicon', class: 'col-sm-2 col-form-label'
+ = f.label :favicon, 'Favicon', class: 'col-sm-2 col-form-label pt-0'
.col-sm-10
- if @appearance.favicon?
= image_tag @appearance.favicon_url, class: 'appearance-light-logo-preview'
@@ -51,7 +51,7 @@
.hint
Description parsed with #{link_to "GitLab Flavored Markdown", help_page_path('user/markdown'), target: '_blank'}.
.form-group.row
- = f.label :logo, class: 'col-sm-2 col-form-label'
+ = f.label :logo, class: 'col-sm-2 col-form-label pt-0'
.col-sm-10
- if @appearance.logo?
= image_tag @appearance.logo_url, class: 'appearance-logo-preview'
@@ -75,7 +75,7 @@
Guidelines parsed with #{link_to "GitLab Flavored Markdown", help_page_path('user/markdown'), target: '_blank'}.
.form-actions
- = f.submit 'Save', class: 'btn btn-save append-right-10'
+ = f.submit 'Save', class: 'btn btn-success append-right-10'
- if @appearance.persisted?
Preview last save:
= link_to 'Sign-in page', preview_sign_in_admin_appearances_path, class: 'btn', target: '_blank', rel: 'noopener noreferrer'
diff --git a/app/views/admin/appearances/preview_sign_in.html.haml b/app/views/admin/appearances/preview_sign_in.html.haml
index 1af7dd5bb67..2cd95071c73 100644
--- a/app/views/admin/appearances/preview_sign_in.html.haml
+++ b/app/views/admin/appearances/preview_sign_in.html.haml
@@ -8,5 +8,5 @@
= label_tag :password
= password_field_tag :password, nil, class: "form-control bottom", title: 'This field is required.'
.form-group
- = button_tag "Sign in", class: "btn-create btn"
+ = button_tag "Sign in", class: "btn-success btn"
diff --git a/app/views/admin/application_settings/_background_jobs.html.haml b/app/views/admin/application_settings/_background_jobs.html.haml
deleted file mode 100644
index 7d1a64b645a..00000000000
--- a/app/views/admin/application_settings/_background_jobs.html.haml
+++ /dev/null
@@ -1,27 +0,0 @@
-= form_for @application_setting, url: admin_application_settings_path(anchor: 'js-background-settings'), html: { class: 'fieldset-form' } do |f|
- = form_errors(@application_setting)
-
- %fieldset
- %p
- These settings require a
- = link_to 'restart', help_page_path('administration/restart_gitlab')
- to take effect.
- .form-group
- .form-check
- = f.check_box :sidekiq_throttling_enabled, class: 'form-check-input'
- = f.label :sidekiq_throttling_enabled, class: 'form-check-label' do
- Enable Sidekiq Job Throttling
- .form-text.text-muted
- Limit the amount of resources slow running jobs are assigned.
- .form-group
- = f.label :sidekiq_throttling_queues, 'Sidekiq queues to throttle', class: 'label-bold'
- = f.select :sidekiq_throttling_queues, sidekiq_queue_options_for_select, { include_hidden: false }, multiple: true, class: 'select2 select-wide', data: { field: 'sidekiq_throttling_queues' }
- .form-text.text-muted
- Choose which queues you wish to throttle.
- .form-group
- = f.label :sidekiq_throttling_factor, 'Throttling Factor', class: 'label-bold'
- = f.number_field :sidekiq_throttling_factor, class: 'form-control', min: '0.01', max: '0.99', step: '0.01'
- .form-text.text-muted
- The factor by which the queues should be throttled. A value between 0.0 and 1.0, exclusive.
-
- = f.submit 'Save changes', class: "btn btn-success"
diff --git a/app/views/admin/application_settings/_influx.html.haml b/app/views/admin/application_settings/_influx.html.haml
index a1eeacd8290..dc5cbb8fa94 100644
--- a/app/views/admin/application_settings/_influx.html.haml
+++ b/app/views/admin/application_settings/_influx.html.haml
@@ -3,7 +3,7 @@
%fieldset
%p
- Setup InfluxDB to measure a wide variety of statistics like the time spent
+ Set up InfluxDB to measure a wide variety of statistics like the time spent
in running SQL queries. These settings require a
= link_to 'restart', help_page_path('administration/restart_gitlab')
to take effect.
diff --git a/app/views/admin/application_settings/_repository_mirrors_form.html.haml b/app/views/admin/application_settings/_repository_mirrors_form.html.haml
index c94f4c74820..615aa6317b0 100644
--- a/app/views/admin/application_settings/_repository_mirrors_form.html.haml
+++ b/app/views/admin/application_settings/_repository_mirrors_form.html.haml
@@ -7,9 +7,9 @@
.form-check
= f.check_box :mirror_available, class: 'form-check-input'
= f.label :mirror_available, class: 'form-check-label' do
- Allow mirrors to be setup for projects
+ Allow mirrors to be set up for projects
%span.form-text.text-muted
- If disabled, only admins will be able to setup mirrors in projects.
+ If disabled, only admins will be able to set up mirrors in projects.
= link_to icon('question-circle'), help_page_path('workflow/repository_mirroring')
= f.submit 'Save changes', class: "btn btn-success"
diff --git a/app/views/admin/application_settings/_signin.html.haml b/app/views/admin/application_settings/_signin.html.haml
index 635a6751e5b..5f36358f599 100644
--- a/app/views/admin/application_settings/_signin.html.haml
+++ b/app/views/admin/application_settings/_signin.html.haml
@@ -31,7 +31,7 @@
.form-check
= f.check_box :require_two_factor_authentication, class: 'form-check-input'
= f.label :require_two_factor_authentication, class: 'form-check-label' do
- Require all users to setup Two-factor authentication
+ Require all users to set up Two-factor authentication
.form-group
= f.label :two_factor_authentication, 'Two-factor grace period (hours)', class: 'label-bold'
= f.number_field :two_factor_grace_period, min: 0, class: 'form-control', placeholder: '0'
diff --git a/app/views/admin/application_settings/ci_cd.html.haml b/app/views/admin/application_settings/ci_cd.html.haml
new file mode 100644
index 00000000000..db24c9982f7
--- /dev/null
+++ b/app/views/admin/application_settings/ci_cd.html.haml
@@ -0,0 +1,26 @@
+- breadcrumb_title _("CI/CD")
+- page_title _("CI/CD")
+- @content_class = "limit-container-width" unless fluid_layout
+
+%section.settings.as-ci-cd.no-animate#js-ci-cd-settings{ class: ('expanded' if expanded_by_default?) }
+ .settings-header
+ %h4
+ = _('Continuous Integration and Deployment')
+ %button.btn.btn-default.js-settings-toggle{ type: 'button' }
+ = expanded_by_default? ? _('Collapse') : _('Expand')
+ %p
+ = _('Auto DevOps, runners and job artifacts')
+ .settings-content
+ = render 'ci_cd'
+
+- if Gitlab.config.registry.enabled
+ %section.settings.as-registry.no-animate#js-registry-settings{ class: ('expanded' if expanded_by_default?) }
+ .settings-header
+ %h4
+ = _('Container Registry')
+ %button.btn.btn-default.js-settings-toggle{ type: 'button' }
+ = expanded_by_default? ? _('Collapse') : _('Expand')
+ %p
+ = _('Various container registry settings.')
+ .settings-content
+ = render 'registry'
diff --git a/app/views/admin/application_settings/integrations.html.haml b/app/views/admin/application_settings/integrations.html.haml
new file mode 100644
index 00000000000..310e86b1377
--- /dev/null
+++ b/app/views/admin/application_settings/integrations.html.haml
@@ -0,0 +1,31 @@
+- breadcrumb_title _("Integrations")
+- page_title _("Integrations")
+- @content_class = "limit-container-width" unless fluid_layout
+
+= render_if_exists 'admin/application_settings/elasticsearch_form', expanded: expanded_by_default?
+
+%section.settings.as-plantuml.no-animate#js-plantuml-settings{ class: ('expanded' if expanded_by_default?) }
+ .settings-header
+ %h4
+ = _('PlantUML')
+ %button.btn.btn-default.js-settings-toggle{ type: 'button' }
+ = expanded_by_default? ? _('Collapse') : _('Expand')
+ %p
+ = _('Allow rendering of PlantUML diagrams in Asciidoc documents.')
+ .settings-content
+ = render 'plantuml'
+
+= render_if_exists 'admin/application_settings/slack', expanded: expanded_by_default?
+
+%section.settings.as-third-party-offers.no-animate#js-third-party-offers-settings{ class: ('expanded' if expanded_by_default?) }
+ .settings-header
+ %h4
+ = _('Third party offers')
+ %button.btn.btn-default.js-settings-toggle{ type: 'button' }
+ = expanded_by_default? ? _('Collapse') : _('Expand')
+ %p
+ = _('Control the display of third party offers.')
+ .settings-content
+ = render 'third_party_offers', application_setting: @application_setting
+
+= render_if_exists 'admin/application_settings/snowplow', expanded: expanded_by_default?
diff --git a/app/views/admin/application_settings/metrics_and_profiling.html.haml b/app/views/admin/application_settings/metrics_and_profiling.html.haml
new file mode 100644
index 00000000000..f50aca32bdf
--- /dev/null
+++ b/app/views/admin/application_settings/metrics_and_profiling.html.haml
@@ -0,0 +1,50 @@
+- breadcrumb_title _("Metrics and profiling")
+- page_title _("Metrics and profiling")
+- @content_class = "limit-container-width" unless fluid_layout
+
+%section.settings.as-influx.no-animate#js-influx-settings{ class: ('expanded' if expanded_by_default?) }
+ .settings-header
+ %h4
+ = _('Metrics - Influx')
+ %button.btn.btn-default.js-settings-toggle{ type: 'button' }
+ = expanded_by_default? ? _('Collapse') : _('Expand')
+ %p
+ = _('Enable and configure InfluxDB metrics.')
+ .settings-content
+ = render 'influx'
+
+%section.settings.as-prometheus.no-animate#js-prometheus-settings{ class: ('expanded' if expanded_by_default?) }
+ .settings-header
+ %h4
+ = _('Metrics - Prometheus')
+ %button.btn.btn-default.js-settings-toggle{ type: 'button' }
+ = expanded_by_default? ? _('Collapse') : _('Expand')
+ %p
+ = _('Enable and configure Prometheus metrics.')
+ .settings-content
+ = render 'prometheus'
+
+%section.settings.as-performance-bar.no-animate#js-performance-bar-settings{ class: ('expanded' if expanded_by_default?) }
+ .settings-header
+ %h4
+ = _('Profiling - Performance bar')
+ %button.btn.btn-default.js-settings-toggle{ type: 'button' }
+ = expanded_by_default? ? _('Collapse') : _('Expand')
+ %p
+ = _('Enable the Performance Bar for a given group.')
+ = link_to icon('question-circle'), help_page_path('administration/monitoring/performance/performance_bar')
+ .settings-content
+ = render 'performance_bar'
+
+%section.settings.as-usage.no-animate#js-usage-settings{ class: ('expanded' if expanded_by_default?) }
+ .settings-header#usage-statistics
+ %h4
+ = _('Usage statistics')
+ %button.btn.btn-default.js-settings-toggle{ type: 'button' }
+ = expanded_by_default? ? _('Collapse') : _('Expand')
+ %p
+ = _('Enable or disable version check and usage ping.')
+ .settings-content
+ = render 'usage'
+
+= render_if_exists 'admin/application_settings/pseudonymizer_settings', expanded: expanded_by_default?
diff --git a/app/views/admin/application_settings/network.html.haml b/app/views/admin/application_settings/network.html.haml
new file mode 100644
index 00000000000..26fd745f45f
--- /dev/null
+++ b/app/views/admin/application_settings/network.html.haml
@@ -0,0 +1,36 @@
+- breadcrumb_title _("Network")
+- page_title _("Network")
+- @content_class = "limit-container-width" unless fluid_layout
+
+%section.settings.as-performance.no-animate#js-performance-settings{ class: ('expanded' if expanded_by_default?) }
+ .settings-header
+ %h4
+ = _('Performance optimization')
+ %button.btn.btn-default.js-settings-toggle{ type: 'button' }
+ = expanded_by_default? ? _('Collapse') : _('Expand')
+ %p
+ = _('Various settings that affect GitLab performance.')
+ .settings-content
+ = render 'performance'
+
+%section.settings.as-ip-limits.no-animate#js-ip-limits-settings{ class: ('expanded' if expanded_by_default?) }
+ .settings-header
+ %h4
+ = _('User and IP Rate Limits')
+ %button.btn.btn-default.js-settings-toggle{ type: 'button' }
+ = expanded_by_default? ? _('Collapse') : _('Expand')
+ %p
+ = _('Configure limits for web and API requests.')
+ .settings-content
+ = render 'ip_limits'
+
+%section.settings.as-outbound.no-animate#js-outbound-settings{ class: ('expanded' if expanded_by_default?) }
+ .settings-header
+ %h4
+ = _('Outbound requests')
+ %button.btn.btn-default.js-settings-toggle{ type: 'button' }
+ = expanded_by_default? ? _('Collapse') : _('Expand')
+ %p
+ = _('Allow requests to the local network from hooks and services.')
+ .settings-content
+ = render 'outbound'
diff --git a/app/views/admin/application_settings/preferences.html.haml b/app/views/admin/application_settings/preferences.html.haml
new file mode 100644
index 00000000000..00000b86ab7
--- /dev/null
+++ b/app/views/admin/application_settings/preferences.html.haml
@@ -0,0 +1,58 @@
+- breadcrumb_title _("Preferences")
+- page_title _("Preferences")
+- @content_class = "limit-container-width" unless fluid_layout
+
+%section.settings.as-email.no-animate#js-email-settings{ class: ('expanded' if expanded_by_default?) }
+ .settings-header
+ %h4
+ = _('Email')
+ %button.btn.btn-default.js-settings-toggle{ type: 'button' }
+ = expanded_by_default? ? _('Collapse') : _('Expand')
+ %p
+ = _('Various email settings.')
+ .settings-content
+ = render 'email'
+
+%section.settings.as-help-page.no-animate#js-help-settings{ class: ('expanded' if expanded_by_default?) }
+ .settings-header
+ %h4
+ = _('Help page')
+ %button.btn.btn-default.js-settings-toggle{ type: 'button' }
+ = expanded_by_default? ? _('Collapse') : _('Expand')
+ %p
+ = _('Help page text and support page url.')
+ .settings-content
+ = render 'help_page'
+
+%section.settings.as-pages.no-animate#js-pages-settings{ class: ('expanded' if expanded_by_default?) }
+ .settings-header
+ %h4
+ = _('Pages')
+ %button.btn.btn-default.js-settings-toggle{ type: 'button' }
+ = expanded_by_default? ? _('Collapse') : _('Expand')
+ %p
+ = _('Size and domain settings for static websites')
+ .settings-content
+ = render 'pages'
+
+%section.settings.as-realtime.no-animate#js-realtime-settings{ class: ('expanded' if expanded_by_default?) }
+ .settings-header
+ %h4
+ = _('Real-time features')
+ %button.btn.btn-default.js-settings-toggle{ type: 'button' }
+ = expanded_by_default? ? _('Collapse') : _('Expand')
+ %p
+ = _('Change this value to influence how frequently the GitLab UI polls for updates.')
+ .settings-content
+ = render 'realtime'
+
+%section.settings.as-gitaly.no-animate#js-gitaly-settings{ class: ('expanded' if expanded_by_default?) }
+ .settings-header
+ %h4
+ = _('Gitaly')
+ %button.btn.btn-default.js-settings-toggle{ type: 'button' }
+ = expanded_by_default? ? _('Collapse') : _('Expand')
+ %p
+ = _('Configure Gitaly timeouts.')
+ .settings-content
+ = render 'gitaly'
diff --git a/app/views/admin/application_settings/reporting.html.haml b/app/views/admin/application_settings/reporting.html.haml
new file mode 100644
index 00000000000..1c2d9ccdb2d
--- /dev/null
+++ b/app/views/admin/application_settings/reporting.html.haml
@@ -0,0 +1,36 @@
+- breadcrumb_title _("Reporting")
+- page_title _("Reporting")
+- @content_class = "limit-container-width" unless fluid_layout
+
+%section.settings.as-spam.no-animate#js-spam-settings{ class: ('expanded' if expanded_by_default?) }
+ .settings-header
+ %h4
+ = _('Spam and Anti-bot Protection')
+ %button.btn.btn-default.js-settings-toggle{ type: 'button' }
+ = expanded_by_default? ? _('Collapse') : _('Expand')
+ %p
+ = _('Enable reCAPTCHA or Akismet and set IP limits.')
+ .settings-content
+ = render 'spam'
+
+%section.settings.as-abuse.no-animate#js-abuse-settings{ class: ('expanded' if expanded_by_default?) }
+ .settings-header
+ %h4
+ = _('Abuse reports')
+ %button.btn.btn-default.js-settings-toggle{ type: 'button' }
+ = expanded_by_default? ? _('Collapse') : _('Expand')
+ %p
+ = _('Set notification email for abuse reports.')
+ .settings-content
+ = render 'abuse'
+
+%section.settings.as-logging.no-animate#js-logging-settings{ class: ('expanded' if expanded_by_default?) }
+ .settings-header
+ %h4
+ = _('Error Reporting and Logging')
+ %button.btn.btn-default.js-settings-toggle{ type: 'button' }
+ = expanded_by_default? ? _('Collapse') : _('Expand')
+ %p
+ = _('Enable Sentry for error reporting and logging.')
+ .settings-content
+ = render 'logging'
diff --git a/app/views/admin/application_settings/repository.html.haml b/app/views/admin/application_settings/repository.html.haml
new file mode 100644
index 00000000000..d8029e0c54a
--- /dev/null
+++ b/app/views/admin/application_settings/repository.html.haml
@@ -0,0 +1,36 @@
+- breadcrumb_title _("Repository")
+- page_title _("Repository")
+- @content_class = "limit-container-width" unless fluid_layout
+
+%section.settings.as-mirror.no-animate#js-mirror-settings{ class: ('expanded' if expanded_by_default?) }
+ .settings-header
+ %h4
+ = _('Repository mirror')
+ %button.btn.js-settings-toggle{ type: 'button' }
+ = expanded_by_default? ? 'Collapse' : 'Expand'
+ %p
+ = _('Configure push mirrors.')
+ .settings-content
+ = render partial: 'repository_mirrors_form'
+
+%section.settings.as-repository-storage.no-animate#js-repository-storage-settings{ class: ('expanded' if expanded_by_default?) }
+ .settings-header
+ %h4
+ = _('Repository storage')
+ %button.btn.btn-default.js-settings-toggle{ type: 'button' }
+ = expanded_by_default? ? _('Collapse') : _('Expand')
+ %p
+ = _('Configure storage path and circuit breaker settings.')
+ .settings-content
+ = render 'repository_storage'
+
+%section.settings.as-repository-check.no-animate#js-repository-check-settings{ class: ('expanded' if expanded_by_default?) }
+ .settings-header
+ %h4
+ = _('Repository maintenance')
+ %button.btn.btn-default.js-settings-toggle{ type: 'button' }
+ = expanded_by_default? ? _('Collapse') : _('Expand')
+ %p
+ = _('Configure automatic git checks and housekeeping on repositories.')
+ .settings-content
+ = render 'repository_check'
diff --git a/app/views/admin/application_settings/show.html.haml b/app/views/admin/application_settings/show.html.haml
index 194a8157013..e2043183a97 100644
--- a/app/views/admin/application_settings/show.html.haml
+++ b/app/views/admin/application_settings/show.html.haml
@@ -1,359 +1,93 @@
-- breadcrumb_title "Settings"
-- page_title "Settings"
+- breadcrumb_title _("Settings")
+- page_title _("Settings")
- @content_class = "limit-container-width" unless fluid_layout
-- expanded = Rails.env.test?
-%section.settings.as-visibility-access.no-animate#js-visibility-settings{ class: ('expanded' if expanded) }
+%section.settings.as-visibility-access.no-animate#js-visibility-settings{ class: ('expanded' if expanded_by_default?) }
.settings-header
%h4
= _('Visibility and access controls')
%button.btn.js-settings-toggle{ type: 'button' }
- = expanded ? _('Collapse') : _('Expand')
+ = expanded_by_default? ? _('Collapse') : _('Expand')
%p
= _('Set default and restrict visibility levels. Configure import sources and git access protocol.')
.settings-content
= render 'visibility_and_access'
-%section.settings.as-account-limit.no-animate#js-account-settings{ class: ('expanded' if expanded) }
+%section.settings.as-account-limit.no-animate#js-account-settings{ class: ('expanded' if expanded_by_default?) }
.settings-header
%h4
= _('Account and limit')
%button.btn.js-settings-toggle{ type: 'button' }
- = expanded ? _('Collapse') : _('Expand')
+ = expanded_by_default? ? _('Collapse') : _('Expand')
%p
= _('Session expiration, projects limit and attachment size.')
.settings-content
= render 'account_and_limit'
-%section.settings.as-signup.no-animate#js-signup-settings{ class: ('expanded' if expanded) }
+%section.settings.as-signup.no-animate#js-signup-settings{ class: ('expanded' if expanded_by_default?) }
.settings-header
%h4
= _('Sign-up restrictions')
%button.btn.js-settings-toggle{ type: 'button' }
- = expanded ? _('Collapse') : _('Expand')
+ = expanded_by_default? ? _('Collapse') : _('Expand')
%p
= _('Configure the way a user creates a new account.')
.settings-content
= render 'signup'
-%section.settings.as-signin.no-animate#js-signin-settings{ class: ('expanded' if expanded) }
+%section.settings.as-signin.no-animate#js-signin-settings{ class: ('expanded' if expanded_by_default?) }
.settings-header
%h4
= _('Sign-in restrictions')
%button.btn.js-settings-toggle{ type: 'button' }
- = expanded ? _('Collapse') : _('Expand')
+ = expanded_by_default? ? _('Collapse') : _('Expand')
%p
= _('Set requirements for a user to sign-in. Enable mandatory two-factor authentication.')
.settings-content
= render 'signin'
-%section.settings.as-terms.no-animate#js-terms-settings{ class: ('expanded' if expanded) }
+%section.qa-terms-settings.settings.as-terms.no-animate#js-terms-settings{ class: ('expanded' if expanded_by_default?) }
.settings-header
%h4
= _('Terms of Service and Privacy Policy')
%button.btn.btn-default.js-settings-toggle{ type: 'button' }
- = expanded ? _('Collapse') : _('Expand')
+ = expanded_by_default? ? _('Collapse') : _('Expand')
%p
= _('Include a Terms of Service agreement and Privacy Policy that all users must accept.')
.settings-content
= render 'terms'
-%section.settings.as-help-page.no-animate#js-help-settings{ class: ('expanded' if expanded) }
- .settings-header
- %h4
- = _('Help page')
- %button.btn.btn-default.js-settings-toggle{ type: 'button' }
- = expanded ? _('Collapse') : _('Expand')
- %p
- = _('Help page text and support page url.')
- .settings-content
- = render 'help_page'
-
-%section.settings.as-pages.no-animate#js-pages-settings{ class: ('expanded' if expanded) }
- .settings-header
- %h4
- = _('Pages')
- %button.btn.btn-default.js-settings-toggle{ type: 'button' }
- = expanded ? _('Collapse') : _('Expand')
- %p
- = _('Size and domain settings for static websites')
- .settings-content
- = render 'pages'
-
-%section.settings.as-ci-cd.no-animate#js-ci-cd-settings{ class: ('expanded' if expanded) }
- .settings-header
- %h4
- = _('Continuous Integration and Deployment')
- %button.btn.btn-default.js-settings-toggle{ type: 'button' }
- = expanded ? _('Collapse') : _('Expand')
- %p
- = _('Auto DevOps, runners and job artifacts')
- .settings-content
- = render 'ci_cd'
-
-%section.settings.as-influx.no-animate#js-influx-settings{ class: ('expanded' if expanded) }
- .settings-header
- %h4
- = _('Metrics - Influx')
- %button.btn.btn-default.js-settings-toggle{ type: 'button' }
- = expanded ? _('Collapse') : _('Expand')
- %p
- = _('Enable and configure InfluxDB metrics.')
- .settings-content
- = render 'influx'
-
-%section.settings.as-prometheus.no-animate#js-prometheus-settings{ class: ('expanded' if expanded) }
- .settings-header
- %h4
- = _('Metrics - Prometheus')
- %button.btn.btn-default.js-settings-toggle{ type: 'button' }
- = expanded ? _('Collapse') : _('Expand')
- %p
- = _('Enable and configure Prometheus metrics.')
- .settings-content
- = render 'prometheus'
-
-%section.settings.as-performance-bar.no-animate#js-performance-bar-settings{ class: ('expanded' if expanded) }
- .settings-header
- %h4
- = _('Profiling - Performance bar')
- %button.btn.btn-default.js-settings-toggle{ type: 'button' }
- = expanded ? _('Collapse') : _('Expand')
- %p
- = _('Enable the Performance Bar for a given group.')
- = link_to icon('question-circle'), help_page_path('administration/monitoring/performance/performance_bar')
- .settings-content
- = render 'performance_bar'
-
-%section.settings.as-background.no-animate#js-background-settings{ class: ('expanded' if expanded) }
- .settings-header
- %h4
- = _('Background jobs')
- %button.btn.btn-default.js-settings-toggle{ type: 'button' }
- = expanded ? _('Collapse') : _('Expand')
- %p
- = _('Configure Sidekiq job throttling.')
- .settings-content
- = render 'background_jobs'
-
-%section.settings.as-spam.no-animate#js-spam-settings{ class: ('expanded' if expanded) }
- .settings-header
- %h4
- = _('Spam and Anti-bot Protection')
- %button.btn.btn-default.js-settings-toggle{ type: 'button' }
- = expanded ? _('Collapse') : _('Expand')
- %p
- = _('Enable reCAPTCHA or Akismet and set IP limits.')
- .settings-content
- = render 'spam'
-
-%section.settings.as-abuse.no-animate#js-abuse-settings{ class: ('expanded' if expanded) }
- .settings-header
- %h4
- = _('Abuse reports')
- %button.btn.btn-default.js-settings-toggle{ type: 'button' }
- = expanded ? _('Collapse') : _('Expand')
- %p
- = _('Set notification email for abuse reports.')
- .settings-content
- = render 'abuse'
-
-%section.settings.as-logging.no-animate#js-logging-settings{ class: ('expanded' if expanded) }
- .settings-header
- %h4
- = _('Error Reporting and Logging')
- %button.btn.btn-default.js-settings-toggle{ type: 'button' }
- = expanded ? _('Collapse') : _('Expand')
- %p
- = _('Enable Sentry for error reporting and logging.')
- .settings-content
- = render 'logging'
-
-%section.qa-repository-storage-settings.settings.as-repository-storage.no-animate#js-repository-storage-settings{ class: ('expanded' if expanded) }
- .settings-header
- %h4
- = _('Repository storage')
- %button.btn.btn-default.js-settings-toggle{ type: 'button' }
- = expanded ? _('Collapse') : _('Expand')
- %p
- = _('Configure storage path and circuit breaker settings.')
- .settings-content
- = render 'repository_storage'
-
-%section.settings.as-repository-check.no-animate#js-repository-check-settings{ class: ('expanded' if expanded) }
- .settings-header
- %h4
- = _('Repository maintenance')
- %button.btn.btn-default.js-settings-toggle{ type: 'button' }
- = expanded ? _('Collapse') : _('Expand')
- %p
- = _('Configure automatic git checks and housekeeping on repositories.')
- .settings-content
- = render 'repository_check'
-
-- if Gitlab.config.registry.enabled
- %section.settings.as-registry.no-animate#js-registry-settings{ class: ('expanded' if expanded) }
- .settings-header
- %h4
- = _('Container Registry')
- %button.btn.btn-default.js-settings-toggle{ type: 'button' }
- = expanded ? _('Collapse') : _('Expand')
- %p
- = _('Various container registry settings.')
- .settings-content
- = render 'registry'
-
- if koding_enabled?
- %section.settings.as-koding.no-animate#js-koding-settings{ class: ('expanded' if expanded) }
+ %section.settings.as-koding.no-animate#js-koding-settings{ class: ('expanded' if expanded_by_default?) }
.settings-header
%h4
= _('Koding')
%button.btn.btn-default.js-settings-toggle{ type: 'button' }
- = expanded ? _('Collapse') : _('Expand')
+ = expanded_by_default? ? _('Collapse') : _('Expand')
%p
= _('Online IDE integration settings.')
.settings-content
= render 'koding'
-%section.settings.as-plantuml.no-animate#js-plantuml-settings{ class: ('expanded' if expanded) }
- .settings-header
- %h4
- = _('PlantUML')
- %button.btn.btn-default.js-settings-toggle{ type: 'button' }
- = expanded ? _('Collapse') : _('Expand')
- %p
- = _('Allow rendering of PlantUML diagrams in Asciidoc documents.')
- .settings-content
- = render 'plantuml'
-
-%section.settings.as-usage.no-animate#js-usage-settings{ class: ('expanded' if expanded) }
- .settings-header#usage-statistics
- %h4
- = _('Usage statistics')
- %button.btn.btn-default.js-settings-toggle{ type: 'button' }
- = expanded ? _('Collapse') : _('Expand')
- %p
- = _('Enable or disable version check and usage ping.')
- .settings-content
- = render 'usage'
-
-%section.settings.as-email.no-animate#js-email-settings{ class: ('expanded' if expanded) }
- .settings-header
- %h4
- = _('Email')
- %button.btn.btn-default.js-settings-toggle{ type: 'button' }
- = expanded ? _('Collapse') : _('Expand')
- %p
- = _('Various email settings.')
- .settings-content
- = render 'email'
-
-%section.settings.as-gitaly.no-animate#js-gitaly-settings{ class: ('expanded' if expanded) }
- .settings-header
- %h4
- = _('Gitaly')
- %button.btn.btn-default.js-settings-toggle{ type: 'button' }
- = expanded ? _('Collapse') : _('Expand')
- %p
- = _('Configure Gitaly timeouts.')
- .settings-content
- = render 'gitaly'
+= render_if_exists 'admin/application_settings/external_authorization_service_form', expanded: expanded_by_default?
-%section.settings.as-terminal.no-animate#js-terminal-settings{ class: ('expanded' if expanded) }
+%section.settings.as-terminal.no-animate#js-terminal-settings{ class: ('expanded' if expanded_by_default?) }
.settings-header
%h4
= _('Web terminal')
%button.btn.btn-default.js-settings-toggle{ type: 'button' }
- = expanded ? _('Collapse') : _('Expand')
+ = expanded_by_default? ? _('Collapse') : _('Expand')
%p
= _('Set max session time for web terminal.')
.settings-content
= render 'terminal'
-%section.settings.as-realtime.no-animate#js-realtime-settings{ class: ('expanded' if expanded) }
- .settings-header
- %h4
- = _('Real-time features')
- %button.btn.btn-default.js-settings-toggle{ type: 'button' }
- = expanded ? _('Collapse') : _('Expand')
- %p
- = _('Change this value to influence how frequently the GitLab UI polls for updates.')
- .settings-content
- = render 'realtime'
-
-%section.settings.as-performance.no-animate#js-performance-settings{ class: ('expanded' if expanded) }
- .settings-header
- %h4
- = _('Performance optimization')
- %button.btn.btn-default.js-settings-toggle{ type: 'button' }
- = expanded ? _('Collapse') : _('Expand')
- %p
- = _('Various settings that affect GitLab performance.')
- .settings-content
- = render 'performance'
-
-%section.settings.as-ip-limits.no-animate#js-ip-limits-settings{ class: ('expanded' if expanded) }
- .settings-header
- %h4
- = _('User and IP Rate Limits')
- %button.btn.btn-default.js-settings-toggle{ type: 'button' }
- = expanded ? _('Collapse') : _('Expand')
- %p
- = _('Configure limits for web and API requests.')
- .settings-content
- = render 'ip_limits'
-
-%section.settings.as-outbound.no-animate#js-outbound-settings{ class: ('expanded' if expanded) }
- .settings-header
- %h4
- = _('Outbound requests')
- %button.btn.btn-default.js-settings-toggle{ type: 'button' }
- = expanded ? _('Collapse') : _('Expand')
- %p
- = _('Allow requests to the local network from hooks and services.')
- .settings-content
- = render 'outbound'
-
-%section.settings.as-mirror.no-animate#js-mirror-settings{ class: ('expanded' if expanded) }
- .settings-header
- %h4
- = _('Repository mirror')
- %button.btn.js-settings-toggle{ type: 'button' }
- = expanded ? 'Collapse' : 'Expand'
- %p
- = _('Configure push mirrors.')
- .settings-content
- = render partial: 'repository_mirrors_form'
-
-= render_if_exists 'admin/application_settings/geo', expanded: expanded
-
-= render_if_exists 'admin/application_settings/external_authorization_service_form', expanded: expanded
-
-= render_if_exists 'admin/application_settings/elasticsearch_form', expanded: expanded
-
-= render_if_exists 'admin/application_settings/slack', expanded: expanded
-
-= render_if_exists 'admin/application_settings/templates', expanded: expanded
-
-%section.settings.as-third-party-offers.no-animate#js-third-party-offers-settings{ class: ('expanded' if expanded) }
- .settings-header
- %h4
- = _('Third party offers')
- %button.btn.btn-default.js-settings-toggle{ type: 'button' }
- = expanded ? _('Collapse') : _('Expand')
- %p
- = _('Control the display of third party offers.')
- .settings-content
- = render 'third_party_offers', application_setting: @application_setting
-
-= render_if_exists 'admin/application_settings/custom_templates_form', expanded: expanded
-
-%section.settings.no-animate#js-web-ide-settings{ class: ('expanded' if expanded) }
+%section.settings.no-animate#js-web-ide-settings{ class: ('expanded' if expanded_by_default?) }
.settings-header
%h4
= _('Web IDE')
%button.btn.btn-default.js-settings-toggle{ type: 'button' }
- = expanded ? _('Collapse') : _('Expand')
+ = expanded_by_default? ? _('Collapse') : _('Expand')
%p
= _('Manage Web IDE features')
.settings-content
@@ -370,5 +104,3 @@
= s_('IDE|Allow live previews of JavaScript projects in the Web IDE using CodeSandbox client side evaluation.')
= f.submit _('Save changes'), class: "btn btn-success"
-
-= render_if_exists 'admin/application_settings/pseudonymizer_settings', expanded: expanded
diff --git a/app/views/admin/applications/_form.html.haml b/app/views/admin/applications/_form.html.haml
index 7f14cddebd8..12690343f6e 100644
--- a/app/views/admin/applications/_form.html.haml
+++ b/app/views/admin/applications/_form.html.haml
@@ -21,17 +21,17 @@
for local tests
= content_tag :div, class: 'form-group row' do
- = f.label :trusted, class: 'col-sm-2 col-form-label'
+ = f.label :trusted, class: 'col-sm-2 col-form-label pt-0'
.col-sm-10
= f.check_box :trusted
%span.form-text.text-muted
Trusted applications are automatically authorized on GitLab OAuth flow.
.form-group.row
- = f.label :scopes, class: 'col-sm-2 col-form-label'
+ = f.label :scopes, class: 'col-sm-2 col-form-label pt-0'
.col-sm-10
= render 'shared/tokens/scopes_form', prefix: 'doorkeeper_application', token: application, scopes: @scopes
.form-actions
- = f.submit 'Submit', class: "btn btn-save wide"
+ = f.submit 'Submit', class: "btn btn-success wide"
= link_to "Cancel", admin_applications_path, class: "btn btn-cancel"
diff --git a/app/views/admin/broadcast_messages/_form.html.haml b/app/views/admin/broadcast_messages/_form.html.haml
index 7f34357f147..c465d9f51d6 100644
--- a/app/views/admin/broadcast_messages/_form.html.haml
+++ b/app/views/admin/broadcast_messages/_form.html.haml
@@ -36,6 +36,6 @@
= f.datetime_select :ends_at, {}, class: 'form-control form-control-inline'
.form-actions
- if @broadcast_message.persisted?
- = f.submit "Update broadcast message", class: "btn btn-create"
+ = f.submit "Update broadcast message", class: "btn btn-success"
- else
- = f.submit "Add broadcast message", class: "btn btn-create"
+ = f.submit "Add broadcast message", class: "btn btn-success"
diff --git a/app/views/admin/dashboard/index.html.haml b/app/views/admin/dashboard/index.html.haml
index fac61f9d249..85c04f8a01d 100644
--- a/app/views/admin/dashboard/index.html.haml
+++ b/app/views/admin/dashboard/index.html.haml
@@ -14,7 +14,7 @@
Projects:
= approximate_count_with_delimiters(@counts, Project)
%hr
- = link_to('New project', new_project_path, class: "btn btn-new")
+ = link_to('New project', new_project_path, class: "btn btn-success")
.col-sm-4
.info-well.dark-well
.well-segment.well-centered
@@ -24,7 +24,7 @@
= approximate_count_with_delimiters(@counts, User)
= render_if_exists 'admin/dashboard/users_statistics'
%hr
- = link_to 'New user', new_admin_user_path, class: "btn btn-new"
+ = link_to 'New user', new_admin_user_path, class: "btn btn-success"
.col-sm-4
.info-well.dark-well
.well-segment.well-centered
@@ -33,7 +33,7 @@
Groups:
= approximate_count_with_delimiters(@counts, Group)
%hr
- = link_to 'New group', new_admin_group_path, class: "btn btn-new"
+ = link_to 'New group', new_admin_group_path, class: "btn btn-success"
.row
.col-md-4
.info-well
diff --git a/app/views/admin/deploy_keys/edit.html.haml b/app/views/admin/deploy_keys/edit.html.haml
index b50adef362f..7c04ef03947 100644
--- a/app/views/admin/deploy_keys/edit.html.haml
+++ b/app/views/admin/deploy_keys/edit.html.haml
@@ -6,5 +6,5 @@
= form_for [:admin, @deploy_key], html: { class: 'deploy-key-form' } do |f|
= render partial: 'shared/deploy_keys/form', locals: { form: f, deploy_key: @deploy_key }
.form-actions
- = f.submit 'Save changes', class: 'btn-save btn'
+ = f.submit 'Save changes', class: 'btn-success btn'
= link_to 'Cancel', admin_deploy_keys_path, class: 'btn btn-cancel'
diff --git a/app/views/admin/deploy_keys/index.html.haml b/app/views/admin/deploy_keys/index.html.haml
index 52ab8bae119..01013be06d6 100644
--- a/app/views/admin/deploy_keys/index.html.haml
+++ b/app/views/admin/deploy_keys/index.html.haml
@@ -3,7 +3,7 @@
%h3.page-title.deploy-keys-title
Public deploy keys (#{@deploy_keys.count})
.float-right
- = link_to 'New deploy key', new_admin_deploy_key_path, class: 'btn btn-new btn-sm btn-inverted'
+ = link_to 'New deploy key', new_admin_deploy_key_path, class: 'btn btn-success btn-sm btn-inverted'
- if @deploy_keys.any?
.table-holder.deploy-keys-list
diff --git a/app/views/admin/deploy_keys/new.html.haml b/app/views/admin/deploy_keys/new.html.haml
index d4f8e340b69..9a563a5bc78 100644
--- a/app/views/admin/deploy_keys/new.html.haml
+++ b/app/views/admin/deploy_keys/new.html.haml
@@ -6,5 +6,5 @@
= form_for [:admin, @deploy_key], html: { class: 'deploy-key-form' } do |f|
= render partial: 'shared/deploy_keys/form', locals: { form: f, deploy_key: @deploy_key }
.form-actions
- = f.submit 'Create', class: 'btn-create btn'
+ = f.submit 'Create', class: 'btn-success btn'
= link_to 'Cancel', admin_deploy_keys_path, class: 'btn btn-cancel'
diff --git a/app/views/admin/groups/_form.html.haml b/app/views/admin/groups/_form.html.haml
index a3773e90cfb..2a117c1414e 100644
--- a/app/views/admin/groups/_form.html.haml
+++ b/app/views/admin/groups/_form.html.haml
@@ -26,12 +26,12 @@
.alert.alert-info
= render 'shared/group_tips'
.form-actions
- = f.submit _('Create group'), class: "btn btn-create"
+ = f.submit _('Create group'), class: "btn btn-success"
= link_to _('Cancel'), admin_groups_path, class: "btn btn-cancel"
- else
.form-actions
- = f.submit _('Save changes'), class: "btn btn-save"
+ = f.submit _('Save changes'), class: "btn btn-success"
= link_to _('Cancel'), admin_group_path(@group), class: "btn btn-cancel"
= render_if_exists 'ldap_group_links/ldap_syncrhonizations', group: @group
diff --git a/app/views/admin/groups/index.html.haml b/app/views/admin/groups/index.html.haml
index 6a9b85b4109..cb833ffd9ac 100644
--- a/app/views/admin/groups/index.html.haml
+++ b/app/views/admin/groups/index.html.haml
@@ -12,7 +12,7 @@
= search_field_tag :name, project_name, class: "form-control search-text-input js-search-input", autofocus: true, spellcheck: false, placeholder: 'Search by name'
= icon("search", class: "search-icon")
= render "shared/groups/dropdown", options_hash: admin_groups_sort_options_hash
- = link_to new_admin_group_path, class: "btn btn-new" do
+ = link_to new_admin_group_path, class: "btn btn-success" do
= _('New group')
%ul.content-list
= render @groups
diff --git a/app/views/admin/groups/show.html.haml b/app/views/admin/groups/show.html.haml
index 72b068ea6b5..0c683f86252 100644
--- a/app/views/admin/groups/show.html.haml
+++ b/app/views/admin/groups/show.html.haml
@@ -111,7 +111,7 @@
.prepend-top-10
= select_tag :access_level, options_for_select(GroupMember.access_level_roles), class: "project-access-select select2"
%hr
- = button_tag _('Add users to group'), class: "btn btn-create"
+ = button_tag _('Add users to group'), class: "btn btn-success"
= render 'shared/members/requests', membership_source: @group, requesters: @requesters, force_mobile_view: true
.card
diff --git a/app/views/admin/hooks/edit.html.haml b/app/views/admin/hooks/edit.html.haml
index b9a650e1f1f..486d0477f20 100644
--- a/app/views/admin/hooks/edit.html.haml
+++ b/app/views/admin/hooks/edit.html.haml
@@ -12,7 +12,7 @@
= form_for @hook, as: :hook, url: admin_hook_path do |f|
= render partial: 'form', locals: { form: f, hook: @hook }
.form-actions
- = f.submit 'Save changes', class: 'btn btn-create'
+ = f.submit 'Save changes', class: 'btn btn-success'
= render 'shared/web_hooks/test_button', triggers: SystemHook.triggers, hook: @hook
= link_to 'Remove', admin_hook_path(@hook), method: :delete, class: 'btn btn-remove float-right', data: { confirm: 'Are you sure?' }
diff --git a/app/views/admin/hooks/index.html.haml b/app/views/admin/hooks/index.html.haml
index 87f9b0e86a7..5d462d7b732 100644
--- a/app/views/admin/hooks/index.html.haml
+++ b/app/views/admin/hooks/index.html.haml
@@ -10,7 +10,7 @@
.col-lg-8.append-bottom-default
= form_for @hook, as: :hook, url: admin_hooks_path do |f|
= render partial: 'form', locals: { form: f, hook: @hook }
- = f.submit 'Add system hook', class: 'btn btn-create'
+ = f.submit 'Add system hook', class: 'btn btn-success'
%hr
diff --git a/app/views/admin/identities/_form.html.haml b/app/views/admin/identities/_form.html.haml
index 946d868da01..3ab7990d9e2 100644
--- a/app/views/admin/identities/_form.html.haml
+++ b/app/views/admin/identities/_form.html.haml
@@ -12,5 +12,5 @@
= f.text_field :extern_uid, class: 'form-control', required: true
.form-actions
- = f.submit _('Save changes'), class: "btn btn-save"
+ = f.submit _('Save changes'), class: "btn btn-success"
diff --git a/app/views/admin/identities/index.html.haml b/app/views/admin/identities/index.html.haml
index df3df159947..9543bbcf977 100644
--- a/app/views/admin/identities/index.html.haml
+++ b/app/views/admin/identities/index.html.haml
@@ -3,7 +3,7 @@
- page_title _("Identities"), @user.name, _("Users")
= render 'admin/users/head'
-= link_to _('New identity'), new_admin_user_identity_path, class: 'float-right btn btn-new'
+= link_to _('New identity'), new_admin_user_identity_path, class: 'float-right btn btn-success'
- if @identities.present?
.table-holder
%table.table
diff --git a/app/views/admin/labels/_form.html.haml b/app/views/admin/labels/_form.html.haml
index ee2d4c8430a..5e7b4817461 100644
--- a/app/views/admin/labels/_form.html.haml
+++ b/app/views/admin/labels/_form.html.haml
@@ -27,5 +27,5 @@
&nbsp;
.form-actions
- = f.submit _('Save'), class: 'btn btn-save js-save-button'
+ = f.submit _('Save'), class: 'btn btn-success js-save-button'
= link_to _("Cancel"), admin_labels_path, class: 'btn btn-cancel'
diff --git a/app/views/admin/labels/index.html.haml b/app/views/admin/labels/index.html.haml
index f1b8658f84e..5a5b3d18c5f 100644
--- a/app/views/admin/labels/index.html.haml
+++ b/app/views/admin/labels/index.html.haml
@@ -1,7 +1,7 @@
- page_title _("Labels")
%div
- = link_to new_admin_label_path, class: "float-right btn btn-nr btn-new" do
+ = link_to new_admin_label_path, class: "float-right btn btn-nr btn-success" do
= _('New label')
%h3.page-title
= _('Labels')
diff --git a/app/views/admin/projects/index.html.haml b/app/views/admin/projects/index.html.haml
index 57de792f92d..46bb57c78a8 100644
--- a/app/views/admin/projects/index.html.haml
+++ b/app/views/admin/projects/index.html.haml
@@ -21,7 +21,7 @@
= dropdown_content
= dropdown_loading
= render 'shared/projects/dropdown'
- = link_to new_project_path, class: 'btn btn-new' do
+ = link_to new_project_path, class: 'btn btn-success' do
New Project
= button_tag "Search", class: "btn btn-primary btn-search hide"
diff --git a/app/views/admin/runners/_runner.html.haml b/app/views/admin/runners/_runner.html.haml
index 9c15226f0ec..e4fc2985087 100644
--- a/app/views/admin/runners/_runner.html.haml
+++ b/app/views/admin/runners/_runner.html.haml
@@ -1,47 +1,65 @@
.gl-responsive-table-row{ id: dom_id(runner) }
- = render layout: 'runner_table_cell', locals: { label: _('Type') } do
- - if runner.instance_type?
- %span.badge.badge-success shared
- - elsif runner.group_type?
- %span.badge.badge-success group
- - else
- %span.badge.badge-info specific
- - if runner.locked?
- %span.badge.badge-warning locked
- - unless runner.active?
- %span.badge.badge-danger paused
-
- = render layout: 'runner_table_cell', locals: { label: _('Runner token') } do
- = link_to runner.short_sha, admin_runner_path(runner)
-
- = render layout: 'runner_table_cell', locals: { label: _('Description') } do
- = runner.description
-
- = render layout: 'runner_table_cell', locals: { label: _('Version') } do
- = runner.version
-
- = render layout: 'runner_table_cell', locals: { label: _('IP Address') } do
- = runner.ip_address
-
- = render layout: 'runner_table_cell', locals: { label: _('Projects') } do
- - if runner.instance_type? || runner.group_type?
- = _('n/a')
- - else
- = runner.projects.count(:all)
-
- = render layout: 'runner_table_cell', locals: { label: _('Jobs') } do
- = runner.builds.count(:all)
-
- = render layout: 'runner_table_cell', locals: { label: _('Tags') } do
- - runner.tag_list.sort.each do |tag|
- %span.badge.badge-primary
- = tag
-
- = render layout: 'runner_table_cell', locals: { label: _('Last contact') } do
- - if runner.contacted_at
- = time_ago_with_tooltip runner.contacted_at
- - else
- = _('Never')
+ .table-section.section-10.section-wrap
+ .table-mobile-header{ role: 'rowheader' }= _('Type')
+ .table-mobile-content
+ - if runner.instance_type?
+ %span.badge.badge-success shared
+ - elsif runner.group_type?
+ %span.badge.badge-success group
+ - else
+ %span.badge.badge-info specific
+ - if runner.locked?
+ %span.badge.badge-warning locked
+ - unless runner.active?
+ %span.badge.badge-danger paused
+
+ .table-section.section-10
+ .table-mobile-header{ role: 'rowheader' }= _('Runner token')
+ .table-mobile-content
+ = link_to runner.short_sha, admin_runner_path(runner)
+
+ .table-section.section-15
+ .table-mobile-header{ role: 'rowheader' }= _('Description')
+ .table-mobile-content.str-truncated.has-tooltip{ title: runner.description }
+ = runner.description
+
+ .table-section.section-15
+ .table-mobile-header{ role: 'rowheader' }= _('Version')
+ .table-mobile-content.str-truncated.has-tooltip{ title: runner.version }
+ = runner.version
+
+ .table-section.section-10
+ .table-mobile-header{ role: 'rowheader' }= _('IP Address')
+ .table-mobile-content
+ = runner.ip_address
+
+ .table-section.section-5
+ .table-mobile-header{ role: 'rowheader' }= _('Projects')
+ .table-mobile-content
+ - if runner.instance_type? || runner.group_type?
+ = _('n/a')
+ - else
+ = runner.projects.count(:all)
+
+ .table-section.section-5
+ .table-mobile-header{ role: 'rowheader' }= _('Jobs')
+ .table-mobile-content
+ = runner.builds.count(:all)
+
+ .table-section.section-10.section-wrap
+ .table-mobile-header{ role: 'rowheader' }= _('Tags')
+ .table-mobile-content
+ - runner.tag_list.sort.each do |tag|
+ %span.badge.badge-primary
+ = tag
+
+ .table-section.section-10
+ .table-mobile-header{ role: 'rowheader' }= _('Last contact')
+ .table-mobile-content
+ - if runner.contacted_at
+ = time_ago_with_tooltip runner.contacted_at
+ - else
+ = _('Never')
.table-section.table-button-footer.section-10
.btn-group.table-action-buttons
diff --git a/app/views/admin/runners/_runner_table_cell.html.haml b/app/views/admin/runners/_runner_table_cell.html.haml
deleted file mode 100644
index 78526ee6d23..00000000000
--- a/app/views/admin/runners/_runner_table_cell.html.haml
+++ /dev/null
@@ -1,4 +0,0 @@
-.table-section.section-10
- .table-mobile-header{ role: 'rowheader' }= label
- .table-mobile-content
- = yield
diff --git a/app/views/admin/runners/index.html.haml b/app/views/admin/runners/index.html.haml
index 4dc076c95c5..a5326f4b909 100644
--- a/app/views/admin/runners/index.html.haml
+++ b/app/views/admin/runners/index.html.haml
@@ -4,7 +4,7 @@
%div{ class: container_class }
.bs-callout
%p
- = (_"A 'Runner' is a process which runs a job. You can setup as many Runners as you need.")
+ = (_"A 'Runner' is a process which runs a job. You can set up as many Runners as you need.")
%br
= _('Runners can be placed on separate users, servers, even on your local machine.')
%br
@@ -69,7 +69,7 @@
%ul{ data: { dropdown: true } }
%li.filter-dropdown-item{ data: { action: 'submit' } }
= button_tag class: %w[btn btn-link] do
- = icon('search')
+ = sprite_icon('search')
%span
= _('Press Enter or click to search')
%ul.filter-dropdown{ data: { dynamic: true, dropdown: true } }
@@ -77,17 +77,27 @@
= button_tag class: %w[btn btn-link] do
-# Encapsulate static class name `{{icon}}` inside #{} to bypass
-# haml lint's ClassAttributeWithStaticValue
- %i.fa{ class: "#{'{{icon}}'}" }
+ %svg
+ %use{ 'xlink:href': "#{'{{icon}}'}" }
%span.js-filter-hint
{{hint}}
%span.js-filter-tag.dropdown-light-content
{{tag}}
+
#js-dropdown-admin-runner-status.filtered-search-input-dropdown-menu.dropdown-menu
%ul{ data: { dropdown: true } }
- Ci::Runner::AVAILABLE_STATUSES.each do |status|
%li.filter-dropdown-item{ data: { value: status } }
= button_tag class: %w[btn btn-link] do
= status.titleize
+
+ #js-dropdown-admin-runner-type.filtered-search-input-dropdown-menu.dropdown-menu
+ %ul{ data: { dropdown: true } }
+ - Ci::Runner::AVAILABLE_TYPES.each do |runner_type|
+ %li.filter-dropdown-item{ data: { value: runner_type } }
+ = button_tag class: %w[btn btn-link] do
+ = runner_type.titleize
+
= button_tag class: %w[clear-search hidden] do
= icon('times')
.filter-dropdown-container
@@ -97,8 +107,16 @@
.runners-content.content-list
.table-holder
.gl-responsive-table-row.table-row-header{ role: 'row' }
- - [_('Type'), _('Runner token'), _('Description'), _('Version'), _('IP Address'), _('Projects'), _('Jobs'), _('Tags'), _('Last contact')].each do |label|
- .table-section.section-10{ role: 'rowheader' }= label
+ .table-section.section-10{ role: 'rowheader' }= _('Type')
+ .table-section.section-10{ role: 'rowheader' }= _('Runner token')
+ .table-section.section-15{ role: 'rowheader' }= _('Description')
+ .table-section.section-15{ role: 'rowheader' }= _('Version')
+ .table-section.section-10{ role: 'rowheader' }= _('IP Address')
+ .table-section.section-5{ role: 'rowheader' }= _('Projects')
+ .table-section.section-5{ role: 'rowheader' }= _('Jobs')
+ .table-section.section-10{ role: 'rowheader' }= _('Tags')
+ .table-section.section-10{ role: 'rowheader' }= _('Last contact')
+ .table-section.section-10{ role: 'rowheader' }
- @runners.each do |runner|
= render 'admin/runners/runner', runner: runner
diff --git a/app/views/admin/services/_form.html.haml b/app/views/admin/services/_form.html.haml
index 993006e8745..1798b44bbb7 100644
--- a/app/views/admin/services/_form.html.haml
+++ b/app/views/admin/services/_form.html.haml
@@ -7,4 +7,4 @@
= render 'shared/service_settings', form: form, subject: @service
.footer-block.row-content-block
- = form.submit 'Save', class: 'btn btn-save'
+ = form.submit 'Save', class: 'btn btn-success'
diff --git a/app/views/admin/users/_form.html.haml b/app/views/admin/users/_form.html.haml
index 7f21bdb91c8..296ef073144 100644
--- a/app/views/admin/users/_form.html.haml
+++ b/app/views/admin/users/_form.html.haml
@@ -75,8 +75,8 @@
.form-actions
- if @user.new_record?
- = f.submit 'Create user', class: "btn btn-create"
+ = f.submit 'Create user', class: "btn btn-success"
= link_to 'Cancel', admin_users_path, class: "btn btn-cancel"
- else
- = f.submit 'Save changes', class: "btn btn-save"
+ = f.submit 'Save changes', class: "btn btn-success"
= link_to 'Cancel', admin_user_path(@user), class: "btn btn-cancel"
diff --git a/app/views/admin/users/index.html.haml b/app/views/admin/users/index.html.haml
index faeb82656ba..f910e90d6ca 100644
--- a/app/views/admin/users/index.html.haml
+++ b/app/views/admin/users/index.html.haml
@@ -31,7 +31,7 @@
= sort_title_recently_updated
= link_to admin_users_path(sort: sort_value_oldest_updated, filter: params[:filter]) do
= sort_title_oldest_updated
- = link_to 'New user', new_admin_user_path, class: 'btn btn-new btn-search'
+ = link_to 'New user', new_admin_user_path, class: 'btn btn-success btn-search'
.top-area.scrolling-tabs-container.inner-page-scroll-tabs
.fade-left
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 c26eb873718..b1b142460b0 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") % { type: type }
+ %h4= _("Set up a %{type} Runner manually") % { type: type }
%ol
%li
diff --git a/app/views/ci/runner/_how_to_setup_specific_runner.html.haml b/app/views/ci/runner/_how_to_setup_specific_runner.html.haml
index e765a353fe4..afe57bdfa01 100644
--- a/app/views/ci/runner/_how_to_setup_specific_runner.html.haml
+++ b/app/views/ci/runner/_how_to_setup_specific_runner.html.haml
@@ -1,6 +1,6 @@
.bs-callout.help-callout
.append-bottom-10
- %h4= _('Setup a specific Runner automatically')
+ %h4= _('Set up a specific Runner automatically')
%p
- link_to_help_page = link_to(_('Learn more about Kubernetes'),
diff --git a/app/views/dashboard/_groups_head.html.haml b/app/views/dashboard/_groups_head.html.haml
index d8f1e50544c..727784141bb 100644
--- a/app/views/dashboard/_groups_head.html.haml
+++ b/app/views/dashboard/_groups_head.html.haml
@@ -10,4 +10,4 @@
= render 'shared/groups/search_form'
= render 'shared/groups/dropdown'
- if current_user.can_create_group?
- = link_to _("New group"), new_group_path, class: "btn btn-new"
+ = link_to _("New group"), new_group_path, class: "btn btn-success"
diff --git a/app/views/dashboard/_projects_head.html.haml b/app/views/dashboard/_projects_head.html.haml
index 9b1d9b659f9..69a2e408073 100644
--- a/app/views/dashboard/_projects_head.html.haml
+++ b/app/views/dashboard/_projects_head.html.haml
@@ -19,4 +19,4 @@
= render 'shared/projects/search_form'
= render 'shared/projects/dropdown'
- if current_user.can_create_project?
- = link_to "New project", new_project_path, class: "btn btn-new"
+ = link_to "New project", new_project_path, class: "btn btn-success"
diff --git a/app/views/dashboard/_snippets_head.html.haml b/app/views/dashboard/_snippets_head.html.haml
index e7e323a8683..4f38339b87a 100644
--- a/app/views/dashboard/_snippets_head.html.haml
+++ b/app/views/dashboard/_snippets_head.html.haml
@@ -9,4 +9,4 @@
- if current_user
.nav-controls.d-none.d-sm-block
- = link_to "New snippet", new_snippet_path, class: "btn btn-new", title: "New snippet"
+ = link_to "New snippet", new_snippet_path, class: "btn btn-success", title: "New snippet"
diff --git a/app/views/dashboard/snippets/index.html.haml b/app/views/dashboard/snippets/index.html.haml
index 4391624196b..b11dc2c8e9b 100644
--- a/app/views/dashboard/snippets/index.html.haml
+++ b/app/views/dashboard/snippets/index.html.haml
@@ -7,7 +7,7 @@
.d-block.d-sm-none
&nbsp;
- = link_to new_snippet_path, class: "btn btn-new btn-block", title: "New snippet" do
+ = link_to new_snippet_path, class: "btn btn-success btn-block", title: "New snippet" do
New snippet
= render partial: 'snippets/snippets', locals: { link_project: true }
diff --git a/app/views/devise/passwords/edit.html.haml b/app/views/devise/passwords/edit.html.haml
index 35dafb3e980..4b8ad5acd5b 100644
--- a/app/views/devise/passwords/edit.html.haml
+++ b/app/views/devise/passwords/edit.html.haml
@@ -7,12 +7,12 @@
= f.hidden_field :reset_password_token
.form-group
= f.label 'New password', for: "user_password"
- = f.password_field :password, class: "form-control top", required: true, title: 'This field is required'
+ = f.password_field :password, class: "form-control top qa-password-field", required: true, title: 'This field is required'
.form-group
= f.label 'Confirm new password', for: "user_password_confirmation"
- = f.password_field :password_confirmation, class: "form-control bottom", title: 'This field is required', required: true
+ = f.password_field :password_confirmation, class: "form-control bottom qa-password-confirmation", title: 'This field is required', required: true
.clearfix
- = f.submit "Change your password", class: "btn btn-primary"
+ = f.submit "Change your password", class: "btn btn-primary qa-change-password-button"
.clearfix.prepend-top-20
%p
diff --git a/app/views/devise/sessions/_new_base.html.haml b/app/views/devise/sessions/_new_base.html.haml
index 17a9c8df872..7dacd0b1d72 100644
--- a/app/views/devise/sessions/_new_base.html.haml
+++ b/app/views/devise/sessions/_new_base.html.haml
@@ -1,10 +1,10 @@
= form_for(resource, as: resource_name, url: session_path(resource_name), html: { class: 'new_user gl-show-field-errors', 'aria-live' => 'assertive'}) do |f|
.form-group
= f.label "Username or email", for: "user_login", class: 'label-bold'
- = f.text_field :login, class: "form-control top", autofocus: "autofocus", autocapitalize: "off", autocorrect: "off", required: true, title: "This field is required."
+ = f.text_field :login, class: "form-control top qa-login-field", autofocus: "autofocus", autocapitalize: "off", autocorrect: "off", required: true, title: "This field is required."
.form-group
= f.label :password, class: 'label-bold'
- = f.password_field :password, class: "form-control bottom", required: true, title: "This field is required."
+ = f.password_field :password, class: "form-control bottom qa-password-field", required: true, title: "This field is required."
- if devise_mapping.rememberable?
.remember-me
%label{ for: "user_remember_me" }
@@ -17,4 +17,4 @@
= recaptcha_tags
.submit-container.move-submit-down
- = f.submit "Sign in", class: "btn btn-save"
+ = f.submit "Sign in", class: "btn btn-success qa-sign-in-button"
diff --git a/app/views/devise/sessions/_new_crowd.html.haml b/app/views/devise/sessions/_new_crowd.html.haml
index 36ff42090be..131544ac0c0 100644
--- a/app/views/devise/sessions/_new_crowd.html.haml
+++ b/app/views/devise/sessions/_new_crowd.html.haml
@@ -10,4 +10,4 @@
%label{ for: "remember_me" }
= check_box_tag :remember_me, '1', false, id: 'remember_me'
%span Remember me
- = submit_tag "Sign in", class: "btn-save btn"
+ = submit_tag "Sign in", class: "btn-success btn"
diff --git a/app/views/devise/sessions/_new_ldap.html.haml b/app/views/devise/sessions/_new_ldap.html.haml
index 6bf7349f602..796c0cadda8 100644
--- a/app/views/devise/sessions/_new_ldap.html.haml
+++ b/app/views/devise/sessions/_new_ldap.html.haml
@@ -1,13 +1,13 @@
= form_tag(omniauth_callback_path(:user, server['provider_name']), id: 'new_ldap_user', class: "gl-show-field-errors") do
.form-group
= label_tag :username, "#{server['label']} Username"
- = text_field_tag :username, nil, { class: "form-control top", title: "This field is required.", autofocus: "autofocus", required: true }
+ = text_field_tag :username, nil, { class: "form-control top qa-username-field", title: "This field is required.", autofocus: "autofocus", required: true }
.form-group
= label_tag :password
- = password_field_tag :password, nil, { class: "form-control bottom", title: "This field is required.", required: true }
+ = password_field_tag :password, nil, { class: "form-control bottom qa-password-field", title: "This field is required.", required: true }
- if devise_mapping.rememberable?
.remember-me
%label{ for: "remember_me" }
= check_box_tag :remember_me, '1', false, id: 'remember_me'
%span Remember me
- = submit_tag "Sign in", class: "btn-save btn"
+ = submit_tag "Sign in", class: "btn-success btn qa-sign-in-button"
diff --git a/app/views/devise/sessions/two_factor.html.haml b/app/views/devise/sessions/two_factor.html.haml
index ba168c4eab8..fefdf5f9531 100644
--- a/app/views/devise/sessions/two_factor.html.haml
+++ b/app/views/devise/sessions/two_factor.html.haml
@@ -11,7 +11,7 @@
= f.text_field :otp_attempt, class: 'form-control', required: true, autofocus: true, autocomplete: 'off', title: 'This field is required.'
%p.form-text.text-muted.hint Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes.
.prepend-top-20
- = f.submit "Verify code", class: "btn btn-save"
+ = f.submit "Verify code", class: "btn btn-success"
- if @user.two_factor_u2f_enabled?
= render "u2f/authenticate", locals: { params: params, resource: resource, resource_name: resource_name }
diff --git a/app/views/devise/shared/_tabs_ldap.html.haml b/app/views/devise/shared/_tabs_ldap.html.haml
index 58c585a29ff..7dced0942f5 100644
--- a/app/views/devise/shared/_tabs_ldap.html.haml
+++ b/app/views/devise/shared/_tabs_ldap.html.haml
@@ -4,10 +4,10 @@
= link_to "Crowd", "#crowd", class: 'nav-link active', 'data-toggle' => 'tab'
- @ldap_servers.each_with_index do |server, i|
%li.nav-item
- = link_to server['label'], "##{server['provider_name']}", class: "nav-link #{active_when(i.zero? && !crowd_enabled?)}", 'data-toggle' => 'tab'
+ = link_to server['label'], "##{server['provider_name']}", class: "nav-link #{active_when(i.zero? && !crowd_enabled?)} qa-ldap-tab", 'data-toggle' => 'tab'
- if password_authentication_enabled_for_web?
%li.nav-item
- = link_to 'Standard', '#login-pane', class: 'nav-link', 'data-toggle' => 'tab'
+ = link_to 'Standard', '#login-pane', class: 'nav-link qa-standard-tab', 'data-toggle' => 'tab'
- if allow_signup?
%li.nav-item
- = link_to 'Register', '#register-pane', class: 'nav-link', 'data-toggle' => 'tab'
+ = link_to 'Register', '#register-pane', class: 'nav-link qa-register-tab', 'data-toggle' => 'tab'
diff --git a/app/views/devise/shared/_tabs_normal.html.haml b/app/views/devise/shared/_tabs_normal.html.haml
index 284d4fa1b89..8745a4e9d3e 100644
--- a/app/views/devise/shared/_tabs_normal.html.haml
+++ b/app/views/devise/shared/_tabs_normal.html.haml
@@ -1,6 +1,6 @@
%ul.nav-links.new-session-tabs.nav-tabs.nav{ role: 'tablist' }
%li.nav-item{ role: 'presentation' }
- %a.nav-link.active{ href: '#login-pane', data: { toggle: 'tab' }, role: 'tab' } Sign in
+ %a.nav-link.qa-sign-in-tab.active{ href: '#login-pane', data: { toggle: 'tab' }, role: 'tab' } Sign in
- if allow_signup?
%li.nav-item{ role: 'presentation' }
- %a.nav-link{ href: '#register-pane', data: { toggle: 'tab' }, role: 'tab' } Register
+ %a.nav-link.qa-register-tab{ href: '#register-pane', data: { toggle: 'tab' }, role: 'tab' } Register
diff --git a/app/views/doorkeeper/applications/_form.html.haml b/app/views/doorkeeper/applications/_form.html.haml
index 0bc057a8864..78904f550c7 100644
--- a/app/views/doorkeeper/applications/_form.html.haml
+++ b/app/views/doorkeeper/applications/_form.html.haml
@@ -20,4 +20,4 @@
= render 'shared/tokens/scopes_form', prefix: 'doorkeeper_application', token: application, scopes: @scopes
.prepend-top-default
- = f.submit _('Save application'), class: "btn btn-create"
+ = f.submit _('Save application'), class: "btn btn-success"
diff --git a/app/views/doorkeeper/applications/index.html.haml b/app/views/doorkeeper/applications/index.html.haml
index b11f441b3ba..1f5c70a6c6e 100644
--- a/app/views/doorkeeper/applications/index.html.haml
+++ b/app/views/doorkeeper/applications/index.html.haml
@@ -16,6 +16,9 @@
= _('Add new application')
= render 'form', application: @application
%hr
+ - else
+ .bs-callout.bs-callout-disabled
+ = _('Adding new applications is disabled in your GitLab instance. Please contact your GitLab administrator to get the permission')
- if user_oauth_applications?
.oauth-applications
%h5
diff --git a/app/views/errors/precondition_failed.html.haml b/app/views/errors/precondition_failed.html.haml
new file mode 100644
index 00000000000..aa3869f33a9
--- /dev/null
+++ b/app/views/errors/precondition_failed.html.haml
@@ -0,0 +1,8 @@
+- content_for(:title, 'Encoding Error')
+%img{ :alt => "GitLab Logo", :src => image_path('logo.svg') }
+ %h1
+ 412
+.container
+ %h3 Precondition failed
+ %hr
+ %p Page can't be loaded because of invalid parameters.
diff --git a/app/views/groups/_group_admin_settings.html.haml b/app/views/groups/_group_admin_settings.html.haml
index f7cc62c6929..ff59013ed67 100644
--- a/app/views/groups/_group_admin_settings.html.haml
+++ b/app/views/groups/_group_admin_settings.html.haml
@@ -1,5 +1,5 @@
.form-group.row
- = f.label :lfs_enabled, 'Large File Storage', class: 'col-form-label col-sm-2'
+ = f.label :lfs_enabled, 'Large File Storage', class: 'col-form-label col-sm-2 pt-0'
.col-sm-10
.form-check
= f.check_box :lfs_enabled, checked: @group.lfs_enabled?, class: 'form-check-input'
@@ -11,13 +11,13 @@
%span.descr This setting can be overridden in each project.
.form-group.row
- = f.label :require_two_factor_authentication, 'Two-factor authentication', class: 'col-form-label col-sm-2'
+ = f.label :require_two_factor_authentication, 'Two-factor authentication', class: 'col-form-label col-sm-2 pt-0'
.col-sm-10
.form-check
= f.check_box :require_two_factor_authentication, class: 'form-check-input'
= f.label :require_two_factor_authentication, class: 'form-check-label' do
%strong
- Require all users in this group to setup Two-factor authentication
+ Require all users in this group to set up Two-factor authentication
= link_to icon('question-circle'), help_page_path('security/two_factor_authentication', anchor: 'enforcing-2fa-for-all-users-in-a-group')
.form-group.row
.offset-sm-2.col-sm-10
diff --git a/app/views/groups/group_members/_new_group_member.html.haml b/app/views/groups/group_members/_new_group_member.html.haml
index aa03f8365f9..04683ec5a9a 100644
--- a/app/views/groups/group_members/_new_group_member.html.haml
+++ b/app/views/groups/group_members/_new_group_member.html.haml
@@ -19,4 +19,4 @@
On this date, the member(s) will automatically lose access to this group and all of its projects.
.col-md-2
- = f.submit 'Add to group', class: "btn btn-create btn-block"
+ = f.submit 'Add to group', class: "btn btn-success btn-block"
diff --git a/app/views/groups/labels/index.html.haml b/app/views/groups/labels/index.html.haml
index 86178eb2ffd..003bd25dd06 100644
--- a/app/views/groups/labels/index.html.haml
+++ b/app/views/groups/labels/index.html.haml
@@ -7,7 +7,7 @@
- if can_admin_label
- content_for(:header_content) do
.nav-controls
- = link_to _('New label'), new_group_label_path(@group), class: "btn btn-new"
+ = link_to _('New label'), new_group_label_path(@group), class: "btn btn-success"
- if @labels.exists? || search.present?
#promote-label-modal
diff --git a/app/views/groups/milestones/_form.html.haml b/app/views/groups/milestones/_form.html.haml
index 6d35457a0ec..39e3af5f6d2 100644
--- a/app/views/groups/milestones/_form.html.haml
+++ b/app/views/groups/milestones/_form.html.haml
@@ -19,9 +19,9 @@
.form-actions
- if @milestone.new_record?
- = f.submit 'Create milestone', class: "btn-create btn"
+ = f.submit 'Create milestone', class: "btn-success btn"
= link_to "Cancel", group_milestones_path(@group), class: "btn btn-cancel"
- else
- = f.submit 'Update milestone', class: "btn-create btn"
+ = f.submit 'Update milestone', class: "btn-success btn"
= link_to "Cancel", group_milestone_path(@group, @milestone), class: "btn btn-cancel"
diff --git a/app/views/groups/milestones/index.html.haml b/app/views/groups/milestones/index.html.haml
index b6424df55cd..af4fe8f2ef8 100644
--- a/app/views/groups/milestones/index.html.haml
+++ b/app/views/groups/milestones/index.html.haml
@@ -6,7 +6,7 @@
.nav-controls
= render 'shared/milestones_sort_dropdown'
- if can?(current_user, :admin_milestone, @group)
- = link_to "New milestone", new_group_milestone_path(@group), class: "btn btn-new"
+ = link_to "New milestone", new_group_milestone_path(@group), class: "btn btn-success"
.milestones
%ul.content-list
diff --git a/app/views/groups/new.html.haml b/app/views/groups/new.html.haml
index 53f54db1ddf..683129fdf6e 100644
--- a/app/views/groups/new.html.haml
+++ b/app/views/groups/new.html.haml
@@ -36,5 +36,5 @@
= render 'shared/group_tips'
.form-actions
- = f.submit 'Create group', class: "btn btn-create"
+ = f.submit 'Create group', class: "btn btn-success"
= link_to 'Cancel', dashboard_groups_path, class: 'btn btn-cancel'
diff --git a/app/views/groups/settings/_permissions.html.haml b/app/views/groups/settings/_permissions.html.haml
index ffce2d4b14f..8dc88ec446c 100644
--- a/app/views/groups/settings/_permissions.html.haml
+++ b/app/views/groups/settings/_permissions.html.haml
@@ -10,7 +10,7 @@
= render 'shared/allow_request_access', form: f
.form-group.row
- %label.col-form-label.col-sm-2
+ %label.col-form-label.col-sm-2.pt-0
= s_('GroupSettings|Share with group lock')
.col-sm-10
.form-check
diff --git a/app/views/groups/show.html.haml b/app/views/groups/show.html.haml
index f1bd817f17a..6a293daaf95 100644
--- a/app/views/groups/show.html.haml
+++ b/app/views/groups/show.html.haml
@@ -15,12 +15,12 @@
- new_project_label = _("New project")
- new_subgroup_label = _("New subgroup")
- if can_create_subgroups
- .btn-group.new-project-subgroup.droplab-dropdown.js-new-project-subgroup{ data: { project_path: new_project_path(namespace_id: @group.id), subgroup_path: new_group_path(parent_id: @group.id) } }
- %input.btn.btn-success.dropdown-primary.js-new-group-child{ type: "button", value: new_project_label, data: { action: "new-project" } }
- %button.btn.btn-success.dropdown-toggle.js-dropdown-toggle{ type: "button", data: { "dropdown-trigger" => "#new-project-or-subgroup-dropdown", 'display' => 'static' } }
+ .btn-group.new-project-subgroup.droplab-dropdown.js-new-project-subgroup.qa-new-project-or-subgroup-dropdown{ data: { project_path: new_project_path(namespace_id: @group.id), subgroup_path: new_group_path(parent_id: @group.id) } }
+ %input.btn.btn-success.dropdown-primary.js-new-group-child.qa-new-in-group-button{ type: "button", value: new_project_label, data: { action: "new-project" } }
+ %button.btn.btn-success.dropdown-toggle.js-dropdown-toggle.qa-new-project-or-subgroup-dropdown-toggle{ type: "button", data: { "dropdown-trigger" => "#new-project-or-subgroup-dropdown", 'display' => 'static' } }
= icon("caret-down", class: "dropdown-btn-icon")
%ul#new-project-or-subgroup-dropdown.dropdown-menu.dropdown-menu-right{ data: { dropdown: true } }
- %li.droplab-item-selected{ role: "button", data: { value: "new-project", text: new_project_label } }
+ %li.droplab-item-selected.qa-new-project-option{ role: "button", data: { value: "new-project", text: new_project_label } }
.menu-item
.icon-container
= icon("check", class: "list-item-checkmark")
@@ -28,7 +28,7 @@
%strong= new_project_label
%span= s_("GroupsTree|Create a project in this group.")
%li.divider.droplap-item-ignore
- %li{ role: "button", data: { value: "new-subgroup", text: new_subgroup_label } }
+ %li.qa-new-subgroup-option{ role: "button", data: { value: "new-subgroup", text: new_subgroup_label } }
.menu-item
.icon-container
= icon("check", class: "list-item-checkmark")
diff --git a/app/views/help/index.html.haml b/app/views/help/index.html.haml
index 7a66bac09cb..198c2d35b29 100644
--- a/app/views/help/index.html.haml
+++ b/app/views/help/index.html.haml
@@ -7,8 +7,7 @@
GitLab
Community Edition
- if user_signed_in?
- %span= Gitlab::VERSION
- %small= link_to Gitlab.revision, Gitlab::COM_URL + namespace_project_commits_path('gitlab-org', 'gitlab-ce', Gitlab.revision)
+ %span= link_to Gitlab::VERSION, Gitlab::COM_URL + namespace_project_tag_path('gitlab-org', 'gitlab-ce', "v#{Gitlab::VERSION}")
= version_status_badge
%hr
diff --git a/app/views/help/instance_configuration/_gitlab_pages.html.haml b/app/views/help/instance_configuration/_gitlab_pages.html.haml
index bdd77730dcc..94c25edaf82 100644
--- a/app/views/help/instance_configuration/_gitlab_pages.html.haml
+++ b/app/views/help/instance_configuration/_gitlab_pages.html.haml
@@ -8,7 +8,7 @@
%p
Below are the settings for
- = succeed('.') { link_to('Gitlab Pages', gitlab_pages[:url], target: '_blank') }
+ = succeed('.') { link_to('GitLab Pages', gitlab_pages[:url], target: '_blank') }
.table-responsive
%table
%thead
diff --git a/app/views/help/ui.html.haml b/app/views/help/ui.html.haml
index b32b602ceb3..506f580b246 100644
--- a/app/views/help/ui.html.haml
+++ b/app/views/help/ui.html.haml
@@ -189,7 +189,7 @@
%li
= link_to 'Sort by date', '#'
- = link_to 'New issue', '#', class: 'btn btn-new btn-inverted'
+ = link_to 'New issue', '#', class: 'btn btn-success btn-inverted'
.lead
Only nav links without button and search
diff --git a/app/views/import/fogbugz/new.html.haml b/app/views/import/fogbugz/new.html.haml
index b54b1af1e0c..626080c284b 100644
--- a/app/views/import/fogbugz/new.html.haml
+++ b/app/views/import/fogbugz/new.html.haml
@@ -21,4 +21,4 @@
.col-md-4
= password_field_tag :password, nil, class: 'form-control'
.form-actions
- = submit_tag _('Continue to the next step'), class: 'btn btn-create'
+ = submit_tag _('Continue to the next step'), class: 'btn btn-success'
diff --git a/app/views/import/fogbugz/new_user_map.html.haml b/app/views/import/fogbugz/new_user_map.html.haml
index ff2f989c509..8ed9dc68bb3 100644
--- a/app/views/import/fogbugz/new_user_map.html.haml
+++ b/app/views/import/fogbugz/new_user_map.html.haml
@@ -39,4 +39,4 @@
scope: :all, email_user: true, selected: user[:gitlab_user])
.form-actions
- = submit_tag _('Continue to the next step'), class: 'btn btn-create'
+ = submit_tag _('Continue to the next step'), class: 'btn btn-success'
diff --git a/app/views/import/gitea/new.html.haml b/app/views/import/gitea/new.html.haml
index 2b3102f9af9..a88b04eccbb 100644
--- a/app/views/import/gitea/new.html.haml
+++ b/app/views/import/gitea/new.html.haml
@@ -19,4 +19,4 @@
.col-sm-4
= text_field_tag :personal_access_token, nil, class: 'form-control'
.form-actions
- = submit_tag _('List Your Gitea Repositories'), class: 'btn btn-create'
+ = submit_tag _('List Your Gitea Repositories'), class: 'btn btn-success'
diff --git a/app/views/import/gitlab_projects/new.html.haml b/app/views/import/gitlab_projects/new.html.haml
index c4218f3d787..5e4595d930b 100644
--- a/app/views/import/gitlab_projects/new.html.haml
+++ b/app/views/import/gitlab_projects/new.html.haml
@@ -10,7 +10,7 @@
.row
.form-group.project-name.col-sm-12
= label_tag :name, _('Project name'), class: 'label-bold'
- = text_field_tag :name, @name, placeholder: "My awesome project", class: "js-project-name form-control input-lg", autofocus: true, required: true
+ = text_field_tag :name, @name, placeholder: "My awesome project", class: "js-project-name form-control input-lg", autofocus: true
.form-group.col-12.col-sm-6
= label_tag :namespace_id, _('Project URL'), class: 'label-bold'
.form-group
@@ -41,5 +41,5 @@
= file_field_tag :file, class: ''
.row
.form-actions.col-sm-12
- = submit_tag _('Import project'), class: 'btn btn-create'
+ = submit_tag _('Import project'), class: 'btn btn-success'
= link_to _('Cancel'), new_project_path, class: 'btn btn-cancel'
diff --git a/app/views/import/google_code/new.html.haml b/app/views/import/google_code/new.html.haml
index fd6e4726fc5..7a6ad28f0aa 100644
--- a/app/views/import/google_code/new.html.haml
+++ b/app/views/import/google_code/new.html.haml
@@ -59,4 +59,4 @@
= _('Yes, let me map Google Code users to full names or GitLab users.')
%li
%p
- = submit_tag _('Continue to the next step'), class: "btn btn-create"
+ = submit_tag _('Continue to the next step'), class: "btn btn-success"
diff --git a/app/views/import/google_code/new_user_map.html.haml b/app/views/import/google_code/new_user_map.html.haml
index baaaf6bdc63..f523b993aa7 100644
--- a/app/views/import/google_code/new_user_map.html.haml
+++ b/app/views/import/google_code/new_user_map.html.haml
@@ -33,4 +33,4 @@
= text_area_tag :user_map, JSON.pretty_generate(@user_map), class: 'form-control', rows: 15
.form-actions
- = submit_tag _('Continue to the next step'), class: "btn btn-create"
+ = submit_tag _('Continue to the next step'), class: "btn btn-success"
diff --git a/app/views/layouts/nav/sidebar/_admin.html.haml b/app/views/layouts/nav/sidebar/_admin.html.haml
index ff25b040913..f912a32ee1a 100644
--- a/app/views/layouts/nav/sidebar/_admin.html.haml
+++ b/app/views/layouts/nav/sidebar/_admin.html.haml
@@ -7,14 +7,14 @@
.sidebar-context-title
= _('Admin Area')
%ul.sidebar-top-level-items
- = nav_link(controller: %w(dashboard admin projects users groups jobs runners gitaly_servers), html_options: {class: 'home'}) do
+ = nav_link(controller: %w(dashboard admin admin/projects users groups jobs runners gitaly_servers), html_options: {class: 'home'}) do
= link_to admin_root_path, class: 'shortcuts-tree' do
.nav-icon-container
= sprite_icon('overview')
%span.nav-item-name
= _('Overview')
%ul.sidebar-sub-level-items
- = nav_link(controller: %w(dashboard admin projects users groups jobs runners gitaly_servers), html_options: { class: "fly-out-top-item" } ) do
+ = nav_link(controller: %w(dashboard admin admin/projects users groups jobs runners gitaly_servers), html_options: { class: "fly-out-top-item" } ) do
= link_to admin_root_path do
%strong.fly-out-top-item-name
= _('Overview')
@@ -23,7 +23,7 @@
= link_to admin_root_path, title: _('Overview') do
%span
= _('Dashboard')
- = nav_link(controller: [:admin, :projects]) do
+ = nav_link(controller: [:admin, 'admin/projects']) do
= link_to admin_projects_path, title: _('Projects') do
%span
= _('Projects')
@@ -199,10 +199,54 @@
= sprite_icon('settings')
%span.nav-item-name
= _('Settings')
- %ul.sidebar-sub-level-items.is-fly-out-only
+
+ %ul.sidebar-sub-level-items
= nav_link(controller: :application_settings, html_options: { class: "fly-out-top-item" } ) do
= link_to admin_application_settings_path do
%strong.fly-out-top-item-name
= _('Settings')
+ %li.divider.fly-out-top-item
+ = nav_link(path: 'application_settings#show') do
+ = link_to admin_application_settings_path, title: _('General') do
+ %span
+ = _('General')
+ = nav_link(path: 'application_settings#integrations') do
+ = link_to integrations_admin_application_settings_path, title: _('Integrations') do
+ %span
+ = _('Integrations')
+ = nav_link(path: 'application_settings#repository') do
+ = link_to repository_admin_application_settings_path, title: _('Repository') do
+ %span
+ = _('Repository')
+ - if template_exists?('admin/application_settings/templates')
+ = nav_link(path: 'application_settings#templates') do
+ = link_to templates_admin_application_settings_path, title: _('Templates') do
+ %span
+ = _('Templates')
+ = nav_link(path: 'application_settings#ci_cd') do
+ = link_to ci_cd_admin_application_settings_path, title: _('CI/CD') do
+ %span
+ = _('CI/CD')
+ = nav_link(path: 'application_settings#reporting') do
+ = link_to reporting_admin_application_settings_path, title: _('Reporting') do
+ %span
+ = _('Reporting')
+ = nav_link(path: 'application_settings#metrics_and_profiling') do
+ = link_to metrics_and_profiling_admin_application_settings_path, title: _('Metrics and profiling') do
+ %span
+ = _('Metrics and profiling')
+ = nav_link(path: 'application_settings#network') do
+ = link_to network_admin_application_settings_path, title: _('Network') do
+ %span
+ = _('Network')
+ - if template_exists?('admin/application_settings/geo')
+ = nav_link(path: 'application_settings#geo') do
+ = link_to geo_admin_application_settings_path, title: _('Geo') do
+ %span
+ = _('Geo')
+ = nav_link(path: 'application_settings#preferences') do
+ = link_to preferences_admin_application_settings_path, title: _('Preferences') do
+ %span
+ = _('Preferences')
= render 'shared/sidebar_toggle_button'
diff --git a/app/views/layouts/nav/sidebar/_group.html.haml b/app/views/layouts/nav/sidebar/_group.html.haml
index 4158bb69452..43170587797 100644
--- a/app/views/layouts/nav/sidebar/_group.html.haml
+++ b/app/views/layouts/nav/sidebar/_group.html.haml
@@ -109,7 +109,7 @@
= link_to edit_group_path(@group) do
.nav-icon-container
= sprite_icon('settings')
- %span.nav-item-name
+ %span.nav-item-name.qa-settings-item
= _('Settings')
%ul.sidebar-sub-level-items
= nav_link(path: %w[groups#projects groups#edit badges#index ci_cd#show], html_options: { class: "fly-out-top-item" } ) do
diff --git a/app/views/layouts/nav/sidebar/_profile.html.haml b/app/views/layouts/nav/sidebar/_profile.html.haml
index d65f153b451..69167edb1df 100644
--- a/app/views/layouts/nav/sidebar/_profile.html.haml
+++ b/app/views/layouts/nav/sidebar/_profile.html.haml
@@ -28,18 +28,17 @@
= link_to profile_account_path do
%strong.fly-out-top-item-name
= _('Account')
- - if Gitlab::CurrentSettings.user_oauth_applications?
- = nav_link(controller: 'oauth/applications') do
- = link_to applications_profile_path do
- .nav-icon-container
- = sprite_icon('applications')
- %span.nav-item-name
- = _('Applications')
- %ul.sidebar-sub-level-items.is-fly-out-only
- = nav_link(controller: 'oauth/applications', html_options: { class: "fly-out-top-item" } ) do
- = link_to applications_profile_path do
- %strong.fly-out-top-item-name
- = _('Applications')
+ = nav_link(controller: 'oauth/applications') do
+ = link_to applications_profile_path do
+ .nav-icon-container
+ = sprite_icon('applications')
+ %span.nav-item-name
+ = _('Applications')
+ %ul.sidebar-sub-level-items.is-fly-out-only
+ = nav_link(controller: 'oauth/applications', html_options: { class: "fly-out-top-item" } ) do
+ = link_to applications_profile_path do
+ %strong.fly-out-top-item-name
+ = _('Applications')
= nav_link(controller: :chat_names) do
= link_to profile_chat_names_path do
.nav-icon-container
diff --git a/app/views/layouts/nav/sidebar/_project.html.haml b/app/views/layouts/nav/sidebar/_project.html.haml
index 30e0e9fca27..25cd53b378a 100644
--- a/app/views/layouts/nav/sidebar/_project.html.haml
+++ b/app/views/layouts/nav/sidebar/_project.html.haml
@@ -158,7 +158,7 @@
- if project_nav_tab? :pipelines
= nav_link(controller: [:pipelines, :builds, :jobs, :pipeline_schedules, :artifacts]) do
- = link_to project_pipelines_path(@project), class: 'shortcuts-pipelines' do
+ = link_to project_pipelines_path(@project), class: 'shortcuts-pipelines qa-link-pipelines' do
.nav-icon-container
= sprite_icon('rocket')
%span.nav-item-name
@@ -245,7 +245,7 @@
= link_to _('Auto DevOps'), help_page_path('topics/autodevops/index.md')
%span= _('uses Kubernetes clusters to deploy your code!')
%hr
- %button.btn.btn-create.btn-sm.dismiss-feature-highlight{ type: 'button' }
+ %button.btn.btn-success.btn-sm.dismiss-feature-highlight{ type: 'button' }
%span= _("Got it!")
= sprite_icon('thumb-up')
diff --git a/app/views/profiles/emails/index.html.haml b/app/views/profiles/emails/index.html.haml
index c8faf2b3af3..1823f191fb3 100644
--- a/app/views/profiles/emails/index.html.haml
+++ b/app/views/profiles/emails/index.html.haml
@@ -15,7 +15,7 @@
= f.label :email, class: 'label-bold'
= f.text_field :email, class: 'form-control'
.prepend-top-default
- = f.submit 'Add email address', class: 'btn btn-create'
+ = f.submit 'Add email address', class: 'btn btn-success'
%hr
%h4.prepend-top-0
Linked emails (#{@emails.count + 1})
diff --git a/app/views/profiles/gpg_keys/_form.html.haml b/app/views/profiles/gpg_keys/_form.html.haml
index aa9b0aad034..6c4cb614a2b 100644
--- a/app/views/profiles/gpg_keys/_form.html.haml
+++ b/app/views/profiles/gpg_keys/_form.html.haml
@@ -7,4 +7,4 @@
= f.text_area :key, class: "form-control", rows: 8, required: true, placeholder: "Don't paste the private part of the GPG key. Paste the public part which begins with '-----BEGIN PGP PUBLIC KEY BLOCK-----'."
.prepend-top-default
- = f.submit 'Add key', class: "btn btn-create"
+ = f.submit 'Add key', class: "btn btn-success"
diff --git a/app/views/profiles/keys/_form.html.haml b/app/views/profiles/keys/_form.html.haml
index 5207921d6fe..21eef08983c 100644
--- a/app/views/profiles/keys/_form.html.haml
+++ b/app/views/profiles/keys/_form.html.haml
@@ -5,10 +5,10 @@
.form-group
= f.label :key, class: 'label-bold'
%p= _("Paste your public SSH key, which is usually contained in the file '~/.ssh/id_rsa.pub' and begins with 'ssh-rsa'. Don't use your private SSH key.")
- = f.text_area :key, class: "form-control js-add-ssh-key-validation-input", rows: 8, required: true, placeholder: s_('Profiles|Typically starts with "ssh-rsa …"')
+ = f.text_area :key, class: "form-control js-add-ssh-key-validation-input qa-key-public-key-field", rows: 8, required: true, placeholder: s_('Profiles|Typically starts with "ssh-rsa …"')
.form-group
= f.label :title, class: 'label-bold'
- = f.text_field :title, class: "form-control input-lg", required: true, placeholder: s_('Profiles|e.g. My MacBook key')
+ = f.text_field :title, class: "form-control input-lg qa-key-title-field", required: true, placeholder: s_('Profiles|e.g. My MacBook key')
%p.form-text.text-muted= _('Name your individual key via a title')
.js-add-ssh-key-validation-warning.hide
@@ -16,7 +16,7 @@
%strong= _('Oops, are you sure?')
%p= s_("Profiles|This doesn't look like a public SSH key, are you sure you want to add it?")
- %button.btn.btn-create.js-add-ssh-key-validation-confirm-submit= _("Yes, add it")
+ %button.btn.btn-success.js-add-ssh-key-validation-confirm-submit= _("Yes, add it")
.prepend-top-default
- = f.submit s_('Profiles|Add key'), class: "btn btn-create js-add-ssh-key-validation-original-submit"
+ = f.submit s_('Profiles|Add key'), class: "btn btn-success js-add-ssh-key-validation-original-submit qa-add-key-button"
diff --git a/app/views/profiles/keys/_key_details.html.haml b/app/views/profiles/keys/_key_details.html.haml
index 2ac514d3f6f..88473c7f72d 100644
--- a/app/views/profiles/keys/_key_details.html.haml
+++ b/app/views/profiles/keys/_key_details.html.haml
@@ -24,4 +24,4 @@
= @key.key
.col-md-12
.float-right
- = link_to 'Remove', path_to_key(@key, is_admin), data: {confirm: 'Are you sure?'}, method: :delete, class: "btn btn-remove delete-key"
+ = link_to 'Remove', path_to_key(@key, is_admin), data: {confirm: 'Are you sure?'}, method: :delete, class: "btn btn-remove delete-key qa-delete-key-button"
diff --git a/app/views/profiles/passwords/edit.html.haml b/app/views/profiles/passwords/edit.html.haml
index 9c8cc9c059b..0b4b9841ea1 100644
--- a/app/views/profiles/passwords/edit.html.haml
+++ b/app/views/profiles/passwords/edit.html.haml
@@ -29,6 +29,6 @@
= f.label :password_confirmation, class: 'label-bold'
= f.password_field :password_confirmation, required: true, class: 'form-control'
.prepend-top-default.append-bottom-default
- = f.submit 'Save password', class: "btn btn-create append-right-10"
+ = f.submit 'Save password', class: "btn btn-success append-right-10"
- unless @user.password_automatically_set?
= link_to "I forgot my password", reset_profile_password_path, method: :put, class: "account-btn-link"
diff --git a/app/views/profiles/passwords/new.html.haml b/app/views/profiles/passwords/new.html.haml
index 2176d7f8a31..d265f3c44ba 100644
--- a/app/views/profiles/passwords/new.html.haml
+++ b/app/views/profiles/passwords/new.html.haml
@@ -1,6 +1,6 @@
- page_title "New Password"
- header_title "New Password"
-%h3.page-title Setup new password
+%h3.page-title Set up new password
%hr
= form_for @user, url: profile_password_path, method: :post do |f|
%p.slead
@@ -22,4 +22,4 @@
.col-sm-10
= f.password_field :password_confirmation, required: true, class: 'form-control'
.form-actions
- = f.submit 'Set new password', class: "btn btn-create"
+ = f.submit 'Set new password', class: "btn btn-success"
diff --git a/app/views/profiles/preferences/show.html.haml b/app/views/profiles/preferences/show.html.haml
index fd6dd74e1c5..156c0d05b02 100644
--- a/app/views/profiles/preferences/show.html.haml
+++ b/app/views/profiles/preferences/show.html.haml
@@ -58,4 +58,4 @@
.form-text.text-muted
Choose what content you want to see on a project’s overview page
.form-group
- = f.submit 'Save changes', class: 'btn btn-save'
+ = f.submit 'Save changes', class: 'btn btn-success'
diff --git a/app/views/profiles/show.html.haml b/app/views/profiles/show.html.haml
index 51f5ecf2166..ea215e3e718 100644
--- a/app/views/profiles/show.html.haml
+++ b/app/views/profiles/show.html.haml
@@ -109,10 +109,11 @@
= f.text_area :bio, rows: 4, maxlength: 250, help: s_("Profiles|Tell us about yourself in fewer than 250 characters.")
%hr
%h5= ("Private profile")
- - private_profile_label = capture do
- = s_("Profiles|Don't display activity-related personal information on your profiles")
+ .checkbox-icon-inline-wrapper
+ - private_profile_label = capture do
+ = s_("Profiles|Don't display activity-related personal information on your profiles")
+ = f.check_box :private_profile, label: private_profile_label
= link_to icon('question-circle'), help_page_path('user/profile/index.md', anchor: 'private-profile')
- = f.check_box :private_profile, label: private_profile_label
%h5= s_("Profiles|Private contributions")
= f.check_box :include_private_contributions, label: 'Include private contributions on my profile'
.help-block
diff --git a/app/views/profiles/two_factor_auths/_codes.html.haml b/app/views/profiles/two_factor_auths/_codes.html.haml
index 93722d7b034..fb4fff12027 100644
--- a/app/views/profiles/two_factor_auths/_codes.html.haml
+++ b/app/views/profiles/two_factor_auths/_codes.html.haml
@@ -10,4 +10,6 @@
%li
%span.monospace= code
-= link_to 'Proceed', profile_account_path, class: 'btn btn-success'
+.d-flex
+ = link_to 'Proceed', profile_account_path, class: 'btn btn-success append-right-10'
+ = link_to 'Download codes', "data:text/plain;charset=utf-8,#{CGI.escape(@codes.join("\n"))}", download: "gitlab-recovery-codes.txt", class: 'btn btn-default'
diff --git a/app/views/projects/_commit_button.html.haml b/app/views/projects/_commit_button.html.haml
index b387e38c1a6..1e27c71d20d 100644
--- a/app/views/projects/_commit_button.html.haml
+++ b/app/views/projects/_commit_button.html.haml
@@ -1,5 +1,5 @@
.form-actions
- = button_tag 'Commit changes', class: 'btn commit-btn js-commit-button btn-create'
+ = button_tag 'Commit changes', class: 'btn commit-btn js-commit-button btn-success'
= link_to 'Cancel', cancel_path,
class: 'btn btn-cancel', data: {confirm: leave_edit_message}
diff --git a/app/views/projects/_fork_suggestion.html.haml b/app/views/projects/_fork_suggestion.html.haml
index c855bfaf067..0b616a0c1ce 100644
--- a/app/views/projects/_fork_suggestion.html.haml
+++ b/app/views/projects/_fork_suggestion.html.haml
@@ -6,6 +6,6 @@
edit
files in this project directly. Please fork this project,
make your changes there, and submit a merge request.
- = link_to 'Fork', nil, method: :post, class: 'js-fork-suggestion-button btn btn-grouped btn-inverted btn-new'
+ = link_to 'Fork', nil, method: :post, class: 'js-fork-suggestion-button btn btn-grouped btn-inverted btn-success'
%button.js-cancel-fork-suggestion-button.btn.btn-grouped{ type: 'button' }
Cancel
diff --git a/app/views/projects/_new_project_fields.html.haml b/app/views/projects/_new_project_fields.html.haml
index 001e65c0f66..cbf89fa8f02 100644
--- a/app/views/projects/_new_project_fields.html.haml
+++ b/app/views/projects/_new_project_fields.html.haml
@@ -7,7 +7,7 @@
.form-group.project-name.col-sm-12
= f.label :name, class: 'label-bold' do
%span= _("Project name")
- = f.text_field :name, placeholder: "My awesome project", class: "form-control input-lg", autofocus: true, required: true
+ = f.text_field :name, placeholder: "My awesome project", class: "form-control input-lg", autofocus: true
.form-group.project-path.col-sm-6
= f.label :namespace_id, class: 'label-bold' do
%span= s_("Project URL")
@@ -60,5 +60,5 @@
.option-description
Allows you to immediately clone this project’s repository. Skip this if you plan to push up an existing repository.
-= f.submit 'Create project', class: "btn btn-create project-submit", tabindex: 4
+= f.submit 'Create project', class: "btn btn-success project-submit", tabindex: 4
= link_to 'Cancel', dashboard_projects_path, class: 'btn btn-cancel'
diff --git a/app/views/projects/_readme.html.haml b/app/views/projects/_readme.html.haml
index 705338c083e..32624ac225b 100644
--- a/app/views/projects/_readme.html.haml
+++ b/app/views/projects/_readme.html.haml
@@ -20,4 +20,4 @@
distributed with computer software, forming part of its documentation.
GitLab will render it here instead of this message.
%p
- = link_to "Add Readme", @project.add_readme_path, class: 'btn btn-new'
+ = link_to "Add Readme", @project.add_readme_path, class: 'btn btn-success'
diff --git a/app/views/projects/blob/_new_dir.html.haml b/app/views/projects/blob/_new_dir.html.haml
index 6f3a691518b..e9010dc63fc 100644
--- a/app/views/projects/blob/_new_dir.html.haml
+++ b/app/views/projects/blob/_new_dir.html.haml
@@ -15,7 +15,7 @@
= render 'shared/new_commit_form', placeholder: _("Add new directory")
.form-actions
- = submit_tag _("Create directory"), class: 'btn btn-create'
+ = submit_tag _("Create directory"), class: 'btn btn-success'
= link_to "Cancel", '#', class: "btn btn-cancel", "data-dismiss" => "modal"
= render 'shared/projects/edit_information'
diff --git a/app/views/projects/blob/_upload.html.haml b/app/views/projects/blob/_upload.html.haml
index 0a5c73c9037..d2b3c8ef96b 100644
--- a/app/views/projects/blob/_upload.html.haml
+++ b/app/views/projects/blob/_upload.html.haml
@@ -20,7 +20,7 @@
= render 'shared/new_commit_form', placeholder: placeholder
.form-actions
- = button_tag class: 'btn btn-create btn-upload-file', id: 'submit-all', type: 'button' do
+ = button_tag class: 'btn btn-success btn-upload-file', id: 'submit-all', type: 'button' do
= icon('spin spinner', class: 'js-loading-icon hidden' )
= button_title
= link_to _("Cancel"), '#', class: "btn btn-cancel", "data-dismiss" => "modal"
diff --git a/app/views/projects/branches/index.html.haml b/app/views/projects/branches/index.html.haml
index d6568c9f64a..ca867961f6b 100644
--- a/app/views/projects/branches/index.html.haml
+++ b/app/views/projects/branches/index.html.haml
@@ -41,7 +41,7 @@
data: { confirm: s_('Branches|Deleting the merged branches cannot be undone. Are you sure?'),
container: 'body' } do
= s_('Branches|Delete merged branches')
- = link_to new_project_branch_path(@project), class: 'btn btn-create' do
+ = link_to new_project_branch_path(@project), class: 'btn btn-success' do
= s_('Branches|New branch')
- if can?(current_user, :admin_project, @project)
diff --git a/app/views/projects/branches/new.html.haml b/app/views/projects/branches/new.html.haml
index 65b414c8af2..500536a5dbc 100644
--- a/app/views/projects/branches/new.html.haml
+++ b/app/views/projects/branches/new.html.haml
@@ -26,7 +26,7 @@
= render 'shared/ref_dropdown', dropdown_class: 'wide'
.form-text.text-muted Existing branch name, tag, or commit SHA
.form-actions
- = button_tag 'Create branch', class: 'btn btn-create', tabindex: 3
+ = button_tag 'Create branch', class: 'btn btn-success', tabindex: 3
= link_to 'Cancel', project_branches_path(@project), class: 'btn btn-cancel'
-# haml-lint:disable InlineJavaScript
%script#availableRefs{ type: "application/json" }= @project.repository.ref_names.to_json.html_safe
diff --git a/app/views/projects/clusters/gcp/_form.html.haml b/app/views/projects/clusters/gcp/_form.html.haml
index 9133de6559d..0222bbf7338 100644
--- a/app/views/projects/clusters/gcp/_form.html.haml
+++ b/app/views/projects/clusters/gcp/_form.html.haml
@@ -61,5 +61,15 @@
%p.form-text.text-muted
= s_('ClusterIntegration|Learn more about %{help_link_start_machine_type}machine types%{help_link_end} and %{help_link_start_pricing}pricing%{help_link_end}.').html_safe % { help_link_start_machine_type: help_link_start % { url: machine_type_link_url }, help_link_start_pricing: help_link_start % { url: pricing_link_url }, help_link_end: help_link_end }
+ - if rbac_clusters_feature_enabled?
+ .form-group
+ .form-check
+ = provider_gcp_field.check_box :legacy_abac, { class: 'form-check-input' }, false, true
+ = provider_gcp_field.label :legacy_abac, s_('ClusterIntegration|RBAC-enabled cluster (experimental)'), class: 'form-check-label label-bold'
+ .form-text.text-muted
+ = s_('ClusterIntegration|Enable this setting if using role-based access control (RBAC).')
+ = s_('ClusterIntegration|This option will allow you to install applications on RBAC clusters.')
+ = link_to _('More information'), help_page_path('user/project/clusters/index.md', anchor: 'role-based-access-control-rbac-experimental-support'), target: '_blank'
+
.form-group
= field.submit s_('ClusterIntegration|Create Kubernetes cluster'), class: 'js-gke-cluster-creation-submit btn btn-success', disabled: true
diff --git a/app/views/projects/clusters/gcp/_show.html.haml b/app/views/projects/clusters/gcp/_show.html.haml
index 877e0cc876c..be84f2ae67c 100644
--- a/app/views/projects/clusters/gcp/_show.html.haml
+++ b/app/views/projects/clusters/gcp/_show.html.haml
@@ -37,5 +37,14 @@
= platform_kubernetes_field.label :namespace, s_('ClusterIntegration|Project namespace (optional, unique)')
= platform_kubernetes_field.text_field :namespace, class: 'form-control', placeholder: s_('ClusterIntegration|Project namespace')
+ - if rbac_clusters_feature_enabled?
+ .form-group
+ .form-check
+ = platform_kubernetes_field.check_box :authorization_type, { class: 'form-check-input', disabled: true }, 'rbac', 'abac'
+ = platform_kubernetes_field.label :authorization_type, s_('ClusterIntegration|RBAC-enabled cluster (experimental)'), class: 'form-check-label label-bold'
+ .form-text.text-muted
+ = s_('ClusterIntegration|Enable this setting if using role-based access control (RBAC).')
+ = s_('ClusterIntegration|This option will allow you to install applications on RBAC clusters.')
+
.form-group
= field.submit s_('ClusterIntegration|Save changes'), class: 'btn btn-success'
diff --git a/app/views/projects/clusters/user/_form.html.haml b/app/views/projects/clusters/user/_form.html.haml
index 1f81e024ab9..f497f5b606c 100644
--- a/app/views/projects/clusters/user/_form.html.haml
+++ b/app/views/projects/clusters/user/_form.html.haml
@@ -33,6 +33,7 @@
.form-text.text-muted
= s_('ClusterIntegration|Enable this setting if using role-based access control (RBAC).')
= s_('ClusterIntegration|This option will allow you to install applications on RBAC clusters.')
+ = link_to _('More information'), help_page_path('user/project/clusters/index.md', anchor: 'role-based-access-control-rbac-experimental-support'), target: '_blank'
.form-group
= field.submit s_('ClusterIntegration|Add Kubernetes cluster'), class: 'btn btn-success'
diff --git a/app/views/projects/commit/_change.html.haml b/app/views/projects/commit/_change.html.haml
index afd70ef5774..e71615dd1c5 100644
--- a/app/views/projects/commit/_change.html.haml
+++ b/app/views/projects/commit/_change.html.haml
@@ -33,7 +33,7 @@
- else
= hidden_field_tag 'create_merge_request', 1, id: nil
.form-actions
- = submit_tag label, class: 'btn btn-create'
+ = submit_tag label, class: 'btn btn-success'
= link_to _("Cancel"), '#', class: "btn btn-cancel", "data-dismiss" => "modal"
= render 'shared/projects/edit_information'
diff --git a/app/views/projects/commits/_commit.html.haml b/app/views/projects/commits/_commit.html.haml
index 7951a5ddc9e..c6789e32dbe 100644
--- a/app/views/projects/commits/_commit.html.haml
+++ b/app/views/projects/commits/_commit.html.haml
@@ -1,3 +1,7 @@
+-#-----------------------------------------------------------------
+ WARNING: Please keep changes up-to-date with the following files:
+ - `assets/javascripts/diffs/components/commit_item.vue`
+-#-----------------------------------------------------------------
- view_details = local_assigns.fetch(:view_details, false)
- merge_request = local_assigns.fetch(:merge_request, nil)
- project = local_assigns.fetch(:project) { merge_request&.project }
@@ -37,7 +41,7 @@
%button.text-expander.js-toggle-button
= sprite_icon('ellipsis_h', size: 12)
- .commiter
+ .committer
- commit_author_link = commit_author_link(commit, avatar: false, size: 24)
- commit_timeago = time_ago_with_tooltip(commit.authored_date, placement: 'bottom')
- commit_text = _('%{commit_author_link} authored %{commit_timeago}') % { commit_author_link: commit_author_link, commit_timeago: commit_timeago }
diff --git a/app/views/projects/compare/_form.html.haml b/app/views/projects/compare/_form.html.haml
index 07112c98804..d24ee4a3251 100644
--- a/app/views/projects/compare/_form.html.haml
+++ b/app/views/projects/compare/_form.html.haml
@@ -22,7 +22,7 @@
.dropdown-toggle-text.str-truncated= params[:from] || _("Select branch/tag")
= render 'shared/ref_dropdown'
&nbsp;
- = button_tag s_("CompareBranches|Compare"), class: "btn btn-create commits-compare-btn"
+ = button_tag s_("CompareBranches|Compare"), class: "btn btn-success commits-compare-btn"
- if @merge_request.present?
= link_to _("View open merge request"), project_merge_request_path(@project, @merge_request), class: 'prepend-left-10 btn'
- elsif create_mr_button?
diff --git a/app/views/projects/deploy_keys/_form.html.haml b/app/views/projects/deploy_keys/_form.html.haml
index f8ab0c1ec54..568930595a2 100644
--- a/app/views/projects/deploy_keys/_form.html.haml
+++ b/app/views/projects/deploy_keys/_form.html.haml
@@ -21,4 +21,4 @@
Allow this key to push to repository as well? (Default only allows pull access.)
.form-group.row
- = f.submit "Add key", class: "btn-create btn"
+ = f.submit "Add key", class: "btn-success btn"
diff --git a/app/views/projects/deploy_keys/edit.html.haml b/app/views/projects/deploy_keys/edit.html.haml
index e009b6fef0e..3e7872ebc1c 100644
--- a/app/views/projects/deploy_keys/edit.html.haml
+++ b/app/views/projects/deploy_keys/edit.html.haml
@@ -6,5 +6,5 @@
= form_for [@project.namespace.becomes(Namespace), @project, @deploy_key], html: { class: 'js-requires-input' } do |f|
= render partial: 'shared/deploy_keys/form', locals: { form: f, deploy_key: @deploy_key }
.form-actions
- = f.submit 'Save changes', class: 'btn-save btn'
+ = f.submit 'Save changes', class: 'btn-success btn'
= link_to 'Cancel', project_settings_repository_path(@project), class: 'btn btn-cancel'
diff --git a/app/views/projects/edit.html.haml b/app/views/projects/edit.html.haml
index acdde9e0f70..07fc9e1c682 100644
--- a/app/views/projects/edit.html.haml
+++ b/app/views/projects/edit.html.haml
@@ -40,14 +40,14 @@
.form-group
= f.label :tag_list, "Tags", class: 'label-bold'
- = f.text_field :tag_list, value: @project.tag_list.sort.join(', '), maxlength: 2000, class: "form-control"
+ = f.text_field :tag_list, value: @project.tag_list.join(', '), maxlength: 2000, class: "form-control"
%p.form-text.text-muted Separate tags with commas.
%fieldset.features
%h5.prepend-top-0= _("Project avatar")
.form-group
- if @project.avatar?
.avatar-container.s160.append-bottom-15
- = project_icon(@project.full_path, alt: '', class: 'avatar project-avatar s160', width: 160, height: 160)
+ = project_icon(@project, alt: '', class: 'avatar project-avatar s160', width: 160, height: 160)
- if @project.avatar_in_git
%p.light
= _("Project avatar in repository: %{link}").html_safe % { link: @project.avatar_in_git }
@@ -59,7 +59,7 @@
- if @project.avatar?
%hr
= link_to _('Remove avatar'), project_avatar_path(@project), data: { confirm: _("Avatar will be removed. Are you sure?") }, method: :delete, class: "btn btn-danger btn-inverted"
- = f.submit 'Save changes', class: "btn btn-success js-btn-save-general-project-settings"
+ = f.submit 'Save changes', class: "btn btn-success js-btn-success-general-project-settings"
%section.settings.sharing-permissions.no-animate#js-shared-permissions{ class: ('expanded' if expanded) }
.settings-header
@@ -75,7 +75,7 @@
-# haml-lint:disable InlineJavaScript
%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"
+ = f.submit 'Save changes', class: "btn btn-success"
= render_if_exists 'projects/issues_settings'
@@ -93,7 +93,7 @@
= form_for [@project.namespace.becomes(Namespace), @project], remote: true, html: { multipart: true, class: "merge-request-settings-form" }, authenticity_token: true do |f|
%input{ name: 'update_section', type: 'hidden', value: 'js-merge-request-settings' }
= render 'projects/merge_request_settings', form: f
- = f.submit 'Save changes', class: "btn btn-save qa-save-merge-request-changes"
+ = f.submit 'Save changes', class: "btn btn-success qa-save-merge-request-changes"
= render_if_exists 'projects/service_desk_settings'
diff --git a/app/views/projects/environments/_form.html.haml b/app/views/projects/environments/_form.html.haml
index 0586dbdf0e2..f942b936037 100644
--- a/app/views/projects/environments/_form.html.haml
+++ b/app/views/projects/environments/_form.html.haml
@@ -18,5 +18,5 @@
= f.url_field :external_url, class: 'form-control'
.form-actions
- = f.submit 'Save', class: 'btn btn-save'
+ = f.submit 'Save', class: 'btn btn-success'
= link_to 'Cancel', project_environments_path(@project), class: 'btn btn-cancel'
diff --git a/app/views/projects/environments/terminal.html.haml b/app/views/projects/environments/terminal.html.haml
index 5b680189bc8..e40d631a1a1 100644
--- a/app/views/projects/environments/terminal.html.haml
+++ b/app/views/projects/environments/terminal.html.haml
@@ -2,7 +2,7 @@
- page_title "Terminal for environment", @environment.name
- content_for :page_specific_javascripts do
- = stylesheet_link_tag "xterm/xterm"
+ = stylesheet_link_tag "xterm.css"
%div{ class: container_class }
.top-area
diff --git a/app/views/projects/forks/_fork_button.html.haml b/app/views/projects/forks/_fork_button.html.haml
index 12cf40bb65f..a69146513d8 100644
--- a/app/views/projects/forks/_fork_button.html.haml
+++ b/app/views/projects/forks/_fork_button.html.haml
@@ -5,7 +5,7 @@
.bordered-box.fork-thumbnail.text-center.prepend-left-default.append-right-default.prepend-top-default.append-bottom-default.forked
= link_to project_path(forked_project) do
- if /no_((\w*)_)*avatar/.match(avatar)
- = project_icon(namespace, class: "avatar s100 identicon")
+ = group_icon(namespace, class: "avatar s100 identicon")
- else
.avatar-container.s100
= image_tag(avatar, class: "avatar s100")
@@ -18,7 +18,7 @@
class: ("disabled has-tooltip" unless can_create_project),
title: (_('You have reached your project limit') unless can_create_project) do
- if /no_((\w*)_)*avatar/.match(avatar)
- = project_icon(namespace, class: "avatar s100 identicon")
+ = group_icon(namespace, class: "avatar s100 identicon")
- else
.avatar-container.s100
= image_tag(avatar, class: "avatar s100")
diff --git a/app/views/projects/forks/index.html.haml b/app/views/projects/forks/index.html.haml
index 57afc7ac9c3..b44ea89510b 100644
--- a/app/views/projects/forks/index.html.haml
+++ b/app/views/projects/forks/index.html.haml
@@ -30,11 +30,11 @@
- if current_user && can?(current_user, :fork_project, @project)
- if current_user.already_forked?(@project) && current_user.manageable_namespaces.size < 2
- = link_to namespace_project_path(current_user, current_user.fork_of(@project)), title: 'Go to your fork', class: 'btn btn-new' do
+ = link_to namespace_project_path(current_user, current_user.fork_of(@project)), title: 'Go to your fork', class: 'btn btn-success' do
= sprite_icon('fork', size: 12)
%span Fork
- else
- = link_to new_project_fork_path(@project), title: "Fork project", class: 'btn btn-new' do
+ = link_to new_project_fork_path(@project), title: "Fork project", class: 'btn btn-success' do
= sprite_icon('fork', size: 12)
%span Fork
diff --git a/app/views/projects/hooks/_index.html.haml b/app/views/projects/hooks/_index.html.haml
index 5990582fd55..0ab7863b77c 100644
--- a/app/views/projects/hooks/_index.html.haml
+++ b/app/views/projects/hooks/_index.html.haml
@@ -9,7 +9,7 @@
.col-lg-8.append-bottom-default
= form_for @hook, as: :hook, url: polymorphic_path([@project.namespace.becomes(Namespace), @project, :hooks]) do |f|
= render partial: 'shared/web_hooks/form', locals: { form: f, hook: @hook }
- = f.submit 'Add webhook', class: 'btn btn-create'
+ = f.submit 'Add webhook', class: 'btn btn-success'
%hr
%h5.prepend-top-default
diff --git a/app/views/projects/hooks/edit.html.haml b/app/views/projects/hooks/edit.html.haml
index c31aef60453..57311284e11 100644
--- a/app/views/projects/hooks/edit.html.haml
+++ b/app/views/projects/hooks/edit.html.haml
@@ -11,7 +11,7 @@
= form_for [@project.namespace.becomes(Namespace), @project, @hook], as: :hook, url: project_hook_path(@project, @hook) do |f|
= render partial: 'shared/web_hooks/form', locals: { form: f, hook: @hook }
- = f.submit 'Save changes', class: 'btn btn-create'
+ = f.submit 'Save changes', class: 'btn btn-success'
= render 'shared/web_hooks/test_button', triggers: ProjectHook.triggers, hook: @hook
= link_to 'Remove', project_hook_path(@project, @hook), method: :delete, class: 'btn btn-remove float-right', data: { confirm: 'Are you sure?' }
diff --git a/app/views/projects/imports/new.html.haml b/app/views/projects/imports/new.html.haml
index 8ce822c43b7..1c50cfbde85 100644
--- a/app/views/projects/imports/new.html.haml
+++ b/app/views/projects/imports/new.html.haml
@@ -16,4 +16,4 @@
= render "shared/import_form", f: f
.form-actions
- = f.submit 'Start import', class: "btn btn-create", tabindex: 4
+ = f.submit 'Start import', class: "btn btn-success", tabindex: 4
diff --git a/app/views/projects/issues/_issue.html.haml b/app/views/projects/issues/_issue.html.haml
index 8a14146cb87..31c72f2f759 100644
--- a/app/views/projects/issues/_issue.html.haml
+++ b/app/views/projects/issues/_issue.html.haml
@@ -2,9 +2,9 @@
.issue-box
- if @can_bulk_update
.issue-check.hidden
- = check_box_tag dom_id(issue, "selected"), nil, false, 'data-id' => issue.id, class: "selected_issue"
- .issue-info-container
- .issue-main-info
+ = check_box_tag dom_id(issue, "selected"), nil, false, 'data-id' => issue.id, class: "selected-issuable"
+ .issuable-info-container
+ .issuable-main-info
.issue-title.title
%span.issue-title-text
- if issue.confidential?
diff --git a/app/views/projects/issues/_nav_btns.html.haml b/app/views/projects/issues/_nav_btns.html.haml
index 0dd2d2e6c5d..e4a0d4b8479 100644
--- a/app/views/projects/issues/_nav_btns.html.haml
+++ b/app/views/projects/issues/_nav_btns.html.haml
@@ -6,6 +6,6 @@
= link_to "New issue", new_project_issue_path(@project,
issue: { assignee_id: finder.assignee.try(:id),
milestone_id: finder.milestones.first.try(:id) }),
- class: "btn btn-new",
+ class: "btn btn-success",
title: "New issue",
id: "new_issue_link"
diff --git a/app/views/projects/issues/show.html.haml b/app/views/projects/issues/show.html.haml
index b81d1a188f0..c39fd0063be 100644
--- a/app/views/projects/issues/show.html.haml
+++ b/app/views/projects/issues/show.html.haml
@@ -55,7 +55,7 @@
- if can_report_spam
= link_to 'Submit as spam', mark_as_spam_project_issue_path(@project, @issue), method: :post, class: 'd-none d-sm-none d-md-block btn btn-grouped btn-spam', title: 'Submit as spam'
- if can_create_issue
- = link_to new_project_issue_path(@project), class: 'd-none d-sm-none d-md-block btn btn-grouped new-issue-link btn-new btn-inverted', title: 'New issue', id: 'new_issue_link' do
+ = link_to new_project_issue_path(@project), class: 'd-none d-sm-none d-md-block btn btn-grouped new-issue-link btn-success btn-inverted', title: 'New issue', id: 'new_issue_link' do
New issue
.issue-details.issuable-details
diff --git a/app/views/projects/jobs/_header.html.haml b/app/views/projects/jobs/_header.html.haml
index b83e8dddccb..e7245622b80 100644
--- a/app/views/projects/jobs/_header.html.haml
+++ b/app/views/projects/jobs/_header.html.haml
@@ -24,7 +24,7 @@
- if show_controls
.nav-controls
- if can?(current_user, :create_issue, @project) && @build.failed?
- = link_to "New issue", new_project_issue_path(@project, issue: build_failed_issue_options), class: 'btn btn-new btn-inverted'
+ = link_to "New issue", new_project_issue_path(@project, issue: build_failed_issue_options), class: 'btn btn-success btn-inverted'
- if can?(current_user, :update_build, @build) && @build.retryable?
= link_to "Retry job", retry_project_job_path(@project, @build), class: 'btn btn-inverted-secondary', method: :post
%button.btn.btn-default.float-right.d-block.d-sm-none.d-md-none.build-gutter-toggle.js-sidebar-build-toggle{ role: "button", type: "button" }
diff --git a/app/views/projects/jobs/_sidebar.html.haml b/app/views/projects/jobs/_sidebar.html.haml
index acc1e17b811..66a3b8b8fd1 100644
--- a/app/views/projects/jobs/_sidebar.html.haml
+++ b/app/views/projects/jobs/_sidebar.html.haml
@@ -3,63 +3,6 @@
.blocks-container
#js-details-block-vue{ data: { terminal_path: can?(current_user, :create_build_terminal, @build) && @build.has_terminal? ? terminal_project_job_path(@project, @build) : nil } }
- - if can?(current_user, :read_build, @project) && (@build.artifacts? || @build.artifacts_expired?)
- .block
- .title
- Job artifacts
- - if @build.artifacts_expired?
- %p.build-detail-row
- The artifacts were removed
- #{time_ago_with_tooltip(@build.artifacts_expire_at)}
- - elsif @build.has_expiring_artifacts?
- %p.build-detail-row
- The artifacts will be removed
- #{time_ago_with_tooltip(@build.artifacts_expire_at)}
-
- - if @build.artifacts?
- .btn-group.d-flex{ role: :group }
- - if @build.has_expiring_artifacts? && can?(current_user, :update_build, @build)
- = link_to keep_project_job_artifacts_path(@project, @build), class: 'btn btn-sm btn-default', method: :post do
- Keep
-
- = link_to download_project_job_artifacts_path(@project, @build), rel: 'nofollow', download: '', class: 'btn btn-sm btn-default' do
- Download
-
- - if @build.browsable_artifacts?
- = link_to browse_project_job_artifacts_path(@project, @build), class: 'btn btn-sm btn-default' do
- Browse
-
- - if @build.trigger_request
- .build-widget.block
- %h4.title
- Trigger
-
- - if @build.trigger_request&.trigger&.short_token
- %p
- %span.build-light-text Token:
- #{@build.trigger_request.trigger.short_token}
-
- - if @build.trigger_variables.any?
- %p
- %button.btn.group.js-reveal-variables Reveal Variables
-
- %dl.js-build-variables.trigger-build-variables.hide
- - @build.trigger_variables.each do |trigger_variable|
- %dt.js-build-variable.trigger-build-variable= trigger_variable[:key]
- %dd.js-build-value.trigger-build-value= trigger_variable[:value]
-
- %div{ class: (@build.pipeline.stages_count > 1 ? "block" : "block-last") }
- %p
- Commit
- = link_to @build.pipeline.short_sha, project_commit_path(@project, @build.pipeline.sha), class: 'commit-sha link-commit'
- = clipboard_button(text: @build.pipeline.short_sha, title: "Copy commit SHA to clipboard")
- - if @build.merge_request
- in
- = link_to "#{@build.merge_request.to_reference}", merge_request_path(@build.merge_request), class: 'link-commit'
-
- %p.build-light-text.append-bottom-0
- #{@build.pipeline.git_commit_title}
-
- if @build.pipeline.stages_count > 1
.block-last.dropdown.build-dropdown
%div
diff --git a/app/views/projects/jobs/show.html.haml b/app/views/projects/jobs/show.html.haml
index 078f40c4477..5321bc46e73 100644
--- a/app/views/projects/jobs/show.html.haml
+++ b/app/views/projects/jobs/show.html.haml
@@ -3,6 +3,9 @@
- breadcrumb_title "##{@build.id}"
- page_title "#{@build.name} (##{@build.id})", "Jobs"
+- content_for :page_specific_javascripts do
+ = stylesheet_link_tag 'page_bundles/xterm'
+
%div{ class: container_class }
.build-page.js-build-page
#js-build-header-vue
@@ -10,7 +13,7 @@
- unless @build.any_runners_online?
.bs-callout.bs-callout-warning.js-build-stuck
%p
- - if no_runners_for_project?(@build.project)
+ - if @project.any_runners?
This job is stuck, because the project doesn't have any runners online assigned to it.
- elsif @build.tags.any?
This job is stuck, because you don't have any active runners online with any of these tags assigned to them:
diff --git a/app/views/projects/labels/index.html.haml b/app/views/projects/labels/index.html.haml
index 1bfd8a85f0f..683dda4f166 100644
--- a/app/views/projects/labels/index.html.haml
+++ b/app/views/projects/labels/index.html.haml
@@ -6,7 +6,7 @@
- if can_admin_label
- content_for(:header_content) do
.nav-controls
- = link_to _('New label'), new_project_label_path(@project), class: "btn btn-new"
+ = link_to _('New label'), new_project_label_path(@project), class: "btn btn-success"
- if @labels.exists? || @prioritized_labels.exists? || search.present?
#promote-label-modal
diff --git a/app/views/projects/mattermosts/_team_selection.html.haml b/app/views/projects/mattermosts/_team_selection.html.haml
index 37c09f12f63..d0a7f89df31 100644
--- a/app/views/projects/mattermosts/_team_selection.html.haml
+++ b/app/views/projects/mattermosts/_team_selection.html.haml
@@ -43,4 +43,4 @@
.clearfix
.float-right
= link_to 'Cancel', edit_project_service_path(@project, @service), class: 'btn btn-lg'
- = f.submit 'Install', class: 'btn btn-save btn-lg'
+ = f.submit 'Install', class: 'btn btn-success btn-lg'
diff --git a/app/views/projects/merge_requests/_merge_request.html.haml b/app/views/projects/merge_requests/_merge_request.html.haml
index cd3d896fff2..faa070d0389 100644
--- a/app/views/projects/merge_requests/_merge_request.html.haml
+++ b/app/views/projects/merge_requests/_merge_request.html.haml
@@ -1,10 +1,10 @@
%li{ id: dom_id(merge_request), class: mr_css_classes(merge_request), data: { labels: merge_request.label_ids, id: merge_request.id } }
- if @can_bulk_update
.issue-check.hidden
- = check_box_tag dom_id(merge_request, "selected"), nil, false, 'data-id' => merge_request.id, class: "selected_issue"
+ = check_box_tag dom_id(merge_request, "selected"), nil, false, 'data-id' => merge_request.id, class: "selected-issuable"
- .issue-info-container
- .issue-main-info
+ .issuable-info-container
+ .issuable-main-info
.merge-request-title.title
%span.merge-request-title-text
= link_to merge_request.title, merge_request_path(merge_request)
diff --git a/app/views/projects/merge_requests/_nav_btns.html.haml b/app/views/projects/merge_requests/_nav_btns.html.haml
index e73dab8ad4a..b7498216334 100644
--- a/app/views/projects/merge_requests/_nav_btns.html.haml
+++ b/app/views/projects/merge_requests/_nav_btns.html.haml
@@ -1,5 +1,5 @@
- if @can_bulk_update
= button_tag "Edit merge requests", class: "btn append-right-10 js-bulk-update-toggle"
- if merge_project
- = link_to new_merge_request_path, class: "btn btn-new", title: "New merge request" do
+ = link_to new_merge_request_path, class: "btn btn-success", title: "New merge request" do
New merge request
diff --git a/app/views/projects/merge_requests/creations/_new_compare.html.haml b/app/views/projects/merge_requests/creations/_new_compare.html.haml
index afa7eb06cb4..1fd71a38472 100644
--- a/app/views/projects/merge_requests/creations/_new_compare.html.haml
+++ b/app/views/projects/merge_requests/creations/_new_compare.html.haml
@@ -61,4 +61,4 @@
- if @merge_request.errors.any?
= form_errors(@merge_request)
- = f.submit 'Compare branches and continue', class: "btn btn-new mr-compare-btn"
+ = f.submit 'Compare branches and continue', class: "btn btn-success mr-compare-btn"
diff --git a/app/views/projects/merge_requests/diffs/_commit_widget.html.haml b/app/views/projects/merge_requests/diffs/_commit_widget.html.haml
index dab95b97346..066c8d5dba6 100644
--- a/app/views/projects/merge_requests/diffs/_commit_widget.html.haml
+++ b/app/views/projects/merge_requests/diffs/_commit_widget.html.haml
@@ -1,3 +1,7 @@
+-#-----------------------------------------------------------------
+ WARNING: Please keep changes up-to-date with the following files:
+ - `assets/javascripts/diffs/components/commit_widget.vue`
+-#-----------------------------------------------------------------
- if @commit
.info-well.d-none.d-sm-block.prepend-top-default
.well-segment
diff --git a/app/views/projects/merge_requests/diffs/_diffs.html.haml b/app/views/projects/merge_requests/diffs/_diffs.html.haml
index bf3df0abf86..9ebd91dea0b 100644
--- a/app/views/projects/merge_requests/diffs/_diffs.html.haml
+++ b/app/views/projects/merge_requests/diffs/_diffs.html.haml
@@ -14,7 +14,7 @@
%span.ref-name= @merge_request.source_branch
and
%span.ref-name= @merge_request.target_branch
- .text-center= link_to 'Create commit', project_new_blob_path(@project, @merge_request.source_branch), class: 'btn btn-save'
+ .text-center= link_to 'Create commit', project_new_blob_path(@project, @merge_request.source_branch), class: 'btn btn-success'
- else
- diff_viewable = @merge_request_diff ? @merge_request_diff.viewable? : true
- if diff_viewable
diff --git a/app/views/projects/milestones/_form.html.haml b/app/views/projects/milestones/_form.html.haml
index 28f0a167128..ebd3229e42b 100644
--- a/app/views/projects/milestones/_form.html.haml
+++ b/app/views/projects/milestones/_form.html.haml
@@ -20,8 +20,8 @@
.form-actions
- if @milestone.new_record?
- = f.submit 'Create milestone', class: "btn-create btn qa-milestone-create-button"
+ = f.submit 'Create milestone', class: "btn-success btn qa-milestone-create-button"
= link_to "Cancel", project_milestones_path(@project), class: "btn btn-cancel"
- else
- = f.submit 'Save changes', class: "btn-save btn"
+ = f.submit 'Save changes', class: "btn-success btn"
= link_to "Cancel", project_milestone_path(@project, @milestone), class: "btn btn-cancel"
diff --git a/app/views/projects/milestones/index.html.haml b/app/views/projects/milestones/index.html.haml
index 26d2ea8447b..57f3c640696 100644
--- a/app/views/projects/milestones/index.html.haml
+++ b/app/views/projects/milestones/index.html.haml
@@ -8,7 +8,7 @@
.nav-controls
= render 'shared/milestones_sort_dropdown'
- if can?(current_user, :admin_milestone, @project)
- = link_to new_project_milestone_path(@project), class: "btn btn-new qa-new-project-milestone", title: 'New milestone' do
+ = link_to new_project_milestone_path(@project), class: "btn btn-success qa-new-project-milestone", title: 'New milestone' do
New milestone
.milestones
diff --git a/app/views/projects/mirrors/_mirror_repos.html.haml b/app/views/projects/mirrors/_mirror_repos.html.haml
index c6764c7607a..d523df1cd90 100644
--- a/app/views/projects/mirrors/_mirror_repos.html.haml
+++ b/app/views/projects/mirrors/_mirror_repos.html.haml
@@ -32,7 +32,7 @@
= link_to icon('question-circle'), help_page_path('user/project/protected_branches')
.panel-footer
- = f.submit _('Mirror repository'), class: 'btn btn-create', name: :update_remote_mirror
+ = f.submit _('Mirror repository'), class: 'btn btn-success', name: :update_remote_mirror
.panel.panel-default
.table-responsive
diff --git a/app/views/projects/pages/show.html.haml b/app/views/projects/pages/show.html.haml
index 7e1a3b9bea6..88ab486a248 100644
--- a/app/views/projects/pages/show.html.haml
+++ b/app/views/projects/pages/show.html.haml
@@ -4,7 +4,7 @@
Pages
- if can?(current_user, :update_pages, @project) && (Gitlab.config.pages.external_http || Gitlab.config.pages.external_https)
- = link_to new_project_pages_domain_path(@project), class: 'btn btn-new float-right', title: 'New Domain' do
+ = link_to new_project_pages_domain_path(@project), class: 'btn btn-success float-right', title: 'New Domain' do
New Domain
%p.light
diff --git a/app/views/projects/pages_domains/edit.html.haml b/app/views/projects/pages_domains/edit.html.haml
index ee70de22f13..342b1482df7 100644
--- a/app/views/projects/pages_domains/edit.html.haml
+++ b/app/views/projects/pages_domains/edit.html.haml
@@ -8,4 +8,4 @@
= form_for [@project.namespace.becomes(Namespace), @project, @domain], html: { class: 'fieldset-form' } do |f|
= render 'form', { f: f }
.form-actions
- = f.submit 'Save Changes', class: "btn btn-save"
+ = f.submit 'Save Changes', class: "btn btn-success"
diff --git a/app/views/projects/pages_domains/new.html.haml b/app/views/projects/pages_domains/new.html.haml
index 376ce3f68aa..94ad1470052 100644
--- a/app/views/projects/pages_domains/new.html.haml
+++ b/app/views/projects/pages_domains/new.html.haml
@@ -7,6 +7,6 @@
= form_for [@project.namespace.becomes(Namespace), @project, @domain], html: { class: 'fieldset-form' } do |f|
= render 'form', { f: f }
.form-actions
- = f.submit 'Create New Domain', class: "btn btn-save"
+ = f.submit 'Create New Domain', class: "btn btn-success"
.float-right
= link_to _('Cancel'), project_pages_path(@project), class: 'btn btn-cancel'
diff --git a/app/views/projects/pipeline_schedules/_form.html.haml b/app/views/projects/pipeline_schedules/_form.html.haml
index 9a981d53ab6..259979417e0 100644
--- a/app/views/projects/pipeline_schedules/_form.html.haml
+++ b/app/views/projects/pipeline_schedules/_form.html.haml
@@ -39,5 +39,5 @@
= f.check_box :active, required: false, value: @schedule.active?
= _('Active')
.footer-block.row-content-block
- = f.submit _('Save pipeline schedule'), class: 'btn btn-create', tabindex: 3
+ = f.submit _('Save pipeline schedule'), class: 'btn btn-success', tabindex: 3
= link_to _('Cancel'), pipeline_schedules_path(@project), class: 'btn btn-cancel'
diff --git a/app/views/projects/pipeline_schedules/index.html.haml b/app/views/projects/pipeline_schedules/index.html.haml
index 3677666070e..0580c15ad15 100644
--- a/app/views/projects/pipeline_schedules/index.html.haml
+++ b/app/views/projects/pipeline_schedules/index.html.haml
@@ -11,7 +11,7 @@
- if can?(current_user, :create_pipeline_schedule, @project)
.nav-controls
- = link_to new_project_pipeline_schedule_path(@project), class: 'btn btn-create' do
+ = link_to new_project_pipeline_schedule_path(@project), class: 'btn btn-success' do
%span= _('New schedule')
- if @schedules.present?
diff --git a/app/views/projects/project_members/_new_project_group.html.haml b/app/views/projects/project_members/_new_project_group.html.haml
index 7de24ec5ad2..74570769117 100644
--- a/app/views/projects/project_members/_new_project_group.html.haml
+++ b/app/views/projects/project_members/_new_project_group.html.haml
@@ -17,4 +17,4 @@
.clearable-input
= text_field_tag :expires_at, nil, class: 'form-control js-access-expiration-date-groups', placeholder: _('Expiration date'), id: 'expires_at_groups'
%i.clear-icon.js-clear-input
- = submit_tag _("Invite"), class: "btn btn-create"
+ = submit_tag _("Invite"), class: "btn btn-success"
diff --git a/app/views/projects/project_members/_new_project_member.html.haml b/app/views/projects/project_members/_new_project_member.html.haml
index 6272687be1c..517fd249f6e 100644
--- a/app/views/projects/project_members/_new_project_member.html.haml
+++ b/app/views/projects/project_members/_new_project_member.html.haml
@@ -17,5 +17,5 @@
= label_tag :expires_at, 'Access expiration date', class: 'label-bold'
= text_field_tag :expires_at, nil, class: 'form-control js-access-expiration-date', placeholder: 'Expiration date'
%i.clear-icon.js-clear-input
- = f.submit "Add to project", class: "btn btn-create"
+ = f.submit "Add to project", class: "btn btn-success"
= link_to "Import", import_project_project_members_path(@project), class: "btn btn-default", title: "Import members from another project"
diff --git a/app/views/projects/project_members/import.html.haml b/app/views/projects/project_members/import.html.haml
index 6a52e72bfd8..8b93e81cd31 100644
--- a/app/views/projects/project_members/import.html.haml
+++ b/app/views/projects/project_members/import.html.haml
@@ -11,5 +11,5 @@
.col-sm-10= select_tag(:source_project_id, options_from_collection_for_select(@projects, :id, :name_with_namespace), prompt: "Select project", class: "select2 lg", required: true)
.form-actions
- = button_tag 'Import project members', class: "btn btn-create"
+ = button_tag 'Import project members', class: "btn btn-success"
= link_to "Cancel", project_project_members_path(@project), class: "btn btn-cancel"
diff --git a/app/views/projects/protected_branches/shared/_create_protected_branch.html.haml b/app/views/projects/protected_branches/shared/_create_protected_branch.html.haml
index df2dcf19ed4..c3b8f2f8964 100644
--- a/app/views/projects/protected_branches/shared/_create_protected_branch.html.haml
+++ b/app/views/projects/protected_branches/shared/_create_protected_branch.html.haml
@@ -30,4 +30,4 @@
= yield :push_access_levels
.card-footer
- = f.submit 'Protect', class: 'btn-create btn', disabled: true
+ = f.submit 'Protect', class: 'btn-success btn', disabled: true
diff --git a/app/views/projects/protected_tags/shared/_create_protected_tag.html.haml b/app/views/projects/protected_tags/shared/_create_protected_tag.html.haml
index f98781b77f4..b274c73d035 100644
--- a/app/views/projects/protected_tags/shared/_create_protected_tag.html.haml
+++ b/app/views/projects/protected_tags/shared/_create_protected_tag.html.haml
@@ -26,4 +26,4 @@
= yield :create_access_levels
.card-footer
- = f.submit 'Protect', class: 'btn-create btn', disabled: true
+ = f.submit 'Protect', class: 'btn-success btn', disabled: true
diff --git a/app/views/projects/releases/edit.html.haml b/app/views/projects/releases/edit.html.haml
index 8093cc2c2d7..52c6c7ec424 100644
--- a/app/views/projects/releases/edit.html.haml
+++ b/app/views/projects/releases/edit.html.haml
@@ -19,5 +19,5 @@
= render 'shared/notes/hints'
.error-alert
.prepend-top-default
- = f.submit 'Save changes', class: 'btn btn-save'
+ = f.submit 'Save changes', class: 'btn btn-success'
= link_to "Cancel", project_tag_path(@project, @tag.name), class: "btn btn-default btn-cancel"
diff --git a/app/views/projects/runners/_group_runners.html.haml b/app/views/projects/runners/_group_runners.html.haml
index 86de71c732b..a6c16c70313 100644
--- a/app/views/projects/runners/_group_runners.html.haml
+++ b/app/views/projects/runners/_group_runners.html.haml
@@ -28,7 +28,7 @@
- group_link = link_to _('Group CI/CD settings'), group_settings_ci_cd_path(@project.group)
= _('Group maintainers can register group runners in the %{link}').html_safe % { link: group_link }
- else
- = _('Ask your group maintainer to setup a group Runner.')
+ = _('Ask your group maintainer to set up a group Runner.')
- else
%h4.underlined-title
diff --git a/app/views/projects/services/mattermost_slash_commands/_detailed_help.html.haml b/app/views/projects/services/mattermost_slash_commands/_detailed_help.html.haml
index 9314804c5dd..9409418bbcc 100644
--- a/app/views/projects/services/mattermost_slash_commands/_detailed_help.html.haml
+++ b/app/views/projects/services/mattermost_slash_commands/_detailed_help.html.haml
@@ -1,6 +1,6 @@
- run_actions_text = "Perform common operations on GitLab project: #{@project.full_name}"
-%p To setup this service:
+%p To set up this service:
%ul.list-unstyled.indent-list
%li
1.
diff --git a/app/views/projects/services/slack_slash_commands/_help.html.haml b/app/views/projects/services/slack_slash_commands/_help.html.haml
index f25d2ecdfb1..9a7004f89c0 100644
--- a/app/views/projects/services/slack_slash_commands/_help.html.haml
+++ b/app/views/projects/services/slack_slash_commands/_help.html.haml
@@ -14,7 +14,7 @@
by entering
%kbd.inline /&lt;command&gt; help
- unless @service.template?
- %p To setup this service:
+ %p To set up this service:
%ul.list-unstyled.indent-list
%li
1.
diff --git a/app/views/projects/settings/ci_cd/_form.html.haml b/app/views/projects/settings/ci_cd/_form.html.haml
index 9134257b631..ae923d8e6dc 100644
--- a/app/views/projects/settings/ci_cd/_form.html.haml
+++ b/app/views/projects/settings/ci_cd/_form.html.haml
@@ -121,7 +121,7 @@
go test -cover (Go)
%code coverage: \d+.\d+% of statements
- = f.submit _('Save changes'), class: "btn btn-save"
+ = f.submit _('Save changes'), class: "btn btn-success"
%hr
diff --git a/app/views/projects/snippets/_actions.html.haml b/app/views/projects/snippets/_actions.html.haml
index 4a3aa3dc626..ea963510a68 100644
--- a/app/views/projects/snippets/_actions.html.haml
+++ b/app/views/projects/snippets/_actions.html.haml
@@ -8,7 +8,7 @@
= link_to project_snippet_path(@project, @snippet), method: :delete, data: { confirm: _("Are you sure?") }, class: "btn btn-grouped btn-inverted btn-remove", title: _('Delete Snippet') do
= _('Delete')
- if can?(current_user, :create_project_snippet, @project)
- = link_to new_project_snippet_path(@project), class: 'btn btn-grouped btn-inverted btn-create', title: _("New snippet") do
+ = link_to new_project_snippet_path(@project), class: 'btn btn-grouped btn-inverted btn-success', title: _("New snippet") do
= _('New snippet')
- if @snippet.submittable_as_spam_by?(current_user)
= link_to _('Submit as spam'), mark_as_spam_project_snippet_path(@project, @snippet), method: :post, class: 'btn btn-grouped btn-spam', title: _('Submit as spam')
diff --git a/app/views/projects/snippets/index.html.haml b/app/views/projects/snippets/index.html.haml
index 1c4c73dc776..a4974d89c1a 100644
--- a/app/views/projects/snippets/index.html.haml
+++ b/app/views/projects/snippets/index.html.haml
@@ -7,6 +7,6 @@
.nav-controls
- if can?(current_user, :create_project_snippet, @project)
- = link_to _("New snippet"), new_project_snippet_path(@project), class: "btn btn-new", title: _("New snippet")
+ = link_to _("New snippet"), new_project_snippet_path(@project), class: "btn btn-success", title: _("New snippet")
= render 'snippets/snippets'
diff --git a/app/views/projects/tags/index.html.haml b/app/views/projects/tags/index.html.haml
index 20b4705521c..37535370940 100644
--- a/app/views/projects/tags/index.html.haml
+++ b/app/views/projects/tags/index.html.haml
@@ -25,7 +25,7 @@
%li
= link_to title, filter_tags_path(sort: value), class: ("is-active" if @sort == value)
- if can?(current_user, :push_code, @project)
- = link_to new_project_tag_path(@project), class: 'btn btn-create new-tag-btn' do
+ = link_to new_project_tag_path(@project), class: 'btn btn-success new-tag-btn' do
= s_('TagsPage|New tag')
= link_to project_tags_path(@project, rss_url_options), title: _("Tags feed"), class: 'btn rss-btn has-tooltip' do
= icon("rss")
diff --git a/app/views/projects/tags/new.html.haml b/app/views/projects/tags/new.html.haml
index da822ac5675..24724394259 100644
--- a/app/views/projects/tags/new.html.haml
+++ b/app/views/projects/tags/new.html.haml
@@ -41,7 +41,7 @@
.form-text.text-muted
= s_('TagsPage|Optionally, add release notes to the tag. They will be stored in the GitLab database and displayed on the tags page.')
.form-actions
- = button_tag s_('TagsPage|Create tag'), class: 'btn btn-create'
+ = button_tag s_('TagsPage|Create tag'), class: 'btn btn-success'
= link_to s_('TagsPage|Cancel'), project_tags_path(@project), class: 'btn btn-cancel'
-# haml-lint:disable InlineJavaScript
%script#availableRefs{ type: "application/json" }= @project.repository.ref_names.to_json.html_safe
diff --git a/app/views/projects/triggers/_form.html.haml b/app/views/projects/triggers/_form.html.haml
index 1a5fc56f429..a9abfac239c 100644
--- a/app/views/projects/triggers/_form.html.haml
+++ b/app/views/projects/triggers/_form.html.haml
@@ -8,4 +8,4 @@
.form-group
= f.label :key, "Description", class: "label-bold"
= f.text_field :description, class: "form-control", required: true, title: 'Trigger description is required.', placeholder: "Trigger description"
- = f.submit btn_text, class: "btn btn-save"
+ = f.submit btn_text, class: "btn btn-success"
diff --git a/app/views/projects/update.js.haml b/app/views/projects/update.js.haml
index e8681da6528..70f1bf8ef46 100644
--- a/app/views/projects/update.js.haml
+++ b/app/views/projects/update.js.haml
@@ -7,4 +7,4 @@
$(".project-edit-errors").html("#{escape_javascript(render('errors'))}");
$('.save-project-loader').hide();
$('.project-edit-container').show();
- $('.edit-project .js-btn-save-general-project-settings').enable();
+ $('.edit-project .js-btn-success-general-project-settings').enable();
diff --git a/app/views/projects/wikis/_form.html.haml b/app/views/projects/wikis/_form.html.haml
index 35872d70db4..7d8826e540c 100644
--- a/app/views/projects/wikis/_form.html.haml
+++ b/app/views/projects/wikis/_form.html.haml
@@ -51,10 +51,10 @@
.form-actions
- if @page && @page.persisted?
- = f.submit _("Save changes"), class: 'btn-save btn'
+ = f.submit _("Save changes"), class: 'btn-success btn'
.float-right
= link_to _("Cancel"), project_wiki_path(@project, @page), class: 'btn btn-cancel btn-grouped'
- else
- = f.submit s_("Wiki|Create page"), class: 'btn-create btn'
+ = f.submit s_("Wiki|Create page"), class: 'btn-success btn'
.float-right
= link_to _("Cancel"), project_wiki_path(@project, :home), class: 'btn btn-cancel'
diff --git a/app/views/projects/wikis/_main_links.html.haml b/app/views/projects/wikis/_main_links.html.haml
index 8d91f411f89..643b51e01d1 100644
--- a/app/views/projects/wikis/_main_links.html.haml
+++ b/app/views/projects/wikis/_main_links.html.haml
@@ -1,6 +1,6 @@
- if (@page && @page.persisted?)
- if can?(current_user, :create_wiki, @project)
- = link_to '#modal-new-wiki', class: "add-new-wiki btn btn-new", "data-toggle" => "modal" do
+ = link_to '#modal-new-wiki', class: "add-new-wiki btn btn-success", "data-toggle" => "modal" do
= s_("Wiki|New page")
= link_to project_wiki_history_path(@project, @page), class: "btn" do
= s_("Wiki|Page history")
diff --git a/app/views/projects/wikis/_new.html.haml b/app/views/projects/wikis/_new.html.haml
index 38382aae67c..dc12e368b35 100644
--- a/app/views/projects/wikis/_new.html.haml
+++ b/app/views/projects/wikis/_new.html.haml
@@ -15,4 +15,4 @@
= icon('lightbulb-o')
= s_("WikiNewPageTip|Tip: You can specify the full path for the new file. We will automatically create any missing directories.")
.form-actions
- = button_tag s_("Wiki|Create page"), class: "build-new-wiki btn btn-create"
+ = button_tag s_("Wiki|Create page"), class: "build-new-wiki btn btn-success"
diff --git a/app/views/projects/wikis/edit.html.haml b/app/views/projects/wikis/edit.html.haml
index e12b8f2858c..80aa1500d53 100644
--- a/app/views/projects/wikis/edit.html.haml
+++ b/app/views/projects/wikis/edit.html.haml
@@ -22,7 +22,7 @@
.nav-controls
- if can?(current_user, :create_wiki, @project)
- = link_to '#modal-new-wiki', class: "add-new-wiki btn btn-new", "data-toggle" => "modal" do
+ = link_to '#modal-new-wiki', class: "add-new-wiki btn btn-success", "data-toggle" => "modal" do
= s_("Wiki|New page")
- if @page.persisted?
= link_to project_wiki_history_path(@project, @page), class: "btn" do
diff --git a/app/views/shared/_event_filter.html.haml b/app/views/shared/_event_filter.html.haml
index 7afb7b3a93b..6612497e7e2 100644
--- a/app/views/shared/_event_filter.html.haml
+++ b/app/views/shared/_event_filter.html.haml
@@ -2,13 +2,13 @@
.fade-left= icon('angle-left')
.fade-right= icon('angle-right')
%ul.nav-links.event-filter.scrolling-tabs.nav.nav-tabs
- = event_filter_link EventFilter.all, _('All'), s_('EventFilterBy|Filter by all')
+ = event_filter_link EventFilter::ALL, _('All'), s_('EventFilterBy|Filter by all')
- if event_filter_visible(:repository)
- = event_filter_link EventFilter.push, _('Push events'), s_('EventFilterBy|Filter by push events')
+ = event_filter_link EventFilter::PUSH, _('Push events'), s_('EventFilterBy|Filter by push events')
- if event_filter_visible(:merge_requests)
- = event_filter_link EventFilter.merged, _('Merge events'), s_('EventFilterBy|Filter by merge events')
+ = event_filter_link EventFilter::MERGED, _('Merge events'), s_('EventFilterBy|Filter by merge events')
- if event_filter_visible(:issues)
- = event_filter_link EventFilter.issue, _('Issue events'), s_('EventFilterBy|Filter by issue events')
+ = event_filter_link EventFilter::ISSUE, _('Issue events'), s_('EventFilterBy|Filter by issue events')
- if comments_visible?
- = event_filter_link EventFilter.comments, _('Comments'), s_('EventFilterBy|Filter by comments')
- = event_filter_link EventFilter.team, _('Team'), s_('EventFilterBy|Filter by team')
+ = event_filter_link EventFilter::COMMENTS, _('Comments'), s_('EventFilterBy|Filter by comments')
+ = event_filter_link EventFilter::TEAM, _('Team'), s_('EventFilterBy|Filter by team')
diff --git a/app/views/shared/_new_project_item_select.html.haml b/app/views/shared/_new_project_item_select.html.haml
index d38d161047b..9bc67a7c715 100644
--- a/app/views/shared/_new_project_item_select.html.haml
+++ b/app/views/shared/_new_project_item_select.html.haml
@@ -1,7 +1,7 @@
- if any_projects?(@projects)
.project-item-select-holder.btn-group
- %a.btn.btn-new.new-project-item-link.qa-new-project-item-link{ href: '', data: { label: local_assigns[:label], type: local_assigns[:type] } }
+ %a.btn.btn-success.new-project-item-link.qa-new-project-item-link{ href: '', data: { label: local_assigns[:label], type: local_assigns[:type] } }
= icon('spinner spin')
= project_select_tag :project_path, class: "project-item-select", data: { include_groups: local_assigns[:include_groups], order_by: 'last_activity_at', relative_path: local_assigns[:path] }, with_feature_enabled: local_assigns[:with_feature_enabled]
- %button.btn.btn-new.new-project-item-select-button.qa-new-project-item-select-button
+ %button.btn.btn-success.new-project-item-select-button.qa-new-project-item-select-button
= icon('caret-down')
diff --git a/app/views/shared/_personal_access_tokens_form.html.haml b/app/views/shared/_personal_access_tokens_form.html.haml
index 58d310fac16..f4df7bdcd83 100644
--- a/app/views/shared/_personal_access_tokens_form.html.haml
+++ b/app/views/shared/_personal_access_tokens_form.html.haml
@@ -26,4 +26,4 @@
= render 'shared/tokens/scopes_form', prefix: 'personal_access_token', token: token, scopes: scopes
.prepend-top-default
- = f.submit "Create #{type} token", class: "btn btn-create"
+ = f.submit "Create #{type} token", class: "btn btn-success"
diff --git a/app/views/shared/_recaptcha_form.html.haml b/app/views/shared/_recaptcha_form.html.haml
index a0ba1afc284..10f358402c1 100644
--- a/app/views/shared/_recaptcha_form.html.haml
+++ b/app/views/shared/_recaptcha_form.html.haml
@@ -17,4 +17,4 @@
- if has_submit
.row-content-block.footer-block
- = f.submit "Submit #{humanized_resource_name}", class: 'btn btn-create'
+ = f.submit "Submit #{humanized_resource_name}", class: 'btn btn-success'
diff --git a/app/views/shared/_visibility_level.html.haml b/app/views/shared/_visibility_level.html.haml
index 01ce1225b8d..ba37b37a3b1 100644
--- a/app/views/shared/_visibility_level.html.haml
+++ b/app/views/shared/_visibility_level.html.haml
@@ -2,7 +2,7 @@
.form-group.row.visibility-level-setting
- if with_label
- = f.label :visibility_level, class: 'col-form-label col-sm-2' do
+ = f.label :visibility_level, class: 'col-form-label col-sm-2 pt-0' do
Visibility Level
= link_to icon('question-circle'), help_page_path("public_access/public_access")
%div{ :class => (with_label ? "col-sm-10" : "col-sm-12") }
diff --git a/app/views/shared/empty_states/_labels.html.haml b/app/views/shared/empty_states/_labels.html.haml
index e8749ee3956..b629ceafeb3 100644
--- a/app/views/shared/empty_states/_labels.html.haml
+++ b/app/views/shared/empty_states/_labels.html.haml
@@ -7,5 +7,5 @@
%h4= _("Labels can be applied to issues and merge requests to categorize them.")
%p= _("You can also star a label to make it a priority label.")
- if can?(current_user, :admin_label, @project)
- = link_to _('New label'), new_project_label_path(@project), class: 'btn btn-new', title: _('New label'), id: 'new_label_link'
+ = link_to _('New label'), new_project_label_path(@project), class: 'btn btn-success', title: _('New label'), id: 'new_label_link'
= link_to _('Generate a default set of labels'), generate_project_labels_path(@project), method: :post, class: 'btn btn-success btn-inverted', title: _('Generate a default set of labels'), id: 'generate_labels_link'
diff --git a/app/views/shared/empty_states/_merge_requests.html.haml b/app/views/shared/empty_states/_merge_requests.html.haml
index 186139f3526..421a1b2415b 100644
--- a/app/views/shared/empty_states/_merge_requests.html.haml
+++ b/app/views/shared/empty_states/_merge_requests.html.haml
@@ -17,7 +17,7 @@
- if project_select_button
= render 'shared/new_project_item_select', path: 'merge_requests/new', label: _('New merge request'), type: :merge_requests, with_feature_enabled: 'merge_requests'
- else
- = link_to _('New merge request'), button_path, class: 'btn btn-new', title: _('New merge request'), id: 'new_merge_request_link'
+ = link_to _('New merge request'), button_path, class: 'btn btn-success', title: _('New merge request'), id: 'new_merge_request_link'
- else
%h4.text-center
= _("There are no merge requests to show")
diff --git a/app/views/shared/empty_states/_wikis.html.haml b/app/views/shared/empty_states/_wikis.html.haml
index f1a41074c28..5351c9ce6a4 100644
--- a/app/views/shared/empty_states/_wikis.html.haml
+++ b/app/views/shared/empty_states/_wikis.html.haml
@@ -2,7 +2,7 @@
- if can?(current_user, :create_wiki, @project)
- create_path = project_wiki_path(@project, params[:id], { view: 'create' })
- - create_link = link_to s_('WikiEmpty|Create your first page'), create_path, class: 'btn btn-new', title: s_('WikiEmpty|Create your first page')
+ - create_link = link_to s_('WikiEmpty|Create your first page'), create_path, class: 'btn btn-success', title: s_('WikiEmpty|Create your first page')
= render layout: layout_path, locals: { image_path: 'illustrations/wiki_login_empty.svg' } do
%h4
@@ -13,7 +13,7 @@
- elsif can?(current_user, :read_issue, @project)
- issues_link = link_to s_('WikiEmptyIssueMessage|issue tracker'), project_issues_path(@project)
- - new_issue_link = link_to s_('WikiEmpty|Suggest wiki improvement'), new_project_issue_path(@project), class: 'btn btn-new', title: s_('WikiEmptyIssueMessage|Suggest wiki improvement')
+ - new_issue_link = link_to s_('WikiEmpty|Suggest wiki improvement'), new_project_issue_path(@project), class: 'btn btn-success', title: s_('WikiEmptyIssueMessage|Suggest wiki improvement')
= render layout: layout_path, locals: { image_path: 'illustrations/wiki_logout_empty.svg' } do
%h4
diff --git a/app/views/shared/issuable/_board_create_list_dropdown.html.haml b/app/views/shared/issuable/_board_create_list_dropdown.html.haml
index 23b2e1b91e5..4597d9439fa 100644
--- a/app/views/shared/issuable/_board_create_list_dropdown.html.haml
+++ b/app/views/shared/issuable/_board_create_list_dropdown.html.haml
@@ -1,5 +1,5 @@
.dropdown.prepend-left-10#js-add-list
- %button.btn.btn-create.btn-inverted.js-new-board-list{ type: "button", data: board_list_data }
+ %button.btn.btn-success.btn-inverted.js-new-board-list{ type: "button", data: board_list_data }
Add list
.dropdown-menu.dropdown-menu-paging.dropdown-menu-right.dropdown-menu-issues-board-new.dropdown-menu-selectable.js-tab-container-labels
= render partial: "shared/issuable/label_page_default", locals: { show_footer: true, show_create: true, show_boards_content: true, title: "Add list" }
diff --git a/app/views/shared/issuable/_form.html.haml b/app/views/shared/issuable/_form.html.haml
index b49e47a7266..5b28a43a361 100644
--- a/app/views/shared/issuable/_form.html.haml
+++ b/app/views/shared/issuable/_form.html.haml
@@ -69,9 +69,9 @@
%span.append-right-10
- if issuable.new_record?
- = form.submit "Submit #{issuable.class.model_name.human.downcase}", class: 'btn btn-create qa-issuable-create-button'
+ = form.submit "Submit #{issuable.class.model_name.human.downcase}", class: 'btn btn-success qa-issuable-create-button'
- else
- = form.submit 'Save changes', class: 'btn btn-save'
+ = form.submit 'Save changes', class: 'btn btn-success'
- if !issuable.persisted? && !issuable.project.empty_repo? && (guide_url = issuable.project.present.contribution_guide_path)
.inline.prepend-top-10
diff --git a/app/views/shared/issuable/_search_bar.html.haml b/app/views/shared/issuable/_search_bar.html.haml
index 9ce7f6fe269..659e03fd67d 100644
--- a/app/views/shared/issuable/_search_bar.html.haml
+++ b/app/views/shared/issuable/_search_bar.html.haml
@@ -34,7 +34,7 @@
%ul{ data: { dropdown: true } }
%li.filter-dropdown-item{ data: { action: 'submit' } }
%button.btn.btn-link
- = icon('search')
+ = sprite_icon('search')
%span
Press Enter or click to search
%ul.filter-dropdown{ data: { dynamic: true, dropdown: true } }
@@ -42,7 +42,8 @@
%button.btn.btn-link
-# Encapsulate static class name `{{icon}}` inside #{} to bypass
-# haml lint's ClassAttributeWithStaticValue
- %i.fa{ class: "#{'{{icon}}'}" }
+ %svg
+ %use{ 'xlink:href': "#{'{{icon}}'}" }
%span.js-filter-hint
{{hint}}
%span.js-filter-tag.dropdown-light-content
diff --git a/app/views/shared/issuable/_sidebar.html.haml b/app/views/shared/issuable/_sidebar.html.haml
index 0ca35ea1298..32b609eed0d 100644
--- a/app/views/shared/issuable/_sidebar.html.haml
+++ b/app/views/shared/issuable/_sidebar.html.haml
@@ -159,7 +159,7 @@
= dropdown_content
= dropdown_loading
= dropdown_footer add_content_class: true do
- %button.btn.btn-new.sidebar-move-issue-confirmation-button.js-move-issue-confirmation-button{ disabled: true }
+ %button.btn.btn-success.sidebar-move-issue-confirmation-button.js-move-issue-confirmation-button{ disabled: true }
= _('Move')
= icon('spinner spin', class: 'sidebar-move-issue-confirmation-loading-icon')
diff --git a/app/views/shared/issuable/form/_metadata.html.haml b/app/views/shared/issuable/form/_metadata.html.haml
index d8580ad8ab4..ac8d58c0bfe 100644
--- a/app/views/shared/issuable/form/_metadata.html.haml
+++ b/app/views/shared/issuable/form/_metadata.html.haml
@@ -34,4 +34,4 @@
= form.label :due_date, "Due date", class: "col-form-label col-md-2 col-lg-4"
.col-8
.issuable-form-select-holder
- = form.text_field :due_date, id: "issuable-due-date", class: "datepicker form-control", placeholder: "Select due date"
+ = form.text_field :due_date, id: "issuable-due-date", class: "datepicker form-control", placeholder: "Select due date", autocomplete: 'off'
diff --git a/app/views/shared/issuable/form/_title.html.haml b/app/views/shared/issuable/form/_title.html.haml
index e49bdec386a..56c4b021eab 100644
--- a/app/views/shared/issuable/form/_title.html.haml
+++ b/app/views/shared/issuable/form/_title.html.haml
@@ -9,7 +9,7 @@
autocomplete: 'off', class: 'form-control pad qa-issuable-form-title', placeholder: _('Title')
- if issuable.respond_to?(:work_in_progress?)
- %p.form-text.text-muted
+ .form-text.text-muted
.js-wip-explanation
%a.js-toggle-wip{ href: '', tabindex: -1 }
Remove the
diff --git a/app/views/shared/labels/_form.html.haml b/app/views/shared/labels/_form.html.haml
index 2bf5efae1e6..335c34a4632 100644
--- a/app/views/shared/labels/_form.html.haml
+++ b/app/views/shared/labels/_form.html.haml
@@ -28,7 +28,7 @@
.form-actions
- if @label.persisted?
- = f.submit 'Save changes', class: 'btn btn-save js-save-button'
+ = f.submit 'Save changes', class: 'btn btn-success js-save-button'
- else
- = f.submit 'Create label', class: 'btn btn-create js-save-button'
+ = f.submit 'Create label', class: 'btn btn-success js-save-button'
= link_to 'Cancel', back_path, class: 'btn btn-cancel'
diff --git a/app/views/shared/members/_member.html.haml b/app/views/shared/members/_member.html.haml
index af29c0fe59e..2682d92fc56 100644
--- a/app/views/shared/members/_member.html.haml
+++ b/app/views/shared/members/_member.html.haml
@@ -22,7 +22,7 @@
%strong Blocked
- if user.two_factor_enabled?
- %label.label.label-info
+ %label.badge.badge-info
2FA
- if source.instance_of?(Group) && source != @group
diff --git a/app/views/shared/notes/_comment_button.html.haml b/app/views/shared/notes/_comment_button.html.haml
index ed336df4e9d..0674c822d63 100644
--- a/app/views/shared/notes/_comment_button.html.haml
+++ b/app/views/shared/notes/_comment_button.html.haml
@@ -1,7 +1,7 @@
- noteable_name = @note.noteable.human_class_name
.float-left.btn-group.append-right-10.droplab-dropdown.comment-type-dropdown.js-comment-type-dropdown
- %input.btn.btn-nr.btn-create.comment-btn.js-comment-button.js-comment-submit-button{ type: 'submit', value: 'Comment' }
+ %input.btn.btn-nr.btn-success.comment-btn.js-comment-button.js-comment-submit-button{ type: 'submit', value: 'Comment' }
- if @note.can_be_discussion_note?
= button_tag type: 'button', class: 'btn btn-nr dropdown-toggle comment-btn js-note-new-discussion js-disable-on-submit', data: { 'dropdown-trigger' => '#resolvable-comment-menu' }, 'aria-label' => 'Open comment type dropdown' do
diff --git a/app/views/shared/notes/_edit_form.html.haml b/app/views/shared/notes/_edit_form.html.haml
index 71a5b94e958..fec966069b9 100644
--- a/app/views/shared/notes/_edit_form.html.haml
+++ b/app/views/shared/notes/_edit_form.html.haml
@@ -9,6 +9,6 @@
.note-form-actions.clearfix
.settings-message.note-edit-warning.js-finish-edit-warning
Finish editing this message first!
- = submit_tag 'Save comment', class: 'btn btn-nr btn-save js-comment-save-button'
+ = submit_tag 'Save comment', class: 'btn btn-nr btn-success js-comment-save-button'
%button.btn.btn-nr.btn-cancel.note-edit-cancel{ type: 'button' }
Cancel
diff --git a/app/views/shared/runners/_form.html.haml b/app/views/shared/runners/_form.html.haml
index fa93307be31..daf08d9bb2c 100644
--- a/app/views/shared/runners/_form.html.haml
+++ b/app/views/shared/runners/_form.html.haml
@@ -51,6 +51,6 @@
= _('Tags')
.col-sm-10
= f.text_field :tag_list, value: runner.tag_list.sort.join(', '), class: 'form-control'
- .form-text.text-muted= _('You can setup jobs to only use Runners with specific tags. Separate tags with commas.')
+ .form-text.text-muted= _('You can set up jobs to only use Runners with specific tags. Separate tags with commas.')
.form-actions
= f.submit _('Save changes'), class: 'btn btn-success'
diff --git a/app/views/shared/runners/_runner_description.html.haml b/app/views/shared/runners/_runner_description.html.haml
index da5c032add5..5935750ca06 100644
--- a/app/views/shared/runners/_runner_description.html.haml
+++ b/app/views/shared/runners/_runner_description.html.haml
@@ -1,6 +1,6 @@
.light.prepend-top-default
%p
- = _("A 'Runner' is a process which runs a job. You can setup as many Runners as you need.")
+ = _("A 'Runner' is a process which runs a job. You can set up as many Runners as you need.")
%br
= _('Runners can be placed on separate users, servers, and even on your local machine.')
diff --git a/app/views/shared/snippets/_form.html.haml b/app/views/shared/snippets/_form.html.haml
index 5e5c050d5c3..1b66d3acd40 100644
--- a/app/views/shared/snippets/_form.html.haml
+++ b/app/views/shared/snippets/_form.html.haml
@@ -32,9 +32,9 @@
.form-actions
- if @snippet.new_record?
- = f.submit 'Create snippet', class: "btn-create btn"
+ = f.submit 'Create snippet', class: "btn-success btn"
- else
- = f.submit 'Save changes', class: "btn-save btn"
+ = f.submit 'Save changes', class: "btn-success btn"
- if @snippet.project_id
= link_to "Cancel", project_snippets_path(@project), class: "btn btn-cancel"
diff --git a/app/views/snippets/_actions.html.haml b/app/views/snippets/_actions.html.haml
index ae69d0d07c7..0ce13ee7a53 100644
--- a/app/views/snippets/_actions.html.haml
+++ b/app/views/snippets/_actions.html.haml
@@ -7,7 +7,7 @@
- if can?(current_user, :admin_personal_snippet, @snippet)
= link_to snippet_path(@snippet), method: :delete, data: { confirm: "Are you sure?" }, class: "btn btn-grouped btn-inverted btn-remove", title: 'Delete Snippet' do
Delete
- = link_to new_snippet_path, class: "btn btn-grouped btn-inverted btn-create", title: "New snippet" do
+ = link_to new_snippet_path, class: "btn btn-grouped btn-inverted btn-success", title: "New snippet" do
New snippet
- if @snippet.submittable_as_spam_by?(current_user)
= link_to 'Submit as spam', mark_as_spam_snippet_path(@snippet), method: :post, class: 'btn btn-grouped btn-spam', title: 'Submit as spam'
diff --git a/app/views/snippets/new.html.haml b/app/views/snippets/new.html.haml
index f01915107e3..c8a5e199674 100644
--- a/app/views/snippets/new.html.haml
+++ b/app/views/snippets/new.html.haml
@@ -1,5 +1,6 @@
- @hide_top_links = true
-- breadcrumb_title "Snippets"
+- add_to_breadcrumbs "Snippets", dashboard_snippets_path
+- breadcrumb_title "New"
- page_title "New Snippet"
%h3.page-title
New Snippet
diff --git a/app/views/u2f/_register.html.haml b/app/views/u2f/_register.html.haml
index cc0e93c0755..39d4d82a77d 100644
--- a/app/views/u2f/_register.html.haml
+++ b/app/views/u2f/_register.html.haml
@@ -8,13 +8,13 @@
- if current_user.two_factor_otp_enabled?
.row.append-bottom-10
.col-md-4
- %button#js-setup-u2f-device.btn.btn-info.btn-block Setup new U2F device
+ %button#js-setup-u2f-device.btn.btn-info.btn-block Set up new U2F device
.col-md-8
%p Your U2F device needs to be set up. Plug it in (if not already) and click the button on the left.
- else
.row.append-bottom-10
.col-md-4
- %button#js-setup-u2f-device.btn.btn-info.btn-block{ disabled: true } Setup new U2F device
+ %button#js-setup-u2f-device.btn.btn-info.btn-block{ disabled: true } Set up new U2F device
.col-md-8
%p.text-warning You need to register a two-factor authentication app before you can set up a U2F device.
diff --git a/app/workers/expire_build_instance_artifacts_worker.rb b/app/workers/expire_build_instance_artifacts_worker.rb
index 4fcd1e5bd24..94426dcf921 100644
--- a/app/workers/expire_build_instance_artifacts_worker.rb
+++ b/app/workers/expire_build_instance_artifacts_worker.rb
@@ -13,7 +13,7 @@ class ExpireBuildInstanceArtifactsWorker
return unless build&.project && !build.project.pending_delete
Rails.logger.info "Removing artifacts for build #{build.id}..."
- build.erase_artifacts!
+ build.erase_erasable_artifacts!
end
# rubocop: enable CodeReuse/ActiveRecord
end
diff --git a/app/workers/new_merge_request_worker.rb b/app/workers/new_merge_request_worker.rb
index 62f9d9b6f57..fa48c1b29a8 100644
--- a/app/workers/new_merge_request_worker.rb
+++ b/app/workers/new_merge_request_worker.rb
@@ -10,7 +10,7 @@ class NewMergeRequestWorker
EventCreateService.new.open_mr(issuable, user)
NotificationService.new.new_merge_request(issuable, user)
- issuable.diffs.write_cache
+ issuable.diffs(include_stats: false).write_cache
issuable.create_cross_references!(user)
end
diff --git a/bin/pkgr_before_precompile.sh b/bin/pkgr_before_precompile.sh
index 5a2007f4ab0..54ff32c711b 100755
--- a/bin/pkgr_before_precompile.sh
+++ b/bin/pkgr_before_precompile.sh
@@ -6,7 +6,7 @@ for file in config/*.yml.example; do
cp ${file} config/$(basename ${file} .example)
done
-# Allow to override the Gitlab URL from an environment variable, as this will avoid having to change the configuration file for simple deployments.
+# Allow to override the GitLab URL from an environment variable, as this will avoid having to change the configuration file for simple deployments.
config=$(echo '<% gitlab_url = URI(ENV["GITLAB_URL"] || "http://localhost:80") %>' | cat - config/gitlab.yml)
echo "$config" > config/gitlab.yml
sed -i "s/host: localhost/host: <%= gitlab_url.host %>/" config/gitlab.yml
diff --git a/bin/setup b/bin/setup
index c60c1267e06..ec1ebe02950 100755
--- a/bin/setup
+++ b/bin/setup
@@ -16,7 +16,7 @@ if rails5?
end
Dir.chdir APP_ROOT do
- # This script is a starting point to setup your application.
+ # This script is a starting point to set up your application.
# Add necessary setup steps to this file:
puts "== Installing dependencies =="
diff --git a/changelogs/archive.md b/changelogs/archive.md
index fe461a6ac5e..b57440f7dc6 100644
--- a/changelogs/archive.md
+++ b/changelogs/archive.md
@@ -739,7 +739,7 @@
- Update duration at the end of pipeline
- ExpireBuildArtifactsWorker query builds table without ordering enqueuing one job per build to cleanup
- Add group level labels. (!6425)
-- Add an example for testing a phoenix application with Gitlab CI in the docs (Manthan Mallikarjun)
+- Add an example for testing a phoenix application with GitLab CI in the docs (Manthan Mallikarjun)
- Cancelled pipelines could be retried. !6927
- Updating verbiage on git basics to be more intuitive
- Fix project_feature record not generated on project creation
@@ -768,7 +768,7 @@
- Log LDAP lookup errors and don't swallow unrelated exceptions. !6103 (Markus Koller)
- Replace unique keyframes mixin with keyframe mixin with specific names (ClemMakesApps)
- Add more tests for calendar contribution (ClemMakesApps)
-- Update Gitlab Shell to fix some problems with moving projects between storages
+- Update GitLab Shell to fix some problems with moving projects between storages
- Cache rendered markdown in the database, rather than Redis
- Add todo toggle event (ClemMakesApps)
- Avoid database queries on Banzai::ReferenceParser::BaseParser for nodes without references
@@ -815,7 +815,7 @@
- Replace static issue fixtures by script !6059 (winniehell)
- Append issue template to existing description !6149 (Joseph Frazier)
- Trending projects now only show public projects and the list of projects is cached for a day
-- Memoize Gitlab Shell's secret token (!6599, Justin DiPierro)
+- Memoize GitLab Shell's secret token (!6599, Justin DiPierro)
- Revoke button in Applications Settings underlines on hover.
- Use higher size on Gitlab::Redis connection pool on Sidekiq servers
- Add missing values to linter !6276 (Katarzyna Kobierska Ula Budziszewska)
@@ -930,7 +930,7 @@
## 8.12.3
- - Update Gitlab Shell to support low IO priority for storage moves
+ - Update GitLab Shell to support low IO priority for storage moves
## 8.12.2
@@ -1001,7 +1001,7 @@
- Added ability to specify URL in environment configuration in gitlab-ci.yml
- Escape search term before passing it to Regexp.new !6241 (winniehell)
- Fix pinned sidebar behavior in smaller viewports !6169
- - Fix file permissions change when updating a file on the Gitlab UI !5979
+ - Fix file permissions change when updating a file on the GitLab UI !5979
- Added horizontal padding on build page sidebar on code coverage block. !6196 (Vitaly Baev)
- Change merge_error column from string to text type
- Fix issue with search filter labels not displaying
@@ -1688,7 +1688,7 @@
- Fix commit avatar alignment in compare view. !5128
- Fix broken migration in MySQL. !5005
- Overwrite Host and X-Forwarded-Host headers in NGINX !5213
- - Keeps issue number when importing from Gitlab.com
+ - Keeps issue number when importing from GitLab.com
- Add Pending tab for Builds (Katarzyna Kobierska, Urszula Budziszewska)
## 8.9.5
@@ -4786,7 +4786,7 @@
## 3.1.0
- Updated gems
-- Services: Gitlab CI integration
+- Services: GitLab CI integration
- Events filter on dashboard
- Own namespace for redis/resque
- Optimized commit diff views
@@ -4869,7 +4869,7 @@
## 2.8.0
-- Gitlab Flavored Markdown
+- GitLab Flavored Markdown
- Bulk issues update
- Issues API
- Cucumber coverage increased
diff --git a/changelogs/unreleased/#47282-Improving-Contributor-On-Boarding-Documentation.yml b/changelogs/unreleased/#47282-Improving-Contributor-On-Boarding-Documentation.yml
deleted file mode 100644
index f7521ff9225..00000000000
--- a/changelogs/unreleased/#47282-Improving-Contributor-On-Boarding-Documentation.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-title: First Improvements made to the contributor on-boarding experience.
-merge_request: 20682
-author: Eddie Stubbington
-type: added
diff --git a/changelogs/unreleased/-48445-Issue-card-in-board-view-is-too-sensitive-to-drag-event.yml b/changelogs/unreleased/-48445-Issue-card-in-board-view-is-too-sensitive-to-drag-event.yml
new file mode 100644
index 00000000000..27c70318b92
--- /dev/null
+++ b/changelogs/unreleased/-48445-Issue-card-in-board-view-is-too-sensitive-to-drag-event.yml
@@ -0,0 +1,5 @@
+---
+title: Fix link handling for issue cards to avoid too sensitive drag events.
+merge_request: 21910
+author: Johann Hubert Sonntagbauer
+type: fixed
diff --git a/changelogs/unreleased/1801-allow-event_filter-to-be-set-in-the-url.yml b/changelogs/unreleased/1801-allow-event_filter-to-be-set-in-the-url.yml
new file mode 100644
index 00000000000..4ceaa7e3139
--- /dev/null
+++ b/changelogs/unreleased/1801-allow-event_filter-to-be-set-in-the-url.yml
@@ -0,0 +1,5 @@
+---
+title: "Allow events filter to be set in the URL in addition to cookie"
+merge_request: 21557
+author: Igor @igas
+type: added
diff --git a/changelogs/unreleased/21305-breadcrumb-link-to-issues-on-new-issue-page.yml b/changelogs/unreleased/21305-breadcrumb-link-to-issues-on-new-issue-page.yml
deleted file mode 100644
index 8e8c3cf53b4..00000000000
--- a/changelogs/unreleased/21305-breadcrumb-link-to-issues-on-new-issue-page.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: "Fix breadcrumb link to issues on new issue page"
-merge_request: 21305
-author: J.D. Bean
-type: fixed
diff --git a/changelogs/unreleased/21307-send-deployment-information-in-job-api.yml b/changelogs/unreleased/21307-send-deployment-information-in-job-api.yml
new file mode 100644
index 00000000000..8f9e24428be
--- /dev/null
+++ b/changelogs/unreleased/21307-send-deployment-information-in-job-api.yml
@@ -0,0 +1,5 @@
+---
+title: Send deployment information in job API
+merge_request: 21307
+author:
+type: other
diff --git a/changelogs/unreleased/21326-avoid-nil-safe-message.yml b/changelogs/unreleased/21326-avoid-nil-safe-message.yml
deleted file mode 100644
index ca1a89191a8..00000000000
--- a/changelogs/unreleased/21326-avoid-nil-safe-message.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: "Avoid nil safe message"
-merge_request: 21326
-author: Yi Siliang
-type: fixed
diff --git a/changelogs/unreleased/21371-avatar-fix.yml b/changelogs/unreleased/21371-avatar-fix.yml
deleted file mode 100644
index 6e00a4ba360..00000000000
--- a/changelogs/unreleased/21371-avatar-fix.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: "Vertically centres landscape avatars."
-merge_request: 21371
-author: Vicary Archangel
-type: fixed
diff --git a/changelogs/unreleased/24128-fix-comment-unresolve-discussions.yml b/changelogs/unreleased/24128-fix-comment-unresolve-discussions.yml
new file mode 100644
index 00000000000..d835d25f39b
--- /dev/null
+++ b/changelogs/unreleased/24128-fix-comment-unresolve-discussions.yml
@@ -0,0 +1,5 @@
+---
+title: Fix resolved discussions being unresolved when commented on
+merge_request: 21881
+author:
+type: fixed
diff --git a/changelogs/unreleased/25990-web-terminal-improvements.yml b/changelogs/unreleased/25990-web-terminal-improvements.yml
deleted file mode 100644
index 99a4a82ea66..00000000000
--- a/changelogs/unreleased/25990-web-terminal-improvements.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Make terminal button more visible
-merge_request:
-author:
-type: changed
diff --git a/changelogs/unreleased/2747-protected-environments-backend-ce.yml b/changelogs/unreleased/2747-protected-environments-backend-ce.yml
deleted file mode 100644
index dcec74a33a7..00000000000
--- a/changelogs/unreleased/2747-protected-environments-backend-ce.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: CE Port of Protected Environments backend
-merge_request: 20859
-author:
-type: other
diff --git a/changelogs/unreleased/28930-add-project-reference-filter.yml b/changelogs/unreleased/28930-add-project-reference-filter.yml
deleted file mode 100644
index c7679c5fe76..00000000000
--- a/changelogs/unreleased/28930-add-project-reference-filter.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Add the ability to reference projects in comments and other markdown text.
-merge_request: 20285
-author: Reuben Pereira
-type: added
diff --git a/changelogs/unreleased/2934-create-new-project-re-add-project-name-field.yml b/changelogs/unreleased/2934-create-new-project-re-add-project-name-field.yml
deleted file mode 100644
index ad9136b69c2..00000000000
--- a/changelogs/unreleased/2934-create-new-project-re-add-project-name-field.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Re-add project name field on "Create new project" page
-merge_request: 21386
-author:
-type: other
diff --git a/changelogs/unreleased/29398-support-kubernetes-rbac-for-gitlab-managed-apps.yml b/changelogs/unreleased/29398-support-kubernetes-rbac-for-gitlab-managed-apps.yml
deleted file mode 100644
index c182946b299..00000000000
--- a/changelogs/unreleased/29398-support-kubernetes-rbac-for-gitlab-managed-apps.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Support Kubernetes RBAC for GitLab Managed Apps when adding a existing cluster
-merge_request: 21127
-author:
-type: changed
diff --git a/changelogs/unreleased/29398-support-rbac-for-gitlab-provisioned-clusters.yml b/changelogs/unreleased/29398-support-rbac-for-gitlab-provisioned-clusters.yml
new file mode 100644
index 00000000000..973dcd0496a
--- /dev/null
+++ b/changelogs/unreleased/29398-support-rbac-for-gitlab-provisioned-clusters.yml
@@ -0,0 +1,5 @@
+---
+title: Support Kubernetes RBAC for GitLab Managed Apps when creating new clusters
+merge_request: 21401
+author:
+type: changed
diff --git a/changelogs/unreleased/36048-move-default-branch-settings-under-repository.yml b/changelogs/unreleased/36048-move-default-branch-settings-under-repository.yml
deleted file mode 100644
index c5788a40dba..00000000000
--- a/changelogs/unreleased/36048-move-default-branch-settings-under-repository.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Move project settings for default branch under "Repository"
-merge_request: 21380
-author:
-type: changed
diff --git a/changelogs/unreleased/36534-show-commit-behind-mr-api.yml b/changelogs/unreleased/36534-show-commit-behind-mr-api.yml
deleted file mode 100644
index 06471146fa3..00000000000
--- a/changelogs/unreleased/36534-show-commit-behind-mr-api.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Adds diverged_commits_count field to GET api/v4/projects/:project_id/merge_requests/:merge_request_iid
-merge_request: 21405
-author: Jacopo Beschi @jacopo-beschi
-type: added
diff --git a/changelogs/unreleased/37356-relative-submodule-link.yml b/changelogs/unreleased/37356-relative-submodule-link.yml
deleted file mode 100644
index 99d1577609d..00000000000
--- a/changelogs/unreleased/37356-relative-submodule-link.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fix git submodule link for subgroup projects with relative path
-merge_request: 21154
-author:
-type: fixed
diff --git a/changelogs/unreleased/37433-solve-n-1-in-refs-controller-logs-tree.yml b/changelogs/unreleased/37433-solve-n-1-in-refs-controller-logs-tree.yml
new file mode 100644
index 00000000000..04662a7cfe2
--- /dev/null
+++ b/changelogs/unreleased/37433-solve-n-1-in-refs-controller-logs-tree.yml
@@ -0,0 +1,6 @@
+---
+title: Adds support for Gitaly ListLastCommitsForTree RPC in order to make bulk-fetch
+ of commits more performant
+merge_request: 21921
+author:
+type: performance
diff --git a/changelogs/unreleased/38208-due-dates-system-notes.yml b/changelogs/unreleased/38208-due-dates-system-notes.yml
deleted file mode 100644
index 60e09ff64de..00000000000
--- a/changelogs/unreleased/38208-due-dates-system-notes.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Add system note when due date is changed
-merge_request:
-author: Eva Kadlecova
-type: added
diff --git a/changelogs/unreleased/39665-restrict-issue-reopen.yml b/changelogs/unreleased/39665-restrict-issue-reopen.yml
deleted file mode 100644
index 204baafb700..00000000000
--- a/changelogs/unreleased/39665-restrict-issue-reopen.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Restrict reopening locked issues for non authorized issue authors
-merge_request: 21299
-author:
-type: changed
diff --git a/changelogs/unreleased/39923-automatically-disable-auto-devops-for-project.yml b/changelogs/unreleased/39923-automatically-disable-auto-devops-for-project.yml
deleted file mode 100644
index 76b411e9e8c..00000000000
--- a/changelogs/unreleased/39923-automatically-disable-auto-devops-for-project.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Disable Auto DevOps for project upon first pipeline failure
-merge_request: 21172
-author:
-type: added
diff --git a/changelogs/unreleased/41040-long-webhook-url-problem.yml b/changelogs/unreleased/41040-long-webhook-url-problem.yml
new file mode 100644
index 00000000000..4057e1ff325
--- /dev/null
+++ b/changelogs/unreleased/41040-long-webhook-url-problem.yml
@@ -0,0 +1,5 @@
+---
+title: Fix long webhook URL overflow for custom integration.
+merge_request:
+author: Kukovskii Vladimir
+type: fixed
diff --git a/changelogs/unreleased/41292-users-stuck-on-a-redirect-loop-after-transferring-project.yml b/changelogs/unreleased/41292-users-stuck-on-a-redirect-loop-after-transferring-project.yml
deleted file mode 100644
index 830c02510f2..00000000000
--- a/changelogs/unreleased/41292-users-stuck-on-a-redirect-loop-after-transferring-project.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fix project transfer name validation issues causing a redirect loop
-merge_request: 21408
-author:
-type: fixed
diff --git a/changelogs/unreleased/41441-add-target-branch-name-to-cherrypick-confirmation.yml b/changelogs/unreleased/41441-add-target-branch-name-to-cherrypick-confirmation.yml
deleted file mode 100644
index c23676a3104..00000000000
--- a/changelogs/unreleased/41441-add-target-branch-name-to-cherrypick-confirmation.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Add target branch name to cherrypick confirmation message
-merge_request: 20846
-author: George Andrinopoulos
-type: other
diff --git a/changelogs/unreleased/41738-fix-sorting-issues-is-wrong-in-list-with-pagination.yml b/changelogs/unreleased/41738-fix-sorting-issues-is-wrong-in-list-with-pagination.yml
deleted file mode 100644
index bc0150c6586..00000000000
--- a/changelogs/unreleased/41738-fix-sorting-issues-is-wrong-in-list-with-pagination.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: "Fix If-Check the result that a function was executed several times"
-merge_request: 20640
-author: Max Dicker
-type: fixed
diff --git a/changelogs/unreleased/41996-copy-to-clipboard-tooltip-appears-under-modal.yml b/changelogs/unreleased/41996-copy-to-clipboard-tooltip-appears-under-modal.yml
deleted file mode 100644
index e452a91d8b7..00000000000
--- a/changelogs/unreleased/41996-copy-to-clipboard-tooltip-appears-under-modal.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Solve tooltip appears under modal
-merge_request: 21017
-author:
-type: fixed
diff --git a/changelogs/unreleased/42754-runners-pagination.yml b/changelogs/unreleased/42754-runners-pagination.yml
deleted file mode 100644
index 8e77b857538..00000000000
--- a/changelogs/unreleased/42754-runners-pagination.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Does not collapse runners section when using pagination
-merge_request:
-author:
-type: fixed
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
deleted file mode 100644
index f4744c868ef..00000000000
--- a/changelogs/unreleased/43096-controller-projects-issuescontroller-referenced_merge_requests-json-executes-more-than-100-sql-queries.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Improve performance when fetching related merge requests for an issue
-merge_request: 21237
-author:
-type: performance
diff --git a/changelogs/unreleased/43140-reduce-logs-tree-load.yml b/changelogs/unreleased/43140-reduce-logs-tree-load.yml
deleted file mode 100644
index 5b0f1996bb3..00000000000
--- a/changelogs/unreleased/43140-reduce-logs-tree-load.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Bulk-render commit titles in the tree view to improve performance
-merge_request: 21500
-author:
-type: performance
diff --git a/changelogs/unreleased/43625-increase-modal-checkout.yml b/changelogs/unreleased/43625-increase-modal-checkout.yml
deleted file mode 100644
index 877550924c1..00000000000
--- a/changelogs/unreleased/43625-increase-modal-checkout.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Increase width of checkout branch modal box
-merge_request:
-author:
-type: fixed
diff --git a/changelogs/unreleased/43832-adds-chdmod-to-commits-actions-api.yml b/changelogs/unreleased/43832-adds-chdmod-to-commits-actions-api.yml
new file mode 100644
index 00000000000..cea1436ae8b
--- /dev/null
+++ b/changelogs/unreleased/43832-adds-chdmod-to-commits-actions-api.yml
@@ -0,0 +1,5 @@
+---
+title: Allows to chmod file with commits API
+merge_request: 21866
+author: Jacopo Beschi @jacopo-beschi
+type: added
diff --git a/changelogs/unreleased/44005-improve-handling-of-projects-shared-with-a-group.yml b/changelogs/unreleased/44005-improve-handling-of-projects-shared-with-a-group.yml
deleted file mode 100644
index a828ee36eb4..00000000000
--- a/changelogs/unreleased/44005-improve-handling-of-projects-shared-with-a-group.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Overhaul listing of projects in the group overview page
-merge_request: 20262
-author:
-type: added
diff --git a/changelogs/unreleased/44596-double-title-merge-request-message.yml b/changelogs/unreleased/44596-double-title-merge-request-message.yml
new file mode 100644
index 00000000000..714d16977fb
--- /dev/null
+++ b/changelogs/unreleased/44596-double-title-merge-request-message.yml
@@ -0,0 +1,5 @@
+---
+title: Fix double title in merge request chat messages.
+merge_request: 21670
+author: Kukovskii Vladimir
+type: fixed
diff --git a/changelogs/unreleased/44704-improve-project-overview-ui.yml b/changelogs/unreleased/44704-improve-project-overview-ui.yml
deleted file mode 100644
index 6fb8359f2dc..00000000000
--- a/changelogs/unreleased/44704-improve-project-overview-ui.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Update design of project overview page
-merge_request: 20536
-author:
-type: changed
diff --git a/changelogs/unreleased/44768-lazy-load-xterm-css.yml b/changelogs/unreleased/44768-lazy-load-xterm-css.yml
new file mode 100644
index 00000000000..85f7b1984e0
--- /dev/null
+++ b/changelogs/unreleased/44768-lazy-load-xterm-css.yml
@@ -0,0 +1,5 @@
+---
+title: Lazy load xterm custom colors css
+merge_request:
+author:
+type: performance
diff --git a/changelogs/unreleased/44943-update-presentation-for-sso-providers-on-log-in-page.yml b/changelogs/unreleased/44943-update-presentation-for-sso-providers-on-log-in-page.yml
deleted file mode 100644
index a378aaec750..00000000000
--- a/changelogs/unreleased/44943-update-presentation-for-sso-providers-on-log-in-page.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Update presentation for SSO providers on log in page
-merge_request: 21233
-author:
-type: other
diff --git a/changelogs/unreleased/44998-split-admin-settings-into-multiple-sub-pages.yml b/changelogs/unreleased/44998-split-admin-settings-into-multiple-sub-pages.yml
new file mode 100644
index 00000000000..4b398e9419d
--- /dev/null
+++ b/changelogs/unreleased/44998-split-admin-settings-into-multiple-sub-pages.yml
@@ -0,0 +1,5 @@
+---
+title: Split admin settings into multiple sub pages
+merge_request: 21467
+author:
+type: other
diff --git a/changelogs/unreleased/45663-tag-quick-action-on-commit-comments.yml b/changelogs/unreleased/45663-tag-quick-action-on-commit-comments.yml
deleted file mode 100644
index 6d664511e6e..00000000000
--- a/changelogs/unreleased/45663-tag-quick-action-on-commit-comments.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: "`/tag` quick action on Commit comments"
-merge_request: 20694
-author: Peter Leitzen
-type: added
diff --git a/changelogs/unreleased/45754-issue-mr-and-archived-projects.yml b/changelogs/unreleased/45754-issue-mr-and-archived-projects.yml
new file mode 100644
index 00000000000..d81f47d9654
--- /dev/null
+++ b/changelogs/unreleased/45754-issue-mr-and-archived-projects.yml
@@ -0,0 +1,5 @@
+---
+title: Issue and MR count now ignores archived projects
+merge_request: 21721
+author:
+type: fixed
diff --git a/changelogs/unreleased/45754-open-issues-from-archived-project-listed-in-group-issue-board.yml b/changelogs/unreleased/45754-open-issues-from-archived-project-listed-in-group-issue-board.yml
new file mode 100644
index 00000000000..34394396020
--- /dev/null
+++ b/changelogs/unreleased/45754-open-issues-from-archived-project-listed-in-group-issue-board.yml
@@ -0,0 +1,5 @@
+---
+title: No longer show open issues from archived projects in group issue board
+merge_request: 21721
+author:
+type: fixed
diff --git a/changelogs/unreleased/45938-postgres-timeout-when-counting-number-of-ci-builds-for-usage-ping.yml b/changelogs/unreleased/45938-postgres-timeout-when-counting-number-of-ci-builds-for-usage-ping.yml
deleted file mode 100644
index f3016a639d9..00000000000
--- a/changelogs/unreleased/45938-postgres-timeout-when-counting-number-of-ci-builds-for-usage-ping.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Handle database statement timeouts in usage ping
-merge_request: 21523
-author:
-type: fixed
diff --git a/changelogs/unreleased/46340-remove-extra-spaces-from-mr-discussion-notes.yml b/changelogs/unreleased/46340-remove-extra-spaces-from-mr-discussion-notes.yml
deleted file mode 100644
index b93d2378d85..00000000000
--- a/changelogs/unreleased/46340-remove-extra-spaces-from-mr-discussion-notes.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Remove extra spaces from MR discussion notes
-merge_request: 18946
-author: Takuya Noguchi
-type: other
diff --git a/changelogs/unreleased/46591-fix-ide-height-issues.yml b/changelogs/unreleased/46591-fix-ide-height-issues.yml
deleted file mode 100644
index d161bda6ab1..00000000000
--- a/changelogs/unreleased/46591-fix-ide-height-issues.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fix IDE issues with persistent banners
-merge_request: 21283
-author:
-type: fixed
diff --git a/changelogs/unreleased/46733-move-filter-dropdown-from-font-awesome-to-our-own-icons.yml b/changelogs/unreleased/46733-move-filter-dropdown-from-font-awesome-to-our-own-icons.yml
new file mode 100644
index 00000000000..07549781330
--- /dev/null
+++ b/changelogs/unreleased/46733-move-filter-dropdown-from-font-awesome-to-our-own-icons.yml
@@ -0,0 +1,5 @@
+---
+title: Updated icons used in filtered search dropdowns
+merge_request: 21694
+author:
+type: changed
diff --git a/changelogs/unreleased/47398-user-is-unable-revoke-a-authorized-application-unless-user-oauth-applications-is-checked-in-admin-settings.yml b/changelogs/unreleased/47398-user-is-unable-revoke-a-authorized-application-unless-user-oauth-applications-is-checked-in-admin-settings.yml
new file mode 100644
index 00000000000..e0dc26301d4
--- /dev/null
+++ b/changelogs/unreleased/47398-user-is-unable-revoke-a-authorized-application-unless-user-oauth-applications-is-checked-in-admin-settings.yml
@@ -0,0 +1,6 @@
+---
+title: Allow user to revoke an authorized application even if User OAuth applications
+ setting is disabled in admin settings
+merge_request: 21835
+author:
+type: changed
diff --git a/changelogs/unreleased/47440-recognize-unlicense-license-file.yml b/changelogs/unreleased/47440-recognize-unlicense-license-file.yml
deleted file mode 100644
index 3521dd613b0..00000000000
--- a/changelogs/unreleased/47440-recognize-unlicense-license-file.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Recognize 'UNLICENSE' license files
-merge_request: 21508
-author: J.D. Bean
-type: added
diff --git a/changelogs/unreleased/47752-buttons-on-new-file-page-wrap-outside-of-container-for-long-branch-names.yml b/changelogs/unreleased/47752-buttons-on-new-file-page-wrap-outside-of-container-for-long-branch-names.yml
deleted file mode 100644
index 81ca632947d..00000000000
--- a/changelogs/unreleased/47752-buttons-on-new-file-page-wrap-outside-of-container-for-long-branch-names.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fix buttons on the new file page wrapping outside of the container
-merge_request: 21015
-author:
-type: fixed
diff --git a/changelogs/unreleased/47765-group-visibility-error-due-to-string-conversion.yml b/changelogs/unreleased/47765-group-visibility-error-due-to-string-conversion.yml
deleted file mode 100644
index ad09527b329..00000000000
--- a/changelogs/unreleased/47765-group-visibility-error-due-to-string-conversion.yml
+++ /dev/null
@@ -1,6 +0,0 @@
----
-title: Importing a project no longer fails when visibility level holds a string value
- type
-merge_request: 21242
-author:
-type: fixed
diff --git a/changelogs/unreleased/47845-propagate_failure_reason-to-job-webhook.yml b/changelogs/unreleased/47845-propagate_failure_reason-to-job-webhook.yml
deleted file mode 100644
index 3f85f75bef4..00000000000
--- a/changelogs/unreleased/47845-propagate_failure_reason-to-job-webhook.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: "#47845 Add failure_reason to job webhook"
-merge_request: 21143
-author: matemaciek
-type: added
diff --git a/changelogs/unreleased/47943-project-milestone-page-deprecation-message.yml b/changelogs/unreleased/47943-project-milestone-page-deprecation-message.yml
deleted file mode 100644
index b9f68e1c46c..00000000000
--- a/changelogs/unreleased/47943-project-milestone-page-deprecation-message.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Show deprecation message on project milestone page for category tabs
-merge_request: 21236
-author:
-type: changed
diff --git a/changelogs/unreleased/48145-illustration.yml b/changelogs/unreleased/48145-illustration.yml
deleted file mode 100644
index 7d84075c2b3..00000000000
--- a/changelogs/unreleased/48145-illustration.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fixes SVGs for empty states in job page overflowing on mobile
-merge_request:
-author:
-type: fixed
diff --git a/changelogs/unreleased/48167-fix-outdated-discussions-new-datastructure.yml b/changelogs/unreleased/48167-fix-outdated-discussions-new-datastructure.yml
deleted file mode 100644
index a8fcce2eeb8..00000000000
--- a/changelogs/unreleased/48167-fix-outdated-discussions-new-datastructure.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fix outdated discussions being shown on Merge Request Changes tab
-merge_request: 21543
-author:
-type: fixed
diff --git a/changelogs/unreleased/48320-cancel-a-created-job.yml b/changelogs/unreleased/48320-cancel-a-created-job.yml
deleted file mode 100644
index 3e7a9e9ae52..00000000000
--- a/changelogs/unreleased/48320-cancel-a-created-job.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Allows to cancel a Created job
-merge_request: 20635
-author: Jacopo Beschi @jacopo-beschi
-type: added
diff --git a/changelogs/unreleased/48399-skip-auto-devops-jobs-based-on-license.yml b/changelogs/unreleased/48399-skip-auto-devops-jobs-based-on-license.yml
new file mode 100644
index 00000000000..042731fb9be
--- /dev/null
+++ b/changelogs/unreleased/48399-skip-auto-devops-jobs-based-on-license.yml
@@ -0,0 +1,6 @@
+---
+title: Skip creating auto devops jobs for sast, container_scanning, dast, dependency_scanning
+ when not licensed
+merge_request: 21959
+author:
+type: performance
diff --git a/changelogs/unreleased/48778-remove-old-storage-logic-from-import-export.yml b/changelogs/unreleased/48778-remove-old-storage-logic-from-import-export.yml
deleted file mode 100644
index 4ddbc118e86..00000000000
--- a/changelogs/unreleased/48778-remove-old-storage-logic-from-import-export.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Update Import/Export to only use new storage uploaders logic
-merge_request: 21409
-author:
-type: added
diff --git a/changelogs/unreleased/48869-wiki-slugs-with-spaces.yml b/changelogs/unreleased/48869-wiki-slugs-with-spaces.yml
deleted file mode 100644
index 88ba8028e2c..00000000000
--- a/changelogs/unreleased/48869-wiki-slugs-with-spaces.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Allow spaces in wiki markdown links when using CommonMark
-merge_request: 20417
-author:
-type: fixed
diff --git a/changelogs/unreleased/48942-rename-backlog-list-to-open-issue-boards.yml b/changelogs/unreleased/48942-rename-backlog-list-to-open-issue-boards.yml
deleted file mode 100644
index 26851fc2dec..00000000000
--- a/changelogs/unreleased/48942-rename-backlog-list-to-open-issue-boards.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Change 'Backlog' list title to 'Open' in Issue Boards
-merge_request: 21131
-author:
-type: changed
diff --git a/changelogs/unreleased/48967-disable-statement-timeout.yml b/changelogs/unreleased/48967-disable-statement-timeout.yml
deleted file mode 100644
index 2da800ed41e..00000000000
--- a/changelogs/unreleased/48967-disable-statement-timeout.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: disable_statement_timeout no longer leak to other migrations
-merge_request: 20503
-author:
-type: fixed
diff --git a/changelogs/unreleased/4907-improve-build-create-performance-for-license-management.yml b/changelogs/unreleased/4907-improve-build-create-performance-for-license-management.yml
new file mode 100644
index 00000000000..e82bda6819f
--- /dev/null
+++ b/changelogs/unreleased/4907-improve-build-create-performance-for-license-management.yml
@@ -0,0 +1,5 @@
+---
+title: Dont create license_management build when not included in license
+merge_request: 21958
+author:
+type: performance
diff --git a/changelogs/unreleased/49110-update-mr-widget-styles.yml b/changelogs/unreleased/49110-update-mr-widget-styles.yml
deleted file mode 100644
index e54866a0908..00000000000
--- a/changelogs/unreleased/49110-update-mr-widget-styles.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-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
deleted file mode 100644
index 69089cfe357..00000000000
--- a/changelogs/unreleased/49292-add-group-name-badge-under-milestone.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Add group name badge under group milestone
-merge_request: 21384
-author:
-type: added
diff --git a/changelogs/unreleased/49329-mr-show-commit-details.yml b/changelogs/unreleased/49329-mr-show-commit-details.yml
new file mode 100644
index 00000000000..23cfc0c675e
--- /dev/null
+++ b/changelogs/unreleased/49329-mr-show-commit-details.yml
@@ -0,0 +1,5 @@
+---
+title: Show commit details for selected commit in MR diffs
+merge_request: 21784
+author:
+type: fixed
diff --git a/changelogs/unreleased/49632-clean-up-the-top-section-of-the-cluster-page.yml b/changelogs/unreleased/49632-clean-up-the-top-section-of-the-cluster-page.yml
deleted file mode 100644
index eae5da45524..00000000000
--- a/changelogs/unreleased/49632-clean-up-the-top-section-of-the-cluster-page.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Make cluster page settings easier to read
-merge_request: 21550
-author:
-type: other
diff --git a/changelogs/unreleased/49644-make-margin-of-user-status-emoji-consistent.yml b/changelogs/unreleased/49644-make-margin-of-user-status-emoji-consistent.yml
deleted file mode 100644
index a2ae582fb1c..00000000000
--- a/changelogs/unreleased/49644-make-margin-of-user-status-emoji-consistent.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Make margin of user status emoji consistent
-merge_request: 21268
-author:
-type: other
diff --git a/changelogs/unreleased/49770-fixes-input-alignment-on-user-admin-form-with-errors.yml b/changelogs/unreleased/49770-fixes-input-alignment-on-user-admin-form-with-errors.yml
deleted file mode 100644
index 00e1f6e638a..00000000000
--- a/changelogs/unreleased/49770-fixes-input-alignment-on-user-admin-form-with-errors.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fixes input alignment in user admin form with errors
-merge_request: 21108
-author: Jacopo Beschi @jacopo-beschi
-type: fixed
diff --git a/changelogs/unreleased/49796-project-deletion-may-not-log-audit-events-during-group-deletion.yml b/changelogs/unreleased/49796-project-deletion-may-not-log-audit-events-during-group-deletion.yml
deleted file mode 100644
index bb7633abdb1..00000000000
--- a/changelogs/unreleased/49796-project-deletion-may-not-log-audit-events-during-group-deletion.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: 'Fix: Project deletion may not log audit events during group deletion'
-merge_request: 21162
-author:
-type: fixed
diff --git a/changelogs/unreleased/49796-project-deletion-may-not-log-audit-events-during-user-deletion.yml b/changelogs/unreleased/49796-project-deletion-may-not-log-audit-events-during-user-deletion.yml
deleted file mode 100644
index a8e3d590a4a..00000000000
--- a/changelogs/unreleased/49796-project-deletion-may-not-log-audit-events-during-user-deletion.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: 'Fix: Project deletion may not log audit events during user deletion'
-merge_request:
-author:
-type: fixed
diff --git a/changelogs/unreleased/49905-fix-checkboxes-runners.yml b/changelogs/unreleased/49905-fix-checkboxes-runners.yml
deleted file mode 100644
index af40e5348b8..00000000000
--- a/changelogs/unreleased/49905-fix-checkboxes-runners.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fix checkboxes on runner admin settings - The labels are now clickable
-merge_request:
-author:
-type: fixed
diff --git a/changelogs/unreleased/49953-add-user_show_add_ssh_key_message-setting.yml b/changelogs/unreleased/49953-add-user_show_add_ssh_key_message-setting.yml
deleted file mode 100644
index 82423092792..00000000000
--- a/changelogs/unreleased/49953-add-user_show_add_ssh_key_message-setting.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Add ability to suppress the global "You won't be able to use SSH" message
-merge_request: 21027
-author: Ævar Arnfjörð Bjarmason
-type: added
diff --git a/changelogs/unreleased/49993-fix-remember-sorting-issue-mr.yml b/changelogs/unreleased/49993-fix-remember-sorting-issue-mr.yml
deleted file mode 100644
index df05bf3f3e2..00000000000
--- a/changelogs/unreleased/49993-fix-remember-sorting-issue-mr.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Split remembering sorting for issues and merge requests
-merge_request: 21153
-author: Jacopo Beschi @jacopo-beschi
-type: fixed
diff --git a/changelogs/unreleased/50019-remove-redundant-header-from-metrics-page.yml b/changelogs/unreleased/50019-remove-redundant-header-from-metrics-page.yml
deleted file mode 100644
index 8057819b223..00000000000
--- a/changelogs/unreleased/50019-remove-redundant-header-from-metrics-page.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Remove redundant header from metrics page
-merge_request: 21282
-author:
-type: changed
diff --git a/changelogs/unreleased/50047-spam-logs-pagination.yml b/changelogs/unreleased/50047-spam-logs-pagination.yml
deleted file mode 100644
index ca5f432cd8c..00000000000
--- a/changelogs/unreleased/50047-spam-logs-pagination.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Add gitlab theme to spam logs pagination
-merge_request: 21145
-author:
-type: fixed
diff --git a/changelogs/unreleased/50063-add-missing-i18n-strings-to-issue-boards.yml b/changelogs/unreleased/50063-add-missing-i18n-strings-to-issue-boards.yml
deleted file mode 100644
index ca17a41d611..00000000000
--- a/changelogs/unreleased/50063-add-missing-i18n-strings-to-issue-boards.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Added missing i18n strings to issue boards lables dropdown
-merge_request: 21081
-author:
-type: other
diff --git a/changelogs/unreleased/50101-add-artifact-information-to-job-api.yml b/changelogs/unreleased/50101-add-artifact-information-to-job-api.yml
deleted file mode 100644
index f98d111a337..00000000000
--- a/changelogs/unreleased/50101-add-artifact-information-to-job-api.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Send artifact information in job API
-merge_request: 50460
-author:
-type: other
diff --git a/changelogs/unreleased/50101-aritfacts-block.yml b/changelogs/unreleased/50101-aritfacts-block.yml
deleted file mode 100644
index 435e9d9d486..00000000000
--- a/changelogs/unreleased/50101-aritfacts-block.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Creates Vue component for artifacts block on job page
-merge_request:
-author:
-type: other
diff --git a/changelogs/unreleased/50101-builds-dropdown.yml b/changelogs/unreleased/50101-builds-dropdown.yml
deleted file mode 100644
index 9194b0e0d31..00000000000
--- a/changelogs/unreleased/50101-builds-dropdown.yml
+++ /dev/null
@@ -1,6 +0,0 @@
----
-title: Creates vue components for stage dropdowns and job list container for job log
- view
-merge_request:
-author:
-type: other
diff --git a/changelogs/unreleased/50101-commit-block.yml b/changelogs/unreleased/50101-commit-block.yml
deleted file mode 100644
index f6bad4c8154..00000000000
--- a/changelogs/unreleased/50101-commit-block.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Creates vue component for commit block in job log page
-merge_request:
-author:
-type: other
diff --git a/changelogs/unreleased/50101-empty-state-component.yml b/changelogs/unreleased/50101-empty-state-component.yml
deleted file mode 100644
index ee99b65d964..00000000000
--- a/changelogs/unreleased/50101-empty-state-component.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Creates empty state vue component for job view
-merge_request:
-author:
-type: other
diff --git a/changelogs/unreleased/50101-env-block.yml b/changelogs/unreleased/50101-env-block.yml
deleted file mode 100644
index 11e603e7a79..00000000000
--- a/changelogs/unreleased/50101-env-block.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Creates vue component for environments information in job log view
-merge_request:
-author:
-type: other
diff --git a/changelogs/unreleased/50101-erased-block.yml b/changelogs/unreleased/50101-erased-block.yml
deleted file mode 100644
index 5a5c9bc0fc4..00000000000
--- a/changelogs/unreleased/50101-erased-block.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Creates vue component for erased block on job view
-merge_request:
-author:
-type: other
diff --git a/changelogs/unreleased/50101-job-log-component.yml b/changelogs/unreleased/50101-job-log-component.yml
deleted file mode 100644
index 0759e7cfbd9..00000000000
--- a/changelogs/unreleased/50101-job-log-component.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Creates vue component for job log trace
-merge_request:
-author:
-type: other
diff --git a/changelogs/unreleased/50101-stuck-component.yml b/changelogs/unreleased/50101-stuck-component.yml
deleted file mode 100644
index bfe4009a2b3..00000000000
--- a/changelogs/unreleased/50101-stuck-component.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Creates Vvue component for warning block about stuck runners
-merge_request:
-author:
-type: other
diff --git a/changelogs/unreleased/50101-trigger.yml b/changelogs/unreleased/50101-trigger.yml
deleted file mode 100644
index df4243afa63..00000000000
--- a/changelogs/unreleased/50101-trigger.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Creates Vue component for trigger variables block in job log page
-merge_request:
-author:
-type: other
diff --git a/changelogs/unreleased/50101-truncated-job-information.yml b/changelogs/unreleased/50101-truncated-job-information.yml
deleted file mode 100644
index b873b8b7bf6..00000000000
--- a/changelogs/unreleased/50101-truncated-job-information.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Creates vue component for job log top bar with controllers
-merge_request:
-author:
-type: other
diff --git a/changelogs/unreleased/50111-improve-design-of-cluster-apps-to-handle-larger-quantity.yml b/changelogs/unreleased/50111-improve-design-of-cluster-apps-to-handle-larger-quantity.yml
new file mode 100644
index 00000000000..438c847327a
--- /dev/null
+++ b/changelogs/unreleased/50111-improve-design-of-cluster-apps-to-handle-larger-quantity.yml
@@ -0,0 +1,5 @@
+---
+title: Improve install flow of Kubernetes cluster apps
+merge_request: 21567
+author:
+type: changed
diff --git a/changelogs/unreleased/50126-blocked-user-card.yml b/changelogs/unreleased/50126-blocked-user-card.yml
deleted file mode 100644
index a42d62e5530..00000000000
--- a/changelogs/unreleased/50126-blocked-user-card.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fix blocked user card style
-merge_request: 21095
-author:
-type: fixed
diff --git a/changelogs/unreleased/50180-fa-icon-google-audit.yml b/changelogs/unreleased/50180-fa-icon-google-audit.yml
deleted file mode 100644
index fb1771a7570..00000000000
--- a/changelogs/unreleased/50180-fa-icon-google-audit.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Show google icon in audit log
-merge_request: 21207
-author: Jan Beckmann
-type: fixed
diff --git a/changelogs/unreleased/50243-auto-devops-behind-a-proxy.yml b/changelogs/unreleased/50243-auto-devops-behind-a-proxy.yml
deleted file mode 100644
index 0f6208d0c7a..00000000000
--- a/changelogs/unreleased/50243-auto-devops-behind-a-proxy.yml
+++ /dev/null
@@ -1,6 +0,0 @@
----
-title: Vendor Auto-DevOps.gitlab-ci.yml with new proxy env vars passed through to
- docker
-merge_request: 21159
-author: kinolaev
-type: added
diff --git a/changelogs/unreleased/50289-vendor-ci-yml-for-the-last-time.yml b/changelogs/unreleased/50289-vendor-ci-yml-for-the-last-time.yml
new file mode 100644
index 00000000000..7aee8720888
--- /dev/null
+++ b/changelogs/unreleased/50289-vendor-ci-yml-for-the-last-time.yml
@@ -0,0 +1,5 @@
+---
+title: Update all gitlab CI templates from gitlab-org/gitlab-ci-yml
+merge_request: 21929
+author:
+type: added
diff --git a/changelogs/unreleased/50345-hashed-storage-feature-flag.yml b/changelogs/unreleased/50345-hashed-storage-feature-flag.yml
deleted file mode 100644
index 4c5182b843b..00000000000
--- a/changelogs/unreleased/50345-hashed-storage-feature-flag.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Feature flag to disable Hashed Storage migration when renaming a repository
-merge_request: 21291
-author:
-type: added
diff --git a/changelogs/unreleased/50414-rubocop-rule-to-enforce-class-methods-over-module.yml b/changelogs/unreleased/50414-rubocop-rule-to-enforce-class-methods-over-module.yml
deleted file mode 100644
index 1694fb2376d..00000000000
--- a/changelogs/unreleased/50414-rubocop-rule-to-enforce-class-methods-over-module.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Adds Rubocop rule to enforce class_methods over module ClassMethods
-merge_request: 21379
-author: Jacopo Beschi @jacopo-beschi
-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
deleted file mode 100644
index 3e360f8d6bb..00000000000
--- a/changelogs/unreleased/50441-high-number-of-statement-timeouts-in-groupdestroyworker-due-to-sitestatistics.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Removing a group no longer triggers hooks for project deletion twice
-merge_request: 21366
-author:
-type: fixed
diff --git a/changelogs/unreleased/50452-breadcrumb-link-to-new-merge-requests.yml b/changelogs/unreleased/50452-breadcrumb-link-to-new-merge-requests.yml
deleted file mode 100644
index 4738f7652a4..00000000000
--- a/changelogs/unreleased/50452-breadcrumb-link-to-new-merge-requests.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: "Fix breadcrumb link to merge requests on new merge request page"
-merge_request: 21502
-author: J.D. Bean
-type: fixed
diff --git a/changelogs/unreleased/50461-add-retried-builds-in-pipeline-stage-endpoint.yml b/changelogs/unreleased/50461-add-retried-builds-in-pipeline-stage-endpoint.yml
new file mode 100644
index 00000000000..539aea4f333
--- /dev/null
+++ b/changelogs/unreleased/50461-add-retried-builds-in-pipeline-stage-endpoint.yml
@@ -0,0 +1,5 @@
+---
+title: Add retried jobs to pipeline stage
+merge_request: 21558
+author:
+type: other
diff --git a/changelogs/unreleased/50524-artifacts-sm.yml b/changelogs/unreleased/50524-artifacts-sm.yml
deleted file mode 100644
index 22bd097f911..00000000000
--- a/changelogs/unreleased/50524-artifacts-sm.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Shows download artifacts button for pipelines on small screens
-merge_request:
-author:
-type: changed
diff --git a/changelogs/unreleased/50535-display-banner-to-notify-user-if-project-is-implicitly-opted-ado.yml b/changelogs/unreleased/50535-display-banner-to-notify-user-if-project-is-implicitly-opted-ado.yml
deleted file mode 100644
index 23d4d504f04..00000000000
--- a/changelogs/unreleased/50535-display-banner-to-notify-user-if-project-is-implicitly-opted-ado.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Display banner on project page if AutoDevOps is implicitly enabled
-merge_request: 21503
-author:
-type: added
diff --git a/changelogs/unreleased/50564-chat-service-refactoring.yml b/changelogs/unreleased/50564-chat-service-refactoring.yml
deleted file mode 100644
index aec5e8fab0a..00000000000
--- a/changelogs/unreleased/50564-chat-service-refactoring.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Use sample data for push event when no commits created
-merge_request: 21440
-author: Takuya Noguchi
-type: fixed
diff --git a/changelogs/unreleased/50567-remove-usage-ping-payload-from-cohorts-add-to-settings.yml b/changelogs/unreleased/50567-remove-usage-ping-payload-from-cohorts-add-to-settings.yml
deleted file mode 100644
index 2a6666e362c..00000000000
--- a/changelogs/unreleased/50567-remove-usage-ping-payload-from-cohorts-add-to-settings.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Move usage ping payload from User Cohorts page to admin application settings
-merge_request: 21343
-author:
-type: other
diff --git a/changelogs/unreleased/50584-fix-ide-commit-twice.yml b/changelogs/unreleased/50584-fix-ide-commit-twice.yml
deleted file mode 100644
index 92b292cf4ab..00000000000
--- a/changelogs/unreleased/50584-fix-ide-commit-twice.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fix Web IDE unable to commit to same file twice
-merge_request: 21372
-author:
-type: fixed
diff --git a/changelogs/unreleased/50657-migrate-issue-labels-and-milestone-to-related-mr-on-creation.yml b/changelogs/unreleased/50657-migrate-issue-labels-and-milestone-to-related-mr-on-creation.yml
deleted file mode 100644
index 65419d3ac77..00000000000
--- a/changelogs/unreleased/50657-migrate-issue-labels-and-milestone-to-related-mr-on-creation.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Merge request copies all associated issue labels and milestone on creation
-merge_request: 21383
-author:
-type: added
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
deleted file mode 100644
index 6e57a215367..00000000000
--- a/changelogs/unreleased/50801-error-getting-performance-bar-results-for-uuid.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Don't show flash messages for performance bar errors
-merge_request: 21411
-author:
-type: other
diff --git a/changelogs/unreleased/50823-not-properly-filled-in-activity-RSS-feed-yml.yml b/changelogs/unreleased/50823-not-properly-filled-in-activity-RSS-feed-yml.yml
deleted file mode 100644
index 924e8867701..00000000000
--- a/changelogs/unreleased/50823-not-properly-filled-in-activity-RSS-feed-yml.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fix links in RSS feed elements
-merge_request: 21424
-author: Marc Schwede
-type: fixed
diff --git a/changelogs/unreleased/50853-vendor-auto-devops-gitlab-ci-yml-to-resolve-redeploying-deleted-app-gives-helm-error.yml b/changelogs/unreleased/50853-vendor-auto-devops-gitlab-ci-yml-to-resolve-redeploying-deleted-app-gives-helm-error.yml
deleted file mode 100644
index 37922eb82f6..00000000000
--- a/changelogs/unreleased/50853-vendor-auto-devops-gitlab-ci-yml-to-resolve-redeploying-deleted-app-gives-helm-error.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: 'Auto-DevOps.gitlab-ci.yml: fix redeploying deleted app gives helm error'
-merge_request: 21429
-author:
-type: fixed
diff --git a/changelogs/unreleased/50879-unused-css-container-fluid.yml b/changelogs/unreleased/50879-unused-css-container-fluid.yml
deleted file mode 100644
index 3f706472523..00000000000
--- a/changelogs/unreleased/50879-unused-css-container-fluid.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Remove unused CSS part in mobile framework
-merge_request: 21439
-author: Takuya Noguchi
-type: other
diff --git a/changelogs/unreleased/50904-move-job-page-vue.yml b/changelogs/unreleased/50904-move-job-page-vue.yml
new file mode 100644
index 00000000000..e907c6301ec
--- /dev/null
+++ b/changelogs/unreleased/50904-move-job-page-vue.yml
@@ -0,0 +1,5 @@
+---
+title: Use Vue components and new API to render Artifacts, Trigger Variables and Commit blocks on Job page
+merge_request: 21777
+author:
+type: other
diff --git a/changelogs/unreleased/50904-update-scroll-utils.yml b/changelogs/unreleased/50904-update-scroll-utils.yml
new file mode 100644
index 00000000000..e301de1a40b
--- /dev/null
+++ b/changelogs/unreleased/50904-update-scroll-utils.yml
@@ -0,0 +1,5 @@
+---
+title: Extracts scroll position check into reusable functions
+merge_request:
+author:
+type: other
diff --git a/changelogs/unreleased/50904-use-vuex-store-job.yml b/changelogs/unreleased/50904-use-vuex-store-job.yml
new file mode 100644
index 00000000000..5b1112a4f5b
--- /dev/null
+++ b/changelogs/unreleased/50904-use-vuex-store-job.yml
@@ -0,0 +1,5 @@
+---
+title: Uses Vuex store in job details page and removes old mediator pattern
+merge_request:
+author:
+type: other
diff --git a/changelogs/unreleased/50930-update-rubyzip-to-1-2-2.yml b/changelogs/unreleased/50930-update-rubyzip-to-1-2-2.yml
deleted file mode 100644
index be5cc60df64..00000000000
--- a/changelogs/unreleased/50930-update-rubyzip-to-1-2-2.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Update rubyzip to 1.2.2 (CVE-2018-1000544)
-merge_request: 21460
-author: Takuya Noguchi
-type: security
diff --git a/changelogs/unreleased/50936-docs-run-review-cleanup-only-for-gitlab-org-repos.yml b/changelogs/unreleased/50936-docs-run-review-cleanup-only-for-gitlab-org-repos.yml
deleted file mode 100644
index 87265506e24..00000000000
--- a/changelogs/unreleased/50936-docs-run-review-cleanup-only-for-gitlab-org-repos.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Run review-docs-cleanup job for gitlab-org repos only
-merge_request: 21463
-author: Takuya Noguchi
-type: other
diff --git a/changelogs/unreleased/51050-fix.yml b/changelogs/unreleased/51050-fix.yml
new file mode 100644
index 00000000000..b58f9ae34f8
--- /dev/null
+++ b/changelogs/unreleased/51050-fix.yml
@@ -0,0 +1,5 @@
+---
+title: Fix broken styling when issue board is collapsed
+merge_request: 21868
+author: Andrea Leone
+type: fixed
diff --git a/changelogs/unreleased/51092-fix-mr-diff-file-filter-clear-button.yml b/changelogs/unreleased/51092-fix-mr-diff-file-filter-clear-button.yml
deleted file mode 100644
index cb5ab15d285..00000000000
--- a/changelogs/unreleased/51092-fix-mr-diff-file-filter-clear-button.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Make MR diff file filter input Clear button functional
-merge_request: 21556
-author:
-type: fixed
diff --git a/changelogs/unreleased/51117-send-terminal-path-in-job-api.yml b/changelogs/unreleased/51117-send-terminal-path-in-job-api.yml
deleted file mode 100644
index f6faa9549be..00000000000
--- a/changelogs/unreleased/51117-send-terminal-path-in-job-api.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Add terminal_path to job API response
-merge_request: 21537
-author:
-type: other
diff --git a/changelogs/unreleased/51180-update-ffi-to-1-9-25.yml b/changelogs/unreleased/51180-update-ffi-to-1-9-25.yml
deleted file mode 100644
index 67354d6a610..00000000000
--- a/changelogs/unreleased/51180-update-ffi-to-1-9-25.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Update ffi to 1.9.25
-merge_request: 21561
-author: Takuya Noguchi
-type: other
diff --git a/changelogs/unreleased/51273-expose-runners-for-build-in-job-api.yml b/changelogs/unreleased/51273-expose-runners-for-build-in-job-api.yml
new file mode 100644
index 00000000000..df43f1dfbae
--- /dev/null
+++ b/changelogs/unreleased/51273-expose-runners-for-build-in-job-api.yml
@@ -0,0 +1,5 @@
+---
+title: Expose project runners in job API
+merge_request: 21618
+author:
+type: other
diff --git a/changelogs/unreleased/51281-on-master-diff-view-contains-extra-and-signs.yml b/changelogs/unreleased/51281-on-master-diff-view-contains-extra-and-signs.yml
deleted file mode 100644
index 2ca74b4bc48..00000000000
--- a/changelogs/unreleased/51281-on-master-diff-view-contains-extra-and-signs.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fixes double +/- on inline diff view
-merge_request: 21634
-author:
-type: fixed
diff --git a/changelogs/unreleased/51282-link-to-user-snippets-on-new-user-snippet-page.yml b/changelogs/unreleased/51282-link-to-user-snippets-on-new-user-snippet-page.yml
new file mode 100644
index 00000000000..1d2075ae549
--- /dev/null
+++ b/changelogs/unreleased/51282-link-to-user-snippets-on-new-user-snippet-page.yml
@@ -0,0 +1,5 @@
+---
+title: Add link to User Snippets in breadcrumbs of New User Snippet page
+merge_request:
+author: J.D. Bean
+type: add
diff --git a/changelogs/unreleased/51318-project-export-broken-when-avatar-is-set.yml b/changelogs/unreleased/51318-project-export-broken-when-avatar-is-set.yml
deleted file mode 100644
index c0f7e88f2b7..00000000000
--- a/changelogs/unreleased/51318-project-export-broken-when-avatar-is-set.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fix broken exports when they include a projet avatar
-merge_request: 21649
-author:
-type: fixed
diff --git a/changelogs/unreleased/51404-update-groups-and-projects-api-docs.yml b/changelogs/unreleased/51404-update-groups-and-projects-api-docs.yml
new file mode 100644
index 00000000000..da02a91041b
--- /dev/null
+++ b/changelogs/unreleased/51404-update-groups-and-projects-api-docs.yml
@@ -0,0 +1,5 @@
+---
+title: Docs for Project/Groups members API with inherited members
+merge_request: 21984
+author: Jacopo Beschi @jacopo-beschi
+type: added
diff --git a/changelogs/unreleased/51412-username-alignment-issue-on-mr-page.yml b/changelogs/unreleased/51412-username-alignment-issue-on-mr-page.yml
deleted file mode 100644
index 5d245f672f2..00000000000
--- a/changelogs/unreleased/51412-username-alignment-issue-on-mr-page.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Add margin between username and subsequent text in issuable header
-merge_request: 21697
-author:
-type: other
diff --git a/changelogs/unreleased/51476-private-profile-help-url-should-not-toggle-checkbox.yml b/changelogs/unreleased/51476-private-profile-help-url-should-not-toggle-checkbox.yml
new file mode 100644
index 00000000000..d4e4503508d
--- /dev/null
+++ b/changelogs/unreleased/51476-private-profile-help-url-should-not-toggle-checkbox.yml
@@ -0,0 +1,5 @@
+---
+title: Prevents private profile help link from toggling checkbox
+merge_request: 21757
+author:
+type: other
diff --git a/changelogs/unreleased/51509-remove-sidekiq-limit-fetch.yml b/changelogs/unreleased/51509-remove-sidekiq-limit-fetch.yml
new file mode 100644
index 00000000000..fcc5aae2bda
--- /dev/null
+++ b/changelogs/unreleased/51509-remove-sidekiq-limit-fetch.yml
@@ -0,0 +1,5 @@
+---
+title: Remove background job throttling feature
+merge_request: 21748
+author:
+type: removed
diff --git a/changelogs/unreleased/51522-add-new-project-via-import-by-url-auto-populates-slug-but-not-project-name.yml b/changelogs/unreleased/51522-add-new-project-via-import-by-url-auto-populates-slug-but-not-project-name.yml
new file mode 100644
index 00000000000..06b7c9c7b34
--- /dev/null
+++ b/changelogs/unreleased/51522-add-new-project-via-import-by-url-auto-populates-slug-but-not-project-name.yml
@@ -0,0 +1,5 @@
+---
+title: Removes the 'required' attribute from the 'project name' field
+merge_request: 21770
+author:
+type: other
diff --git a/changelogs/unreleased/51549-runners-table.yml b/changelogs/unreleased/51549-runners-table.yml
new file mode 100644
index 00000000000..fe36bfc1b30
--- /dev/null
+++ b/changelogs/unreleased/51549-runners-table.yml
@@ -0,0 +1,5 @@
+---
+title: Fixes admin runners table not wrapping content
+merge_request:
+author:
+type: fixed
diff --git a/changelogs/unreleased/51564-fix-commit-email-usage.yml b/changelogs/unreleased/51564-fix-commit-email-usage.yml
new file mode 100644
index 00000000000..2f1b042ae8a
--- /dev/null
+++ b/changelogs/unreleased/51564-fix-commit-email-usage.yml
@@ -0,0 +1,5 @@
+---
+title: Respect the user commit email in more places
+merge_request: 21773
+author:
+type: fixed
diff --git a/changelogs/unreleased/51569-performance-bar.yml b/changelogs/unreleased/51569-performance-bar.yml
new file mode 100644
index 00000000000..ab62e7d3b3e
--- /dev/null
+++ b/changelogs/unreleased/51569-performance-bar.yml
@@ -0,0 +1,5 @@
+---
+title: Fixes performance bar looking for a key in a undefined prop
+merge_request:
+author:
+type: fixed
diff --git a/changelogs/unreleased/51571-wrapper-rake-task-uploads-migrate-os.yml b/changelogs/unreleased/51571-wrapper-rake-task-uploads-migrate-os.yml
new file mode 100644
index 00000000000..50710ca0aa8
--- /dev/null
+++ b/changelogs/unreleased/51571-wrapper-rake-task-uploads-migrate-os.yml
@@ -0,0 +1,5 @@
+---
+title: Add wrapper rake task to migrate all uploads to OS
+merge_request: 21779
+author:
+type: other
diff --git a/changelogs/unreleased/51651-fill-pipeline-source-for-external-pipelines.yml b/changelogs/unreleased/51651-fill-pipeline-source-for-external-pipelines.yml
new file mode 100644
index 00000000000..6720430e5fc
--- /dev/null
+++ b/changelogs/unreleased/51651-fill-pipeline-source-for-external-pipelines.yml
@@ -0,0 +1,5 @@
+---
+title: Retroactively fill pipeline source for external pipelines.
+merge_request: 21814
+author:
+type: other
diff --git a/changelogs/unreleased/51725-push-mirrors-default-branch-reset-to-master.yml b/changelogs/unreleased/51725-push-mirrors-default-branch-reset-to-master.yml
new file mode 100644
index 00000000000..b3caa119253
--- /dev/null
+++ b/changelogs/unreleased/51725-push-mirrors-default-branch-reset-to-master.yml
@@ -0,0 +1,5 @@
+---
+title: Doesn't synchronize the default branch for push mirrors
+merge_request: 21861
+author:
+type: fixed
diff --git a/changelogs/unreleased/51747-gitlab-com-unable-to-import-a-project-that-was-just-exported.yml b/changelogs/unreleased/51747-gitlab-com-unable-to-import-a-project-that-was-just-exported.yml
new file mode 100644
index 00000000000..29f7fd872bc
--- /dev/null
+++ b/changelogs/unreleased/51747-gitlab-com-unable-to-import-a-project-that-was-just-exported.yml
@@ -0,0 +1,5 @@
+---
+title: Fix NULL pipeline import problem and pipeline user mapping issue
+merge_request: 21875
+author:
+type: fixed
diff --git a/changelogs/unreleased/51839-remove-sorting-on-project-tags.yml b/changelogs/unreleased/51839-remove-sorting-on-project-tags.yml
new file mode 100644
index 00000000000..38a7c06b34c
--- /dev/null
+++ b/changelogs/unreleased/51839-remove-sorting-on-project-tags.yml
@@ -0,0 +1,5 @@
+---
+title: Preserve order of project tags list
+merge_request: 21897
+author:
+type: changed
diff --git a/changelogs/unreleased/51925-expose-has_trace-in-job-api.yml b/changelogs/unreleased/51925-expose-has_trace-in-job-api.yml
new file mode 100644
index 00000000000..eade86d97ac
--- /dev/null
+++ b/changelogs/unreleased/51925-expose-has_trace-in-job-api.yml
@@ -0,0 +1,5 @@
+---
+title: Expose has_trace in job API
+merge_request: 21950
+author:
+type: other
diff --git a/changelogs/unreleased/6010_remove_gemnasium_service.yml b/changelogs/unreleased/6010_remove_gemnasium_service.yml
deleted file mode 100644
index 900e84c9eed..00000000000
--- a/changelogs/unreleased/6010_remove_gemnasium_service.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Remove Gemnasium service
-merge_request: 21185
-author:
-type: removed
diff --git a/changelogs/unreleased/6028-show-generic-percent-stacked-progress-bar.yml b/changelogs/unreleased/6028-show-generic-percent-stacked-progress-bar.yml
deleted file mode 100644
index 94098dd0144..00000000000
--- a/changelogs/unreleased/6028-show-generic-percent-stacked-progress-bar.yml
+++ /dev/null
@@ -1,6 +0,0 @@
----
-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/6717_extend_reports_for_security_products.yml b/changelogs/unreleased/6717_extend_reports_for_security_products.yml
new file mode 100644
index 00000000000..184c3212e54
--- /dev/null
+++ b/changelogs/unreleased/6717_extend_reports_for_security_products.yml
@@ -0,0 +1,5 @@
+---
+title: Extend reports feature to support Security Products
+merge_request: 21892
+author:
+type: added
diff --git a/changelogs/unreleased/7573-show-click-to-expand-on-not-rendered-diffs.yml b/changelogs/unreleased/7573-show-click-to-expand-on-not-rendered-diffs.yml
deleted file mode 100644
index 4611a1f1f29..00000000000
--- a/changelogs/unreleased/7573-show-click-to-expand-on-not-rendered-diffs.yml
+++ /dev/null
@@ -1,6 +0,0 @@
----
-title: Fix absent Click to Expand link on diffs not rendered on first load of Merge
- Requests Changes tab
-merge_request: 21716
-author:
-type: fixed
diff --git a/changelogs/unreleased/_acet-disable-ide-button.yml b/changelogs/unreleased/_acet-disable-ide-button.yml
deleted file mode 100644
index 2fff3847052..00000000000
--- a/changelogs/unreleased/_acet-disable-ide-button.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Disable Web IDE button if user is not allowed to push the source branch.
-merge_request: 21288
-author:
-type: added
diff --git a/changelogs/unreleased/ab-49446-internal-ids-inconsistency.yml b/changelogs/unreleased/ab-49446-internal-ids-inconsistency.yml
deleted file mode 100644
index bfea57d79e0..00000000000
--- a/changelogs/unreleased/ab-49446-internal-ids-inconsistency.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Add migration to cleanup internal_ids inconsistency.
-merge_request: 20926
-author:
-type: fixed
diff --git a/changelogs/unreleased/add-2fa-button.yml b/changelogs/unreleased/add-2fa-button.yml
new file mode 100644
index 00000000000..6cb71d52781
--- /dev/null
+++ b/changelogs/unreleased/add-2fa-button.yml
@@ -0,0 +1,5 @@
+---
+title: Add button to download 2FA codes
+merge_request:
+author: Luke Picciau
+type: added
diff --git a/changelogs/unreleased/add-background-migration-for-legacy-traces.yml b/changelogs/unreleased/add-background-migration-for-legacy-traces.yml
deleted file mode 100644
index 3d5a0b4e452..00000000000
--- a/changelogs/unreleased/add-background-migration-for-legacy-traces.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Add background migrations for legacy artifacts
-merge_request: 18615
-author:
-type: performance
diff --git a/changelogs/unreleased/add-ci_archive_traces_cron_worker-to-gitlab-yml.yml b/changelogs/unreleased/add-ci_archive_traces_cron_worker-to-gitlab-yml.yml
deleted file mode 100644
index d963dc5bac3..00000000000
--- a/changelogs/unreleased/add-ci_archive_traces_cron_worker-to-gitlab-yml.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Add an example of the configuration of archive trace cron worker in gitlab.yml.example
-merge_request: 20583
-author:
-type: other
diff --git a/changelogs/unreleased/add-most-stars-for-filter-option.yml b/changelogs/unreleased/add-most-stars-for-filter-option.yml
new file mode 100644
index 00000000000..be95d6db55f
--- /dev/null
+++ b/changelogs/unreleased/add-most-stars-for-filter-option.yml
@@ -0,0 +1,5 @@
+---
+title: Allows to sort projects by most stars
+merge_request: 21762
+author: Jacopo Beschi @jacopo-beschi
+type: added
diff --git a/changelogs/unreleased/add-rake-command-to-migrate-locally-persisted-archived-traces.yml b/changelogs/unreleased/add-rake-command-to-migrate-locally-persisted-archived-traces.yml
deleted file mode 100644
index b82344e3c9c..00000000000
--- a/changelogs/unreleased/add-rake-command-to-migrate-locally-persisted-archived-traces.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Add rake command to migrate archived traces from local storage to object storage
-merge_request: 21193
-author:
-type: added
diff --git a/changelogs/unreleased/add_google_noto_color_emoji_font.yml b/changelogs/unreleased/add_google_noto_color_emoji_font.yml
deleted file mode 100644
index 9ba46262767..00000000000
--- a/changelogs/unreleased/add_google_noto_color_emoji_font.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Add Noto Color Emoji font support
-merge_request: 19036
-author: Alexander Popov
-type: changed
diff --git a/changelogs/unreleased/align-form-labels.yml b/changelogs/unreleased/align-form-labels.yml
new file mode 100644
index 00000000000..fd781e3b910
--- /dev/null
+++ b/changelogs/unreleased/align-form-labels.yml
@@ -0,0 +1,5 @@
+---
+title: Align form labels following Bootstrap 4 docs
+merge_request: 21752
+author:
+type: fixed
diff --git a/changelogs/unreleased/an-ap_log_gitaly_calls.yml b/changelogs/unreleased/an-ap_log_gitaly_calls.yml
deleted file mode 100644
index 65bac55a73e..00000000000
--- a/changelogs/unreleased/an-ap_log_gitaly_calls.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Add gitaly_calls attribute to API logs
-merge_request: 21496
-author:
-type: other
diff --git a/changelogs/unreleased/an-api-route-logger.yml b/changelogs/unreleased/an-api-route-logger.yml
deleted file mode 100644
index cca3ef44f36..00000000000
--- a/changelogs/unreleased/an-api-route-logger.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Add route information to lograge structured logging for API logs
-merge_request: 21487
-author:
-type: other
diff --git a/changelogs/unreleased/api-empty-commit-message.yml b/changelogs/unreleased/api-empty-commit-message.yml
deleted file mode 100644
index 34ddc020644..00000000000
--- a/changelogs/unreleased/api-empty-commit-message.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: 'API: Catch empty commit messages'
-merge_request: 21322
-author: Robert Schilling
-type: fixed
diff --git a/changelogs/unreleased/api-empty-project-snippets.yml b/changelogs/unreleased/api-empty-project-snippets.yml
deleted file mode 100644
index 7b8c7c9e48d..00000000000
--- a/changelogs/unreleased/api-empty-project-snippets.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: 'API: Catch empty code content for project snippets'
-merge_request: 21325
-author: Robert Schilling
-type: fixed
diff --git a/changelogs/unreleased/api-promote-find-branch.yml b/changelogs/unreleased/api-promote-find-branch.yml
deleted file mode 100644
index cfa767809b2..00000000000
--- a/changelogs/unreleased/api-promote-find-branch.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: 'API: Use find_branch! in all places'
-merge_request: 21614
-author: Robert Schilling
-type: fixed
diff --git a/changelogs/unreleased/api-protected-tags.yml b/changelogs/unreleased/api-protected-tags.yml
deleted file mode 100644
index 6e7ecf24b6e..00000000000
--- a/changelogs/unreleased/api-protected-tags.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: 'API: Protected tags'
-merge_request: 14986
-author: Robert Schilling
-type: added
diff --git a/changelogs/unreleased/api-shared_group_expires-at.yml b/changelogs/unreleased/api-shared_group_expires-at.yml
deleted file mode 100644
index 3d569de65fa..00000000000
--- a/changelogs/unreleased/api-shared_group_expires-at.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: 'API: Add expiration date for shared projects to the project entity'
-merge_request: 21104
-author: Robert Schilling
-type: added
diff --git a/changelogs/unreleased/arguments-keyword-sast.yml b/changelogs/unreleased/arguments-keyword-sast.yml
deleted file mode 100644
index 2ecbc5e8174..00000000000
--- a/changelogs/unreleased/arguments-keyword-sast.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Don't use arguments keyword in gettext script
-merge_request: 21296
-author: gfyoung
-type: fixed
diff --git a/changelogs/unreleased/ash-mckenzie-geo-git-push-ssh-proxy.yml b/changelogs/unreleased/ash-mckenzie-geo-git-push-ssh-proxy.yml
deleted file mode 100644
index c145c744cef..00000000000
--- a/changelogs/unreleased/ash-mckenzie-geo-git-push-ssh-proxy.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: 'Support a custom action, such as proxying to another server, after /api/v4/internal/allowed check succeeds'
-merge_request: 21034
-author:
-type: changed
diff --git a/changelogs/unreleased/auto-devops-gitlab-ci-glic-228.yml b/changelogs/unreleased/auto-devops-gitlab-ci-glic-228.yml
deleted file mode 100644
index a1625193189..00000000000
--- a/changelogs/unreleased/auto-devops-gitlab-ci-glic-228.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: 'Auto-DevOps.gitlab-ci.yml: update glibc package to 2.28'
-merge_request: 21191
-author: sgerrand
-type: fixed
diff --git a/changelogs/unreleased/bvl-add-czech.yml b/changelogs/unreleased/bvl-add-czech.yml
deleted file mode 100644
index 49e0e4a74b7..00000000000
--- a/changelogs/unreleased/bvl-add-czech.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Add Czech as an available language.
-merge_request: 21201
-author:
-type: added
diff --git a/changelogs/unreleased/bvl-add-galician.yml b/changelogs/unreleased/bvl-add-galician.yml
deleted file mode 100644
index e7035901ace..00000000000
--- a/changelogs/unreleased/bvl-add-galician.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Add Galician as an available language.
-merge_request: 21202
-author:
-type: added
diff --git a/changelogs/unreleased/bvl-merge-base-api.yml b/changelogs/unreleased/bvl-merge-base-api.yml
deleted file mode 100644
index 78fb3ce0897..00000000000
--- a/changelogs/unreleased/bvl-merge-base-api.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Get the merge base of two refs through the API
-merge_request: 20929
-author:
-type: added
diff --git a/changelogs/unreleased/bvl-remove-sha-from-help.yml b/changelogs/unreleased/bvl-remove-sha-from-help.yml
new file mode 100644
index 00000000000..37f797f98f4
--- /dev/null
+++ b/changelogs/unreleased/bvl-remove-sha-from-help.yml
@@ -0,0 +1,5 @@
+---
+title: Link to the tag for a version on the help page instead of to the commit
+merge_request: 22015
+author:
+type: changed
diff --git a/changelogs/unreleased/bw-commonmark-for-files.yml b/changelogs/unreleased/bw-commonmark-for-files.yml
deleted file mode 100644
index f932ccb704f..00000000000
--- a/changelogs/unreleased/bw-commonmark-for-files.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Render files (`.md`) and wikis using CommonMark
-merge_request: 21228
-author:
-type: changed
diff --git a/changelogs/unreleased/ccr-43283_allow_author_upvote.yml b/changelogs/unreleased/ccr-43283_allow_author_upvote.yml
deleted file mode 100644
index 12ef6e3f790..00000000000
--- a/changelogs/unreleased/ccr-43283_allow_author_upvote.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-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
deleted file mode 100644
index c08578cddba..00000000000
--- a/changelogs/unreleased/ccr-48800-ping_for_boards.yml
+++ /dev/null
@@ -1,6 +0,0 @@
----
-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/ccr-6699_image_for_object_error.yml b/changelogs/unreleased/ccr-6699_image_for_object_error.yml
deleted file mode 100644
index dec1adaceff..00000000000
--- a/changelogs/unreleased/ccr-6699_image_for_object_error.yml
+++ /dev/null
@@ -1,6 +0,0 @@
----
-title: Handles exception during file upload - replaces the stack trace with a small
- error message.
-merge_request: 21528
-author:
-type: fixed
diff --git a/changelogs/unreleased/ce-5666-optimize_querying_manageable_groups.yml b/changelogs/unreleased/ce-5666-optimize_querying_manageable_groups.yml
deleted file mode 100644
index 0c6a1071cdd..00000000000
--- a/changelogs/unreleased/ce-5666-optimize_querying_manageable_groups.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Optimize querying User#manageable_groups
-merge_request: 21050
-author:
-type: performance
diff --git a/changelogs/unreleased/ci-builds-status-index.yml b/changelogs/unreleased/ci-builds-status-index.yml
deleted file mode 100644
index 8b7252f09e5..00000000000
--- a/changelogs/unreleased/ci-builds-status-index.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Remove redundant ci_builds (status) index
-merge_request: 21070
-author:
-type: performance
diff --git a/changelogs/unreleased/dm-create-note-return-discussion.yml b/changelogs/unreleased/dm-create-note-return-discussion.yml
new file mode 100644
index 00000000000..49ab5c0ca14
--- /dev/null
+++ b/changelogs/unreleased/dm-create-note-return-discussion.yml
@@ -0,0 +1,5 @@
+---
+title: Increase performance when creating discussions on diff
+merge_request:
+author:
+type: performance
diff --git a/changelogs/unreleased/dm-fix-assign-unassign-quick-actions.yml b/changelogs/unreleased/dm-fix-assign-unassign-quick-actions.yml
new file mode 100644
index 00000000000..bfc1ff7b8af
--- /dev/null
+++ b/changelogs/unreleased/dm-fix-assign-unassign-quick-actions.yml
@@ -0,0 +1,6 @@
+---
+title: Don't ignore first action when assign and unassign quick actions are used in
+ the same comment
+merge_request: 21749
+author:
+type: fixed
diff --git a/changelogs/unreleased/dz-fix-sql-error-admin-users-2fa.yml b/changelogs/unreleased/dz-fix-sql-error-admin-users-2fa.yml
deleted file mode 100644
index 67926f3738a..00000000000
--- a/changelogs/unreleased/dz-fix-sql-error-admin-users-2fa.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fix SQL error when sorting 2FA-enabled users by name in admin area
-merge_request: 21324
-author:
-type: fixed
diff --git a/changelogs/unreleased/dz-group-labels-search.yml b/changelogs/unreleased/dz-group-labels-search.yml
deleted file mode 100644
index bb4719df22d..00000000000
--- a/changelogs/unreleased/dz-group-labels-search.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Add search to a group labels page
-merge_request: 21480
-author:
-type: added
diff --git a/changelogs/unreleased/ee-6381-multiseries.yml b/changelogs/unreleased/ee-6381-multiseries.yml
deleted file mode 100644
index a749e31d27c..00000000000
--- a/changelogs/unreleased/ee-6381-multiseries.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Allow gaps in multiseries metrics charts
-merge_request: 21427
-author:
-type: fixed
diff --git a/changelogs/unreleased/emoji-cutoff-1px.yml b/changelogs/unreleased/emoji-cutoff-1px.yml
deleted file mode 100644
index 815d9c177e8..00000000000
--- a/changelogs/unreleased/emoji-cutoff-1px.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fix 1px cutoff of emojis
-merge_request: 21180
-author: gfyoung
-type: fixed
diff --git a/changelogs/unreleased/enable-force-write-auth-keys-restore.yml b/changelogs/unreleased/enable-force-write-auth-keys-restore.yml
new file mode 100644
index 00000000000..f6c83cc7950
--- /dev/null
+++ b/changelogs/unreleased/enable-force-write-auth-keys-restore.yml
@@ -0,0 +1,5 @@
+---
+title: Enable the ability to use the force env for rebuilding authorized_keys during a restore
+merge_request: 21896
+author:
+type: fixed
diff --git a/changelogs/unreleased/expose-all-artifacts-sizes-in-jobs-api.yml b/changelogs/unreleased/expose-all-artifacts-sizes-in-jobs-api.yml
deleted file mode 100644
index 1453d39934b..00000000000
--- a/changelogs/unreleased/expose-all-artifacts-sizes-in-jobs-api.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Expose all artifacts sizes in jobs api
-merge_request: 20821
-author: Peter Marko
-type: added
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
deleted file mode 100644
index 0b8ae527214..00000000000
--- a/changelogs/unreleased/expose-users-id-in-admin-users-show-page.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Expose user's id in /admin/users/ show page
-merge_request:
-author: Eva Kadlecova
-type: changed
diff --git a/changelogs/unreleased/fa-handle_invalid_utf8_errors.yml b/changelogs/unreleased/fa-handle_invalid_utf8_errors.yml
new file mode 100644
index 00000000000..9cae193d858
--- /dev/null
+++ b/changelogs/unreleased/fa-handle_invalid_utf8_errors.yml
@@ -0,0 +1,5 @@
+---
+title: Render 412 when invalid UTF-8 parameters are passed to controller
+merge_request:
+author:
+type: other
diff --git a/changelogs/unreleased/feat-add-default-avatar-to-group.yml b/changelogs/unreleased/feat-add-default-avatar-to-group.yml
deleted file mode 100644
index 56d8f2ccd6d..00000000000
--- a/changelogs/unreleased/feat-add-default-avatar-to-group.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Add default avatar to group
-merge_request: 17271
-author: George Tsiolis
-type: changed
diff --git a/changelogs/unreleased/feat-update-contribution-calendar.yml b/changelogs/unreleased/feat-update-contribution-calendar.yml
deleted file mode 100644
index 4ada8b1fcd5..00000000000
--- a/changelogs/unreleased/feat-update-contribution-calendar.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Include private contributions to contributions calendar
-merge_request: 17296
-author: George Tsiolis
-type: added
diff --git a/changelogs/unreleased/feature--32877-add-default-field-branch-api.yml b/changelogs/unreleased/feature--32877-add-default-field-branch-api.yml
deleted file mode 100644
index a99ecc9a67e..00000000000
--- a/changelogs/unreleased/feature--32877-add-default-field-branch-api.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Add default parameter to branches API
-merge_request: 21294
-author: Riccardo Padovani
-type: changed
diff --git a/changelogs/unreleased/feature-add-public-email-to-users-api.yml b/changelogs/unreleased/feature-add-public-email-to-users-api.yml
new file mode 100644
index 00000000000..1f5d3fb113d
--- /dev/null
+++ b/changelogs/unreleased/feature-add-public-email-to-users-api.yml
@@ -0,0 +1,5 @@
+---
+title: Adds the user's public_email attribute to the API
+merge_request: 21909
+author: Alexis Reigel
+type: added
diff --git a/changelogs/unreleased/feature-gb-allow-to-extend-keys-in-gitlab-ci-yml.yml b/changelogs/unreleased/feature-gb-allow-to-extend-keys-in-gitlab-ci-yml.yml
deleted file mode 100644
index b46dfd47e7a..00000000000
--- a/changelogs/unreleased/feature-gb-allow-to-extend-keys-in-gitlab-ci-yml.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Add support for extendable CI/CD config with
-merge_request: 21243
-author:
-type: added
diff --git a/changelogs/unreleased/feature-git-v2-flag.yml b/changelogs/unreleased/feature-git-v2-flag.yml
deleted file mode 100644
index c105c477666..00000000000
--- a/changelogs/unreleased/feature-git-v2-flag.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Add git_v2 feature flag
-merge_request: 21520
-author:
-type: added
diff --git a/changelogs/unreleased/feature-runner-type-filter-for-admin-view.yml b/changelogs/unreleased/feature-runner-type-filter-for-admin-view.yml
new file mode 100644
index 00000000000..e7812cd0944
--- /dev/null
+++ b/changelogs/unreleased/feature-runner-type-filter-for-admin-view.yml
@@ -0,0 +1,5 @@
+---
+title: Add a type filter to the admin runners view
+merge_request: 19649
+author: Alexis Reigel
+type: added
diff --git a/changelogs/unreleased/feature-whitelist-new-users-as-internal.yml b/changelogs/unreleased/feature-whitelist-new-users-as-internal.yml
deleted file mode 100644
index 7a3bd11c119..00000000000
--- a/changelogs/unreleased/feature-whitelist-new-users-as-internal.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Add an option to whitelist users based on email address as internal when the "New user set to external" setting is enabled.
-merge_request: 17711
-author: Roger Rüttimann
-type: added
diff --git a/changelogs/unreleased/filter-web-hooks-by-branch.yml b/changelogs/unreleased/filter-web-hooks-by-branch.yml
deleted file mode 100644
index 7bd2c191d7f..00000000000
--- a/changelogs/unreleased/filter-web-hooks-by-branch.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Add branch filter to project webhooks
-merge_request: 20338
-author: Duana Saskia
-type: added
diff --git a/changelogs/unreleased/fix-api-group-createdat.yml b/changelogs/unreleased/fix-api-group-createdat.yml
deleted file mode 100644
index e628facf1bf..00000000000
--- a/changelogs/unreleased/fix-api-group-createdat.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-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-chat-notification-service-for-ee.yml b/changelogs/unreleased/fix-chat-notification-service-for-ee.yml
new file mode 100644
index 00000000000..b69d08b95db
--- /dev/null
+++ b/changelogs/unreleased/fix-chat-notification-service-for-ee.yml
@@ -0,0 +1,5 @@
+---
+title: Fix activity titles for MRs in chat notification services
+merge_request: 21834
+author:
+type: fixed
diff --git a/changelogs/unreleased/fix-closing-issues.yml b/changelogs/unreleased/fix-closing-issues.yml
deleted file mode 100644
index ba80f371580..00000000000
--- a/changelogs/unreleased/fix-closing-issues.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fix closing issue default pattern
-merge_request: 21531
-author: Samuele Kaplun
-type: fixed
diff --git a/changelogs/unreleased/fix-committer-typo.yml b/changelogs/unreleased/fix-committer-typo.yml
new file mode 100644
index 00000000000..6033912b6c0
--- /dev/null
+++ b/changelogs/unreleased/fix-committer-typo.yml
@@ -0,0 +1,5 @@
+---
+title: Fix committer typo
+merge_request: 21899
+author: George Tsiolis
+type: other
diff --git a/changelogs/unreleased/fix-download-dropdown-link.yml b/changelogs/unreleased/fix-download-dropdown-link.yml
deleted file mode 100644
index 998476b07bd..00000000000
--- a/changelogs/unreleased/fix-download-dropdown-link.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Hide PAT creation advice for HTTP clone if PAT exists
-merge_request: 18208
-author: George Thomas @thegeorgeous
-type: fixed
diff --git a/changelogs/unreleased/fix-help-text-font-color-in-merge-request-creation.yml b/changelogs/unreleased/fix-help-text-font-color-in-merge-request-creation.yml
new file mode 100644
index 00000000000..4ac192cd056
--- /dev/null
+++ b/changelogs/unreleased/fix-help-text-font-color-in-merge-request-creation.yml
@@ -0,0 +1,5 @@
+---
+title: Fix wrong text color of help text in merge request creation
+merge_request:
+author: Gerard Montemayor
+type: fixed
diff --git a/changelogs/unreleased/fix-junit-parser.yml b/changelogs/unreleased/fix-junit-parser.yml
deleted file mode 100644
index e0a9ad8f210..00000000000
--- a/changelogs/unreleased/fix-junit-parser.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fix edge cases of JUnitParser
-merge_request: 21469
-author:
-type: fixed
diff --git a/changelogs/unreleased/fix-labels-list-item-height-with-no-description.yml b/changelogs/unreleased/fix-labels-list-item-height-with-no-description.yml
deleted file mode 100644
index d215d034917..00000000000
--- a/changelogs/unreleased/fix-labels-list-item-height-with-no-description.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fix label list item container height when there is no label description
-merge_request: 21106
-author:
-type: fixed
diff --git a/changelogs/unreleased/fix-leading-slash-in-redirects-plus-rubocop.yml b/changelogs/unreleased/fix-leading-slash-in-redirects-plus-rubocop.yml
new file mode 100644
index 00000000000..38b2486a475
--- /dev/null
+++ b/changelogs/unreleased/fix-leading-slash-in-redirects-plus-rubocop.yml
@@ -0,0 +1,5 @@
+---
+title: Fix leading slash in redirects and add rubocop cop
+merge_request: 21828
+author: Sanad Liaquat
+type: fixed
diff --git a/changelogs/unreleased/fix-mr-title-fallback-logic.yml b/changelogs/unreleased/fix-mr-title-fallback-logic.yml
deleted file mode 100644
index 5056c38573b..00000000000
--- a/changelogs/unreleased/fix-mr-title-fallback-logic.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fix fallback logic for automatic MR title assignment
-merge_request: 20930
-author: Franz Liedke
-type: fixed
diff --git a/changelogs/unreleased/fix-namespace-upload.yml b/changelogs/unreleased/fix-namespace-upload.yml
deleted file mode 100644
index 383d79a998f..00000000000
--- a/changelogs/unreleased/fix-namespace-upload.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fix workhorse temp path for namespace uploads
-merge_request: 21650
-author:
-type: fixed
diff --git a/changelogs/unreleased/fix-namespace-uploader.yml b/changelogs/unreleased/fix-namespace-uploader.yml
deleted file mode 100644
index 081adc9a6f1..00000000000
--- a/changelogs/unreleased/fix-namespace-uploader.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fix NamespaceUploader.base_dir for remote uploads
-merge_request:
-author:
-type: fixed
diff --git a/changelogs/unreleased/fix-pipeline-fixture-seeder.yml b/changelogs/unreleased/fix-pipeline-fixture-seeder.yml
deleted file mode 100644
index 02b83062e07..00000000000
--- a/changelogs/unreleased/fix-pipeline-fixture-seeder.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fix pipeline fixture seeder
-merge_request: 21088
-author:
-type: fixed
diff --git a/changelogs/unreleased/fix_emojis_cutting_and_regressions.yml b/changelogs/unreleased/fix_emojis_cutting_and_regressions.yml
deleted file mode 100644
index a9c1b88a61c..00000000000
--- a/changelogs/unreleased/fix_emojis_cutting_and_regressions.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fix Emojis cutting in the right way
-merge_request:
-author: Alexander Popov
-type: fixed
diff --git a/changelogs/unreleased/fix_event_api_permissions.yml b/changelogs/unreleased/fix_event_api_permissions.yml
deleted file mode 100644
index dee280e93ad..00000000000
--- a/changelogs/unreleased/fix_event_api_permissions.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: 'Events API now requires the read_user or api scope.'
-merge_request: 20627
-author: Warren Parad
-type: fixed
diff --git a/changelogs/unreleased/fj-2635-enable-rss-for-tags.yml b/changelogs/unreleased/fj-2635-enable-rss-for-tags.yml
deleted file mode 100644
index ee197572385..00000000000
--- a/changelogs/unreleased/fj-2635-enable-rss-for-tags.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Added atom feed for tags
-merge_request: 21428
-author:
-type: added
diff --git a/changelogs/unreleased/fj-33475-files-inside-wiki-repo.yml b/changelogs/unreleased/fj-33475-files-inside-wiki-repo.yml
deleted file mode 100644
index 8c1f0e3dbf2..00000000000
--- a/changelogs/unreleased/fj-33475-files-inside-wiki-repo.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Store wiki uploads inside git repository
-merge_request: 21362
-author:
-type: added
diff --git a/changelogs/unreleased/fj-47229-fix-logo-lfs-tracked.yml b/changelogs/unreleased/fj-47229-fix-logo-lfs-tracked.yml
deleted file mode 100644
index ed2af81f779..00000000000
--- a/changelogs/unreleased/fj-47229-fix-logo-lfs-tracked.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fixed bug when the project logo file is stored in LFS
-merge_request: 20948
-author:
-type: fixed
diff --git a/changelogs/unreleased/fj-51194-fix-wiki-attachments-with-whitespaces.yml b/changelogs/unreleased/fj-51194-fix-wiki-attachments-with-whitespaces.yml
deleted file mode 100644
index a6464807e01..00000000000
--- a/changelogs/unreleased/fj-51194-fix-wiki-attachments-with-whitespaces.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Replace white spaces in wiki attachments file names
-merge_request: 21569
-author:
-type: fixed
diff --git a/changelogs/unreleased/fl-reduce-ee-conflicts-reports-code.yml b/changelogs/unreleased/fl-reduce-ee-conflicts-reports-code.yml
deleted file mode 100644
index 068681dfe19..00000000000
--- a/changelogs/unreleased/fl-reduce-ee-conflicts-reports-code.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Reduce differences between CE and EE code base in reports components
-merge_request:
-author:
-type: other
diff --git a/changelogs/unreleased/force-post-migration-dir-schema-load.yml b/changelogs/unreleased/force-post-migration-dir-schema-load.yml
new file mode 100644
index 00000000000..19119515929
--- /dev/null
+++ b/changelogs/unreleased/force-post-migration-dir-schema-load.yml
@@ -0,0 +1,5 @@
+---
+title: Ensure the schema is loaded with post_migrations included
+merge_request: 21689
+author:
+type: changed
diff --git a/changelogs/unreleased/frozen-string-enable-app-vestigial.yml b/changelogs/unreleased/frozen-string-app-controller-more.yml
index 8cb7bd43784..ea2c81e7afc 100644
--- a/changelogs/unreleased/frozen-string-enable-app-vestigial.yml
+++ b/changelogs/unreleased/frozen-string-app-controller-more.yml
@@ -1,5 +1,5 @@
---
-title: Enable frozen string in vestigial app files
+title: Enable more frozen string in app/controllers/
merge_request:
author: gfyoung
type: performance
diff --git a/changelogs/unreleased/frozen-string-app-controller.yml b/changelogs/unreleased/frozen-string-app-controller.yml
new file mode 100644
index 00000000000..95fea4eae63
--- /dev/null
+++ b/changelogs/unreleased/frozen-string-app-controller.yml
@@ -0,0 +1,5 @@
+---
+title: Enable frozen string in app/controllers/**/*.rb
+merge_request: gfyoung
+author:
+type: performance
diff --git a/changelogs/unreleased/frozen-string-app-controllers-much-more.yml b/changelogs/unreleased/frozen-string-app-controllers-much-more.yml
new file mode 100644
index 00000000000..6e32d5ba039
--- /dev/null
+++ b/changelogs/unreleased/frozen-string-app-controllers-much-more.yml
@@ -0,0 +1,5 @@
+---
+title: Enable even more frozen string in app/controllers
+merge_request:
+author: gfyoung
+type: performance
diff --git a/changelogs/unreleased/frozen-string-app-enforce.yml b/changelogs/unreleased/frozen-string-app-enforce.yml
new file mode 100644
index 00000000000..44686557c45
--- /dev/null
+++ b/changelogs/unreleased/frozen-string-app-enforce.yml
@@ -0,0 +1,5 @@
+---
+title: Check frozen string in style builds
+merge_request:
+author: gfyoung
+type: other
diff --git a/changelogs/unreleased/frozen-string-docs.yml b/changelogs/unreleased/frozen-string-docs.yml
new file mode 100644
index 00000000000..2eb8a446ee8
--- /dev/null
+++ b/changelogs/unreleased/frozen-string-docs.yml
@@ -0,0 +1,5 @@
+---
+title: Update docs regarding frozen string
+merge_request:
+author: gfyoung
+type: other
diff --git a/changelogs/unreleased/frozen-string-enable-app-mailers.yml b/changelogs/unreleased/frozen-string-enable-app-mailers.yml
deleted file mode 100644
index 2cd247ca76c..00000000000
--- a/changelogs/unreleased/frozen-string-enable-app-mailers.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Enable frozen in app/mailers/**/*.rb
-merge_request: 21147
-author: gfyoung
-type: performance
diff --git a/changelogs/unreleased/frozen-string-enable-app-models-even-more-still.yml b/changelogs/unreleased/frozen-string-enable-app-models-even-more-still.yml
deleted file mode 100644
index a77f3baeed3..00000000000
--- a/changelogs/unreleased/frozen-string-enable-app-models-even-more-still.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Enable frozen string in rest of app/models/**/*.rb
-merge_request: gfyoung
-author:
-type: performance
diff --git a/changelogs/unreleased/gitaly-install-path.yml b/changelogs/unreleased/gitaly-install-path.yml
deleted file mode 100644
index 4b24cd81dc7..00000000000
--- a/changelogs/unreleased/gitaly-install-path.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Remove storage path dependency of gitaly install task
-merge_request: 21101
-author:
-type: changed
diff --git a/changelogs/unreleased/ide-commit-panel-improved.yml b/changelogs/unreleased/ide-commit-panel-improved.yml
deleted file mode 100644
index 245214185e5..00000000000
--- a/changelogs/unreleased/ide-commit-panel-improved.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Improved commit panel in Web IDE
-merge_request: 21471
-author:
-type: changed
diff --git a/changelogs/unreleased/ide-delete-new-files-state.yml b/changelogs/unreleased/ide-delete-new-files-state.yml
deleted file mode 100644
index 500115d19d0..00000000000
--- a/changelogs/unreleased/ide-delete-new-files-state.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fixed IDE deleting new files creating wrong state
-merge_request:
-author:
-type: fixed
diff --git a/changelogs/unreleased/ide-fetch-templates-pages.yml b/changelogs/unreleased/ide-fetch-templates-pages.yml
new file mode 100644
index 00000000000..d4703e530f2
--- /dev/null
+++ b/changelogs/unreleased/ide-fetch-templates-pages.yml
@@ -0,0 +1,5 @@
+---
+title: Fixed file templates not fully being fetched in Web IDE
+merge_request:
+author:
+type: fixed
diff --git a/changelogs/unreleased/ide-file-templates.yml b/changelogs/unreleased/ide-file-templates.yml
deleted file mode 100644
index 68983670b25..00000000000
--- a/changelogs/unreleased/ide-file-templates.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Added file templates to the Web IDE
-merge_request:
-author:
-type: added
diff --git a/changelogs/unreleased/ide-header-buttons-tooltip.yml b/changelogs/unreleased/ide-header-buttons-tooltip.yml
deleted file mode 100644
index 4c8f6fd554f..00000000000
--- a/changelogs/unreleased/ide-header-buttons-tooltip.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Added tooltips to tree list header
-merge_request: 21138
-author:
-type: added
diff --git a/changelogs/unreleased/ide-job-top-bar-ui-polish.yml b/changelogs/unreleased/ide-job-top-bar-ui-polish.yml
deleted file mode 100644
index d917c14e5f8..00000000000
--- a/changelogs/unreleased/ide-job-top-bar-ui-polish.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Improved styling of top bar in IDE job trace pane
-merge_request:
-author:
-type: changed
diff --git a/changelogs/unreleased/ide-multiple-file-uploads.yml b/changelogs/unreleased/ide-multiple-file-uploads.yml
deleted file mode 100644
index 6bb73739864..00000000000
--- a/changelogs/unreleased/ide-multiple-file-uploads.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Enabled multiple file uploads in the Web IDE
-merge_request:
-author:
-type: added
diff --git a/changelogs/unreleased/ide-open-empty-merge-request.yml b/changelogs/unreleased/ide-open-empty-merge-request.yml
deleted file mode 100644
index 05f2de5d31c..00000000000
--- a/changelogs/unreleased/ide-open-empty-merge-request.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fix empty merge requests not opening in the Web IDE
-merge_request: 21102
-author:
-type: fixed
diff --git a/changelogs/unreleased/ide-row-hover-scroll.yml b/changelogs/unreleased/ide-row-hover-scroll.yml
deleted file mode 100644
index 24c273b4f25..00000000000
--- a/changelogs/unreleased/ide-row-hover-scroll.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fixed IDE file row scrolling into view when hovering
-merge_request:
-author:
-type: fixed
diff --git a/changelogs/unreleased/import-all-common-metrics-into-database.yml b/changelogs/unreleased/import-all-common-metrics-into-database.yml
deleted file mode 100644
index 524112fe115..00000000000
--- a/changelogs/unreleased/import-all-common-metrics-into-database.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Import all common metrics into database
-merge_request: 21459
-author:
-type: changed
diff --git a/changelogs/unreleased/issue_36138.yml b/changelogs/unreleased/issue_36138.yml
deleted file mode 100644
index 2fb2eea65f5..00000000000
--- a/changelogs/unreleased/issue_36138.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Allow to delete group milestones
-merge_request:
-author:
-type: added
diff --git a/changelogs/unreleased/issue_50488.yml b/changelogs/unreleased/issue_50488.yml
deleted file mode 100644
index dad7ae55a0d..00000000000
--- a/changelogs/unreleased/issue_50488.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Move project services log to a separate file
-merge_request:
-author:
-type: other
diff --git a/changelogs/unreleased/jivl-fix-monitoring-dashboard-resizing-navbar.yml b/changelogs/unreleased/jivl-fix-monitoring-dashboard-resizing-navbar.yml
new file mode 100644
index 00000000000..c21301bf6b3
--- /dev/null
+++ b/changelogs/unreleased/jivl-fix-monitoring-dashboard-resizing-navbar.yml
@@ -0,0 +1,5 @@
+---
+title: Fix resizing of monitoring dashboard
+merge_request: 21730
+author:
+type: fixed
diff --git a/changelogs/unreleased/jprovazn-fix-form-uploads.yml b/changelogs/unreleased/jprovazn-fix-form-uploads.yml
deleted file mode 100644
index 8bcee335e93..00000000000
--- a/changelogs/unreleased/jprovazn-fix-form-uploads.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Accept upload files in public/uplaods/tmp when using accelerated uploads.
-merge_request:
-author:
-type: fixed
diff --git a/changelogs/unreleased/label-event.yml b/changelogs/unreleased/label-event.yml
deleted file mode 100644
index e543abe5649..00000000000
--- a/changelogs/unreleased/label-event.yml
+++ /dev/null
@@ -1,6 +0,0 @@
----
-title: Use separate model for tracking resource label changes and render label system
- notes based on data from this model.
-merge_request:
-author:
-type: added
diff --git a/changelogs/unreleased/leipert-fix-mr-widget-header-margins.yml b/changelogs/unreleased/leipert-fix-mr-widget-header-margins.yml
new file mode 100644
index 00000000000..9c23244d48b
--- /dev/null
+++ b/changelogs/unreleased/leipert-fix-mr-widget-header-margins.yml
@@ -0,0 +1,5 @@
+---
+title: Fix merge request header margins
+merge_request: 21878
+author:
+type: other
diff --git a/changelogs/unreleased/limit-navbar-search-for-current-project-or-group-for-small-viewports.yml b/changelogs/unreleased/limit-navbar-search-for-current-project-or-group-for-small-viewports.yml
deleted file mode 100644
index 09d97d200de..00000000000
--- a/changelogs/unreleased/limit-navbar-search-for-current-project-or-group-for-small-viewports.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Limit navbar search for current project or group for small viewports
-merge_request: 18634
-author: George Tsiolis
-type: changed
diff --git a/changelogs/unreleased/sh-set-secure-cookies.yml b/changelogs/unreleased/mk-asymmetric-exists-cache.yml
index da741288b42..b6eec7d1fc6 100644
--- a/changelogs/unreleased/sh-set-secure-cookies.yml
+++ b/changelogs/unreleased/mk-asymmetric-exists-cache.yml
@@ -1,5 +1,6 @@
---
-title: Set issuable_sort, diff_view, and perf_bar_enabled cookies to secure when possible
-merge_request: 21442
+title: 'Resolve "Geo: Does not mark repositories as missing on primary due to stale
+ cache"'
+merge_request: 21789
author:
-type: security
+type: fixed
diff --git a/changelogs/unreleased/mk-bump-rainbow-gem.yml b/changelogs/unreleased/mk-bump-rainbow-gem.yml
deleted file mode 100644
index 31c003fb4d9..00000000000
--- a/changelogs/unreleased/mk-bump-rainbow-gem.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fix bin/secpick error and security branch prefixing
-merge_request: 21210
-author:
-type: fixed
diff --git a/changelogs/unreleased/monaco-upgrade.yml b/changelogs/unreleased/monaco-upgrade.yml
deleted file mode 100644
index ec441ba182b..00000000000
--- a/changelogs/unreleased/monaco-upgrade.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Upgrade Monaco editor
-merge_request:
-author:
-type: other
diff --git a/changelogs/unreleased/more-table-widths.yml b/changelogs/unreleased/more-table-widths.yml
new file mode 100644
index 00000000000..61956e7068e
--- /dev/null
+++ b/changelogs/unreleased/more-table-widths.yml
@@ -0,0 +1,5 @@
+---
+title: Adds an extra width to the responsive tables
+merge_request: 21928
+author:
+type: other
diff --git a/changelogs/unreleased/mr-fixed-expanded-state-not-working.yml b/changelogs/unreleased/mr-fixed-expanded-state-not-working.yml
deleted file mode 100644
index b8bf8306546..00000000000
--- a/changelogs/unreleased/mr-fixed-expanded-state-not-working.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fixed resolved discussions not toggling expanded state on changes tab
-merge_request: 21676
-author:
-type: fixed
diff --git a/changelogs/unreleased/mr-legacy-diff-notes.yml b/changelogs/unreleased/mr-legacy-diff-notes.yml
new file mode 100644
index 00000000000..bca5ac8297f
--- /dev/null
+++ b/changelogs/unreleased/mr-legacy-diff-notes.yml
@@ -0,0 +1,5 @@
+---
+title: Correctly show legacy diff notes in the merge request changes tab
+merge_request: 21652
+author:
+type: fixed
diff --git a/changelogs/unreleased/mr-widget-discussion-state-fix.yml b/changelogs/unreleased/mr-widget-discussion-state-fix.yml
new file mode 100644
index 00000000000..562d78a7aa7
--- /dev/null
+++ b/changelogs/unreleased/mr-widget-discussion-state-fix.yml
@@ -0,0 +1,5 @@
+---
+title: Fixed merge request widget discussion state not updating after resolving discussions
+merge_request: 21705
+author:
+type: fixed
diff --git a/changelogs/unreleased/n8rzz-consolidate-specs-testing-emoji-awards.yml b/changelogs/unreleased/n8rzz-consolidate-specs-testing-emoji-awards.yml
deleted file mode 100644
index bcf3d2c8e16..00000000000
--- a/changelogs/unreleased/n8rzz-consolidate-specs-testing-emoji-awards.yml
+++ /dev/null
@@ -1,6 +0,0 @@
----
-title: Combines emoji award spec files into single user_interacts_with_awards_in_issue_spec.rb
- file
-merge_request: 21126
-author: Nate Geslin
-type: other
diff --git a/changelogs/unreleased/osw-clean-up-phase-for-diff-files-removal.yml b/changelogs/unreleased/osw-clean-up-phase-for-diff-files-removal.yml
new file mode 100644
index 00000000000..03189d934a7
--- /dev/null
+++ b/changelogs/unreleased/osw-clean-up-phase-for-diff-files-removal.yml
@@ -0,0 +1,5 @@
+---
+title: Add clean-up phase for ScheduleDiffFilesDeletion migration
+merge_request: 21734
+author:
+type: other
diff --git a/changelogs/unreleased/osw-gitaly-diff-stats-client.yml b/changelogs/unreleased/osw-gitaly-diff-stats-client.yml
new file mode 100644
index 00000000000..9f280162409
--- /dev/null
+++ b/changelogs/unreleased/osw-gitaly-diff-stats-client.yml
@@ -0,0 +1,5 @@
+---
+title: Add Gitaly diff stats RPC client
+merge_request: 21732
+author:
+type: changed
diff --git a/changelogs/unreleased/osw-send-max-patch-bytes-to-gitaly.yml b/changelogs/unreleased/osw-send-max-patch-bytes-to-gitaly.yml
deleted file mode 100644
index 3c50448e3ff..00000000000
--- a/changelogs/unreleased/osw-send-max-patch-bytes-to-gitaly.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Send max_patch_bytes to Gitaly via Gitaly::CommitDiffRequest
-merge_request: 21575
-author:
-type: other
diff --git a/changelogs/unreleased/osw-use-diff-stats-rpc-on-comparison-views.yml b/changelogs/unreleased/osw-use-diff-stats-rpc-on-comparison-views.yml
new file mode 100644
index 00000000000..c71d4e58d6f
--- /dev/null
+++ b/changelogs/unreleased/osw-use-diff-stats-rpc-on-comparison-views.yml
@@ -0,0 +1,5 @@
+---
+title: Use stats RPC when comparing diffs
+merge_request: 21778
+author:
+type: fixed
diff --git a/changelogs/unreleased/osw-write-cache-upon-mr-creation-and-cache-refactoring.yml b/changelogs/unreleased/osw-write-cache-upon-mr-creation-and-cache-refactoring.yml
deleted file mode 100644
index 4fba33decfa..00000000000
--- a/changelogs/unreleased/osw-write-cache-upon-mr-creation-and-cache-refactoring.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Write diff highlighting cache upon MR creation (refactors caching)
-merge_request: 21489
-author:
-type: performance
diff --git a/changelogs/unreleased/pedroms-master-patch-57786.yml b/changelogs/unreleased/pedroms-master-patch-57786.yml
new file mode 100644
index 00000000000..cdf179046aa
--- /dev/null
+++ b/changelogs/unreleased/pedroms-master-patch-57786.yml
@@ -0,0 +1,5 @@
+---
+title: Fix blue, orange, and red color inconsistencies
+merge_request: 21972
+author:
+type: other
diff --git a/changelogs/unreleased/rails5-explicit-hashed-path-check.yml b/changelogs/unreleased/rails5-explicit-hashed-path-check.yml
deleted file mode 100644
index 93fe4a38411..00000000000
--- a/changelogs/unreleased/rails5-explicit-hashed-path-check.yml
+++ /dev/null
@@ -1,6 +0,0 @@
----
-title: Explicit hashed path check for trace, prevents background migration from accessing
- file_location column that doesn't exist
-merge_request: 21533
-author: Jasper Maes
-type: other
diff --git a/changelogs/unreleased/rails5-fix-duplicate-gpg-signature.yml b/changelogs/unreleased/rails5-fix-duplicate-gpg-signature.yml
deleted file mode 100644
index e31768773b1..00000000000
--- a/changelogs/unreleased/rails5-fix-duplicate-gpg-signature.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Rails5 fix specs duplicate key value violates unique constraint 'index_gpg_signatures_on_commit_sha'
-merge_request: 21119
-author: Jasper Maes
-type: fixed
diff --git a/changelogs/unreleased/rails5-fix-import-merge-request-creator.yml b/changelogs/unreleased/rails5-fix-import-merge-request-creator.yml
deleted file mode 100644
index 661bd748333..00000000000
--- a/changelogs/unreleased/rails5-fix-import-merge-request-creator.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: 'Rails5: fix can''t quote ActiveSupport::HashWithIndifferentAccess'
-merge_request: 21397
-author: Jasper Maes
-type: other
diff --git a/changelogs/unreleased/rails5-fix-job-artifact-hashed-path.yml b/changelogs/unreleased/rails5-fix-job-artifact-hashed-path.yml
deleted file mode 100644
index a70bfafb1c9..00000000000
--- a/changelogs/unreleased/rails5-fix-job-artifact-hashed-path.yml
+++ /dev/null
@@ -1,6 +0,0 @@
----
-title: 'Rails 5: fix hashed_path? method that looks up file_location that doesn''t
- exist when running certain migration specs'
-merge_request: 21510
-author: Jasper Maes
-type: other
diff --git a/changelogs/unreleased/rails5-include-opclasses-in-schema-dump.yml b/changelogs/unreleased/rails5-include-opclasses-in-schema-dump.yml
deleted file mode 100644
index 2dea84bc266..00000000000
--- a/changelogs/unreleased/rails5-include-opclasses-in-schema-dump.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: 'Rails 5: include opclasses in rails 5 schema dump'
-merge_request: 21416
-author: Jasper Maes
-type: fixed
diff --git a/changelogs/unreleased/rails5-mysql-binary-column-index-length.yml b/changelogs/unreleased/rails5-mysql-binary-column-index-length.yml
deleted file mode 100644
index c4eb0ddac4c..00000000000
--- a/changelogs/unreleased/rails5-mysql-binary-column-index-length.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: 'Rails 5: support schema t.index for mysql'
-merge_request: 21485
-author: Jasper Maes
-type: other
diff --git a/changelogs/unreleased/rails5-silence-stream.yml b/changelogs/unreleased/rails5-silence-stream.yml
deleted file mode 100644
index df4fd14a077..00000000000
--- a/changelogs/unreleased/rails5-silence-stream.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-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
deleted file mode 100644
index 3891b16e2b8..00000000000
--- a/changelogs/unreleased/rails5-update-gemfile-lock.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Rails5 update Gemfile.rails5.lock
-merge_request: 21388
-author: Jasper Maes
-type: other
diff --git a/changelogs/unreleased/rails5-verbose-query-logs.yml b/changelogs/unreleased/rails5-verbose-query-logs.yml
deleted file mode 100644
index 7585e75d30b..00000000000
--- a/changelogs/unreleased/rails5-verbose-query-logs.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: 'Rails5: Enable verbose query logs'
-merge_request: 21231
-author: Jasper Maes
-type: other
diff --git a/changelogs/unreleased/rd-26044-new-option-to-prevent-too-big-git-pushes.yml b/changelogs/unreleased/rd-26044-new-option-to-prevent-too-big-git-pushes.yml
deleted file mode 100644
index f464b6dda5b..00000000000
--- a/changelogs/unreleased/rd-26044-new-option-to-prevent-too-big-git-pushes.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Allow admins to configure the maximum Git push size
-merge_request: 20758
-author:
-type: added
diff --git a/changelogs/unreleased/remove-background-migration-worker-feature-flag.yml b/changelogs/unreleased/remove-background-migration-worker-feature-flag.yml
deleted file mode 100644
index 429ab6c59e3..00000000000
--- a/changelogs/unreleased/remove-background-migration-worker-feature-flag.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Remove health check feature flag in BackgroundMigrationWorker
-merge_request:
-author:
-type: changed
diff --git a/changelogs/unreleased/remove-zebra-table-background.yml b/changelogs/unreleased/remove-zebra-table-background.yml
deleted file mode 100644
index dafba72035d..00000000000
--- a/changelogs/unreleased/remove-zebra-table-background.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Remove striped table styling of Find files and Admin Area Applications views
-merge_request: 21560
-author: Andreas Kämmerle
-type: other
diff --git a/changelogs/unreleased/rename-local-variable.yml b/changelogs/unreleased/rename-local-variable.yml
new file mode 100644
index 00000000000..70281dfef08
--- /dev/null
+++ b/changelogs/unreleased/rename-local-variable.yml
@@ -0,0 +1,5 @@
+---
+title: Rename block scope local variable in table pagination spec
+merge_request: 21969
+author: George Tsiolis
+type: other
diff --git a/changelogs/unreleased/rename-squash-before-merge-vue-component.yml b/changelogs/unreleased/rename-squash-before-merge-vue-component.yml
new file mode 100644
index 00000000000..66eeeb225dd
--- /dev/null
+++ b/changelogs/unreleased/rename-squash-before-merge-vue-component.yml
@@ -0,0 +1,5 @@
+---
+title: Rename squash before merge vue component
+merge_request: 21851
+author: George Tsiolis
+type: other
diff --git a/changelogs/unreleased/repopulate_site_statistics.yml b/changelogs/unreleased/repopulate_site_statistics.yml
deleted file mode 100644
index 1961088061d..00000000000
--- a/changelogs/unreleased/repopulate_site_statistics.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Migrate NULL wiki_access_level to correct number so we count active wikis correctly
-merge_request: 21030
-author:
-type: changed
diff --git a/changelogs/unreleased/runners-online.yml b/changelogs/unreleased/runners-online.yml
deleted file mode 100644
index a732d9cb723..00000000000
--- a/changelogs/unreleased/runners-online.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Clarify current runners online text
-merge_request: 21151
-author: Ben Bodenmiller
-type: other
diff --git a/changelogs/unreleased/schema-changed-ee-backport.yml b/changelogs/unreleased/schema-changed-ee-backport.yml
deleted file mode 100644
index f3b16fc0c27..00000000000
--- a/changelogs/unreleased/schema-changed-ee-backport.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Backport schema_changed.sh from EE which prints the diff if the schema is different
-merge_request: 21422
-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
deleted file mode 100644
index dc15d356c1c..00000000000
--- a/changelogs/unreleased/security-49085-persistent-xss-rendering.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fixed persistent XSS rendering/escaping of diff location lines
-merge_request:
-author:
-type: security
diff --git a/changelogs/unreleased/sh-add-ua-to-lograge-logs.yml b/changelogs/unreleased/sh-add-ua-to-lograge-logs.yml
deleted file mode 100644
index eec55bd3a24..00000000000
--- a/changelogs/unreleased/sh-add-ua-to-lograge-logs.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Add User-Agent to production_json.log
-merge_request: 21546
-author:
-type: other
diff --git a/changelogs/unreleased/sh-block-link-local-master.yml b/changelogs/unreleased/sh-block-link-local-master.yml
deleted file mode 100644
index 0a6017479af..00000000000
--- a/changelogs/unreleased/sh-block-link-local-master.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Block link-local addresses in URLBlocker
-merge_request:
-author:
-type: security
diff --git a/changelogs/unreleased/sh-bump-fog-google.yml b/changelogs/unreleased/sh-bump-fog-google.yml
deleted file mode 100644
index b5fa55e53a5..00000000000
--- a/changelogs/unreleased/sh-bump-fog-google.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Bump fog-google to 1.7.0 and google-api-client to 0.23.0
-merge_request: 21295
-author:
-type: fixed
diff --git a/changelogs/unreleased/sh-bump-gitlab-pages-v1-1-0.yml b/changelogs/unreleased/sh-bump-gitlab-pages-v1-1-0.yml
deleted file mode 100644
index bc5b6b36ac5..00000000000
--- a/changelogs/unreleased/sh-bump-gitlab-pages-v1-1-0.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Bump GitLab Pages to v1.1.0
-merge_request: 21419
-author:
-type: fixed
diff --git a/changelogs/unreleased/sh-bump-unauth-expiration.yml b/changelogs/unreleased/sh-bump-unauth-expiration.yml
deleted file mode 100644
index 107069f3b30..00000000000
--- a/changelogs/unreleased/sh-bump-unauth-expiration.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Bump unauthenticated session time from 1 hour to 2 hours
-merge_request: 21453
-author:
-type: other
diff --git a/changelogs/unreleased/sh-delete-container-registry-async.yml b/changelogs/unreleased/sh-delete-container-registry-async.yml
deleted file mode 100644
index dfe0e812112..00000000000
--- a/changelogs/unreleased/sh-delete-container-registry-async.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Delete a container registry asynchronously
-merge_request: 21553
-author:
-type: fixed
diff --git a/changelogs/unreleased/sh-delete-tags-outside-transaction.yml b/changelogs/unreleased/sh-delete-tags-outside-transaction.yml
new file mode 100644
index 00000000000..974da70251e
--- /dev/null
+++ b/changelogs/unreleased/sh-delete-tags-outside-transaction.yml
@@ -0,0 +1,5 @@
+---
+title: Delete container repository tags outside of transaction
+merge_request: 21679
+author:
+type: fixed
diff --git a/changelogs/unreleased/sh-disable-sidekiq-session.yml b/changelogs/unreleased/sh-disable-sidekiq-session.yml
deleted file mode 100644
index d018bbed841..00000000000
--- a/changelogs/unreleased/sh-disable-sidekiq-session.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Disable the Sidekiq Admin Rack session
-merge_request: 21441
-author:
-type: security
diff --git a/changelogs/unreleased/sh-disable-unnecessary-avatar-revalidation.yml b/changelogs/unreleased/sh-disable-unnecessary-avatar-revalidation.yml
deleted file mode 100644
index 386410484fe..00000000000
--- a/changelogs/unreleased/sh-disable-unnecessary-avatar-revalidation.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Disable project avatar validation if avatar has not changed
-merge_request:
-author:
-type: performance
diff --git a/changelogs/unreleased/sh-fix-attachments-inline.yml b/changelogs/unreleased/sh-fix-attachments-inline.yml
deleted file mode 100644
index 2926edca97a..00000000000
--- a/changelogs/unreleased/sh-fix-attachments-inline.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fix attachments not displaying inline with Google Cloud Storage
-merge_request: 21265
-author:
-type: fixed
diff --git a/changelogs/unreleased/sh-fix-bitbucket-cloud-importer-replies.yml b/changelogs/unreleased/sh-fix-bitbucket-cloud-importer-replies.yml
deleted file mode 100644
index 3f7044833f1..00000000000
--- a/changelogs/unreleased/sh-fix-bitbucket-cloud-importer-replies.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fix Bitbucket Cloud importer omitting replies
-merge_request: 21076
-author:
-type: fixed
diff --git a/changelogs/unreleased/sh-fix-confidential-note-option.yml b/changelogs/unreleased/sh-fix-confidential-note-option.yml
deleted file mode 100644
index 14d70281760..00000000000
--- a/changelogs/unreleased/sh-fix-confidential-note-option.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fix "Confidential comments" button not saving in project hooks
-merge_request: 21289
-author:
-type: fixed
diff --git a/changelogs/unreleased/sh-fix-dedupe-group-importer.yml b/changelogs/unreleased/sh-fix-dedupe-group-importer.yml
deleted file mode 100644
index 1b874c64718..00000000000
--- a/changelogs/unreleased/sh-fix-dedupe-group-importer.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fix importers not assigning a new default group
-merge_request: 21456
-author:
-type: fixed
diff --git a/changelogs/unreleased/sh-fix-error-500-updating-wikis.yml b/changelogs/unreleased/sh-fix-error-500-updating-wikis.yml
deleted file mode 100644
index d80d4952ba5..00000000000
--- a/changelogs/unreleased/sh-fix-error-500-updating-wikis.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fix Error 500s due to encoding issues when Wiki hooks fire
-merge_request: 21414
-author:
-type: fixed
diff --git a/changelogs/unreleased/sh-fix-forks-with-no-gravatar.yml b/changelogs/unreleased/sh-fix-forks-with-no-gravatar.yml
new file mode 100644
index 00000000000..f18e6207b87
--- /dev/null
+++ b/changelogs/unreleased/sh-fix-forks-with-no-gravatar.yml
@@ -0,0 +1,5 @@
+---
+title: Fix Error 500 when forking projects with Gravatar disabled
+merge_request:
+author:
+type: fixed
diff --git a/changelogs/unreleased/sh-fix-issue-50562.yml b/changelogs/unreleased/sh-fix-issue-50562.yml
deleted file mode 100644
index a207dd28622..00000000000
--- a/changelogs/unreleased/sh-fix-issue-50562.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fix remote mirrors failing if Git remotes have not been added
-merge_request: 21351
-author:
-type: fixed
diff --git a/changelogs/unreleased/sh-fix-issue-52009.yml b/changelogs/unreleased/sh-fix-issue-52009.yml
new file mode 100644
index 00000000000..fc22a58a66a
--- /dev/null
+++ b/changelogs/unreleased/sh-fix-issue-52009.yml
@@ -0,0 +1,5 @@
+---
+title: Prevent Error 500s with invalid relative links
+merge_request: 22001
+author:
+type: fixed
diff --git a/changelogs/unreleased/sh-guard-against-ldap-login-csrf-fail.yml b/changelogs/unreleased/sh-guard-against-ldap-login-csrf-fail.yml
new file mode 100644
index 00000000000..7233f6f3d7b
--- /dev/null
+++ b/changelogs/unreleased/sh-guard-against-ldap-login-csrf-fail.yml
@@ -0,0 +1,5 @@
+---
+title: Guard against a login attempt with invalid CSRF token
+merge_request: 21934
+author:
+type: fixed
diff --git a/changelogs/unreleased/sh-improve-bitbucket-server-logging.yml b/changelogs/unreleased/sh-improve-bitbucket-server-logging.yml
deleted file mode 100644
index c94ff959f1c..00000000000
--- a/changelogs/unreleased/sh-improve-bitbucket-server-logging.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Add JSON logging for Bitbucket Server importer
-merge_request: 21378
-author:
-type: other
diff --git a/changelogs/unreleased/sh-insert-git-data-in-separate-transaction.yml b/changelogs/unreleased/sh-insert-git-data-in-separate-transaction.yml
deleted file mode 100644
index 116929b2f53..00000000000
--- a/changelogs/unreleased/sh-insert-git-data-in-separate-transaction.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-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
deleted file mode 100644
index c44c67bcc90..00000000000
--- a/changelogs/unreleased/sh-limit-commit-renderering.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Speed up diff comparisons by limiting number of commit messages rendered
-merge_request: 21335
-author:
-type: performance
diff --git a/changelogs/unreleased/sh-remove-orphaned-label-links.yml b/changelogs/unreleased/sh-remove-orphaned-label-links.yml
deleted file mode 100644
index b035b57ff1b..00000000000
--- a/changelogs/unreleased/sh-remove-orphaned-label-links.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Remove orphaned label links
-merge_request: 21552
-author:
-type: fixed
diff --git a/changelogs/unreleased/sh-sanitize-project-import-names.yml b/changelogs/unreleased/sh-sanitize-project-import-names.yml
deleted file mode 100644
index 6e0284bda08..00000000000
--- a/changelogs/unreleased/sh-sanitize-project-import-names.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Use slugs for default project path and sanitize names before import
-merge_request: 21367
-author:
-type: fixed
diff --git a/changelogs/unreleased/sh-send-put-headers-object-storage.yml b/changelogs/unreleased/sh-send-put-headers-object-storage.yml
deleted file mode 100644
index cbd8b6deb5b..00000000000
--- a/changelogs/unreleased/sh-send-put-headers-object-storage.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Send back required object storage PUT headers in /uploads/authorize API
-merge_request: 21319
-author:
-type: changed
diff --git a/changelogs/unreleased/skip-irrelevant-sql-commands-in-metrics.yml b/changelogs/unreleased/skip-irrelevant-sql-commands-in-metrics.yml
deleted file mode 100644
index 56d236d0029..00000000000
--- a/changelogs/unreleased/skip-irrelevant-sql-commands-in-metrics.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Ignore irrelevant sql commands in metrics
-merge_request: 21498
-author:
-type: other
diff --git a/changelogs/unreleased/tc-api-fork-owners.yml b/changelogs/unreleased/tc-api-fork-owners.yml
deleted file mode 100644
index feaa3c1705e..00000000000
--- a/changelogs/unreleased/tc-api-fork-owners.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Allow project owners to set up forking relation through API
-merge_request: 18104
-author:
-type: changed
diff --git a/changelogs/unreleased/toon-copy-meta-data-fix.yml b/changelogs/unreleased/toon-copy-meta-data-fix.yml
new file mode 100644
index 00000000000..f2f8a1a82a4
--- /dev/null
+++ b/changelogs/unreleased/toon-copy-meta-data-fix.yml
@@ -0,0 +1,5 @@
+---
+title: Allow /copy_metadata for new issues and MRs
+merge_request: 21953
+author:
+type: changed
diff --git a/changelogs/unreleased/tz-mr-incremental-rendering.yml b/changelogs/unreleased/tz-mr-incremental-rendering.yml
deleted file mode 100644
index a35fa200363..00000000000
--- a/changelogs/unreleased/tz-mr-incremental-rendering.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-title: Incremental rendering with Vue on merge request page
-merge_request: 21063
-author:
-type: performance
diff --git a/changelogs/unreleased/update-gitlab-shell-8-3-3.yml b/changelogs/unreleased/update-gitlab-shell-8-3-3.yml
deleted file mode 100644
index 3f9cca59528..00000000000
--- a/changelogs/unreleased/update-gitlab-shell-8-3-3.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Update GitLab Shell to v8.3.3
-merge_request: 21750
-author:
-type: fixed
diff --git a/changelogs/unreleased/update-gitlab-shell.yml b/changelogs/unreleased/update-gitlab-shell.yml
deleted file mode 100644
index f5d0e30a7be..00000000000
--- a/changelogs/unreleased/update-gitlab-shell.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Update GitLab Shell to v8.3.2
-merge_request: 21701
-author:
-type: fixed
diff --git a/changelogs/unreleased/update-padding-markdown.yml b/changelogs/unreleased/update-padding-markdown.yml
deleted file mode 100644
index 51037200bd1..00000000000
--- a/changelogs/unreleased/update-padding-markdown.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Increase padding in code blocks
-merge_request:
-author:
-type: fixed
diff --git a/changelogs/unreleased/usage_consent.yml b/changelogs/unreleased/usage_consent.yml
deleted file mode 100644
index 56e00879b9a..00000000000
--- a/changelogs/unreleased/usage_consent.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Ask user explicitly about usage stats agreement on single user deployments.
-merge_request: 21423
-author:
-type: added
diff --git a/changelogs/unreleased/vendor-gitlab-ci-auto-devops-yml.yml b/changelogs/unreleased/vendor-gitlab-ci-auto-devops-yml.yml
new file mode 100644
index 00000000000..98d0e24c00a
--- /dev/null
+++ b/changelogs/unreleased/vendor-gitlab-ci-auto-devops-yml.yml
@@ -0,0 +1,5 @@
+---
+title: Make AutoDevOps work behind proxy
+merge_request: 21775
+author: Sergej - @kinolaev
+type: other
diff --git a/changelogs/unreleased/visual-improvements-language-bar.yml b/changelogs/unreleased/visual-improvements-language-bar.yml
deleted file mode 100644
index 23cae22b962..00000000000
--- a/changelogs/unreleased/visual-improvements-language-bar.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Improve visuals of language bar on projects
-merge_request: 21006
-author:
-type: changed
diff --git a/changelogs/unreleased/winh-default-status-emoji.yml b/changelogs/unreleased/winh-default-status-emoji.yml
deleted file mode 100644
index 00cca4db0a6..00000000000
--- a/changelogs/unreleased/winh-default-status-emoji.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Display default status emoji if only message is entered
-merge_request: 21330
-author:
-type: changed
diff --git a/changelogs/unreleased/winh-move-badge-settings.yml b/changelogs/unreleased/winh-move-badge-settings.yml
deleted file mode 100644
index 9638ba04c1e..00000000000
--- a/changelogs/unreleased/winh-move-badge-settings.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Move badge settings to general settings
-merge_request: 21333
-author:
-type: changed
diff --git a/changelogs/unreleased/winh-page-title-margin.yml b/changelogs/unreleased/winh-page-title-margin.yml
new file mode 100644
index 00000000000..f21f07d396b
--- /dev/null
+++ b/changelogs/unreleased/winh-page-title-margin.yml
@@ -0,0 +1,5 @@
+---
+title: Change vertical margin of page titles to 16px
+merge_request: 21888
+author:
+type: changed
diff --git a/changelogs/unreleased/zj-cleanup-port-gitaly.yml b/changelogs/unreleased/zj-cleanup-port-gitaly.yml
deleted file mode 100644
index 25e13b0fd50..00000000000
--- a/changelogs/unreleased/zj-cleanup-port-gitaly.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Administrative cleanup rake tasks now leverage Gitaly
-merge_request: 21588
-author:
-type: changed
diff --git a/config/application.rb b/config/application.rb
index f3c53fa63f3..9074cf02c46 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -134,6 +134,7 @@ module Gitlab
config.assets.precompile << "notify.css"
config.assets.precompile << "mailers/*.css"
config.assets.precompile << "page_bundles/ide.css"
+ config.assets.precompile << "page_bundles/xterm.css"
config.assets.precompile << "performance_bar.css"
config.assets.precompile << "lib/ace.js"
config.assets.precompile << "test.css"
@@ -204,7 +205,7 @@ module Gitlab
ENV['GITLAB_PATH_OUTSIDE_HOOK'] = ENV['PATH']
ENV['GIT_TERMINAL_PROMPT'] = '0'
- # Gitlab Read-only middleware support
+ # GitLab Read-only middleware support
config.middleware.insert_after ActionDispatch::Flash, ::Gitlab::Middleware::ReadOnly
config.generators do |g|
diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example
index fdaf6a6472d..67337f4b82f 100644
--- a/config/gitlab.yml.example
+++ b/config/gitlab.yml.example
@@ -760,8 +760,8 @@ test:
host: localhost
port: 80
- # When you run tests we clone and setup gitlab-shell
- # In order to setup it correctly you need to specify
+ # When you run tests we clone and set up gitlab-shell
+ # In order to set it up correctly you need to specify
# your system username you use to run GitLab
# user: YOUR_USERNAME
pages:
diff --git a/config/initializers/0_post_deployment_migrations.rb b/config/initializers/0_post_deployment_migrations.rb
index 3d81b869b52..2d647f72840 100644
--- a/config/initializers/0_post_deployment_migrations.rb
+++ b/config/initializers/0_post_deployment_migrations.rb
@@ -1,14 +1,4 @@
# Post deployment migrations are included by default. This file must be loaded
# before other initializers as Rails may otherwise memoize a list of migrations
# excluding the post deployment migrations.
-unless ENV['SKIP_POST_DEPLOYMENT_MIGRATIONS']
- Rails.application.config.paths['db'].each do |db_path|
- path = Rails.root.join(db_path, 'post_migrate').to_s
-
- Rails.application.config.paths['db/migrate'] << path
-
- # Rails memoizes migrations at certain points where it won't read the above
- # path just yet. As such we must also update the following list of paths.
- ActiveRecord::Migrator.migrations_paths << path
- end
-end
+Gitlab::Database.add_post_migrate_path_to_rails
diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb
index c41b2db722c..179e00cdbd0 100644
--- a/config/initializers/devise.rb
+++ b/config/initializers/devise.rb
@@ -71,7 +71,7 @@ Devise.setup do |config|
# a value less than 10 in other environments.
config.stretches = Rails.env.test? ? 1 : 10
- # Setup a pepper to generate the encrypted password.
+ # Set up a pepper to generate the encrypted password.
# config.pepper = "2ef62d549c4ff98a5d3e0ba211e72cff592060247e3bbbb9f499af1222f876f53d39b39b823132affb32858168c79c1d7741d26499901b63c6030a42129924ef"
# ==> Configuration for :confirmable
diff --git a/config/initializers/postgresql_opclasses_support.rb b/config/initializers/postgresql_opclasses_support.rb
index 12a0770a455..07b06629dea 100644
--- a/config/initializers/postgresql_opclasses_support.rb
+++ b/config/initializers/postgresql_opclasses_support.rb
@@ -208,5 +208,9 @@ module ActiveRecord
index_parts << "comment: #{index.comment.inspect}" if Gitlab.rails5? && index.comment
index_parts
end
+
+ def format_options(options)
+ options.map { |key, value| "#{key}: #{value.inspect}" }.join(", ")
+ end
end
end
diff --git a/config/initializers/sidekiq.rb b/config/initializers/sidekiq.rb
index 476eaabfed8..6c1079faad1 100644
--- a/config/initializers/sidekiq.rb
+++ b/config/initializers/sidekiq.rb
@@ -55,8 +55,6 @@ Sidekiq.configure_server do |config|
end
Sidekiq::Cron::Job.load_from_hash! cron_jobs
- Gitlab::SidekiqThrottler.execute!
-
Gitlab::SidekiqVersioning.install!
config = Gitlab::Database.config ||
diff --git a/config/initializers/warden.rb b/config/initializers/warden.rb
index 33f55069c3e..1d2bb2bce0a 100644
--- a/config/initializers/warden.rb
+++ b/config/initializers/warden.rb
@@ -31,6 +31,11 @@ Rails.application.configure do |config|
Warden::Manager.before_logout(scope: :user) do |user, auth, opts|
user ||= auth.user
+
+ # Rails CSRF protection may attempt to log out a user before that
+ # user even logs in
+ next unless user
+
activity = Gitlab::Auth::Activity.new(opts)
tracker = Gitlab::Auth::BlockedUserTracker.new(user, auth)
diff --git a/config/routes/admin.rb b/config/routes/admin.rb
index fa1f79a90be..7489b01ded6 100644
--- a/config/routes/admin.rb
+++ b/config/routes/admin.rb
@@ -110,6 +110,7 @@ namespace :admin do
put :reset_runners_token
put :reset_health_check_token
put :clear_repository_check_states
+ get :integrations, :repository, :templates, :ci_cd, :reporting, :metrics_and_profiling, :network, :geo, :preferences
end
resources :labels
diff --git a/config/routes/instance_statistics.rb b/config/routes/instance_statistics.rb
index 824ef47cda3..1102ef6b017 100644
--- a/config/routes/instance_statistics.rb
+++ b/config/routes/instance_statistics.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
namespace :instance_statistics do
- root to: redirect('/-/instance_statistics/conversational_development_index')
+ root to: redirect('-/instance_statistics/conversational_development_index')
resources :cohorts, only: :index
resources :conversational_development_index, only: :index
diff --git a/config/routes/wiki.rb b/config/routes/wiki.rb
index cd3828b743c..1a07b1c206b 100644
--- a/config/routes/wiki.rb
+++ b/config/routes/wiki.rb
@@ -2,7 +2,7 @@ scope(controller: :wikis) do
scope(path: 'wikis', as: :wikis) do
get :git_access
get :pages
- get '/', to: redirect('/%{namespace_id}/%{project_id}/wikis/home')
+ get '/', to: redirect('%{namespace_id}/%{project_id}/wikis/home')
post '/', to: 'wikis#create'
end
diff --git a/danger/commit_messages/Dangerfile b/danger/commit_messages/Dangerfile
index e982e8ed7c5..c5ebb9b457e 100644
--- a/danger/commit_messages/Dangerfile
+++ b/danger/commit_messages/Dangerfile
@@ -1,5 +1,7 @@
# frozen_string_literal: true
+require 'json'
+
# rubocop: disable Style/SignalException
# rubocop: disable Metrics/CyclomaticComplexity
# rubocop: disable Metrics/PerceivedComplexity
@@ -8,10 +10,38 @@
# https://github.com/jonallured/danger-commit_lint because its output is not
# very helpful, and it doesn't offer the means of ignoring merge commits.
+class EmojiChecker
+ DIGESTS = File.expand_path('../../fixtures/emojis/digests.json', __dir__)
+ ALIASES = File.expand_path('../../fixtures/emojis/aliases.json', __dir__)
+
+ # A regex that indicates a piece of text _might_ include an Emoji. The regex
+ # alone is not enough, as we'd match `:foo:bar:baz`. Instead, we use this
+ # regex to save us from having to check for all possible emoji names when we
+ # know one definitely is not included.
+ LIKELY_EMOJI = /:[\+a-z0-9_\-]+:/
+
+ def initialize
+ names = JSON.parse(File.read(DIGESTS)).keys +
+ JSON.parse(File.read(ALIASES)).keys
+
+ @emoji = names.map { |name| ":#{name}:" }
+ end
+
+ def includes_emoji?(text)
+ return false unless text.match?(LIKELY_EMOJI)
+
+ @emoji.any? { |emoji| text.include?(emoji) }
+ end
+end
+
def fail_commit(commit, message)
fail("#{commit.sha}: #{message}")
end
+def warn_commit(commit, message)
+ warn("#{commit.sha}: #{message}")
+end
+
def lines_changed_in_commit(commit)
commit.diff_parent.stats[:total][:lines]
end
@@ -33,6 +63,7 @@ end
def lint_commits(commits)
failures = false
+ emoji_checker = EmojiChecker.new
unicode_emoji_regex = %r((
[\u{1F300}-\u{1F5FF}] |
@@ -60,13 +91,21 @@ def lint_commits(commits)
failures = true
end
- if subject.length > 50
+ if subject.length > 72
fail_commit(
commit,
- 'The commit subject may not be longer than 50 characters'
+ 'The commit subject may not be longer than 72 characters'
)
failures = true
+ elsif subject.length > 50
+ warn_commit(
+ commit,
+ "This commit's subject line could be improved. " \
+ 'Commit subjects are ideally no longer than roughly 50 characters, ' \
+ 'though we allow up to 72 characters in the subject. ' \
+ 'If possible, try to reduce the length of the subject to roughly 50 characters.'
+ )
end
unless subject_starts_with_capital?(subject)
@@ -117,7 +156,7 @@ def lint_commits(commits)
failures = true
end
- if commit.message.match?(/:[\+a-z0-9_\-]+:/)
+ if emoji_checker.includes_emoji?(commit.message)
fail_commit(
commit,
'Avoid the use of Markdown Emoji such as `:+1:`. ' \
diff --git a/db/migrate/20170222111732_create_gpg_keys.rb b/db/migrate/20170222111732_create_gpg_keys.rb
index 541228e8735..0d6d454bbf3 100644
--- a/db/migrate/20170222111732_create_gpg_keys.rb
+++ b/db/migrate/20170222111732_create_gpg_keys.rb
@@ -1,4 +1,6 @@
class CreateGpgKeys < ActiveRecord::Migration
+ include Gitlab::Database::MigrationHelpers
+
DOWNTIME = false
def change
@@ -12,8 +14,8 @@ class CreateGpgKeys < ActiveRecord::Migration
t.text :key
- t.index :primary_keyid, unique: true, length: Gitlab::Database.mysql? ? 20 : nil
- t.index :fingerprint, unique: true, length: Gitlab::Database.mysql? ? 20 : nil
+ t.index :primary_keyid, unique: true, length: mysql_compatible_index_length
+ t.index :fingerprint, unique: true, length: mysql_compatible_index_length
end
end
end
diff --git a/db/migrate/20170613154149_create_gpg_signatures.rb b/db/migrate/20170613154149_create_gpg_signatures.rb
index f6b5e7ebb7b..abef13a7a0b 100644
--- a/db/migrate/20170613154149_create_gpg_signatures.rb
+++ b/db/migrate/20170613154149_create_gpg_signatures.rb
@@ -1,4 +1,6 @@
class CreateGpgSignatures < ActiveRecord::Migration
+ include Gitlab::Database::MigrationHelpers
+
DOWNTIME = false
def change
@@ -16,8 +18,8 @@ class CreateGpgSignatures < ActiveRecord::Migration
t.text :gpg_key_user_name
t.text :gpg_key_user_email
- t.index :commit_sha, unique: true, length: Gitlab::Database.mysql? ? 20 : nil
- t.index :gpg_key_primary_keyid, length: Gitlab::Database.mysql? ? 20 : nil
+ t.index :commit_sha, unique: true, length: mysql_compatible_index_length
+ t.index :gpg_key_primary_keyid, length: mysql_compatible_index_length
end
end
end
diff --git a/db/migrate/20170827123848_add_index_on_merge_request_diff_commit_sha.rb b/db/migrate/20170827123848_add_index_on_merge_request_diff_commit_sha.rb
index 1b360b231a8..2140ff7b05e 100644
--- a/db/migrate/20170827123848_add_index_on_merge_request_diff_commit_sha.rb
+++ b/db/migrate/20170827123848_add_index_on_merge_request_diff_commit_sha.rb
@@ -8,7 +8,7 @@ class AddIndexOnMergeRequestDiffCommitSha < ActiveRecord::Migration
disable_ddl_transaction!
def up
- add_concurrent_index :merge_request_diff_commits, :sha, length: Gitlab::Database.mysql? ? 20 : nil
+ add_concurrent_index :merge_request_diff_commits, :sha, length: mysql_compatible_index_length
end
def down
diff --git a/db/migrate/20170927161718_create_gpg_key_subkeys.rb b/db/migrate/20170927161718_create_gpg_key_subkeys.rb
index c03c40416a8..d9dc2404cac 100644
--- a/db/migrate/20170927161718_create_gpg_key_subkeys.rb
+++ b/db/migrate/20170927161718_create_gpg_key_subkeys.rb
@@ -1,4 +1,6 @@
class CreateGpgKeySubkeys < ActiveRecord::Migration
+ include Gitlab::Database::MigrationHelpers
+
DOWNTIME = false
def up
@@ -8,8 +10,8 @@ class CreateGpgKeySubkeys < ActiveRecord::Migration
t.binary :keyid
t.binary :fingerprint
- t.index :keyid, unique: true, length: Gitlab::Database.mysql? ? 20 : nil
- t.index :fingerprint, unique: true, length: Gitlab::Database.mysql? ? 20 : nil
+ t.index :keyid, unique: true, length: mysql_compatible_index_length
+ t.index :fingerprint, unique: true, length: mysql_compatible_index_length
end
add_reference :gpg_signatures, :gpg_key_subkey, index: true, foreign_key: { on_delete: :nullify }
diff --git a/db/migrate/20180813101999_change_default_of_auto_devops_instance_wide.rb b/db/migrate/20180813101999_change_default_of_auto_devops_instance_wide.rb
new file mode 100644
index 00000000000..05d1124f5c4
--- /dev/null
+++ b/db/migrate/20180813101999_change_default_of_auto_devops_instance_wide.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+class ChangeDefaultOfAutoDevopsInstanceWide < ActiveRecord::Migration
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ def up
+ change_column_default :application_settings, :auto_devops_enabled, true
+ end
+
+ def down
+ change_column_default :application_settings, :auto_devops_enabled, false
+ end
+end
diff --git a/db/migrate/20180813102000_enable_auto_devops_instance_wide_for_everyone.rb b/db/migrate/20180813102000_enable_auto_devops_instance_wide_for_everyone.rb
new file mode 100644
index 00000000000..21fb62806b3
--- /dev/null
+++ b/db/migrate/20180813102000_enable_auto_devops_instance_wide_for_everyone.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+class EnableAutoDevopsInstanceWideForEveryone < ActiveRecord::Migration
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ def up
+ execute "UPDATE application_settings SET auto_devops_enabled = true"
+ end
+
+ def down
+ # No way to know here what their previous setting was...
+ end
+end
diff --git a/db/migrate/20180907015926_add_legacy_abac_to_cluster_providers_gcp.rb b/db/migrate/20180907015926_add_legacy_abac_to_cluster_providers_gcp.rb
new file mode 100644
index 00000000000..933047e32de
--- /dev/null
+++ b/db/migrate/20180907015926_add_legacy_abac_to_cluster_providers_gcp.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+class AddLegacyAbacToClusterProvidersGcp < ActiveRecord::Migration
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def up
+ add_column_with_default(:cluster_providers_gcp, :legacy_abac, :boolean, default: true)
+ end
+
+ def down
+ remove_column(:cluster_providers_gcp, :legacy_abac)
+ end
+end
diff --git a/db/migrate/20180916011959_add_index_pipelines_project_id_source.rb b/db/migrate/20180916011959_add_index_pipelines_project_id_source.rb
new file mode 100644
index 00000000000..b9bebf30cf0
--- /dev/null
+++ b/db/migrate/20180916011959_add_index_pipelines_project_id_source.rb
@@ -0,0 +1,20 @@
+# frozen_string_literal: true
+
+# See http://doc.gitlab.com/ce/development/migration_style_guide.html
+# for more information on how to write migrations for GitLab.
+
+class AddIndexPipelinesProjectIdSource < ActiveRecord::Migration
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_index :ci_pipelines, [:project_id, :source]
+ end
+
+ def down
+ remove_concurrent_index :ci_pipelines, [:project_id, :source]
+ end
+end
diff --git a/db/post_migrate/20180913051323_consume_remaining_diff_files_deletion_jobs.rb b/db/post_migrate/20180913051323_consume_remaining_diff_files_deletion_jobs.rb
new file mode 100644
index 00000000000..ed9422a3894
--- /dev/null
+++ b/db/post_migrate/20180913051323_consume_remaining_diff_files_deletion_jobs.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+class ConsumeRemainingDiffFilesDeletionJobs < ActiveRecord::Migration
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ MIGRATION = 'ScheduleDiffFilesDeletion'.freeze
+ TMP_INDEX = 'tmp_partial_diff_id_with_files_index'.freeze
+
+ def up
+ # Perform any ongoing background migration that might still be scheduled.
+ Gitlab::BackgroundMigration.steal(MIGRATION)
+
+ remove_concurrent_index_by_name(:merge_request_diffs, TMP_INDEX)
+ end
+
+ def down
+ add_concurrent_index(:merge_request_diffs, :id, where: "(state NOT IN ('without_files', 'empty'))", name: TMP_INDEX)
+ end
+end
diff --git a/db/post_migrate/20180914201132_remove_sidekiq_throttling_from_application_settings.rb b/db/post_migrate/20180914201132_remove_sidekiq_throttling_from_application_settings.rb
new file mode 100644
index 00000000000..b3ed0d3f1e9
--- /dev/null
+++ b/db/post_migrate/20180914201132_remove_sidekiq_throttling_from_application_settings.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+# See http://doc.gitlab.com/ce/development/migration_style_guide.html
+# for more information on how to write migrations for GitLab.
+
+class RemoveSidekiqThrottlingFromApplicationSettings < ActiveRecord::Migration
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ def change
+ remove_column :application_settings, :sidekiq_throttling_enabled, :boolean, default: false
+ remove_column :application_settings, :sidekiq_throttling_queues, :string
+ remove_column :application_settings, :sidekiq_throttling_factor, :decimal
+
+ Rails.cache.delete("ApplicationSetting:#{Gitlab::VERSION}:#{Rails.version}")
+ end
+end
diff --git a/db/post_migrate/20180916014356_populate_external_pipeline_source.rb b/db/post_migrate/20180916014356_populate_external_pipeline_source.rb
new file mode 100644
index 00000000000..5577d05cf40
--- /dev/null
+++ b/db/post_migrate/20180916014356_populate_external_pipeline_source.rb
@@ -0,0 +1,33 @@
+# frozen_string_literal: true
+
+# See http://doc.gitlab.com/ce/development/migration_style_guide.html
+# for more information on how to write migrations for GitLab.
+
+class PopulateExternalPipelineSource < ActiveRecord::Migration
+ include Gitlab::Database::MigrationHelpers
+
+ # Set this constant to true if this migration requires downtime.
+ DOWNTIME = false
+ MIGRATION = 'PopulateExternalPipelineSource'.freeze
+ BATCH_SIZE = 500
+
+ disable_ddl_transaction!
+
+ class Pipeline < ActiveRecord::Base
+ include EachBatch
+ self.table_name = 'ci_pipelines'
+ end
+
+ def up
+ Pipeline.where(source: nil).tap do |relation|
+ queue_background_migration_jobs_by_range_at_intervals(relation,
+ MIGRATION,
+ 5.minutes,
+ batch_size: BATCH_SIZE)
+ end
+ end
+
+ def down
+ # noop
+ end
+end
diff --git a/db/post_migrate/20180917172041_remove_wikis_count_from_site_statistics.rb b/db/post_migrate/20180917172041_remove_wikis_count_from_site_statistics.rb
new file mode 100644
index 00000000000..0a39abe3bdf
--- /dev/null
+++ b/db/post_migrate/20180917172041_remove_wikis_count_from_site_statistics.rb
@@ -0,0 +1,6 @@
+# frozen_string_literal: true
+class RemoveWikisCountFromSiteStatistics < ActiveRecord::Migration
+ def change
+ remove_column :site_statistics, :wikis_count, :integer
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 2528a0c1b72..ecb9d4391d7 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: 20180906101639) do
+ActiveRecord::Schema.define(version: 20180917172041) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -119,9 +119,6 @@ ActiveRecord::Schema.define(version: 20180906101639) do
t.integer "housekeeping_incremental_repack_period", default: 10, null: false
t.integer "housekeeping_full_repack_period", default: 50, null: false
t.integer "housekeeping_gc_period", default: 200, null: false
- t.boolean "sidekiq_throttling_enabled", default: false
- t.string "sidekiq_throttling_queues"
- t.decimal "sidekiq_throttling_factor"
t.boolean "html_emails_enabled", default: true
t.string "plantuml_url"
t.boolean "plantuml_enabled"
@@ -141,7 +138,7 @@ ActiveRecord::Schema.define(version: 20180906101639) do
t.integer "performance_bar_allowed_group_id"
t.boolean "hashed_storage_enabled", default: false, null: false
t.boolean "project_export_enabled", default: true, null: false
- t.boolean "auto_devops_enabled", default: false, null: false
+ t.boolean "auto_devops_enabled", default: true, null: false
t.integer "circuitbreaker_failure_count_threshold", default: 3
t.integer "circuitbreaker_failure_reset_time", default: 1800
t.integer "circuitbreaker_storage_timeout", default: 15
@@ -478,6 +475,7 @@ ActiveRecord::Schema.define(version: 20180906101639) do
add_index "ci_pipelines", ["project_id", "iid"], name: "index_ci_pipelines_on_project_id_and_iid", unique: true, where: "(iid IS NOT NULL)", using: :btree
add_index "ci_pipelines", ["project_id", "ref", "status", "id"], name: "index_ci_pipelines_on_project_id_and_ref_and_status_and_id", using: :btree
add_index "ci_pipelines", ["project_id", "sha"], name: "index_ci_pipelines_on_project_id_and_sha", using: :btree
+ add_index "ci_pipelines", ["project_id", "source"], name: "index_ci_pipelines_on_project_id_and_source", using: :btree
add_index "ci_pipelines", ["project_id", "status", "config_source"], name: "index_ci_pipelines_on_project_id_and_status_and_config_source", using: :btree
add_index "ci_pipelines", ["project_id"], name: "index_ci_pipelines_on_project_id", using: :btree
add_index "ci_pipelines", ["status"], name: "index_ci_pipelines_on_status", using: :btree
@@ -620,6 +618,7 @@ ActiveRecord::Schema.define(version: 20180906101639) do
t.string "endpoint"
t.text "encrypted_access_token"
t.string "encrypted_access_token_iv"
+ t.boolean "legacy_abac", default: true, null: false
end
add_index "cluster_providers_gcp", ["cluster_id"], name: "index_cluster_providers_gcp_on_cluster_id", unique: true, using: :btree
@@ -1910,7 +1909,6 @@ ActiveRecord::Schema.define(version: 20180906101639) do
create_table "site_statistics", force: :cascade do |t|
t.integer "repositories_count", default: 0, null: false
- t.integer "wikis_count", default: 0, null: false
end
create_table "snippets", force: :cascade do |t|
diff --git a/doc/README.md b/doc/README.md
index 4248f62c08c..7548240bfef 100644
--- a/doc/README.md
+++ b/doc/README.md
@@ -191,7 +191,7 @@ instant how code changes impact your production environment.
### User account
- [User account](user/profile/index.md): Manage your account
- - [Authentication](topics/authentication/index.md): Account security with two-factor authentication, setup your ssh keys and deploy keys for secure access to your projects.
+ - [Authentication](topics/authentication/index.md): Account security with two-factor authentication, set up your ssh keys and deploy keys for secure access to your projects.
- [Profile settings](user/profile/index.md#profile-settings): Manage your profile settings, two factor authentication and more.
- [User permissions](user/permissions.md): Learn what each role in a project (external/guest/reporter/developer/maintainer/owner) can do.
diff --git a/doc/administration/auth/ldap.md b/doc/administration/auth/ldap.md
index 5c7392b99d0..54ded25291a 100644
--- a/doc/administration/auth/ldap.md
+++ b/doc/administration/auth/ldap.md
@@ -111,7 +111,7 @@ main:
uid: 'sAMAccountName' # This should be the attribute, not the value that maps to uid.
##
- ## Examples: 'america\\momo' or 'CN=Gitlab Git,CN=Users,DC=mydomain,DC=com'
+ ## Examples: 'america\momo' or 'CN=Gitlab Git,CN=Users,DC=mydomain,DC=com'
##
bind_dn: '_the_full_dn_of_the_user_you_will_bind_with'
password: '_the_password_of_the_bind_user'
@@ -132,7 +132,7 @@ main:
## Enables SSL certificate verification if encryption method is
## "start_tls" or "simple_tls". Defaults to true since GitLab 10.0 for
## security. This may break installations upon upgrade to 10.0, that did
- ## not know their LDAP SSL certificates were not setup properly.
+ ## not know their LDAP SSL certificates were not set up properly.
##
verify_certificates: true
diff --git a/doc/administration/external_database.md b/doc/administration/external_database.md
index 31199f2cdc7..ec2d30c82d1 100644
--- a/doc/administration/external_database.md
+++ b/doc/administration/external_database.md
@@ -9,7 +9,7 @@ separate from the GitLab Omnibus package.
If you use a cloud-managed service, or provide your own PostgreSQL instance:
-1. Setup PostgreSQL according to the
+1. Set up PostgreSQL according to the
[database requirements document](../install/requirements.md#database).
1. Set up a `gitlab` username with a password of your choice. The `gitlab` user
needs privileges to create the `gitlabhq_production` database.
diff --git a/doc/administration/gitaly/index.md b/doc/administration/gitaly/index.md
index 964758837e5..b5e2b5448f7 100644
--- a/doc/administration/gitaly/index.md
+++ b/doc/administration/gitaly/index.md
@@ -101,6 +101,12 @@ documentation on configuring Gitaly
authentication](https://gitlab.com/gitlab-org/gitaly/blob/master/doc/configuration/README.md#authentication)
.
+Gitaly must trigger some callbacks to GitLab via GitLab Shell. As a result,
+the GitLab Shell secret must be the same between the other GitLab servers and
+the Gitaly server. The easiest way to accomplish this is to copy `/etc/gitlab/gitlab-secrets.json`
+from an existing GitLab server to the Gitaly server. Without this shared secret,
+Git operations in GitLab will result in an API error.
+
> **NOTE:** In most or all cases the storage paths below end in `/repositories` which is
different than `path` in `git_data_dirs` of Omnibus installations. Check the
directory layout on your Gitaly server to be sure.
@@ -213,7 +219,7 @@ repository from your GitLab server over HTTP.
If you are running Gitaly [as a remote
service](#running-gitaly-on-its-own-server) you may want to disable
-the local Gitaly service that runs on your Gitlab server by default.
+the local Gitaly service that runs on your GitLab server by default.
> 'Disabling Gitaly' only makes sense when you run GitLab in a custom
cluster configuration, where different services run on different
diff --git a/doc/administration/high_availability/database.md b/doc/administration/high_availability/database.md
index b5124b1d540..c1eeb40b98f 100644
--- a/doc/administration/high_availability/database.md
+++ b/doc/administration/high_availability/database.md
@@ -13,7 +13,7 @@ Database Service (RDS) that runs PostgreSQL.
If you use a cloud-managed service, or provide your own PostgreSQL:
-1. Setup PostgreSQL according to the
+1. Set up PostgreSQL according to the
[database requirements document](../../install/requirements.md#database).
1. Set up a `gitlab` username with a password of your choice. The `gitlab` user
needs privileges to create the `gitlabhq_production` database.
diff --git a/doc/administration/high_availability/redis.md b/doc/administration/high_availability/redis.md
index e05bebbef18..b5d1ff698c6 100644
--- a/doc/administration/high_availability/redis.md
+++ b/doc/administration/high_availability/redis.md
@@ -81,7 +81,7 @@ When a **Master** fails to respond, it's the application's responsibility
(in our case GitLab) to handle timeout and reconnect (querying a **Sentinel**
for a new **Master**).
-To get a better understanding on how to correctly setup Sentinel, please read
+To get a better understanding on how to correctly set up Sentinel, please read
the [Redis Sentinel documentation](http://redis.io/topics/sentinel) first, as
failing to configure it correctly can lead to data loss or can bring your
whole cluster down, invalidating the failover effort.
@@ -217,7 +217,7 @@ Pick the one that suits your needs.
and configure Sentinel, jump directly to the Sentinel section in the
[Redis HA installation from source](redis_source.md#step-3-configuring-the-redis-sentinel-instances) documentation.
- [Omnibus GitLab **Enterprise Edition** (EE) package][ee]: Both Redis and Sentinel
- are bundled in the package, so you can use the EE package to setup the whole
+ are bundled in the package, so you can use the EE package to set up the whole
Redis HA infrastructure (master, slave and Sentinel) which is described in
this document.
- If you have installed GitLab using the Omnibus GitLab packages (CE or EE),
@@ -228,7 +228,7 @@ Pick the one that suits your needs.
## Configuring Redis HA
-This is the section where we install and setup the new Redis instances.
+This is the section where we install and set up the new Redis instances.
> **Notes:**
> - We assume that you have installed GitLab and all HA components from scratch. If you
@@ -370,7 +370,7 @@ You must have at least `3` Redis Sentinel servers, and they need to
be each in an independent machine. You can configure them in the same
machines where you've configured the other Redis servers.
-With GitLab Enterprise Edition, you can use the Omnibus package to setup
+With GitLab Enterprise Edition, you can use the Omnibus package to set up
multiple machines with the Sentinel daemon.
---
@@ -535,7 +535,7 @@ In this example we consider that all servers have an internal network
interface with IPs in the `10.0.0.x` range, and that they can connect
to each other using these IPs.
-In a real world usage, you would also setup firewall rules to prevent
+In a real world usage, you would also set up firewall rules to prevent
unauthorized access from other machines and block traffic from the
outside (Internet).
diff --git a/doc/administration/high_availability/redis_source.md b/doc/administration/high_availability/redis_source.md
index 8b7a515a076..5823c575251 100644
--- a/doc/administration/high_availability/redis_source.md
+++ b/doc/administration/high_availability/redis_source.md
@@ -24,7 +24,7 @@ the Omnibus Redis HA documentation.
## Configuring your own Redis server
-This is the section where we install and setup the new Redis instances.
+This is the section where we install and set up the new Redis instances.
### Prerequisites
@@ -204,7 +204,7 @@ In this example we consider that all servers have an internal network
interface with IPs in the `10.0.0.x` range, and that they can connect
to each other using these IPs.
-In a real world usage, you would also setup firewall rules to prevent
+In a real world usage, you would also set up firewall rules to prevent
unauthorized access from other machines, and block traffic from the
outside ([Internet][it]).
diff --git a/doc/administration/index.md b/doc/administration/index.md
index 8b6a42b0ca5..702d8e554a8 100644
--- a/doc/administration/index.md
+++ b/doc/administration/index.md
@@ -60,7 +60,7 @@ Learn how to install, configure, update, and maintain your GitLab instance.
- [Raketasks](../raketasks/README.md): Perform various tasks for maintenance, backups, automatic webhooks setup, etc.
- [Backup and restore](../raketasks/backup_restore.md): Backup and restore your GitLab instance.
-- [Operations](operations/index.md): Keeping GitLab up and running (clean up Redis sessions, moving repositories, Sidekiq Job throttling, Sidekiq MemoryKiller, Unicorn).
+- [Operations](operations/index.md): Keeping GitLab up and running (clean up Redis sessions, moving repositories, Sidekiq MemoryKiller, Unicorn).
- [Restart GitLab](restart_gitlab.md): Learn how to restart GitLab and its components.
#### Updating GitLab
diff --git a/doc/administration/job_artifacts.md b/doc/administration/job_artifacts.md
index 1f3bc611cdf..757865ea2c5 100644
--- a/doc/administration/job_artifacts.md
+++ b/doc/administration/job_artifacts.md
@@ -127,6 +127,7 @@ The connection settings match those provided by [Fog](https://github.com/fog), a
| `host` | S3 compatible host for when not using AWS, e.g. `localhost` or `storage.example.com` | s3.amazonaws.com |
| `endpoint` | Can be used when configuring an S3 compatible service such as [Minio](https://www.minio.io), by entering a URL such as `http://127.0.0.1:9000` | (optional) |
| `path_style` | Set to true to use `host/bucket_name/object` style paths instead of `bucket_name.host/object`. Leave as false for AWS S3 | false |
+| `use_iam_profile` | Set to true to use IAM profile instead of access keys | false
**In Omnibus installations:**
diff --git a/doc/administration/logs.md b/doc/administration/logs.md
index 98134075b94..a8cdd20581d 100644
--- a/doc/administration/logs.md
+++ b/doc/administration/logs.md
@@ -13,7 +13,7 @@ This guide talks about how to read and use these system log files.
This file lives in `/var/log/gitlab/gitlab-rails/production_json.log` for
Omnibus GitLab packages or in `/home/git/gitlab/log/production_json.log` for
-installations from source. (When Gitlab is running in an environment
+installations from source. (When GitLab is running in an environment
other than production, the corresponding logfile is shown here.)
It contains a structured log for Rails controller requests received from
@@ -42,7 +42,7 @@ In addition, the log contains the IP address from which the request originated
This file lives in `/var/log/gitlab/gitlab-rails/production.log` for
Omnibus GitLab packages or in `/home/git/gitlab/log/production.log` for
-installations from source. (When Gitlab is running in an environment
+installations from source. (When GitLab is running in an environment
other than production, the corresponding logfile is shown here.)
It contains information about all performed requests. You can see the
@@ -187,7 +187,7 @@ This file lives in `/var/log/gitlab/gitlab-shell/gitlab-shell.log` for
Omnibus GitLab packages or in `/home/git/gitlab-shell/gitlab-shell.log` for
installations from source.
-GitLab shell is used by Gitlab for executing Git commands and provide
+GitLab shell is used by GitLab for executing Git commands and provide
SSH access to Git repositories. For example:
```
diff --git a/doc/administration/operations/img/sidekiq_job_throttling.png b/doc/administration/operations/img/sidekiq_job_throttling.png
deleted file mode 100644
index abd09f3b115..00000000000
--- a/doc/administration/operations/img/sidekiq_job_throttling.png
+++ /dev/null
Binary files differ
diff --git a/doc/administration/operations/index.md b/doc/administration/operations/index.md
index e9cad99c4b0..dea98cb8197 100644
--- a/doc/administration/operations/index.md
+++ b/doc/administration/operations/index.md
@@ -9,8 +9,6 @@ GitLab 7.3 we recommend cleaning up stale sessions to compact the Redis
database after you upgrade to GitLab 7.3.
- [Moving repositories](moving_repositories.md): Moving all repositories managed
by GitLab to another file system or another server.
-- [Sidekiq job throttling](sidekiq_job_throttling.md): Throttle Sidekiq queues
-that to prioritize important jobs.
- [Sidekiq MemoryKiller](sidekiq_memory_killer.md): Configure Sidekiq MemoryKiller
to restart Sidekiq.
- [Unicorn](unicorn.md): Understand Unicorn and unicorn-worker-killer.
diff --git a/doc/administration/operations/sidekiq_job_throttling.md b/doc/administration/operations/sidekiq_job_throttling.md
deleted file mode 100644
index ddeaa22e288..00000000000
--- a/doc/administration/operations/sidekiq_job_throttling.md
+++ /dev/null
@@ -1,33 +0,0 @@
-# Sidekiq Job throttling
-
-> Note: Introduced with GitLab 8.14
-
-When your GitLab installation needs to handle tens of thousands of background
-jobs, it can be convenient to throttle queues that do not need to be executed
-immediately, e.g. long running jobs like Pipelines, thus allowing jobs that do
-need to be executed immediately to have access to more resources.
-
-In order to accomplish this, you can limit the amount of workers that certain
-slow running queues can have available. This is what we call Sidekiq Job
-Throttling. Depending on your infrastructure, you might have different slow
-running queues, which is why you can choose which queues you want to throttle
-and by how much you want to throttle them.
-
-These settings are available in the Application Settings of your GitLab
-installation.
-
-![Sidekiq Job Throttling](img/sidekiq_job_throttling.png)
-
-The throttle factor determines the maximum number of workers a queue can run on.
-This value gets multiplied by `:concurrency` value set in the Sidekiq settings
-and rounded up to the closest full integer.
-
-So, for example, you set the `:concurrency` to 25 and the `Throttling factor` to
-0.1, the maximum workers assigned to the selected queues would be 3.
-
-```ruby
-queue_limit = (factor * Sidekiq.options[:concurrency]).ceil
-```
-
-After enabling the job throttling, you will need to restart your GitLab
-instance, in order for the changes to take effect. \ No newline at end of file
diff --git a/doc/administration/operations/ssh_certificates.md b/doc/administration/operations/ssh_certificates.md
index 9edccd25ced..b00301fec1c 100644
--- a/doc/administration/operations/ssh_certificates.md
+++ b/doc/administration/operations/ssh_certificates.md
@@ -31,7 +31,7 @@ uploading user SSH keys to GitLab entirely.
## Setting up SSH certificate lookup via GitLab Shell
-How to fully setup SSH certificates is outside the scope of this
+How to fully set up SSH certificates is outside the scope of this
document. See [OpenSSH's
PROTOCOL.certkeys](https://cvsweb.openbsd.org/cgi-bin/cvsweb/src/usr.bin/ssh/PROTOCOL.certkeys?annotate=HEAD)
for how it works, and e.g. [RedHat's documentation about
@@ -132,7 +132,7 @@ message about this being an invalid user.
## Interaction with the `authorized_keys` file
SSH certificates can be used in conjunction with the `authorized_keys`
-file, and if setup as configured above the `authorized_keys` file will
+file, and if set up as configured above the `authorized_keys` file will
still serve as a fallback.
This is because if the `AuthorizedPrincipalsCommand` can't
diff --git a/doc/administration/raketasks/maintenance.md b/doc/administration/raketasks/maintenance.md
index 2b4252a7b1d..29af07d12dc 100644
--- a/doc/administration/raketasks/maintenance.md
+++ b/doc/administration/raketasks/maintenance.md
@@ -56,11 +56,11 @@ Runs the following rake tasks:
- `gitlab:sidekiq:check`
- `gitlab:app:check`
-It will check that each component was setup according to the installation guide and suggest fixes for issues found.
+It will check that each component was set up according to the installation guide and suggest fixes for issues found.
-You may also have a look at our Trouble Shooting Guides:
-- [Trouble Shooting Guide (GitLab)](http://docs.gitlab.com/ee/README.html#troubleshooting)
-- [Trouble Shooting Guide (Omnibus Gitlab)](http://docs.gitlab.com/omnibus/README.html#troubleshooting)
+You may also have a look at our Troubleshooting Guides:
+- [Troubleshooting Guide (GitLab)](http://docs.gitlab.com/ee/README.html#troubleshooting)
+- [Troubleshooting Guide (Omnibus Gitlab)](http://docs.gitlab.com/omnibus/README.html#troubleshooting)
**Omnibus Installation**
diff --git a/doc/administration/raketasks/uploads/migrate.md b/doc/administration/raketasks/uploads/migrate.md
index 0cd33ffc122..b5c40478ea5 100644
--- a/doc/administration/raketasks/uploads/migrate.md
+++ b/doc/administration/raketasks/uploads/migrate.md
@@ -7,10 +7,32 @@ After [configuring the object storage](../../uploads.md#using-object-storage) fo
>**Note:**
All of the processing will be done in a background worker and requires **no downtime**.
-This tasks uses 3 parameters to find uploads to migrate.
+### All-in-one rake task
+
+GitLab provides a wrapper rake task that migrates all uploaded files - avatars,
+logos, attachments, favicon, etc. - to object storage in one go. Under the hood,
+it invokes individual rake tasks to migrate files falling under each of this
+category one by one. The specifications of these individual rake tasks are
+described in the next section.
+
+**Omnibus Installation**
+
+```bash
+gitlab-rake "gitlab:uploads:migrate:all"
+```
+
+**Source Installation**
+
+```bash
+sudo RAILS_ENV=production -u git -H bundle exec rake gitlab:uploads:migrate:all
+```
+
+### Individual rake tasks
>**Note:**
-These parameters are mainly internal to GitLab's structure, you may want to refer to the task list instead below.
+If you already ran the rake task mentioned above, no need to run these individual rake tasks as that has been done automatically.
+
+The rake task uses 3 parameters to find uploads to migrate.
Parameter | Type | Description
--------- | ---- | -----------
@@ -18,6 +40,9 @@ Parameter | Type | Description
`model_class` | string | Type of the model to migrate from
`mount_point` | string/symbol | Name of the model's column on which the uploader is mounted on.
+>**Note:**
+These parameters are mainly internal to GitLab's structure, you may want to refer to the task list instead below.
+
This task also accepts some environment variables which you can use to override
certain values:
@@ -25,7 +50,7 @@ Variable | Type | Description
-------- | ---- | -----------
`BATCH` | integer | Specifies the size of the batch. Defaults to 200.
-** Omnibus Installation**
+**Omnibus Installation**
```bash
# gitlab-rake gitlab:uploads:migrate[uploader_class, model_class, mount_point]
@@ -40,6 +65,9 @@ gitlab-rake "gitlab:uploads:migrate[AttachmentUploader, Note, :attachment]"
gitlab-rake "gitlab:uploads:migrate[AttachmentUploader, Appearance, :logo]"
gitlab-rake "gitlab:uploads:migrate[AttachmentUploader, Appearance, :header_logo]"
+# Favicon
+gitlab-rake "gitlab:uploads:migrate[FaviconUploader, Appearance, :favicon]"
+
# Markdown
gitlab-rake "gitlab:uploads:migrate[FileUploader, Project]"
gitlab-rake "gitlab:uploads:migrate[PersonalFileUploader, Snippet]"
@@ -65,6 +93,9 @@ sudo -u git -H bundle exec rake "gitlab:uploads:migrate[AttachmentUploader, Note
sudo -u git -H bundle exec rake "gitlab:uploads:migrate[AttachmentUploader, Appearance, :logo]"
sudo -u git -H bundle exec rake "gitlab:uploads:migrate[AttachmentUploader, Appearance, :header_logo]"
+# Favicon
+sudo -u git -H bundle exec rake "gitlab:uploads:migrate[FaviconUploader, Appearance, :favicon]"
+
# Markdown
sudo -u git -H bundle exec rake "gitlab:uploads:migrate[FileUploader, Project]"
sudo -u git -H bundle exec rake "gitlab:uploads:migrate[PersonalFileUploader, Snippet]"
diff --git a/doc/administration/reply_by_email.md b/doc/administration/reply_by_email.md
index 426245c7aca..6d7069dd461 100644
--- a/doc/administration/reply_by_email.md
+++ b/doc/administration/reply_by_email.md
@@ -5,7 +5,7 @@ replying to notification emails.
## Requirement
-Make sure [incoming email](incoming_email.md) is setup.
+Make sure [incoming email](incoming_email.md) is set up.
## How it works?
diff --git a/doc/administration/reply_by_email_postfix_setup.md b/doc/administration/reply_by_email_postfix_setup.md
index 3e8b78e56d5..d1a03219542 100644
--- a/doc/administration/reply_by_email_postfix_setup.md
+++ b/doc/administration/reply_by_email_postfix_setup.md
@@ -245,7 +245,7 @@ Courier, which we will install later to add IMAP authentication, requires mailbo
220 gitlab.example.com ESMTP Postfix (Ubuntu)
```
- If you get a `Connection refused` error instead, make sure your firewall is setup to allow inbound traffic on port 25.
+ If you get a `Connection refused` error instead, make sure your firewall is set up to allow inbound traffic on port 25.
1. Send the `incoming` user a dummy email to test SMTP, by entering the following into the SMTP prompt:
diff --git a/doc/administration/repository_checks.md b/doc/administration/repository_checks.md
index efeec9db517..715bc0cd08c 100644
--- a/doc/administration/repository_checks.md
+++ b/doc/administration/repository_checks.md
@@ -18,7 +18,8 @@ repositories and wiki repositories in order to detect data corruption.
A project will be checked no more than once per month. If any projects
fail their repository checks all GitLab administrators will receive an email
notification of the situation. This notification is sent out once a week,
-by default, midnight at the start of Sunday.
+by default, midnight at the start of Sunday. Repositories with known check
+failures can be found at `/admin/projects?last_repository_check_failed=1`.
## Disabling periodic checks
diff --git a/doc/administration/uploads.md b/doc/administration/uploads.md
index 467deb43644..aec9a359ada 100644
--- a/doc/administration/uploads.md
+++ b/doc/administration/uploads.md
@@ -18,7 +18,7 @@ below.
>**Notes:**
For historical reasons, uploads are stored into a base directory, which by default is `uploads/-/system`. It is strongly discouraged to change this configuration option on an existing GitLab installation.
-_The uploads are stored by default in `/var/opt/gitlab/gitlab-rails/public/uploads/-/system`._
+_The uploads are stored by default in `/var/opt/gitlab/gitlab-rails/uploads/-/system`._
1. To change the storage path for example to `/mnt/storage/uploads`, edit
`/etc/gitlab/gitlab.rb` and add the following line:
@@ -86,6 +86,7 @@ The connection settings match those provided by [Fog](https://github.com/fog), a
| `host` | S3 compatible host for when not using AWS, e.g. `localhost` or `storage.example.com` | s3.amazonaws.com |
| `endpoint` | Can be used when configuring an S3 compatible service such as [Minio](https://www.minio.io), by entering a URL such as `http://127.0.0.1:9000` | (optional) |
| `path_style` | Set to true to use `host/bucket_name/object` style paths instead of `bucket_name.host/object`. Leave as false for AWS S3 | false |
+| `use_iam_profile` | Set to true to use IAM profile instead of access keys | false
**In Omnibus installations:**
diff --git a/doc/api/commits.md b/doc/api/commits.md
index 624ed529009..5ff1e1f60e0 100644
--- a/doc/api/commits.md
+++ b/doc/api/commits.md
@@ -83,12 +83,13 @@ POST /projects/:id/repository/commits
| `actions[]` Attribute | Type | Required | Description |
| --------------------- | ---- | -------- | ----------- |
-| `action` | string | yes | The action to perform, `create`, `delete`, `move`, `update` |
+| `action` | string | yes | The action to perform, `create`, `delete`, `move`, `update`, `chmod`|
| `file_path` | string | yes | Full path to the file. Ex. `lib/class.rb` |
-| `previous_path` | string | no | Original full path to the file being moved. Ex. `lib/class1.rb` |
-| `content` | string | no | File content, required for all except `delete`. Optional for `move` |
+| `previous_path` | string | no | Original full path to the file being moved. Ex. `lib/class1.rb`. Only considered for `move` action. |
+| `content` | string | no | File content, required for all except `delete` and `chmod`. Optional for `move` |
| `encoding` | string | no | `text` or `base64`. `text` is default. |
| `last_commit_id` | string | no | Last known file commit id. Will be only considered in update, move and delete actions. |
+| `execute_filemode` | boolean | no | When `true/false` enables/disables the execute flag on the file. Only considered for `chmod` action. |
```bash
PAYLOAD=$(cat << 'JSON'
@@ -115,6 +116,11 @@ PAYLOAD=$(cat << 'JSON'
"action": "update",
"file_path": "foo/bar5",
"content": "new content"
+ },
+ {
+ "action": "chmod",
+ "file_path": "foo/bar5",
+ "execute_filemode": true
}
]
}
diff --git a/doc/api/deployments.md b/doc/api/deployments.md
index fd11894ea8f..1963b0a21de 100644
--- a/doc/api/deployments.md
+++ b/doc/api/deployments.md
@@ -46,19 +46,21 @@ Example of response
"status": "success",
"tag": false,
"user": {
+ "id": 1,
+ "name": "Administrator",
+ "username": "root",
+ "state": "active",
"avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon",
+ "web_url": "http://gitlab.dev/root",
+ "created_at": "2015-12-21T13:14:24.077Z",
"bio": null,
- "created_at": "2016-08-11T07:09:20.351Z",
- "id": 1,
- "linkedin": "",
"location": null,
- "name": "Administrator",
+ "public_email": "",
"skype": "",
- "state": "active",
+ "linkedin": "",
"twitter": "",
- "username": "root",
- "web_url": "http://localhost:3000/root",
- "website_url": ""
+ "website_url": "",
+ "organization": ""
}
},
"environment": {
@@ -103,19 +105,21 @@ Example of response
"status": "success",
"tag": false,
"user": {
+ "id": 1,
+ "name": "Administrator",
+ "username": "root",
+ "state": "active",
"avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon",
+ "web_url": "http://gitlab.dev/root",
+ "created_at": "2015-12-21T13:14:24.077Z",
"bio": null,
- "created_at": "2016-08-11T07:09:20.351Z",
- "id": 1,
- "linkedin": "",
"location": null,
- "name": "Administrator",
+ "public_email": "",
"skype": "",
- "state": "active",
+ "linkedin": "",
"twitter": "",
- "username": "root",
- "web_url": "http://localhost:3000/root",
- "website_url": ""
+ "website_url": "",
+ "organization": ""
}
},
"environment": {
@@ -188,19 +192,20 @@ Example of response
"started_at": null,
"finished_at": "2016-08-11T11:32:35.145Z",
"user": {
+ "id": 1,
"name": "Administrator",
"username": "root",
- "id": 1,
"state": "active",
"avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon",
- "web_url": "http://localhost:3000/root",
- "created_at": "2016-08-11T07:09:20.351Z",
+ "web_url": "http://gitlab.dev/root",
+ "created_at": "2015-12-21T13:14:24.077Z",
"bio": null,
"location": null,
"skype": "",
"linkedin": "",
"twitter": "",
- "website_url": ""
+ "website_url": "",
+ "organization": ""
},
"commit": {
"id": "a91957a858320c0e17f3a0eca7cfacbff50ea29a",
diff --git a/doc/api/jobs.md b/doc/api/jobs.md
index cf292adf150..aa290ff4cf8 100644
--- a/doc/api/jobs.md
+++ b/doc/api/jobs.md
@@ -53,18 +53,21 @@ Example of response
"tag": false,
"web_url": "https://example.com/foo/bar/-/jobs/6",
"user": {
- "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon",
- "bio": null,
- "created_at": "2015-12-21T13:14:24.077Z",
"id": 1,
- "linkedin": "",
"name": "Administrator",
- "skype": "",
- "state": "active",
- "twitter": "",
"username": "root",
+ "state": "active",
+ "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon",
"web_url": "http://gitlab.dev/root",
- "website_url": ""
+ "created_at": "2015-12-21T13:14:24.077Z",
+ "bio": null,
+ "location": null,
+ "public_email": "",
+ "skype": "",
+ "linkedin": "",
+ "twitter": "",
+ "website_url": "",
+ "organization": ""
}
},
{
@@ -109,18 +112,21 @@ Example of response
"tag": false,
"web_url": "https://example.com/foo/bar/-/jobs/7",
"user": {
- "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon",
- "bio": null,
- "created_at": "2015-12-21T13:14:24.077Z",
"id": 1,
- "linkedin": "",
"name": "Administrator",
- "skype": "",
- "state": "active",
- "twitter": "",
"username": "root",
+ "state": "active",
+ "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon",
"web_url": "http://gitlab.dev/root",
- "website_url": ""
+ "created_at": "2015-12-21T13:14:24.077Z",
+ "bio": null,
+ "location": null,
+ "public_email": "",
+ "skype": "",
+ "linkedin": "",
+ "twitter": "",
+ "website_url": "",
+ "organization": ""
}
}
]
@@ -180,18 +186,21 @@ Example of response
"tag": false,
"web_url": "https://example.com/foo/bar/-/jobs/6",
"user": {
- "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon",
- "bio": null,
- "created_at": "2015-12-21T13:14:24.077Z",
"id": 1,
- "linkedin": "",
"name": "Administrator",
- "skype": "",
- "state": "active",
- "twitter": "",
"username": "root",
+ "state": "active",
+ "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon",
"web_url": "http://gitlab.dev/root",
- "website_url": ""
+ "created_at": "2015-12-21T13:14:24.077Z",
+ "bio": null,
+ "location": null,
+ "public_email": "",
+ "skype": "",
+ "linkedin": "",
+ "twitter": "",
+ "website_url": "",
+ "organization": ""
}
},
{
@@ -236,18 +245,21 @@ Example of response
"tag": false,
"web_url": "https://example.com/foo/bar/-/jobs/7",
"user": {
- "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon",
- "bio": null,
- "created_at": "2015-12-21T13:14:24.077Z",
"id": 1,
- "linkedin": "",
"name": "Administrator",
- "skype": "",
- "state": "active",
- "twitter": "",
"username": "root",
+ "state": "active",
+ "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon",
"web_url": "http://gitlab.dev/root",
- "website_url": ""
+ "created_at": "2015-12-21T13:14:24.077Z",
+ "bio": null,
+ "location": null,
+ "public_email": "",
+ "skype": "",
+ "linkedin": "",
+ "twitter": "",
+ "website_url": "",
+ "organization": ""
}
}
]
@@ -305,18 +317,21 @@ Example of response
"tag": false,
"web_url": "https://example.com/foo/bar/-/jobs/8",
"user": {
- "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon",
- "bio": null,
- "created_at": "2015-12-21T13:14:24.077Z",
"id": 1,
- "linkedin": "",
"name": "Administrator",
- "skype": "",
- "state": "active",
- "twitter": "",
"username": "root",
+ "state": "active",
+ "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon",
"web_url": "http://gitlab.dev/root",
- "website_url": ""
+ "created_at": "2015-12-21T13:14:24.077Z",
+ "bio": null,
+ "location": null,
+ "public_email": "",
+ "skype": "",
+ "linkedin": "",
+ "twitter": "",
+ "website_url": "",
+ "organization": ""
}
}
```
diff --git a/doc/api/keys.md b/doc/api/keys.md
index ddcf7830621..06b31a67d6a 100644
--- a/doc/api/keys.md
+++ b/doc/api/keys.md
@@ -27,10 +27,16 @@ Parameters:
"web_url": "http://localhost:3000/john_smith",
"created_at": "2015-09-03T07:24:01.670Z",
"bio": null,
+ "location": null,
+ "public_email": "john@example.com",
"skype": "",
"linkedin": "",
"twitter": "",
"website_url": "",
+ "organization": null,
+ "last_sign_in_at": "2015-09-03T07:24:01.670Z",
+ "confirmed_at": "2015-09-03T07:24:01.670Z",
+ "last_activity_on": "2015-09-03",
"email": "john@example.com",
"theme_id": 2,
"color_scheme_id": 1,
@@ -40,6 +46,8 @@ Parameters:
"can_create_group": true,
"can_create_project": true,
"two_factor_enabled": false
+ "external": false,
+ "private_profile": null
}
}
```
diff --git a/doc/api/members.md b/doc/api/members.md
index 7b228b92594..bb4fae35f52 100644
--- a/doc/api/members.md
+++ b/doc/api/members.md
@@ -15,6 +15,7 @@ The access levels are defined in the `Gitlab::Access` module. Currently, these l
## List all members of a group or project
Gets a list of group or project members viewable by the authenticated user.
+Returns only direct members and not inherited members through ancestors groups.
```
GET /groups/:id/members
@@ -61,6 +62,7 @@ Example response:
## List all members of a group or project including inherited members
Gets a list of group or project members viewable by the authenticated user, including inherited members through ancestor groups.
+Returns multiple times the same user (with different member attributes) when the user is a member of the project/group and of one or more ancestor group.
```
GET /groups/:id/members/all
diff --git a/doc/api/merge_requests.md b/doc/api/merge_requests.md
index 9e6676d62fe..4c099581f07 100644
--- a/doc/api/merge_requests.md
+++ b/doc/api/merge_requests.md
@@ -437,6 +437,11 @@ Parameters:
"id" : 1,
"name" : "Administrator"
},
+ "diff_refs": {
+ "base_sha": "1111111111111111111111111111111111111111",
+ "head_sha": "2222222222222222222222222222222222222222",
+ "start_sha": "3333333333333333333333333333333333333333"
+ },
"diverged_commits_count": 2
}
```
diff --git a/doc/api/oauth2.md b/doc/api/oauth2.md
index 77bb7a55d8c..8a1e6b52092 100644
--- a/doc/api/oauth2.md
+++ b/doc/api/oauth2.md
@@ -1,6 +1,6 @@
# GitLab as an OAuth2 provider
-This document covers using the [OAuth2](https://oauth.net/2/) protocol to allow other services access Gitlab resources on user's behalf.
+This document covers using the [OAuth2](https://oauth.net/2/) protocol to allow other services access GitLab resources on user's behalf.
If you want GitLab to be an OAuth authentication service provider to sign into other services please see the [OAuth2 provider](../integration/oauth_provider.md)
documentation.
@@ -9,7 +9,7 @@ This functionality is based on [doorkeeper gem](https://github.com/doorkeeper-ge
## Supported OAuth2 Flows
-Gitlab currently supports following authorization flows:
+GitLab currently supports following authorization flows:
* *Web Application Flow* - Most secure and common type of flow, designed for the applications with secure server-side.
* *Implicit Flow* - This flow is designed for user-agent only apps (e.g. single page web application running on GitLab Pages).
@@ -76,7 +76,7 @@ Check [RFC spec](http://tools.ietf.org/html/rfc6749#section-4.2) for a detailed
Unlike the web flow, the client receives an `access token` immediately as a result of the authorization request. The flow does not use client secret
or authorization code because all of the application code and storage is easily accessible, therefore __secrets__ can leak easily.
->**Important:** Avoid using this flow for applications that store data outside of the Gitlab instance. If you do, make sure to verify `application id`
+>**Important:** Avoid using this flow for applications that store data outside of the GitLab instance. If you do, make sure to verify `application id`
associated with access token before granting access to the data
(see [/oauth/token/info](https://github.com/doorkeeper-gem/doorkeeper/wiki/API-endpoint-descriptions-and-examples#get----oauthtokeninfo)).
@@ -146,7 +146,7 @@ access_token = client.password.get_token('user@example.com', 'secret')
puts access_token.token
```
-## Access Gitlab API with `access token`
+## Access GitLab API with `access token`
The `access token` allows you to make requests to the API on a behalf of a user. You can pass the token either as GET parameter
```
diff --git a/doc/api/protected_branches.md b/doc/api/protected_branches.md
index f6813f27dc0..ed8837574a0 100644
--- a/doc/api/protected_branches.md
+++ b/doc/api/protected_branches.md
@@ -4,7 +4,7 @@
**Valid access levels**
-The access levels are defined in the `ProtectedRefAccess::ALLOWED_ACCESS_LEVELS` constant. Currently, these levels are recognized:
+The access levels are defined in the `ProtectedRefAccess.allowed_access_levels` method. Currently, these levels are recognized:
```
0 => No access
30 => Developer access
diff --git a/doc/api/repository_files.md b/doc/api/repository_files.md
index 49fb9bc141d..0623a6b02ae 100644
--- a/doc/api/repository_files.md
+++ b/doc/api/repository_files.md
@@ -90,6 +90,8 @@ Like [Get file from repository](repository_files.md#get-file-from-repository) yo
## Create new file in repository
+This allows you to create a single file. For creating multiple files with a single request see the [commits API](commits.html#create-a-commit-with-multiple-files-and-actions).
+
```
POST /projects/:id/repository/files/:file_path
```
@@ -120,6 +122,8 @@ Parameters:
## Update existing file in repository
+This allows you to update a single file. For updating multiple files with a single request see the [commits API](commits.html#create-a-commit-with-multiple-files-and-actions).
+
```
PUT /projects/:id/repository/files/:file_path
```
@@ -160,6 +164,8 @@ Currently gitlab-shell has a boolean return code, preventing GitLab from specify
## Delete existing file in repository
+This allows you to delete a single file. For deleting multiple files with a singleh request see the [commits API](commits.html#create-a-commit-with-multiple-files-and-actions).
+
```
DELETE /projects/:id/repository/files/:file_path
```
diff --git a/doc/api/runners.md b/doc/api/runners.md
index 66476e7db64..0bcbd0aebf0 100644
--- a/doc/api/runners.md
+++ b/doc/api/runners.md
@@ -11,11 +11,15 @@ Get a list of specific runners available to the user.
```
GET /runners
GET /runners?scope=active
+GET /runners?type=project_type
+GET /runners?status=active
```
| Attribute | Type | Required | Description |
|-----------|---------|----------|---------------------|
-| `scope` | string | no | The scope of specific runners to show, one of: `active`, `paused`, `online`, `offline`; showing all runners if none provided |
+| `scope` | string | no | Deprecated: Use `type` or `status` instead. The scope of specific runners to show, one of: `active`, `paused`, `online`, `offline`; showing all runners if none provided |
+| `type` | string | no | The type of runners to show, one of: `instance_type`, `group_type`, `project_type` |
+| `status` | string | no | The status of runners to show, one of: `active`, `paused`, `online`, `offline` |
```
curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/runners"
@@ -56,11 +60,15 @@ is restricted to users with `admin` privileges.
```
GET /runners/all
GET /runners/all?scope=online
+GET /runners/all?type=project_type
+GET /runners/all?status=active
```
| Attribute | Type | Required | Description |
|-----------|---------|----------|---------------------|
-| `scope` | string | no | The scope of runners to show, one of: `specific`, `shared`, `active`, `paused`, `online`, `offline`; showing all runners if none provided |
+| `scope` | string | no | Deprecated: Use `type` or `status` instead. The scope of runners to show, one of: `specific`, `shared`, `active`, `paused`, `online`, `offline`; showing all runners if none provided |
+| `type` | string | no | The type of runners to show, one of: `instance_type`, `group_type`, `project_type` |
+| `status` | string | no | The status of runners to show, one of: `active`, `paused`, `online`, `offline` |
```
curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/runners/all"
@@ -286,6 +294,7 @@ Example response:
"created_at": "2017-11-16T18:38:46.000Z",
"bio": null,
"location": null,
+ "public_email": "",
"skype": "",
"linkedin": "",
"twitter": "",
@@ -336,11 +345,17 @@ usage is enabled in the project's settings.
```
GET /projects/:id/runners
+GET /projects/:id/runners?scope=active
+GET /projects/:id/runners?type=project_type
+GET /projects/:id/runners?status=active
```
-| Attribute | Type | Required | Description |
-|-----------|---------|----------|---------------------|
+| 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 |
+| `scope` | string | no | Deprecated: Use `type` or `status` instead. The scope of specific runners to show, one of: `active`, `paused`, `online`, `offline`; showing all runners if none provided |
+| `type` | string | no | The type of runners to show, one of: `instance_type`, `group_type`, `project_type` |
+| `status` | string | no | The status of runners to show, one of: `active`, `paused`, `online`, `offline` |
```
curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v4/projects/9/runners"
diff --git a/doc/api/settings.md b/doc/api/settings.md
index 83fa9b055d1..1c41b3345ad 100644
--- a/doc/api/settings.md
+++ b/doc/api/settings.md
@@ -193,7 +193,7 @@ are listed in the descriptions of the relevant settings.
| `metrics_port` | integer | required by: `metrics_enabled` | The UDP port to use for connecting to InfluxDB. |
| `metrics_sample_interval` | integer | required by: `metrics_enabled` | The sampling interval in seconds. |
| `metrics_timeout` | integer | required by: `metrics_enabled` | The amount of seconds after which InfluxDB will time out. |
-| `mirror_available` | boolean | no | Allow mirrors to be setup for projects. If disabled, only admins will be able to setup mirrors in projects. |
+| `mirror_available` | boolean | no | Allow mirrors to be set up for projects. If disabled, only admins will be able to set up mirrors in projects. |
| `pages_domain_verification_enabled` | boolean | no | Require users to prove ownership of custom domains. Domain verification is an essential security measure for public GitLab sites. Users are required to demonstrate they control a domain before it is enabled. |
| `password_authentication_enabled_for_git` | boolean | no | Enable authentication for Git over HTTP(S) via a GitLab account password. Default is `true`. |
| `password_authentication_enabled_for_web` | boolean | no | Enable authentication for the web interface via a GitLab account password. Default is `true`. |
@@ -219,9 +219,6 @@ are listed in the descriptions of the relevant settings.
| `session_expire_delay` | integer | no | Session duration in minutes. GitLab restart is required to apply changes |
| `shared_runners_enabled` | boolean | no | (**If enabled, requires:** `shared_runners_text`) Enable shared runners for new projects. |
| `shared_runners_text` | string | required by: `shared_runners_enabled` | Shared runners text. |
-| `sidekiq_throttling_enabled` | boolean | no | (**If enabled, requires:** `sidekiq_throttling_factor` and `sidekiq_throttling_queues`) Enable Sidekiq Job Throttling. |
-| `sidekiq_throttling_factor` | decimal | required by: `sidekiq_throttling_enabled` | The factor by which the queues should be throttled. A value between `0.0` and `1.0`, exclusive. |
-| `sidekiq_throttling_queues` | array of strings | required by: `sidekiq_throttling_enabled` | Choose which queues you wish to throttle. |
| `sign_in_text` | string | no | Text on the login page. |
| `signin_enabled` | string | no | (Deprecated: Use `password_authentication_enabled_for_web` instead) Flag indicating if password authentication is enabled for the web interface. |
| `signup_enabled` | boolean | no | Enable registration. Default is `true`. |
diff --git a/doc/api/users.md b/doc/api/users.md
index 8a9fb9b1447..3b41e0f7ec6 100644
--- a/doc/api/users.md
+++ b/doc/api/users.md
@@ -199,6 +199,7 @@ Parameters:
"created_at": "2012-05-23T08:00:58Z",
"bio": null,
"location": null,
+ "public_email": "john@example.com",
"skype": "",
"linkedin": "",
"twitter": "",
@@ -230,6 +231,7 @@ Parameters:
"is_admin": false,
"bio": null,
"location": null,
+ "public_email": "john@example.com",
"skype": "",
"linkedin": "",
"twitter": "",
@@ -369,6 +371,7 @@ GET /user
"created_at": "2012-05-23T08:00:58Z",
"bio": null,
"location": null,
+ "public_email": "john@example.com",
"skype": "",
"linkedin": "",
"twitter": "",
@@ -417,6 +420,7 @@ GET /user
"is_admin": false,
"bio": null,
"location": null,
+ "public_email": "john@example.com",
"skype": "",
"linkedin": "",
"twitter": "",
diff --git a/doc/ci/README.md b/doc/ci/README.md
index d782d64e971..dba1f38abe2 100644
--- a/doc/ci/README.md
+++ b/doc/ci/README.md
@@ -132,5 +132,3 @@ your whole GitLab instance as well as in each project.
- [New CI job permissions model](../user/project/new_ci_build_permissions_model.md)
Read about what changed in GitLab 8.12 and how that affects your jobs.
There's a new way to access your Git submodules and LFS objects in jobs.
-
-[gitlab-ci-templates]: https://gitlab.com/gitlab-org/gitlab-ci-yml
diff --git a/doc/ci/autodeploy/quick_start_guide.md b/doc/ci/autodeploy/quick_start_guide.md
index cc6c9ec0e0a..3836216e951 100644
--- a/doc/ci/autodeploy/quick_start_guide.md
+++ b/doc/ci/autodeploy/quick_start_guide.md
@@ -11,7 +11,7 @@ We made a minimal [Ruby application](https://gitlab.com/gitlab-examples/minimal-
Let’s start by forking our sample application. Go to [the project page](https://gitlab.com/gitlab-examples/minimal-ruby-app) and press the `Fork` button. Soon you should have a project under your namespace with the necessary files.
-## Setup your own cluster on Google Kubernetes Engine
+## Set up your own cluster on Google Kubernetes Engine
If you do not already have a Google Cloud account, create one at https://console.cloud.google.com.
@@ -71,7 +71,7 @@ Use this IP address to configure your DNS. This part heavily depends on your pre
Use `nslookup minimal-ruby-app-staging.<yourdomain>` to confirm that domain is assigned to the cluster IP.
-## Setup Auto Deploy
+## Set up Auto Deploy
Visit the home page of your GitLab.com project and press "Set up Auto Deploy" button.
diff --git a/doc/ci/caching/index.md b/doc/ci/caching/index.md
index b41101695f6..f479dc74d1f 100644
--- a/doc/ci/caching/index.md
+++ b/doc/ci/caching/index.md
@@ -178,8 +178,8 @@ runs of jobs for things like dependencies and commonly used libraries
so they don't have to be re-fetched from the public internet.
NOTE: **Note:**
-For more examples, check the [GitLab CI Yml](https://gitlab.com/gitlab-org/gitlab-ci-yml)
-project.
+For more examples, check out our [GitLab CI/CD
+templates](https://gitlab.com/gitlab-org/gitlab-ce/tree/master/lib/gitlab/ci/templates).
### Caching Nodejs dependencies
@@ -190,7 +190,7 @@ Nodejs modules are installed in `node_modules/` and are cached per-branch:
```yaml
#
-# https://gitlab.com/gitlab-org/gitlab-ci-yml/blob/master/Nodejs.gitlab-ci.yml
+# https://gitlab.com/gitlab-org/gitlab-ce/tree/master/lib/gitlab/ci/templates/Nodejs.gitlab-ci.yml
#
image: node:latest
@@ -217,7 +217,7 @@ are cached per-branch:
```yaml
#
-# https://gitlab.com/gitlab-org/gitlab-ci-yml/blob/master/PHP.gitlab-ci.yml
+# https://gitlab.com/gitlab-org/gitlab-ce/tree/master/lib/gitlab/ci/templates/PHP.gitlab-ci.yml
#
image: php:7.2
@@ -246,7 +246,7 @@ pip's cache is defined under `.cache/pip/` and both are cached per-branch:
```yaml
#
-# https://gitlab.com/gitlab-org/gitlab-ci-yml/blob/master/Python.gitlab-ci.yml
+# https://gitlab.com/gitlab-org/gitlab-ce/tree/master/lib/gitlab/ci/templates/Python.gitlab-ci.yml
#
image: python:latest
@@ -286,7 +286,7 @@ jobs inherit it. Gems are installed in `vendor/ruby/` and are cached per-branch:
```yaml
#
-# https://gitlab.com/gitlab-org/gitlab-ci-yml/blob/master/Ruby.gitlab-ci.yml
+# https://gitlab.com/gitlab-org/gitlab-ce/tree/master/lib/gitlab/ci/templates/Ruby.gitlab-ci.yml
#
image: ruby:2.5
diff --git a/doc/ci/docker/using_docker_build.md b/doc/ci/docker/using_docker_build.md
index aa997d15b64..0b64c8caba7 100644
--- a/doc/ci/docker/using_docker_build.md
+++ b/doc/ci/docker/using_docker_build.md
@@ -314,8 +314,8 @@ build:
stage: build
script:
- docker pull $CONTAINER_IMAGE:latest || true
- - docker build --cache-from $CONTAINER_IMAGE:latest --tag $CONTAINER_IMAGE:$CI_BUILD_REF --tag $CONTAINER_IMAGE:latest .
- - docker push $CONTAINER_IMAGE:$CI_BUILD_REF
+ - docker build --cache-from $CONTAINER_IMAGE:latest --tag $CONTAINER_IMAGE:$CI_COMMIT_SHA --tag $CONTAINER_IMAGE:latest .
+ - docker push $CONTAINER_IMAGE:$CI_COMMIT_SHA
- docker push $CONTAINER_IMAGE:latest
```
diff --git a/doc/ci/environments.md b/doc/ci/environments.md
index f1e5b00e927..4d740c32fd6 100644
--- a/doc/ci/environments.md
+++ b/doc/ci/environments.md
@@ -370,7 +370,7 @@ review_app:
url: https://$CI_COMMIT_REF_SLUG.example.com
```
-It is assumed that the user has already setup NGINX and GitLab Runner in the
+It is assumed that the user has already set up NGINX and GitLab Runner in the
server this job will run on.
>**Note:**
diff --git a/doc/ci/examples/README.md b/doc/ci/examples/README.md
index 8eb96ae10b2..fdf09d332a5 100644
--- a/doc/ci/examples/README.md
+++ b/doc/ci/examples/README.md
@@ -4,8 +4,8 @@ comments: false
# GitLab CI/CD Examples
-A collection of `.gitlab-ci.yml` template files is maintained at the [GitLab CI/CD YAML project][gitlab-ci-templates]. When you create a new file via the UI,
-GitLab will give you the option to choose one of the templates existent on this project.
+A collection of [`.gitlab-ci.yml` template files][gitlab-ci-templates] is maintained in GitLab. When you create a new file via the UI,
+GitLab will give you the option to choose one of these templates.
If your favorite programming language or framework are missing we would love your
help by sending a merge request with a new `.gitlab-ci.yml` to this project.
@@ -87,4 +87,4 @@ language users and GitLab by sending a merge request with a guide for that langu
You may want to apply for the [GitLab Community Writers Program](https://about.gitlab.com/community-writers/)
to get paid for writing complete articles for GitLab.
-[gitlab-ci-templates]: https://gitlab.com/gitlab-org/gitlab-ci-yml
+[gitlab-ci-templates]: https://gitlab.com/gitlab-org/gitlab-ce/tree/master/lib/gitlab/ci/templates
diff --git a/doc/ci/examples/browser_performance.md b/doc/ci/examples/browser_performance.md
index 0dab07a7f80..d36e97ebfd3 100644
--- a/doc/ci/examples/browser_performance.md
+++ b/doc/ci/examples/browser_performance.md
@@ -110,4 +110,4 @@ performance:
- sitespeed-results/
```
-A complete example can be found in our [Auto DevOps CI YML](https://gitlab.com/gitlab-org/gitlab-ci-yml/blob/master/Auto-DevOps.gitlab-ci.yml).
+A complete example can be found in our [Auto DevOps CI YML](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml).
diff --git a/doc/ci/examples/devops_and_game_dev_with_gitlab_ci_cd/index.md b/doc/ci/examples/devops_and_game_dev_with_gitlab_ci_cd/index.md
index c226b5bfb71..b75ed87bc91 100644
--- a/doc/ci/examples/devops_and_game_dev_with_gitlab_ci_cd/index.md
+++ b/doc/ci/examples/devops_and_game_dev_with_gitlab_ci_cd/index.md
@@ -520,7 +520,7 @@ a lot of breathing room in quickly getting changes to players.
Here are some ideas to further investigate that can speed up or improve your pipeline:
- [Yarn](https://yarnpkg.com) instead of npm
-- Setup a custom [Docker](../../../ci/docker/using_docker_images.md#define-image-and-services-from-gitlab-ci-yml) image that can preload dependencies and tools (like AWS CLI)
+- Set up a custom [Docker](../../../ci/docker/using_docker_images.md#define-image-and-services-from-gitlab-ci-yml) image that can preload dependencies and tools (like AWS CLI)
- Forward a [custom domain](http://docs.aws.amazon.com/AmazonS3/latest/dev/website-hosting-custom-domain-walkthrough.html) to your game's S3 static website
- Combine jobs if you find it unnecessary for a small project
- Avoid the queues and set up your own [custom GitLab CI/CD runner](https://about.gitlab.com/2016/03/01/gitlab-runner-with-docker/)
diff --git a/doc/ci/examples/laravel_with_gitlab_and_envoy/index.md b/doc/ci/examples/laravel_with_gitlab_and_envoy/index.md
index 39c65399332..ab429e0ded3 100644
--- a/doc/ci/examples/laravel_with_gitlab_and_envoy/index.md
+++ b/doc/ci/examples/laravel_with_gitlab_and_envoy/index.md
@@ -13,7 +13,7 @@ date: 2017-08-31
GitLab features our applications with Continuous Integration, and it is possible to easily deploy the new code changes to the production server whenever we want.
-In this tutorial, we'll show you how to initialize a [Laravel](http://laravel.com/) application and setup our [Envoy](https://laravel.com/docs/envoy) tasks, then we'll jump into see how to test and deploy it with [GitLab CI/CD](../README.md) via [Continuous Delivery](https://about.gitlab.com/2016/08/05/continuous-integration-delivery-and-deployment-with-gitlab/).
+In this tutorial, we'll show you how to initialize a [Laravel](http://laravel.com/) application and set up our [Envoy](https://laravel.com/docs/envoy) tasks, then we'll jump into see how to test and deploy it with [GitLab CI/CD](../README.md) via [Continuous Delivery](https://about.gitlab.com/2016/08/05/continuous-integration-delivery-and-deployment-with-gitlab/).
We assume you have a basic experience with Laravel, Linux servers,
and you know how to use GitLab.
@@ -23,7 +23,7 @@ It has a great community with a [fantastic documentation](https://laravel.com/do
Aside from the usual routing, controllers, requests, responses, views, and (blade) templates, out of the box Laravel provides plenty of additional services such as cache, events, localization, authentication and many others.
We will use [Envoy](https://laravel.com/docs/master/envoy) as an SSH task runner based on PHP.
-It uses a clean, minimal [Blade syntax](https://laravel.com/docs/blade) to setup tasks that can run on remote servers, such as, cloning your project from the repository, installing the Composer dependencies, and running [Artisan commands](https://laravel.com/docs/artisan).
+It uses a clean, minimal [Blade syntax](https://laravel.com/docs/blade) to set up tasks that can run on remote servers, such as, cloning your project from the repository, installing the Composer dependencies, and running [Artisan commands](https://laravel.com/docs/artisan).
## Initialize our Laravel app on GitLab
@@ -372,7 +372,7 @@ At the end, our `Envoy.blade.php` file will look like this:
One more thing we should do before any deployment is to manually copy our application `storage` folder to the `/var/www/app` directory on the server for the first time.
You might want to create another Envoy task to do that for you.
-We also create the `.env` file in the same path to setup our production environment variables for Laravel.
+We also create the `.env` file in the same path to set up our production environment variables for Laravel.
These are persistent data and will be shared to every new release.
Now, we would need to deploy our app by running `envoy run deploy`, but it won't be necessary since GitLab can handle that for us with CI's [environments](../../environments.md), which will be described [later](#setting-up-gitlab-ci-cd) in this tutorial.
@@ -587,7 +587,7 @@ unit_test:
script:
# Install app dependencies
- composer install
- # Setup .env
+ # Set up .env
- cp .env.example .env
# Generate an environment key
- php artisan key:generate
diff --git a/doc/ci/examples/php.md b/doc/ci/examples/php.md
index a2ba29a4ee2..df4805ea7ac 100644
--- a/doc/ci/examples/php.md
+++ b/doc/ci/examples/php.md
@@ -199,7 +199,7 @@ pecl install <extension>
```
It's not advised to add this to `.gitlab-ci.yml`. You should execute this
-command once, only to setup the build environment.
+command once, only to set up the build environment.
## Extend your tests
diff --git a/doc/ci/examples/test-scala-application.md b/doc/ci/examples/test-scala-application.md
index 09d83c33f95..b3961ec91f3 100644
--- a/doc/ci/examples/test-scala-application.md
+++ b/doc/ci/examples/test-scala-application.md
@@ -1,6 +1,6 @@
# Test and deploy to Heroku a Scala application
-This example demonstrates the integration of Gitlab CI with Scala
+This example demonstrates the integration of GitLab CI with Scala
applications using SBT. Checkout the example
[project](https://gitlab.com/gitlab-examples/scala-sbt) and
[build status](https://gitlab.com/gitlab-examples/scala-sbt/builds).
diff --git a/doc/ci/interactive_web_terminal/index.md b/doc/ci/interactive_web_terminal/index.md
index 8ce4fe55cec..7990917f809 100644
--- a/doc/ci/interactive_web_terminal/index.md
+++ b/doc/ci/interactive_web_terminal/index.md
@@ -3,7 +3,7 @@
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/50144) in GitLab 11.3.
Interactive web terminals give the user access to a terminal in GitLab for
-running one-of commands for their CI pipeline.
+running one-off commands for their CI pipeline.
NOTE: **Note:**
This is not available for the shared Runners on GitLab.com.
diff --git a/doc/ci/junit_test_reports.md b/doc/ci/junit_test_reports.md
index cf22450914c..3fd54647abb 100644
--- a/doc/ci/junit_test_reports.md
+++ b/doc/ci/junit_test_reports.md
@@ -140,6 +140,27 @@ java:
- target/failsafe-reports/TEST-*.xml
```
+### C/C++ example
+
+There are a few tools that can produce JUnit reports in C/C++.
+
+#### GoogleTest
+
+In the following example, `gtest` is used to generate the test reports.
+If there are multiple gtest executables created for different architectures (`x86`, `x64` or `arm`),
+you will be required to run each test providing a unique filename. The results
+will then be aggregated together.
+
+```yaml
+cpp:
+ stage: test
+ script:
+ - gtest.exe --gtest_output="xml:report.xml"
+ artifacts:
+ reports:
+ junit: report.xml
+```
+
## Limitations
Currently, the following tools might not work because their XML formats are unsupported in GitLab.
diff --git a/doc/ci/runners/README.md b/doc/ci/runners/README.md
index 7859d2ec631..83e0fa34ad6 100644
--- a/doc/ci/runners/README.md
+++ b/doc/ci/runners/README.md
@@ -29,7 +29,7 @@ are:
- **Specific Runners** are useful for jobs that have special requirements or for
projects with a specific demand. If a job has certain requirements, you can set
up the specific Runner with this in mind, while not having to do this for all
- Runners. For example, if you want to deploy a certain project, you can setup
+ Runners. For example, if you want to deploy a certain project, you can set up
a specific Runner to have the right credentials for this. The [usage of tags](#using-tags)
may be useful in this case. Specific Runners process jobs using a [FIFO] queue.
- **Group Runners** are useful when you have multiple projects under one group
@@ -222,7 +222,7 @@ should keep in mind.
### Using tags
-You must setup a Runner to be able to run all the different types of jobs
+You must set up a Runner to be able to run all the different types of jobs
that it may encounter on the projects it's shared over. This would be
problematic for large amounts of projects, if it wasn't for tags.
@@ -298,7 +298,7 @@ and using more secure [Runner Executors](https://docs.gitlab.com/runner/executor
### Forks
Whenever a project is forked, it copies the settings of the jobs that relate
-to it. This means that if you have shared Runners setup for a project and
+to it. This means that if you have shared Runners set up for a project and
someone forks that project, the shared Runners will also serve jobs of this
project.
diff --git a/doc/ci/yaml/README.md b/doc/ci/yaml/README.md
index 41de9a50efc..e38628b288b 100644
--- a/doc/ci/yaml/README.md
+++ b/doc/ci/yaml/README.md
@@ -188,7 +188,7 @@ used for time of the job. The configuration of this feature is covered in
## `before_script` and `after_script`
-> Introduced in GitLab 8.7 and requires Gitlab Runner v1.2
+> Introduced in GitLab 8.7 and requires GitLab Runner v1.2
`before_script` is used to define the command that should be run before all
jobs, including deploy jobs, but after the restoration of [artifacts](#artifacts).
@@ -492,6 +492,7 @@ osx job:
`allow_failure` is used when you want to allow a job to fail without impacting
the rest of the CI suite. Failed jobs don't contribute to the commit status.
+The default value is `false`.
When enabled and the job fails, the pipeline will be successful/green for all
intents and purposes, but a "CI build passed with warnings" message will be
@@ -1231,13 +1232,16 @@ rspec:
```
The collected JUnit reports will be uploaded to GitLab as an artifact and will
-be automatically [shown in merge requests](../junit_test_reports.md).
+be automatically shown in merge requests.
+
+For more examples, see [JUnit test reports](../junit_test_reports.md).
NOTE: **Note:**
In case the JUnit tool you use exports to multiple XML files, you can specify
-multiple test report paths within a single job
-(`junit: [rspec-1.xml, rspec-2.xml, rspec-3.xml]`) and they will be automatically
-concatenated into a single file.
+multiple test report paths within a single job and they will be automatically
+concatenated into a single file. Use a filename pattern (`junit: rspec-*.xml`),
+an array of filenames (`junit: [rspec-1.xml, rspec-2.xml, rspec-3.xml]`), or a
+combination thereof (`junit: [rspec.xml, test-results/TEST-*.xml]`).
## `dependencies`
diff --git a/doc/development/README.md b/doc/development/README.md
index efe37b8ba0b..43d3865da0e 100644
--- a/doc/development/README.md
+++ b/doc/development/README.md
@@ -7,7 +7,7 @@ description: 'Learn how to contribute to GitLab.'
## Get started!
-- Setup GitLab's development environment with [GitLab Development Kit (GDK)](https://gitlab.com/gitlab-org/gitlab-development-kit/blob/master/doc/howto/README.md)
+- Set up GitLab's development environment with [GitLab Development Kit (GDK)](https://gitlab.com/gitlab-org/gitlab-development-kit/blob/master/doc/howto/README.md)
- [GitLab contributing guide](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md)
- [Architecture](architecture.md) of GitLab
- [Rake tasks](rake_tasks.md) for development
@@ -53,11 +53,14 @@ description: 'Learn how to contribute to GitLab.'
## Performance guides
-- [Instrumentation](instrumentation.md)
-- [Performance guidelines](performance.md)
+- [Instrumentation](instrumentation.md) for Ruby code running in production
+ environments
+- [Performance guidelines](performance.md) for writing code, benchmarks, and
+ certain patterns to avoid
- [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
+- [Profiling](profiling.md) a URL, measuring performance using Sherlock, or
+ tracking down N+1 queries using Bullet
## Database guides
@@ -91,6 +94,7 @@ description: 'Learn how to contribute to GitLab.'
- [Verifying database capabilities](verifying_database_capabilities.md)
- [Database Debugging and Troubleshooting](database_debugging.md)
- [Query Count Limits](query_count_limits.md)
+- [Database helper modules](database_helpers.md)
## Testing guides
diff --git a/doc/development/automatic_ce_ee_merge.md b/doc/development/automatic_ce_ee_merge.md
index f6509b5c1dd..9dd78806a12 100644
--- a/doc/development/automatic_ce_ee_merge.md
+++ b/doc/development/automatic_ce_ee_merge.md
@@ -63,7 +63,7 @@ EE version of your CE merge request.
For each commit (except on `master`), the `ee_compat_check` CI job tries to
detect if the current branch's changes will conflict during the CE->EE merge.
-The job reports what files are conflicting and how to setup a merge request
+The job reports what files are conflicting and how to set up a merge request
against EE.
#### How the job works
diff --git a/doc/development/contributing/community_roles.md b/doc/development/contributing/community_roles.md
new file mode 100644
index 00000000000..c508969f7f4
--- /dev/null
+++ b/doc/development/contributing/community_roles.md
@@ -0,0 +1,12 @@
+### Community members & roles
+
+GitLab community members and their privileges/responsibilities.
+
+| Roles | Responsibilities | Requirements |
+|-------|------------------|--------------|
+| Maintainer | Accepts merge requests on several GitLab projects | Added to the [team page](https://about.gitlab.com/team/). An expert on code reviews and knows the product/code base |
+| Reviewer | Performs code reviews on MRs | Added to the [team page](https://about.gitlab.com/team/) |
+| Developer |Has access to GitLab internal infrastructure & issues (e.g. HR-related) | GitLab employee or a Core Team member (with an NDA) |
+| Contributor | Can make contributions to all GitLab public projects | Have a GitLab.com account |
+
+[List of current reviewers/maintainers](https://about.gitlab.com/handbook/engineering/projects/#gitlab-ce) \ No newline at end of file
diff --git a/doc/development/contributing/design.md b/doc/development/contributing/design.md
index 45fe8c26591..be7891061f9 100644
--- a/doc/development/contributing/design.md
+++ b/doc/development/contributing/design.md
@@ -1,13 +1,4 @@
-<!-- START doctoc generated TOC please keep comment here to allow auto update -->
-<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
-**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)*
-
-- [Implement design & UI elements](#implement-design--ui-elements)
-- [Style guides](#style-guides)
-
-<!-- END doctoc generated TOC please keep comment here to allow auto update -->
-
-## Implement design & UI elements
+# Implement design & UI elements
For guidance on UX implementation at GitLab, please refer to our [Design System](https://design.gitlab.com/).
@@ -34,27 +25,27 @@ In order to complete a product discovery issue in a release, you must complete t
## Style guides
-1. [Ruby](https://github.com/bbatsov/ruby-style-guide).
- Important sections include [Source Code Layout][rss-source] and
- [Naming][rss-naming]. Use:
- - multi-line method chaining style **Option A**: dot `.` on the second line
- - string literal quoting style **Option A**: single quoted by default
-1. [Rails](https://github.com/bbatsov/rails-style-guide)
-1. [Newlines styleguide][newlines-styleguide]
-1. [Testing][testing]
-1. [JavaScript styleguide][js-styleguide]
-1. [SCSS styleguide][scss-styleguide]
-1. [Shell commands](../shell_commands.md) created by GitLab
- contributors to enhance security
-1. [Database Migrations](../migration_style_guide.md)
-1. [Markdown](http://www.cirosantilli.com/markdown-styleguide)
-1. [Documentation styleguide](https://docs.gitlab.com/ee/development/documentation/styleguide.html)
-1. Interface text should be written subjectively instead of objectively. It
- should be the GitLab core team addressing a person. It should be written in
- present time and never use past tense (has been/was). For example instead
- of _prohibited this user from being saved due to the following errors:_ the
- text should be _sorry, we could not create your account because:_
-1. Code should be written in [US English][us-english]
+1. [Ruby](https://github.com/bbatsov/ruby-style-guide).
+ Important sections include [Source Code Layout][rss-source] and
+ [Naming][rss-naming]. Use:
+ - multi-line method chaining style **Option A**: dot `.` on the second line
+ - string literal quoting style **Option A**: single quoted by default
+1. [Rails](https://github.com/bbatsov/rails-style-guide)
+1. [Newlines styleguide][newlines-styleguide]
+1. [Testing][testing]
+1. [JavaScript styleguide][js-styleguide]
+1. [SCSS styleguide][scss-styleguide]
+1. [Shell commands](../shell_commands.md) created by GitLab
+ contributors to enhance security
+1. [Database Migrations](../migration_style_guide.md)
+1. [Markdown](http://www.cirosantilli.com/markdown-styleguide)
+1. [Documentation styleguide](https://docs.gitlab.com/ee/development/documentation/styleguide.html)
+1. Interface text should be written subjectively instead of objectively. It
+ should be the GitLab core team addressing a person. It should be written in
+ present time and never use past tense (has been/was). For example instead
+ of _prohibited this user from being saved due to the following errors:_ the
+ text should be _sorry, we could not create your account because:_
+1. Code should be written in [US English][us-english]
This is also the style used by linting tools such as
[RuboCop](https://github.com/bbatsov/rubocop),
diff --git a/doc/development/contributing/index.md b/doc/development/contributing/index.md
index eac7cb44c40..f4486ae3549 100644
--- a/doc/development/contributing/index.md
+++ b/doc/development/contributing/index.md
@@ -1,41 +1,4 @@
-<!-- START doctoc generated TOC please keep comment here to allow auto update -->
-<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
-**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)*
-
-- [Contribute to GitLab](#contribute-to-gitlab)
-- [Security vulnerability disclosure](#security-vulnerability-disclosure)
-- [Code of conduct](#code-of-conduct)
-- [Closing policy for issues and merge requests](#closing-policy-for-issues-and-merge-requests)
-- [Helping others](#helping-others)
-- [I want to contribute!](#i-want-to-contribute)
-- [Contribution Flow](#contribution-flow)
-- [Workflow labels](#workflow-labels)
- - [Type labels](#type-labels)
- - [Subject labels](#subject-labels)
- - [Team labels](#team-labels)
- - [Milestone labels](#milestone-labels)
- - [Bug Priority labels](#bug-priority-labels)
- - [Bug Severity labels](#bug-severity-labels)
- - [Severity impact guidance](#severity-impact-guidance)
- - [Label for community contributors](#label-for-community-contributors)
-- [Implement design & UI elements](#implement-design--ui-elements)
-- [Issue tracker](#issue-tracker)
- - [Issue triaging](#issue-triaging)
- - [Feature proposals](#feature-proposals)
- - [Issue tracker guidelines](#issue-tracker-guidelines)
- - [Issue weight](#issue-weight)
- - [Regression issues](#regression-issues)
- - [Technical and UX debt](#technical-and-ux-debt)
- - [Stewardship](#stewardship)
-- [Merge requests](#merge-requests)
- - [Merge request guidelines](#merge-request-guidelines)
- - [Contribution acceptance criteria](#contribution-acceptance-criteria)
-- [Definition of done](#definition-of-done)
-- [Style guides](#style-guides)
-
-<!-- END doctoc generated TOC please keep comment here to allow auto update -->
-
-## Contribute to GitLab
+# Contribute to GitLab
For a first-time step-by-step guide to the contribution process, see
["Contributing to GitLab"](https://about.gitlab.com/contributing/).
diff --git a/doc/development/contributing/issue_workflow.md b/doc/development/contributing/issue_workflow.md
index 08042fa2aec..fed29d37b26 100644
--- a/doc/development/contributing/issue_workflow.md
+++ b/doc/development/contributing/issue_workflow.md
@@ -1,27 +1,4 @@
-<!-- START doctoc generated TOC please keep comment here to allow auto update -->
-<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
-**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)*
-
-- [Workflow labels](#workflow-labels)
- - [Type labels](#type-labels)
- - [Subject labels](#subject-labels)
- - [Team labels](#team-labels)
- - [Release Scoping labels](#release-scoping-labels)
- - [Priority labels](#priority-labels)
- - [Severity labels](#severity-labels)
- - [Severity impact guidance](#severity-impact-guidance)
- - [Label for community contributors](#label-for-community-contributors)
- - [Issue triaging](#issue-triaging)
- - [Feature proposals](#feature-proposals)
- - [Issue tracker guidelines](#issue-tracker-guidelines)
- - [Issue weight](#issue-weight)
- - [Regression issues](#regression-issues)
- - [Technical and UX debt](#technical-and-ux-debt)
- - [Stewardship](#stewardship)
-
-<!-- END doctoc generated TOC please keep comment here to allow auto update -->
-
-## Workflow labels
+# Workflow labels
To allow for asynchronous issue handling, we use [milestones][milestones-page]
and [labels][labels-page]. Leads and product managers handle most of the
@@ -45,7 +22,7 @@ labels, you can _always_ add the team and type, and often also the subject.
[milestones-page]: https://gitlab.com/gitlab-org/gitlab-ce/milestones
[labels-page]: https://gitlab.com/gitlab-org/gitlab-ce/labels
-### Type labels
+## Type labels
Type labels are very important. They define what kind of issue this is. Every
issue should have one or more.
@@ -61,7 +38,7 @@ already reserved for subject labels).
The descriptions on the [labels page][labels-page] explain what falls under each type label.
-### Subject labels
+## Subject labels
Subject labels are labels that define what area or feature of GitLab this issue
hits. They are not always necessary, but very convenient.
@@ -75,7 +52,7 @@ issue is labeled with a subject label corresponding to your expertise.
Subject labels are always all-lowercase.
-### Team labels
+## Team labels
Team labels specify what team is responsible for this issue.
Assigning a team label makes sure issues get the attention of the appropriate
@@ -107,7 +84,7 @@ indicate if an issue needs backend work, frontend work, or both.
Team labels are always capitalized so that they show up as the first label for
any issue.
-### Release Scoping labels
+## Release Scoping labels
Release Scoping labels help us clearly communicate expectations of the work for the
release. There are three levels of Release Scoping labels:
@@ -138,7 +115,7 @@ This label documents the planned timeline & urgency which is used to measure aga
| ~P3 | Medium Priority | Within the next 3 releases (approx one quarter) |
| ~P4 | Low Priority | Anything outside the next 3 releases (approx beyond one quarter) |
-### Severity labels
+## Severity labels
Severity labels help us clearly communicate the impact of a ~bug on users.
@@ -149,7 +126,7 @@ Severity labels help us clearly communicate the impact of a ~bug on users.
| ~S3 | Major Severity | Broken Feature, workaround acceptable | Can create merge requests only from the Merge Requests page, not through the Issue. |
| ~S4 | Low Severity | Functionality inconvenience or cosmetic issue | Label colors are incorrect / not being displayed. |
-#### Severity impact guidance
+### Severity impact guidance
Severity levels can be applied further depending on the facet of the impact; e.g. Affected customers, GitLab.com availability, performance and etc. The below is a guideline.
@@ -160,7 +137,7 @@ Severity levels can be applied further depending on the facet of the impact; e.g
| ~S3 | A few users or a single paid customer affected | Limited impact on important portions of GitLab.com | Degradation is likely to occur in the near future |
| ~S4 | No paid users/customer affected, or expected to in the near future | Minor impact on on GitLab.com | Degradation _may_ occur but it's not likely |
-### Label for community contributors
+## Label for community contributors
Issues that are beneficial to our users, 'nice to haves', that we currently do
not have the capacity for or want to give the priority to, are labeled as
@@ -200,7 +177,7 @@ If you've decided that you would like to work on an issue, please @-mention
the [appropriate product manager](https://about.gitlab.com/handbook/product/#who-to-talk-to-for-what)
as soon as possible. The product manager will then pull in appropriate GitLab team
members to further discuss scope, design, and technical considerations. This will
-ensure that that your contribution is aligned with the GitLab product and minimize
+ensure that your contribution is aligned with the GitLab product and minimize
any rework and delay in getting it merged into master.
GitLab team members who apply the ~"Accepting Merge Requests" label to an issue
@@ -210,8 +187,7 @@ any potential community contributor to @-mention per above.
[up-for-grabs]: https://gitlab.com/gitlab-org/gitlab-ce/issues?label_name=Accepting+Merge+Requests&scope=all&sort=weight_asc&state=opened
[firt-timers]: https://gitlab.com/gitlab-org/gitlab-ce/issues?label_name%5B%5D=Accepting+Merge+Requests&scope=all&sort=upvotes_desc&state=opened&weight=1
-
-### Issue triaging
+## Issue triaging
Our issue triage policies are [described in our handbook]. You are very welcome
to help the GitLab team triage issues. We also organize [issue bash events] once
@@ -224,7 +200,7 @@ on those issues. Please select someone with relevant experience from the
the commit history for the affected files to find someone.
We also use [GitLab Triage] to automate some triaging policies. This is
-currently setup as a [scheduled pipeline] running on [quality/triage-ops]
+currently set up as a [scheduled pipeline] running on [quality/triage-ops]
project.
[described in our handbook]: https://about.gitlab.com/handbook/engineering/issue-triage/
@@ -233,7 +209,7 @@ project.
[scheduled pipeline]: https://gitlab.com/gitlab-org/quality/triage-ops/pipeline_schedules/10512/edit
[quality/triage-ops]: https://gitlab.com/gitlab-org/quality/triage-ops
-### Feature proposals
+## Feature proposals
To create a feature proposal for CE, open an issue on the
[issue tracker of CE][ce-tracker].
@@ -250,7 +226,7 @@ code snippet right after your description in a new line: `~"feature proposal"`.
Please keep feature proposals as small and simple as possible, complex ones
might be edited to make them small and simple.
-Please submit Feature Proposals using the ['Feature Proposal' issue template](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/.gitlab/issue_templates/Feature%20Proposal.md) provided on the issue tracker.
+Please submit Feature Proposals using the ['Feature Proposal' issue template](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/.gitlab/issue_templates/Feature%20proposal.md) provided on the issue tracker.
For changes in the interface, it is helpful to include a mockup. Issues that add to, or change, the interface should
be given the ~"UX" label. This will allow the UX team to provide input and guidance. You may
@@ -259,7 +235,7 @@ need to ask one of the [core team] members to add the label, if you do not have
If you want to create something yourself, consider opening an issue first to
discuss whether it is interesting to include this in GitLab.
-### Issue tracker guidelines
+## Issue tracker guidelines
**[Search the issue tracker][ce-tracker]** for similar entries before
submitting your own, there's a good chance somebody else had the same issue or
@@ -271,7 +247,7 @@ The text in the parenthesis is there to help you with what to include. Omit it
when submitting the actual issue. You can copy-paste it and then edit as you
see fit.
-### Issue weight
+## Issue weight
Issue weight allows us to get an idea of the amount of work required to solve
one or multiple issues. This makes it possible to schedule work more accurately.
@@ -293,7 +269,7 @@ is probably 1, adding a new Git Hook maybe 4 or 5, big features 7-9.
issues or chunks. You can simply not set the weight of a parent issue and set
weights to children issues.
-### Regression issues
+## Regression issues
Every monthly release has a corresponding issue on the CE issue tracker to keep
track of functionality broken by that release and any fixes that need to be
@@ -313,7 +289,7 @@ addressed.
[8.3 Regressions]: https://gitlab.com/gitlab-org/gitlab-ce/issues/4127
[update the notes]: https://gitlab.com/gitlab-org/release-tools/blob/master/doc/pro-tips.md#update-the-regression-issue
-### Technical and UX debt
+## Technical and UX debt
In order to track things that can be improved in GitLab's codebase,
we use the ~"technical debt" label in [GitLab's issue tracker][ce-tracker].
@@ -337,7 +313,7 @@ for a release by the appropriate person.
Make sure to mention the merge request that the ~"technical debt" issue or
~"UX debt" issue is associated with in the description of the issue.
-### Stewardship
+## Stewardship
For issues related to the open source stewardship of GitLab,
there is the ~"stewardship" label.
diff --git a/doc/development/contributing/merge_request_workflow.md b/doc/development/contributing/merge_request_workflow.md
index 685287f7a0c..a286e74908c 100644
--- a/doc/development/contributing/merge_request_workflow.md
+++ b/doc/development/contributing/merge_request_workflow.md
@@ -1,15 +1,4 @@
-<!-- START doctoc generated TOC please keep comment here to allow auto update -->
-<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
-**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)*
-
-- [Merge requests](#merge-requests)
- - [Merge request guidelines](#merge-request-guidelines)
- - [Contribution acceptance criteria](#contribution-acceptance-criteria)
-- [Definition of done](#definition-of-done)
-
-<!-- END doctoc generated TOC please keep comment here to allow auto update -->
-
-## Merge requests
+# Merge requests
We welcome merge requests with fixes and improvements to GitLab code, tests,
and/or documentation. The issues that are specifically suitable for
@@ -36,7 +25,7 @@ some potentially easy issues.
To start with GitLab development download the [GitLab Development Kit][gdk] and
see the [Development section](../README.md) for some guidelines.
-### Merge request guidelines
+## Merge request guidelines
If you can, please submit a merge request with the fix or improvements
including tests. If you don't know how to fix the issue but can write a test
@@ -114,7 +103,7 @@ Please ensure that your merge request meets the contribution acceptance criteria
When having your code reviewed and when reviewing merge requests please take the
[code review guidelines](../code_review.md) into account.
-### Contribution acceptance criteria
+## Contribution acceptance criteria
1. The change is as small as possible
1. Include proper tests and make all tests pass (unless it contains a test
diff --git a/doc/development/database_debugging.md b/doc/development/database_debugging.md
index 9c31265e417..b2c804b2ff0 100644
--- a/doc/development/database_debugging.md
+++ b/doc/development/database_debugging.md
@@ -33,7 +33,7 @@ If your test DB is giving you problems, it is safe to nuke it because it doesn't
- `bundle exec rake db:migrate RAILS_ENV=development`: Execute any pending migrations that you may have picked up from a MR
- `bundle exec rake db:migrate:status RAILS_ENV=development`: Check if all migrations are `up` or `down`
- `bundle exec rake db:migrate:down VERSION=20170926203418 RAILS_ENV=development`: Tear down a migration
- - `bundle exec rake db:migrate:up VERSION=20170926203418 RAILS_ENV=development`: Setup a migration
+ - `bundle exec rake db:migrate:up VERSION=20170926203418 RAILS_ENV=development`: Set up a migration
- `bundle exec rake db:migrate:redo VERSION=20170926203418 RAILS_ENV=development`: Re-run a specific migration
diff --git a/doc/development/database_helpers.md b/doc/development/database_helpers.md
new file mode 100644
index 00000000000..21e4e725de6
--- /dev/null
+++ b/doc/development/database_helpers.md
@@ -0,0 +1,63 @@
+# Database helpers
+
+There are a number of useful helper modules defined in `/lib/gitlab/database/`.
+
+## Subquery
+
+In some cases it is not possible to perform an operation on a query.
+For example:
+
+```ruby
+Geo::EventLog.where('id < 100').limit(10).delete_all
+```
+
+Will give this error:
+
+> ActiveRecord::ActiveRecordError: delete_all doesn't support limit
+
+One solution would be to wrap it in another `where`:
+
+```ruby
+Geo::EventLog.where(id: Geo::EventLog.where('id < 100').limit(10)).delete_all
+```
+
+This works with PostgreSQL, but with MySQL it gives this error:
+
+> ActiveRecord::StatementInvalid: Mysql2::Error: This version of MySQL
+> doesn't yet support 'LIMIT & IN/ALL/ANY/SOME subquery'
+
+Also, that query doesn't have very good performance. Using a
+`INNER JOIN` with itself is better.
+
+So instead of this query:
+
+```sql
+SELECT geo_event_log.*
+FROM geo_event_log
+WHERE geo_event_log.id IN
+ (SELECT geo_event_log.id
+ FROM geo_event_log
+ WHERE (id < 100)
+ LIMIT 10)
+```
+
+It's better to write:
+
+```sql
+SELECT geo_event_log.*
+FROM geo_event_log
+INNER JOIN
+ (SELECT geo_event_log.*
+ FROM geo_event_log
+ WHERE (id < 100)
+ LIMIT 10) t2 ON geo_event_log.id = t2.id
+```
+
+And this is where `Gitlab::Database::Subquery.self_join` can help
+you. So you can rewrite the above statement as:
+
+```ruby
+Gitlab::Database::Subquery.self_join(Geo::EventLog.where('id < 100').limit(10)).delete_all
+```
+
+And this also works with MySQL, so you don't need to worry about that.
diff --git a/doc/development/documentation/index.md b/doc/development/documentation/index.md
index 7ac211ed550..2db78e4a365 100644
--- a/doc/development/documentation/index.md
+++ b/doc/development/documentation/index.md
@@ -43,13 +43,13 @@ how to structure GitLab docs.
Currently GitLab docs use Redcarpet as [markdown](../../user/markdown.md) engine, but there's an [open discussion](https://gitlab.com/gitlab-com/gitlab-docs/issues/50) for implementing Kramdown in the near future.
-All the docs follow the [documentation style guidelines](styleguide.md).
+All the docs follow the [documentation style guidelines](styleguide.md). See [Linting](#linting) for help to follow the guidelines.
## Documentation directory structure
The documentation is structured based on the GitLab UI structure itself,
separated by [`user`](https://gitlab.com/gitlab-org/gitlab-ce/tree/master/doc/user),
-[`administrator`](https://gitlab.com/gitlab-org/gitlab-ce/tree/master/doc/administration), and [`contributor`](https://gitlab.com/gitlab-org/gitlab-ce/tree/master/doc/development).
+[`administrator`](https://gitlab.com/gitlab-org/gitlab-ce/tree/master/doc/administration), and [`contributor`](https://gitlab.com/gitlab-org/gitlab-ce/tree/master/doc/development).
In order to have a [solid site structure](https://searchengineland.com/seo-benefits-developing-solid-site-structure-277456) for our documentation,
all docs should be linked. Every new document should be cross-linked to its related documentation, and linked from its topic-related index, when existent.
@@ -223,6 +223,108 @@ redirect_from: 'https://docs.gitlab.com/my-old-location/README.html'
Note: it is necessary to include the file name in the `redirect_from` URL,
even if it's `index.html` or `README.html`.
+## Linting
+
+To help adhere to the [documentation style guidelines](styleguide.md), and to improve the content
+ added to documentation, consider locally installing and running documentation linters. This will
+ help you catch common issues before raising merge requests for review of documentation.
+
+The following are some suggested linters you can install locally and sample configuration:
+
+- `proselint`
+- `markdownlint`
+
+NOTE: **Note:**
+This list does not limit what other linters you can add to your local documentation writing
+ toolchain.
+
+### `proselint`
+
+`proselint` checks for common problems with English prose. It provides a
+ [plethora of checks](http://proselint.com/checks/) that are helpful for technical writing.
+
+`proselint` can be used [on the command line](http://proselint.com/utility/), either on a single
+ Markdown file or on all Markdown files in a project. For example, to run `proselint` on all
+ documentation in the [`gitlab-ce` project](https://gitlab.com/gitlab-org/gitlab-ce), run the
+ following commands from within the `gitlab-ce` project:
+
+```sh
+cd doc
+proselint **/*.md
+```
+
+`proselint` can also be run from within editors using plugins. For example, the following plugins
+ are available:
+
+- [Sublime Text](https://packagecontrol.io/packages/SublimeLinter-contrib-proselint)
+- [Visual Studio Code](https://marketplace.visualstudio.com/items?itemName=PatrykPeszko.vscode-proselint)
+- [Others](https://github.com/amperser/proselint#plugins-for-other-software)
+
+#### Sample `proselint` configuration
+
+All of the checks are good to use. However, excluding the `typography.symbols` checks might reduce
+ noise. The following sample `proselint` configuration disables the `typography.symbols` checks:
+
+```json
+{
+ "checks": {
+ "typography.symbols": false
+ }
+}
+```
+
+A file with `proselint` configuration must be placed in a
+ [valid location](https://github.com/amperser/proselint#checks). For example, `~/.config/proselint/config`.
+
+### `markdownlint`
+
+`markdownlint` checks that certain rules ([example](https://github.com/DavidAnson/markdownlint/blob/master/README.md#rules--aliases))
+ are followed for Markdown syntax. Our [style guidelines](styleguide.md) elaborate on which choices
+ must be made when selecting Markdown syntax for GitLab documentation and this tool helps
+ catch deviations from those guidelines.
+
+`markdownlint` can be used [on the command line](https://github.com/igorshubovych/markdownlint-cli#markdownlint-cli--),
+ either on a single Markdown file or on all Markdown files in a project. For example, to run
+ `markdownlint` on all documentation in the [`gitlab-ce` project](https://gitlab.com/gitlab-org/gitlab-ce),
+ run the following commands from within the `gitlab-ce` project:
+
+```sh
+cd doc
+markdownlint **/*.md
+```
+
+`markdownlint` can also be run from within editors using plugins. For example, the following plugins
+ are available:
+
+- [Sublime Text](https://packagecontrol.io/packages/SublimeLinter-contrib-markdownlint)
+- [Visual Studio Code](https://marketplace.visualstudio.com/items?itemName=DavidAnson.vscode-markdownlint)
+- [Others](https://github.com/DavidAnson/markdownlint#related)
+
+#### Sample `markdownlint` configuration
+
+The following sample `markdownlint` configuration modifies the available default rules to:
+
+- Adhere to the [style guidelines](styleguide.md).
+- Apply conventions found in the GitLab documentation.
+
+```json
+{
+ "default": true,
+ "header-style": { "style": "atx" },
+ "ul-style": { "style": "dash" },
+ "line-length": false,
+ "no-trailing-punctuation": false,
+ "ol-prefix": { "style": "one" },
+ "blanks-around-fences": false,
+ "hr-style": { "style": "---" },
+ "fenced-code-language": false
+}
+```
+
+For [`markdownlint`](https://gitahub.com/DavidAnson/markdownlint/), this configuration must be
+ placed in a [valid location](https://github.com/igorshubovych/markdownlint-cli#configuration). For
+ example, `~/.markdownlintrc`.
+
## Testing
We treat documentation as code, thus have implemented some testing.
@@ -278,7 +380,6 @@ for GitLab Team members.
- Label the MR `Documentation`
- Assign the correct milestone (see note below)
-
NOTE: **Note:**
If the release version you want to add the documentation to has already been
frozen or released, use the label `Pick into X.Y` to get it merged into
@@ -411,6 +512,22 @@ The following GitLab features are used among others:
Every GitLab instance includes the documentation, which is available from `/help`
(`http://my-instance.com/help`), e.g., <https://gitlab.com/help>.
+The documentation available online on docs.gitlab.com is continuously
+deployed every hour from the `master` branch of CE, EE, Omnibus, and Runner. Therefore,
+once a merge request gets merged, it will be available online on the same day,
+but they will be shipped (and available on `/help`) within the milestone assigned
+to the MR.
+
+For instance, let's say your merge request has a milestone set to 11.3, which
+will be released on 2018-09-22. If it gets merged on 2018-09-15, it will be
+available online on 2018-09-15, but, as the feature freeze date has passed, if
+the MR does not have a "pick into 11.3" label, the milestone has to be changed
+to 11.4 and it will be shipped with all GitLab packages only on 2018-10-22,
+with GitLab 11.4. Meaning, it will only be available under `/help` from GitLab
+11.4 onwards, but available on docs.gitlab.com on the same day it was merged.
+
+### Linking to `/help`
+
When you're building a new feature, you may need to link the documentation
from GitLab, the application. This is normally done in files inside the
`app/views/` directory with the help of the `help_page_path` helper method.
diff --git a/doc/development/documentation/styleguide.md b/doc/development/documentation/styleguide.md
index 8083f219d4a..c43f91278de 100644
--- a/doc/development/documentation/styleguide.md
+++ b/doc/development/documentation/styleguide.md
@@ -10,6 +10,8 @@ GitLab documentation. Check the
Check the GitLab handbook for the [writing styles guidelines](https://about.gitlab.com/handbook/communication/#writing-style-guidelines).
+For help adhering to the guidelines, see [Linting](index.md#linting).
+
## Files
- [Directory structure](index.md#location-and-naming-documents): place the docs
@@ -251,7 +253,7 @@ below.
(in that order) that introduced it. The above quote would be then transformed to:
```md
- > [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/1242) in GitLab 8.3.
+ > [Introduced](<link-to-issue>) in GitLab 8.3.
```
- If the feature is only available in GitLab Enterprise Edition, don't forget to mention
@@ -259,10 +261,22 @@ below.
the feature is available in:
```md
- > [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/1242)
- in [GitLab Starter](https://about.gitlab.com/pricing/) 8.3.
+ > [Introduced](<link-to-issue>) in [GitLab Starter](https://about.gitlab.com/pricing/) 10.3.
```
+#### Early versions of EE
+
+If the feature was created before GitLab 9.2 (before [different EE tiers were introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/1851)):
+
+- Declare it as "Introduced in GitLab Enterprise Edition X.Y".
+- Note which tier the feature is available in.
+
+For example:
+
+```md
+> [Introduced](<link-to-issue>) in GitLab Enterprise Edition 9.0. Available in [GitLab Premium](https://about.gitlab.com/pricing/).
+```
+
### Product badges
When a feature is available in EE-only tiers, add the corresponding tier according to the
diff --git a/doc/development/fe_guide/components.md b/doc/development/fe_guide/components.md
index 66a8abe42f7..ee0c2d534ff 100644
--- a/doc/development/fe_guide/components.md
+++ b/doc/development/fe_guide/components.md
@@ -42,7 +42,7 @@ See also the [corresponding UX guide](../ux_guide/components.md#dropdowns).
See also the [corresponding UX guide](../ux_guide/components.md#modals).
-We have a reusable Vue component for modals: [vue_shared/components/gl-modal.vue](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/app/assets/javascripts/vue_shared/components/gl-modal.vue)
+We have a reusable Vue component for modals: [vue_shared/components/gl_modal.vue](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/app/assets/javascripts/vue_shared/components/gl_modal.vue)
Here is an example of how to use it:
diff --git a/doc/development/feature_flags.md b/doc/development/feature_flags.md
index 6f757f1ce7b..417298205f5 100644
--- a/doc/development/feature_flags.md
+++ b/doc/development/feature_flags.md
@@ -65,13 +65,18 @@ In the rare case that you need the feature flag to be on automatically, use
Feature.enabled?(:feature_flag, project, default_enabled: true)
```
+For more information about rolling out changes using feature flags, refer to the
+[Rolling out changes using feature flags](rolling_out_changes_using_feature_flags.md)
+guide.
+
### 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:
+Whenever a feature flag is present, make sure to test _both_ states of the
+feature flag. You can stub a feature flag as follows:
```ruby
stub_feature_flags(my_feature_flag: false)
diff --git a/doc/development/file_storage.md b/doc/development/file_storage.md
index fdbd7f1fa37..6e014e8c751 100644
--- a/doc/development/file_storage.md
+++ b/doc/development/file_storage.md
@@ -45,6 +45,11 @@ In the case of Issues/MR/Notes Markdown attachments, there is a different approa
instead of basing the path into a mutable variable `:project_path_with_namespace`, it's possible to use the
hash of the project ID instead, if project migrates to the new approach (introduced in 10.2).
+> Note: We provide an [all-in-one rake task] to migrate all uploads to object
+> storage in one go. If a new Uploader class or model type is introduced, make
+> sure you add a rake task invocation corresponding to it to the [category
+> list].
+
### Path segments
Files are stored at multiple locations and use different path schemes.
@@ -137,3 +142,5 @@ end
[CarrierWave]: https://github.com/carrierwaveuploader/carrierwave
[Hashed Storage]: ../administration/repository_storage_types.md
+[all-in-one rake task]: ../administration/raketasks/uploads/migrate.md
+[category list]: https://gitlab.com/gitlab-org/gitlab-ce/blob/master/lib/tasks/gitlab/uploads/migrate.rake
diff --git a/doc/development/gitaly.md b/doc/development/gitaly.md
index 4f9ca1920a5..f4784c19359 100644
--- a/doc/development/gitaly.md
+++ b/doc/development/gitaly.md
@@ -9,7 +9,7 @@ status of the migration.
## Developing new Git features
-Starting with Gitlab 10.8, all new Git features should be developed in
+Starting with GitLab 10.8, all new Git features should be developed in
Gitaly.
> This is a new process that is not clearly defined yet. If you want
diff --git a/doc/development/i18n/index.md b/doc/development/i18n/index.md
index 7290a175501..c44690a4c5d 100644
--- a/doc/development/i18n/index.md
+++ b/doc/development/i18n/index.md
@@ -50,3 +50,5 @@ able to proofread and instructions on becoming a proofreader yourself.
## Release
Translations are typically included in the next major or minor release.
+
+See [Merging translations from Crowdin](merging_translations.md)
diff --git a/doc/development/i18n/merging_translations.md b/doc/development/i18n/merging_translations.md
new file mode 100644
index 00000000000..d172aa6da21
--- /dev/null
+++ b/doc/development/i18n/merging_translations.md
@@ -0,0 +1,60 @@
+# Merging translations from Crowdin
+
+Crowdin automatically syncs the `gitlab.pot` file presenting newly
+added translations to the community of translators.
+
+At the same time, it creates a merge request to merge all newly added
+& approved translations. Find the [merge reqeust created by
+`gitlab-crowdin-bot`](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests?scope=all&utf8=%E2%9C%93&state=opened&author_username=gitlab-crowdin-bot)
+to see new and merged merge requests. They are created in EE and need
+to be ported to CE manually.
+
+## Validation
+
+By default Crowdin commits translations with `[skip ci]` in the commit
+message. This is done to avoid a bunch of pipelines being run. Before
+merging translations, make sure to trigger a pipeline to validate
+translations, we have static analysis validating things Crowdin
+doesn't do. Create a [new pipeline](https://gitlab.com/gitlab-org/gitlab-ee/pipelines/new) for the
+`master-i18n` branch.
+
+If there are validation errors, the easiest solution is to disapprove
+the offending string in Crowdin, leaving a comment with what is
+required to fix the offense. There is an
+[issue](https://gitlab.com/gitlab-org/gitlab-ce/issues/49208)
+suggesting to automate this process. Disapproving will exclude the
+invalid translation, the merge request will be updated within a few
+minutes.
+
+It might be handy to pause the integration on the Crowdin side for a
+little while so translations don't keep coming. This can be done by
+clicking `Pause sync` on the [Crowdin integration settings
+page](https://translate.gitlab.com/project/gitlab-ee/settings#integration).
+
+When all failures are resolved, the translations need to be double
+checked once more [as discussed in this
+issue](https://gitlab.com/gitlab-org/gitlab-ce/issues/37850).
+
+## Merging translations
+
+When all translations are found good and pipelines pass the
+translations can be merged into the master branch. After that is done,
+create a new merge request cherry-picking the translations from EE to
+CE. When merging the translations, make sure to check the `Remove
+source branch` checkbox, so Crowdin recreates the `master-i18n` from
+master after the new translation was merged.
+
+We are discussing automating this entire process
+[here](https://gitlab.com/gitlab-org/gitlab-ce/issues/39309).
+
+## Recreate the merge request
+
+Crowdin creates a new merge request as soon as the old one is closed
+or merged. But it won't recreate the `master-i18n` branch every
+time. To force Crowdin to recreate the branch, close any [open merge
+request](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests?scope=all&utf8=%E2%9C%93&state=opened&author_username=gitlab-crowdin-bot)
+and delete the
+[`master-18n`](https://gitlab.com/gitlab-org/gitlab-ee/branches/all?utf8=%E2%9C%93&search=master-i18n).
+
+This might be needed when the merge request contains failures that
+have been fixed on master.
diff --git a/doc/development/i18n/proofreader.md b/doc/development/i18n/proofreader.md
index 7054ff39da0..5e13c725e15 100644
--- a/doc/development/i18n/proofreader.md
+++ b/doc/development/i18n/proofreader.md
@@ -30,6 +30,7 @@ are very appreciative of the work done by translators and proofreaders!
- Korean
- Chang-Ho Cha - [GitLab](https://gitlab.com/changho-cha), [Crowdin](https://crowdin.com/profile/zzazang)
- Huang Tao - [GitLab](https://gitlab.com/htve), [Crowdin](https://crowdin.com/profile/htve)
+ - Ji Hun Oh - [GitLab](https://gitlab.com/Baw-Appie), [Crowdin](https://crowdin.com/profile/BawAppie)
- Polish
- Filip Mech - [GitLab](https://gitlab.com/mehenz), [Crowdin](https://crowdin.com/profile/mehenz)
- Portuguese, Brazilian
diff --git a/doc/development/merge_request_performance_guidelines.md b/doc/development/merge_request_performance_guidelines.md
index 12badbe39b2..ee01c89e0ed 100644
--- a/doc/development/merge_request_performance_guidelines.md
+++ b/doc/development/merge_request_performance_guidelines.md
@@ -168,6 +168,7 @@ user objects for every username we can remove the need for running the same
query for every mention of `@alice`.
Caching data per transaction can be done using
-[RequestStore](https://github.com/steveklabnik/request_store). Caching data in
-Redis can be done using [Rails' caching
+[RequestStore](https://github.com/steveklabnik/request_store) (use
+`Gitlab::SafeRequestStore` to avoid having to remember to check
+`RequestStore.active?`). Caching data in Redis can be done using [Rails' caching
system](http://guides.rubyonrails.org/caching_with_rails.html).
diff --git a/doc/development/module_with_instance_variables.md b/doc/development/module_with_instance_variables.md
index 48a1b7f847e..7bdfa04fc57 100644
--- a/doc/development/module_with_instance_variables.md
+++ b/doc/development/module_with_instance_variables.md
@@ -60,7 +60,7 @@ as long as it's contained in the same module; that is, no other modules or
objects are touching them, then it would be an acceptable use.
We especially allow the case where a single instance variable is used with
-`||=` to setup the value. This would look like:
+`||=` to set up the value. This would look like:
``` ruby
module M
diff --git a/doc/development/ordering_table_columns.md b/doc/development/ordering_table_columns.md
index 5d00e1f7a0c..e9c6481635b 100644
--- a/doc/development/ordering_table_columns.md
+++ b/doc/development/ordering_table_columns.md
@@ -1,32 +1,49 @@
-# Ordering Table Columns
+# Ordering Table Columns in PostgreSQL
Similar to C structures the space of a table is influenced by the order of
columns. This is because the size of columns is aligned depending on the type of
-the column. Take the following column order for example:
+the following column. Let's consider an example:
-* id (integer, 4 bytes)
-* name (text, variable)
-* user_id (integer, 4 bytes)
+- `id` (integer, 4 bytes)
+- `name` (text, variable)
+- `user_id` (integer, 4 bytes)
-Integers are aligned to the word size. This means that on a 64 bit platform the
-actual size of each column would be: 8 bytes, variable, 8 bytes. This means that
-each row will require at least 16 bytes for the two integers, and a variable
-amount for the text field. If a table has a few rows this is not an issue, but
-once you start storing millions of rows you can save space by using a different
-order. For the above example a more ideal column order would be the following:
+The first column is a 4-byte integer. The next is text of variable length. The
+`text` data type requires 1-word alignment, and on 64-bit platform, 1 word is 8
+bytes. To meet the alignment requirements, four zeros are to be added right
+after the first column, so `id` occupies 4 bytes, then 4 bytes of alignment
+padding, and only next `name` is being stored. Therefore, in this case, 8 bytes
+will be spent for storing a 4-byte integer.
-* id (integer, 4 bytes)
-* user_id (integer, 4 bytes)
-* name (text, variable)
+The space between rows is also subject to alignment padding. The `user_id`
+column takes only 4 bytes, and on 64-bit platform, 4 zeroes will be added for
+alignment padding, to allow storing the next row beginning with the "clear" word.
-In this setup the `id` and `user_id` columns can be packed together, which means
-we only need 8 bytes to store _both_ of them. This in turn each row will require
-8 bytes less of space.
+As a result, the actual size of each column would be (ommiting variable length
+data and 24-byte tuple header): 8 bytes, variable, 8 bytes. This means that
+each row will require at least 16 bytes for the two 4-byte integers. If a table
+has a few rows this is not an issue. However, once you start storing millions of
+rows you can save space by using a different order. For the above example, the
+ideal column order would be the following:
+
+- `id` (integer, 4 bytes)
+- `user_id` (integer, 4 bytes)
+- `name` (text, variable)
+
+or
+
+- `name` (text, variable)
+- `id` (integer, 4 bytes)
+- `user_id` (integer, 4 bytes)
+
+In these examples, the `id` and `user_id` columns are packed together, which
+means we only need 8 bytes to store _both_ of them. This in turn means each row
+will require 8 bytes less space.
For GitLab we require that columns of new tables are ordered based to use the
least amount of space. An easy way of doing this is to order them based on the
-type size in descending order with variable sizes (string and text columns for
-example) at the end.
+type size in descending order with variable sizes (`text`, `varchar`, arrays,
+`json`, `jsonb`, and so on) at the end.
## Type Sizes
@@ -36,7 +53,7 @@ of information we will list the sizes of common types here so it's easier to
look them up. Here "word" refers to the word size, which is 4 bytes for a 32
bits platform and 8 bytes for a 64 bits platform.
-| Type | Size | Aligned To |
+| Type | Size | Alignment needed |
|:-----------------|:-------------------------------------|:-----------|
| smallint | 2 bytes | 1 word |
| integer | 4 bytes | 1 word |
@@ -58,7 +75,7 @@ always be at the end of a table.
## Real Example
-Let's use the "events" table as an example, which currently has the following
+Let's use the `events` table as an example, which currently has the following
layout:
| Column | Type | Size |
@@ -89,8 +106,8 @@ divided into fixed size chunks as follows:
| 8 bytes | updated_at |
| 8 bytes | action, author_id |
-This means that excluding the variable sized data we need at least 48 bytes per
-row.
+This means that excluding the variable sized data and tuple header, we need at
+least 8 * 6 = 48 bytes per row.
We can optimise this by using the following column order instead:
@@ -120,8 +137,8 @@ This would produce the following chunks:
| variable | title |
| variable | data |
-Here we only need 40 bytes per row excluding the variable sized data. 8 bytes
-being saved may not sound like much, but for tables as large as the "events"
-table it does begin to matter. For example, when storing 80 000 000 rows this
-translates to a space saving of at least 610 MB: all by just changing the order
-of a few columns.
+Here we only need 40 bytes per row excluding the variable sized data and 24-byte
+tuple header. 8 bytes being saved may not sound like much, but for tables as
+large as the `events` table it does begin to matter. For example, when storing
+80 000 000 rows this translates to a space saving of at least 610 MB, all by
+just changing the order of a few columns.
diff --git a/doc/development/performance.md b/doc/development/performance.md
index 05caffb150a..c7b10dfd5ce 100644
--- a/doc/development/performance.md
+++ b/doc/development/performance.md
@@ -364,8 +364,7 @@ Depending on the size of the String and how frequently it would be allocated
there's no guarantee it will.
Strings will be frozen by default in Ruby 3.0. To prepare our code base for
-this eventuality, it's a good practice to add the following header to all
-Ruby files:
+this eventuality, we will be adding the following header to all Ruby files:
```ruby
# frozen_string_literal: true
@@ -379,6 +378,9 @@ test = +"hello"
test += " world"
```
+When adding new Ruby files, please check that you can add the above header,
+as omitting it may lead to style check failures.
+
## Anti-Patterns
This is a collection of [anti-patterns][anti-pattern] that should be avoided
diff --git a/doc/development/rake_tasks.md b/doc/development/rake_tasks.md
index fc51b74da1d..2ad748d4802 100644
--- a/doc/development/rake_tasks.md
+++ b/doc/development/rake_tasks.md
@@ -1,6 +1,6 @@
# Rake tasks for developers
-## Setup db with developer seeds
+## Set up db with developer seeds
Note that if your db user does not have advanced privileges you must create the db manually before running this command.
diff --git a/doc/development/rolling_out_changes_using_feature_flags.md b/doc/development/rolling_out_changes_using_feature_flags.md
new file mode 100644
index 00000000000..905aa26a40b
--- /dev/null
+++ b/doc/development/rolling_out_changes_using_feature_flags.md
@@ -0,0 +1,153 @@
+# Rolling out changes using feature flags
+
+[Feature flags](feature_flags.md) can be used to gradually roll out changes, be
+it a new feature, or a performance improvement. By using feature flags, we can
+comfortably measure the impact of our changes, while still being able to easily
+disable those changes, without having to revert an entire release.
+
+## When to use feature flags
+
+Starting with GitLab 11.4, developers are required to use feature flags for
+non-trivial changes. Such changes include:
+
+* New features (e.g. a new merge request widget, epics, etc).
+* Complex performance improvements that may require additional testing in
+ production, such as rewriting complex queries.
+* Invasive changes to the user interface, such as a new navigation bar or the
+ removal of a sidebar.
+* Adding support for importing projects from a third-party service.
+
+In all cases, those working on the changes can best decide if a feature flag is
+necessary. For example, changing the color of a button doesn't need a feature
+flag, while changing the navigation bar definitely needs one. In case you are
+uncertain if a feature flag is necessary, simply ask about this in the merge
+request, and those reviewing the changes will likely provide you with an answer.
+
+When using a feature flag for UI elements, make sure to _also_ use a feature
+flag for the underlying backend code, if there is any. This ensures there is
+absolutely no way to use the feature until it is enabled.
+
+## The cost of feature flags
+
+When reading the above, one might be tempted to think this procedure is going to
+add a lot of work. Fortunately, this is not the case, and we'll show why. For
+this example we'll specify the cost of the work to do as a number, ranging from
+0 to infinity. The greater the number, the more expensive the work is. The cost
+does _not_ translate to time, it's just a way of measuring complexity of one
+change relative to another.
+
+Let's say we are building a new feature, and we have determined that the cost of
+this is 10. We have also determined that the cost of adding a feature flag check
+in a variety of places is 1. If we do not use feature flags, and our feature
+works as intended, our total cost is 10. This however is the best case scenario.
+Optimising for the best case scenario is guaranteed to lead to trouble, whereas
+optimising for the worst case scenario is almost always better.
+
+To illustrate this, let's say our feature causes an outage, and there's no
+immediate way to resolve it. This means we'd have to take the following steps to
+resolve the outage:
+
+1. Revert the release.
+1. Perform any cleanups that might be necessary, depending on the changes that
+ were made.
+1. Revert the commit, ensuring the "master" branch remains stable. This is
+ especially necessary if solving the problem can take days or even weeks.
+1. Pick the revert commit into the appropriate stable branches, ensuring we
+ don't block any future releases until the problem is resolved.
+
+As history has shown, these steps are time consuming, complex, often involve
+many developers, and worst of all: our users will have a bad experience using
+GitLab.com until the problem is resolved.
+
+Now let's say that all of this has an associated cost of 10. This means that in
+the worst case scenario, which we should optimise for, our total cost is now 20.
+
+If we had used a feature flag, things would have been very different. We don't
+need to revert a release, and because feature flags are disabled by default we
+don't need to revert and pick any Git commits. In fact, all we have to do is
+disable the feature, and _maybe_ perform some cleanup. Let's say that the cost
+of this is 1. In this case, our best case cost is 11: 10 to build the feature,
+and 1 to add the feature flag. The worst case cost is now 12: 10 to build the
+feature, 1 to add the feature flag, and 1 to disable it.
+
+Here we can see that in the best case scenario the work necessary is only a tiny
+bit more compared to not using a feature flag. Meanwhile, the process of
+reverting our changes has been made significantly cheaper, to the point of being
+trivial.
+
+In other words, feature flags do not slow down the development process. Instead,
+they speed up the process as managing incidents now becomes _much_ easier. Once
+continuous deployments are easier to perform, the time to iterate on a feature
+is reduced even further, as you no longer need to wait weeks before your changes
+are available on GitLab.com.
+
+## Rolling out changes
+
+The procedure of using feature flags is straightforward, and similar to not
+using them. You add the necessary tests (make sure to test both the on and off
+states of your feature flag(s)), make sure they all pass, have the code
+reviewed, etc. You then submit your merge request, and add the ~"feature flag"
+label. This label is used to signal to release managers that your changes are
+hidden behind a feature flag and that it is safe to pick the MR into a stable
+branch, without the need for an exception request.
+
+When the changes are deployed it is time to start rolling out the feature to our
+users. The exact procedure of rolling out a change is unspecified, as this can
+vary from change to change. However, in general we recommend rolling out changes
+incrementally, instead of enabling them for everybody right away. We also
+recommend you to _not_ enable a feature _before_ the code is being deployed.
+This allows you to separate rolling out a feature from a deploy, making it
+easier to measure the impact of both separately.
+
+GitLab's feature library (using
+[Flipper](https://github.com/jnunemaker/flipper), and covered in the [Feature
+Flags](feature_flags.md) guide) supports rolling out changes to a percentage of
+users. This in turn can be controlled using [GitLab
+chatops](https://docs.gitlab.com/ee/ci/chatops/).
+
+For example, to enable a feature for 25% of all users, run the following in
+Slack:
+
+```
+/chatops run feature set new_navigation_bar 25
+```
+
+This will enable the feature for GitLab.com, with `new_navigation_bar` being the
+name of the feature. We can also enable the feature for <https://dev.gitlab.org>
+or <https://staging.gitlab.com>:
+
+```
+/chatops run feature set new_navigation_bar 25 --dev
+/chatops run feature set new_navigation_bar 25 --staging
+```
+
+If you are not certain what percentages to use, simply use the following steps:
+
+1. 25%
+1. 50%
+1. 75%
+1. 100%
+
+Between every step you'll want to wait a little while and monitor the
+appropriate graphs on <https://dashboards.gitlab.net>. The exact time to wait
+may differ. For some features a few minutes is enough, while for others you may
+want to wait several hours or even days. This is entirely up to you, just make
+sure it is clearly communicated to your team, and the Production team if you
+anticipate any potential problems.
+
+Once a change is deemed stable, submit a new merge request to remove the
+feature flag. This ensures the change is available to all users and self-hosted
+instances. Make sure to add the ~"feature flag" label to this merge request so
+release managers are aware the changes are hidden behind a feature flag. If the
+merge request has to be picked into a stable branch (e.g. after the 7th), make
+sure to also add the appropriate "Pick into X" label (e.g. "Pick into 11.4").
+
+One might be tempted to think this will delay the release of a feature by at
+least one month (= one release). This is not the case. A feature flag does not
+have to stick around for a specific amount of time (e.g. at least one release),
+instead they should stick around until the feature is deemed stable. Stable
+means it works on GitLab.com without causing any problems, such as outages. In
+most cases this will translate to a feature (with a feature flag) being shipped
+in RC1, followed by the feature flag being removed in RC2. This in turn means
+the feature will be stable by the time we publish a stable package around the
+22nd of the month.
diff --git a/doc/development/testing_guide/index.md b/doc/development/testing_guide/index.md
index 0cd63a54b55..67e4cfeda0e 100644
--- a/doc/development/testing_guide/index.md
+++ b/doc/development/testing_guide/index.md
@@ -59,6 +59,12 @@ parallelization, monitoring.
---
+## [Review apps](review_apps.md)
+
+How review apps are set up for GitLab CE/EE and how to use them.
+
+---
+
## [Testing Rake tasks](testing_rake_tasks.md)
Everything you should know about how to test Rake tasks.
diff --git a/doc/development/testing_guide/review_apps.md b/doc/development/testing_guide/review_apps.md
new file mode 100644
index 00000000000..25c6371f3d7
--- /dev/null
+++ b/doc/development/testing_guide/review_apps.md
@@ -0,0 +1,82 @@
+# Review apps
+
+We currently have review apps available as a manual job in EE pipelines. Here is
+[the first implementation](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/6259).
+
+That said, [the Quality team is working](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/6665)
+on making Review Apps automatically deployed by each pipeline, both in CE and EE.
+
+## How does it work?
+
+1. On every EE [pipeline][gitlab-pipeline] during the `test` stage, you can
+ start the [`review` job][review-job]
+1. The `review` job [triggers a pipeline][cng-pipeline] in the
+ [`CNG-mirror`][cng-mirror] [^1] project
+1. The `CNG-mirror` pipeline creates the Docker images of each component (e.g. `gitlab-rails-ee`,
+ `gitlab-shell`, `gitaly` etc.) based on the commit from the
+ [GitLab pipeline][gitlab-pipeline] and store them in its
+ [registry][cng-mirror-registry]
+1. Once all images are built, the review app is deployed using
+ [the official GitLab Helm chart][helm-chart] [^2] to the
+ [`review-apps-ee` Kubernetes cluster on GCP][review-apps-ee]
+ - The actual scripts used to deploy the review app can be found at
+ [`scripts/review_apps/review-apps.sh`][review-apps.sh]
+ - These scripts are basically
+ [our official Auto DevOps scripts][Auto-DevOps.gitlab-ci.yml] where the
+ default CNG images are overriden with the images built and stored in the
+ [`CNG-mirror` project's registry][cng-mirror-registry]
+1. Once the `review` job succeeds, you should be able to use your review app
+ thanks to the direct link to it from the MR widget. The default username is
+ `root` and its password can be found in the 1Password secure note named
+ **gitlab-{ce,ee} review app's root password**.
+
+**Additional notes:**
+
+- The Kubernetes cluster is connected to the `gitlab-ee` project using [GitLab's
+ Kubernetes integration][gitlab-k8s-integration]. This basically allows to have
+ a link to the review app directly from the merge request widget.
+- The manual `stop_review` in the `post-cleanup` stage can be used to stop a
+ review app manually, and is also started by GitLab once a branch is deleted
+- [TBD] Review apps are cleaned up regularly using a pipeline schedule that runs
+ the [`scripts/review_apps/automated_cleanup.rb`][automated_cleanup.rb] script
+
+[^1]: We use the `CNG-mirror` project so that the `CNG`, (**C**loud **N**ative **G**itLab), project's registry is
+ not overloaded with a lot of transient Docker images.
+[^2]: Since we're using [the official GitLab Helm chart][helm-chart], this means
+ you get the a dedicated environment for your branch that's very close to what it
+ would look in production
+
+## Frequently Asked Questions
+
+**Will it be too much to trigger CNG image builds on every test run? This could create thousands of unused docker images.**
+
+ > We have to start somewhere and improve later. If we see this getting out of hand, we will revisit.
+
+**How big is the Kubernetes cluster?**
+
+ > The cluster is currently setup with a single pool of preemptible
+ nodes, with a minimum of 1 node and a maximum of 30 nodes.
+
+**What are the machine running on the cluster?**
+
+ > We're currently using `n1-standard-4` (4 vCPUs, 15 GB memory) machines.
+
+**How do we secure this from abuse? Apps are open to the world so we need to find a way to limit it to only us.**
+
+ > This won't work for forks. We will add a root password to 1password shared vault.
+
+[gitlab-pipeline]: https://gitlab.com/gitlab-org/gitlab-ee/pipelines/29302122
+[review-job]: https://gitlab.com/gitlab-org/gitlab-ee/-/jobs/94294136
+[cng-mirror]: https://gitlab.com/gitlab-org/build/CNG-mirror
+[cng-pipeline]: https://gitlab.com/gitlab-org/build/CNG-mirror/pipelines/29307727
+[cng-mirror-registry]: https://gitlab.com/gitlab-org/build/CNG-mirror/container_registry
+[helm-chart]: https://gitlab.com/charts/gitlab/
+[review-apps-ee]: https://console.cloud.google.com/kubernetes/clusters/details/us-central1-b/review-apps-ee?project=gitlab-review-apps
+[review-apps.sh]: https://gitlab.com/gitlab-org/gitlab-ee/blob/master/scripts/review_apps/review-apps.sh
+[automated_cleanup.rb]: https://gitlab.com/gitlab-org/gitlab-ee/blob/master/scripts/review_apps/automated_cleanup.rb
+[Auto-DevOps.gitlab-ci.yml]: https://gitlab.com/gitlab-org/gitlab-ce/blob/master/lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml
+[gitlab-k8s-integration]: https://docs.gitlab.com/ee/user/project/clusters/index.html
+
+---
+
+[Return to Testing documentation](index.md)
diff --git a/doc/development/ux_guide/users.md b/doc/development/ux_guide/users.md
index 6afb33cfc36..f9c395b2dff 100644
--- a/doc/development/ux_guide/users.md
+++ b/doc/development/ux_guide/users.md
@@ -154,7 +154,7 @@ He credits himself as being entirely responsible for moving his company to GitLa
#### Updating to the latest release
Matthieu introduced his company to GitLab. He is responsible for maintaining and managing the company's installation in addition to his day job. He feels updates are too frequent and he doesn't always have sufficient time to update GitLab. As a result, he's not up to date with releases.
-Matthieu tried to set up automatic updates, however, as he isn't a Systems Administrator, he wasn't confident in his set-up. He feels he should be able to "upgrade without users even noticing" but hasn't figured out how to do this yet. Matthieu would like the "update process to be triggered from the Admin Panel, perhaps accompanied with a changelog and the option to skip updates."
+Matthieu tried to set up automatic updates, however, as he isn't a Systems Administrator, he wasn't confident in his setup. He feels he should be able to "upgrade without users even noticing" but hasn't figured out how to do this yet. Matthieu would like the "update process to be triggered from the Admin Panel, perhaps accompanied with a changelog and the option to skip updates."
Matthieu is looking for confirmation that his update procedure is "secure and efficient" so more tutorials related to this topic would be useful to him.
@@ -242,7 +242,7 @@ Some of GitLab EE's features are too basic, in particular, issues boards which d
James and his team use CI quite heavily for several projects. Whilst they've welcomed improvements to the builds and pipelines interface, they still have some difficulty following build process on the different tabs under Pipelines. Some confusion has arisen from not knowing where to find different pieces of information or how to get to the next stages logs from the current stage's log output screen. They feel more intuitive linking and flow may alleviate the problem. Generally, they feel GitLab's navigation needs to reviewed and optimized.
#### Permissions
->"There is no granular control over user or group permissions. The permissions for a project are too tightly coupled to the permissions for Gitlab CI/build pipelines."
+>"There is no granular control over user or group permissions. The permissions for a project are too tightly coupled to the permissions for GitLab CI/build pipelines."
### Goals
@@ -290,7 +290,7 @@ JavaScript and SQL
Web development, mobile development, UX, open source, gaming, and travel.
### Motivations
-Karolina has been using GitLab.com for around a year. She roughly spends 8 hours every week programming, of that, 2 hours is spent contributing to open source projects. Karolina contributes to open source projects to gain programming experience and to give back to the community. She likes GitLab.com for its free private repositories and range of features which provide her with everything she needs for her personal projects. Karolina is also a massive fan of GitLab's values and the fact that it isn't a "behemoth of a company". She explains that "displaying every single thing (doc, culture, assumptions, development...) in the open gives me greater confidence to choose Gitlab personally and to recommend it at work." She's also an avid reader of GitLab's blog.
+Karolina has been using GitLab.com for around a year. She roughly spends 8 hours every week programming, of that, 2 hours is spent contributing to open source projects. Karolina contributes to open source projects to gain programming experience and to give back to the community. She likes GitLab.com for its free private repositories and range of features which provide her with everything she needs for her personal projects. Karolina is also a massive fan of GitLab's values and the fact that it isn't a "behemoth of a company". She explains that "displaying every single thing (doc, culture, assumptions, development...) in the open gives me greater confidence to choose GitLab personally and to recommend it at work." She's also an avid reader of GitLab's blog.
Karolina works for a software development company which currently hires around 500 people. Karolina would love to use GitLab at work but the company has used GitHub Enterprise for a number of years. She describes management at her company as "old fashioned" and explains that it's "less of a technical issue and more of a cultural issue" to convince upper management to move to GitLab. Karolina is also relatively new to the company so she's apprehensive about pushing too hard to change version control platforms.
diff --git a/doc/gitlab-basics/add-image.md b/doc/gitlab-basics/add-image.md
index 1a44123aa81..17c210c43e0 100644
--- a/doc/gitlab-basics/add-image.md
+++ b/doc/gitlab-basics/add-image.md
@@ -5,7 +5,7 @@ in Windows, or...), put the image file into the GitLab project. You can find the
project as a regular folder in your files.
Go to your [shell](command-line-commands.md), and move into the folder of your
-Gitlab project. This usually means running the following command until you get
+GitLab project. This usually means running the following command until you get
to the desired destination:
```
diff --git a/doc/install/azure/index.md b/doc/install/azure/index.md
index 570bd18c172..7835401cc0b 100644
--- a/doc/install/azure/index.md
+++ b/doc/install/azure/index.md
@@ -74,7 +74,7 @@ The first items we need to configure are the basic settings of the underlying vi
> **Note:** if you're unsure which authentication type to use, select **Password**
1. If you chose **SSH public key** - enter your `SSH public key` into the field provided
- _(read the [SSH documentation][GitLab-Docs-SSH] to learn more about how to setup SSH
+ _(read the [SSH documentation][GitLab-Docs-SSH] to learn more about how to set up SSH
public keys)_
1. If you chose **Password** - enter the password you wish to use _(this is the password that you
will use later in this tutorial to [SSH] into the VM, so make sure it's a strong password/passphrase)_
@@ -154,7 +154,7 @@ on the Azure Dashboard (you may need to refresh the page):
The new VM can also be accessed by clicking the `All resources` or `Virtual machines` icons in the
Azure Portal sidebar navigation menu.
-## Setup a domain name
+## Set up a domain name
The VM will have a public IP address (static by default), but Azure allows us to assign a friendly
DNS name to the VM, so let's go ahead and do that.
@@ -296,7 +296,7 @@ homepage for the project:
![GitLab - Empty Project](img/gitlab-project-home-empty.png)
If you scroll further down the project's home page, you'll see some basic instructions on how to
-setup a local clone of your new repository and push and pull from it:
+set up a local clone of your new repository and push and pull from it:
![GitLab - Empty Project - Basic Instructions](img/gitlab-project-home-instructions.png)
@@ -347,7 +347,7 @@ If you're running [SSH] from the command-line (terminal), then type in the follo
connect to your VM, substituting `username` and `your-azure-domain-name.com` for the correct values.
Again, remember that your Azure VM domain name will be the one you
-[setup previously in the tutorial](#set-up-a-domain-name). If you didn't setup a domain name for
+[set up previously in the tutorial](#set-up-a-domain-name). If you didn't set up a domain name for
your VM, you can use the IP address in its place in the following command:
```bash
@@ -401,7 +401,7 @@ is now showing **"up-to-date"**:
Naturally, we believe that GitLab is a great git repository tool. However, GitLab is a whole lot
more than that too. GitLab unifies issues, code review, CI and CD into a single UI, helping you to
move faster from idea to production, and in this tutorial we showed you how quick and easy it is to
-setup and run your own instance of GitLab on Azure, Microsoft's cloud service.
+set up and run your own instance of GitLab on Azure, Microsoft's cloud service.
Azure is a great way to experiment with GitLab, and if you decide (as we hope) that GitLab is for
you, you can continue to use Azure as your secure, scalable cloud provider or of course run GitLab
@@ -424,7 +424,7 @@ Check out our other [Technical Articles][GitLab-Technical-Articles] or browse th
- [Azure - Properly Shutdown an Azure VM][Azure-Properly-Shutdown-VM]
- [SSH], [PuTTY] and [Using SSH in PuTTY][Using-SSH-In-Putty]
-[Original-Blog-Post]: https://about.gitlab.com/2016/07/13/how-to-setup-a-gitlab-instance-on-microsoft-azure/ "How to Setup a GitLab Instance on Microsoft Azure"
+[Original-Blog-Post]: https://about.gitlab.com/2016/07/13/how-to-setup-a-gitlab-instance-on-microsoft-azure/ "How to Set up a GitLab Instance on Microsoft Azure"
[GitLab-Docs]: https://docs.gitlab.com/ce/README.html "GitLab Documentation"
[GitLab-Technical-Articles]: https://docs.gitlab.com/ce/articles/index.html "GitLab Technical Articles"
[GitLab-Docs-SSH]: https://docs.gitlab.com/ce/ssh/README.html "GitLab Documentation: SSH"
diff --git a/doc/install/database_mysql.md b/doc/install/database_mysql.md
index 4cf18f53239..acaed53e052 100644
--- a/doc/install/database_mysql.md
+++ b/doc/install/database_mysql.md
@@ -79,7 +79,7 @@ After installation or upgrade, remember to [convert any new tables](#tables-and-
---
-GitLab 8.14 has introduced [a feature](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/7420) requiring `utf8mb4` encoding to be supported in your GitLab MySQL Database, which is not the case if you have setup your database before GitLab 8.16.
+GitLab 8.14 has introduced [a feature](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/7420) requiring `utf8mb4` encoding to be supported in your GitLab MySQL Database, which is not the case if you have set up your database before GitLab 8.16.
Follow the below instructions to ensure you use the most up to date requirements for your GitLab MySQL Database.
diff --git a/doc/install/digitaloceandocker.md b/doc/install/digitaloceandocker.md
index 8efc0530b8a..676392eacf2 100644
--- a/doc/install/digitaloceandocker.md
+++ b/doc/install/digitaloceandocker.md
@@ -87,7 +87,7 @@ You can add this to your `~/.bash_profile` file to ensure the `docker` client us
+ Container name: `gitlab-test-8.10`
+ GitLab version: **EE** `8.10.8-ee.0`
-##### Setup container settings
+##### Set up container settings
```
export SSH_PORT=2222
diff --git a/doc/install/installation.md b/doc/install/installation.md
index 85431a80a81..7df81fbc46f 100644
--- a/doc/install/installation.md
+++ b/doc/install/installation.md
@@ -515,7 +515,7 @@ Make GitLab start on boot:
sudo update-rc.d gitlab defaults 21
-### Setup Logrotate
+### Set up 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 09f5aaa04a7..6d1bc4aedc4 100644
--- a/doc/install/kubernetes/gitlab_chart.md
+++ b/doc/install/kubernetes/gitlab_chart.md
@@ -93,7 +93,7 @@ You can access the GitLab instance by visiting the domain name beginning with
above, the URL would be `https://gitlab.example.com`.
If you manually created the secret for initial root password, you
-can use that to sign in as `root` user. If not, Gitlab automatically
+can use that to sign in as `root` user. If not, GitLab automatically
created a random password for `root` user. This can be extracted by the
following command (replace `<name>` by name of the release - which is `gitlab`
if you used the command above):
diff --git a/doc/install/openshift_and_gitlab/index.md b/doc/install/openshift_and_gitlab/index.md
index 70bc3ff770f..5c8a830ac8f 100644
--- a/doc/install/openshift_and_gitlab/index.md
+++ b/doc/install/openshift_and_gitlab/index.md
@@ -80,7 +80,7 @@ This will download the VirtualBox image and fire up the VM with some preconfigur
values as you can see in the Vagrantfile. As you may have noticed, you need
plenty of RAM (5GB in our example), so make sure you have enough.
-Now that OpenShift is setup, let's see how the web console looks like.
+Now that OpenShift is set up, let's see how the web console looks like.
### Explore the OpenShift web console
diff --git a/doc/install/relative_url.md b/doc/install/relative_url.md
index 2f5d4142d04..5f129fd3bd1 100644
--- a/doc/install/relative_url.md
+++ b/doc/install/relative_url.md
@@ -124,5 +124,5 @@ To disable the relative URL:
1. Follow the same as above starting from 2. and set up the
GitLab URL to one that doesn't contain a relative path.
-[omnibus-rel]: http://docs.gitlab.com/omnibus/settings/configuration.html#configuring-a-relative-url-for-gitlab "How to setup relative URL in Omnibus GitLab"
+[omnibus-rel]: http://docs.gitlab.com/omnibus/settings/configuration.html#configuring-a-relative-url-for-gitlab "How to set up relative URL in Omnibus GitLab"
[restart gitlab]: ../administration/restart_gitlab.md#installations-from-source "How to restart GitLab"
diff --git a/doc/install/requirements.md b/doc/install/requirements.md
index 5531dcde4e9..13a6a1c68ad 100644
--- a/doc/install/requirements.md
+++ b/doc/install/requirements.md
@@ -27,7 +27,7 @@ Please see the [installation from source guide](installation.md) and the [instal
### Non-Unix operating systems such as Windows
-GitLab is developed for Unix operating systems.
+GitLab is developed for Unix operating systems.
It does **not** run on Windows, and we have no plans to support it in the near future. For the latest development status view this [issue](https://gitlab.com/gitlab-org/gitlab-ce/issues/46567).
Please consider using a virtual machine to run GitLab.
@@ -103,19 +103,21 @@ features of GitLab work with MySQL/MariaDB:
1. MySQL support for subgroups was [dropped with GitLab 9.3][post].
See [issue #30472][30472] for more information.
-1. GitLab Geo does [not support MySQL](https://docs.gitlab.com/ee/gitlab-geo/database.html#mysql-replication).
-1. [Zero downtime migrations][zero] do not work with MySQL
+1. Geo does [not support MySQL](https://docs.gitlab.com/ee/administration/geo/replication/database.html#mysql-replication). This means no supported Disaster Recovery solution if using MySQL. **[PREMIUM ONLY]**
+1. [Zero downtime migrations][../update/README.md#upgrading-without-downtime] do not work with MySQL.
1. GitLab [optimizes the loading of dashboard events](https://gitlab.com/gitlab-org/gitlab-ce/issues/31806) using [PostgreSQL LATERAL JOINs](https://blog.heapanalytics.com/postgresqls-powerful-new-join-type-lateral/).
1. In general, SQL optimized for PostgreSQL may run much slower in MySQL due to
differences in query planners. For example, subqueries that work well in PostgreSQL
- may not be [performant in MySQL](https://dev.mysql.com/doc/refman/5.7/en/optimizing-subqueries.html)
+ may not be [performant in MySQL](https://dev.mysql.com/doc/refman/5.7/en/optimizing-subqueries.html).
+1. Binary column index length is limited to 20 bytes. This is accomplished with [a hack](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/config/initializers/mysql_set_length_for_binary_indexes.rb).
+1. MySQL requires a variety of hacks to increase limits on various columns, [for example](https://gitlab.com/gitlab-org/gitlab-ce/issues/49583).
+1. [The milestone filter runs slower queries on MySQL](https://gitlab.com/gitlab-org/gitlab-ce/issues/51173#note_99391731).
1. We expect this list to grow over time.
Existing users using GitLab with MySQL/MariaDB are advised to
[migrate to PostgreSQL](../update/mysql_to_postgresql.md) instead.
[30472]: https://gitlab.com/gitlab-org/gitlab-ce/issues/30472
-[zero]: ../update/README.md#upgrading-without-downtime
[post]: https://about.gitlab.com/2017/06/22/gitlab-9-3-released/#dropping-support-for-subgroups-in-mysql
### PostgreSQL Requirements
diff --git a/doc/integration/github.md b/doc/integration/github.md
index 680712f9e01..7a83b8e4b35 100644
--- a/doc/integration/github.md
+++ b/doc/integration/github.md
@@ -19,7 +19,7 @@ GitHub will generate an application ID and secret key for you to use.
- Application name: This can be anything. Consider something like `<Organization>'s GitLab` or `<Your Name>'s GitLab` or something else descriptive.
- Homepage URL: The URL to your GitLab installation. 'https://gitlab.company.com'
- Application description: Fill this in if you wish.
- - Authorization callback URL is 'http(s)://${YOUR_DOMAIN}'. Please make sure the port is included if your Gitlab instance is not configured on default port.
+ - Authorization callback URL is 'http(s)://${YOUR_DOMAIN}'. Please make sure the port is included if your GitLab instance is not configured on default port.
1. Select "Register application".
1. You should now see a Client ID and Client Secret near the top right of the page (see screenshot).
@@ -154,7 +154,7 @@ You will also need to disable Git SSL verification on the server hosting GitLab.
$ git config --global http.sslVerify false
```
-For the changes to take effect, [reconfigure Gitlab] if you installed
+For the changes to take effect, [reconfigure GitLab] if you installed
via Omnibus, or [restart GitLab] if you installed from source.
[reconfigure GitLab]: ../administration/restart_gitlab.md#omnibus-gitlab-reconfigure
diff --git a/doc/integration/gmail_action_buttons_for_gitlab.md b/doc/integration/gmail_action_buttons_for_gitlab.md
index 05a91d9bef9..c19320471e3 100644
--- a/doc/integration/gmail_action_buttons_for_gitlab.md
+++ b/doc/integration/gmail_action_buttons_for_gitlab.md
@@ -2,7 +2,7 @@
GitLab supports [Google actions in email](https://developers.google.com/gmail/markup/actions/actions-overview).
-If correctly setup, emails that require an action will be marked in Gmail.
+If correctly set up, emails that require an action will be marked in Gmail.
![gmail_actions_button.png](img/gmail_action_buttons_for_gitlab.png)
diff --git a/doc/policy/maintenance.md b/doc/policy/maintenance.md
index 7f028565412..fc7b97b3cc2 100644
--- a/doc/policy/maintenance.md
+++ b/doc/policy/maintenance.md
@@ -44,7 +44,7 @@ This decision is made on a case-by-case basis.
## Upgrade recommendations
-We encourage everyone to run the [latest stable release](https://about.gitlab.com/blog/categories/release/) to ensure that you can
+We encourage everyone to run the [latest stable release](https://about.gitlab.com/blog/categories/releases/) to ensure that you can
easily upgrade to the most secure and feature-rich GitLab experience. In order
to make sure you can easily run the most recent stable release, we are working
hard to keep the update process simple and reliable.
diff --git a/doc/raketasks/backup_restore.md b/doc/raketasks/backup_restore.md
index 1d29f6d4e43..2b9cce6539f 100644
--- a/doc/raketasks/backup_restore.md
+++ b/doc/raketasks/backup_restore.md
@@ -523,7 +523,7 @@ more of the following options:
- `BACKUP=timestamp_of_backup` - Required if more than one backup exists.
Read what the [backup timestamp is about](#backup-timestamp).
-- `force=yes` - Does not ask if the authorized_keys file should get regenerated and assumes 'yes' for warning that database tables will be removed.
+- `force=yes` - Does not ask if the authorized_keys file should get regenerated and assumes 'yes' for warning that database tables will be removed, enabling the "Write to authorized_keys file" setting, and updating LDAP providers.
If you are restoring into directories that are mountpoints you will need to make
sure these directories are empty before attempting a restore. Otherwise GitLab
@@ -591,10 +591,11 @@ This procedure assumes that:
First make sure your backup tar file is in the backup directory described in the
`gitlab.rb` configuration `gitlab_rails['backup_path']`. The default is
-`/var/opt/gitlab/backups`.
+`/var/opt/gitlab/backups`. It needs to be owned by the `git` user.
```shell
sudo cp 11493107454_2018_04_25_10.6.4-ce_gitlab_backup.tar /var/opt/gitlab/backups/
+sudo chown git.git /var/opt/gitlab/backups/11493107454_2018_04_25_10.6.4-ce_gitlab_backup.tar
```
Stop the processes that are connected to the database. Leave the rest of GitLab
diff --git a/doc/security/two_factor_authentication.md b/doc/security/two_factor_authentication.md
index f02f7b807cf..cd290a80314 100644
--- a/doc/security/two_factor_authentication.md
+++ b/doc/security/two_factor_authentication.md
@@ -11,7 +11,7 @@ You can read more about it here:
## Enforcing 2FA for all users
Users on GitLab, can enable it without any admin's intervention. If you want to
-enforce everyone to setup 2FA, you can choose from two different ways:
+enforce everyone to set up 2FA, you can choose from two different ways:
1. Enforce on next login
2. Suggest on next login, but allow a grace period before enforcing.
diff --git a/doc/security/user_email_confirmation.md b/doc/security/user_email_confirmation.md
index 48c79cd4769..8c07e11dcb1 100644
--- a/doc/security/user_email_confirmation.md
+++ b/doc/security/user_email_confirmation.md
@@ -1,6 +1,6 @@
# User email confirmation at sign-up
-Gitlab admin can enable email confirmation on sign-up, if you want to confirm all
+GitLab admin can enable email confirmation on sign-up, if you want to confirm all
user emails before they are able to sign-in.
In the Admin area under **Settings** (`/admin/application_settings`), go to section
diff --git a/doc/topics/authentication/index.md b/doc/topics/authentication/index.md
index a8aa11265d0..a645f65938f 100644
--- a/doc/topics/authentication/index.md
+++ b/doc/topics/authentication/index.md
@@ -44,6 +44,6 @@ This page gathers all the resources for the topic **Authentication** within GitL
- [Kanboard Plugin GitLab Authentication](https://kanboard.net/plugin/gitlab-auth)
- [Jenkins GitLab OAuth Plugin](https://wiki.jenkins-ci.org/display/JENKINS/GitLab+OAuth+Plugin)
-- [Setup Gitlab CE with Active Directory authentication](https://www.caseylabs.com/setup-gitlab-ce-with-active-directory-authentication/)
+- [Set up Gitlab CE with Active Directory authentication](https://www.caseylabs.com/setup-gitlab-ce-with-active-directory-authentication/)
- [How to customize GitLab to support OpenID authentication](http://eric.van-der-vlist.com/blog/2013/11/23/how-to-customize-gitlab-to-support-openid-authentication/)
- [Openshift - Configuring Authentication and User Agent](https://docs.openshift.org/latest/install_config/configuring_authentication.html#GitLab)
diff --git a/doc/topics/autodevops/index.md b/doc/topics/autodevops/index.md
index e778f1d83df..681dc8ff20d 100644
--- a/doc/topics/autodevops/index.md
+++ b/doc/topics/autodevops/index.md
@@ -71,11 +71,6 @@ For an overview on the creation of Auto DevOps, read the blog post [From 2/3 of
## Requirements
-TIP: **Tip:**
-For self-hosted installations, the easiest way to make use of Auto DevOps is to
-install GitLab inside a Kubernetes cluster using the [GitLab Omnibus Helm Chart]
-which automatically installs and configures everything you need!
-
To make full use of Auto DevOps, you will need:
1. **GitLab Runner** (needed for all stages) - Your Runner needs to be
@@ -101,10 +96,6 @@ To make full use of Auto DevOps, you will need:
Kubernetes cluster using the
[`nginx-ingress`](https://github.com/kubernetes/charts/tree/master/stable/nginx-ingress)
Helm chart.
- 1. **Wildcard TLS termination** - You can deploy the
- [`kube-lego`](https://github.com/kubernetes/charts/tree/master/stable/kube-lego)
- Helm chart to your Kubernetes cluster to automatically issue certificates
- for your domains using Let's Encrypt.
1. **Prometheus** (needed for Auto Monitoring) - To enable Auto Monitoring, you
will need Prometheus installed somewhere (inside or outside your cluster) and
configured to scrape your Kubernetes cluster. To get response metrics
@@ -148,18 +139,13 @@ Auto DevOps base domain to `1.2.3.4.nip.io`.
Once set up, all requests will hit the load balancer, which in turn will route
them to the Kubernetes pods that run your application(s).
-NOTE: **Note:**
-If GitLab is installed using the [GitLab Omnibus Helm Chart], there are two
-options: provide a static IP, or have one assigned. For more information see the
-relevant docs on the [network prerequisites](../../install/kubernetes/gitlab_omnibus.md#networking-prerequisites).
-
## Using multiple Kubernetes clusters **[PREMIUM]**
When using Auto DevOps, you may want to deploy different environments to
different Kubernetes clusters. This is possible due to the 1:1 connection that
[exists between them](../../user/project/clusters/index.md#multiple-kubernetes-clusters).
-In the [Auto DevOps template](https://gitlab.com/gitlab-org/gitlab-ci-yml/blob/master/Auto-DevOps.gitlab-ci.yml)
+In the [Auto DevOps template](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml)
(used behind the scenes by Auto DevOps), there are currently 3 defined environment names that you need to know:
- `review/` (every environment starting with `review/`)
@@ -482,10 +468,7 @@ The metrics include:
- **Response Metrics:** latency, throughput, error rate
- **System Metrics:** CPU utilization, memory utilization
-If GitLab has been deployed using the [GitLab Omnibus Helm Chart], no
-configuration is required.
-
-If you have installed GitLab using a different method, you need to:
+In order to make use of monitoring you need to:
1. [Deploy Prometheus](../../user/project/integrations/prometheus.md#configuring-your-own-prometheus-server-within-kubernetes) into your Kubernetes cluster
1. If you would like response metrics, ensure you are running at least version
@@ -849,7 +832,6 @@ curl --data "value=true" --header "PRIVATE-TOKEN: personal_access_token" https:/
[review-app]: ../../ci/review_apps/index.md
[container-registry]: ../../user/project/container_registry.md
[postgresql]: https://www.postgresql.org/
-[Auto DevOps template]: https://gitlab.com/gitlab-org/gitlab-ci-yml/blob/master/Auto-DevOps.gitlab-ci.yml
-[GitLab Omnibus Helm Chart]: ../../install/kubernetes/gitlab_omnibus.md
+[Auto DevOps template]: https://gitlab.com/gitlab-org/gitlab-ce/blob/master/lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml
[ee]: https://about.gitlab.com/pricing/
[ce-19507]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/19507
diff --git a/doc/university/README.md b/doc/university/README.md
index 203981b85ec..5edf92b3b09 100644
--- a/doc/university/README.md
+++ b/doc/university/README.md
@@ -11,7 +11,7 @@ and [Blog Articles](https://about.gitlab.com/blog/).
Would you like to contribute to GitLab University? Then please take a look at our contribution [process](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/PROCESS.md) for more information.
-## Gitlab University Curriculum
+## GitLab University Curriculum
The curriculum is composed of GitLab videos, screencasts, presentations, projects and external GitLab content hosted on other services and has been organized into the following sections.
diff --git a/doc/university/glossary/README.md b/doc/university/glossary/README.md
index 89516dba60b..6ff27e495fb 100644
--- a/doc/university/glossary/README.md
+++ b/doc/university/glossary/README.md
@@ -395,7 +395,7 @@ Allow you to [organize issues](../../user/project/milestones/index.md) and merge
### Mirror Repositories
-A project that is setup to automatically have its branches, tags, and commits [updated from an upstream repository](https://docs.gitlab.com/ee/workflow/repository_mirroring.html). This is useful when a repository you're interested in is located on a different server, and you want to be able to browse its content and activity using the familiar GitLab interface.
+A project that is set up to automatically have its branches, tags, and commits [updated from an upstream repository](https://docs.gitlab.com/ee/workflow/repository_mirroring.html). This is useful when a repository you're interested in is located on a different server, and you want to be able to browse its content and activity using the familiar GitLab interface.
### MIT License
@@ -673,7 +673,7 @@ Version control is a system that records changes to a file or set of files over
### Virtual Private Cloud (VPC)
-A [VPC](https://docs.gitlab.com/ce/university/glossary/README.html#virtual-private-cloud-vpc) is an on demand configurable pool of shared computing resources allocated within a public cloud environment, providing some isolation between the different users using the resources. GitLab users need to create a new Amazon VPC in order to [setup High Availability](https://docs.gitlab.com/ce/university/high-availability/aws/).
+A [VPC](https://docs.gitlab.com/ce/university/glossary/README.html#virtual-private-cloud-vpc) is an on demand configurable pool of shared computing resources allocated within a public cloud environment, providing some isolation between the different users using the resources. GitLab users need to create a new Amazon VPC in order to [set up High Availability](https://docs.gitlab.com/ce/university/high-availability/aws/).
### Virtual private server (VPS)
diff --git a/doc/university/high-availability/aws/README.md b/doc/university/high-availability/aws/README.md
index 1bff1488746..0a7ce922de1 100644
--- a/doc/university/high-availability/aws/README.md
+++ b/doc/university/high-availability/aws/README.md
@@ -286,7 +286,7 @@ to make the EFS integration easier to manage.
gitlab_rails['redis_port'] = 6379
Finally run reconfigure, you might find it useful to run a check and
-a service status to make sure everything has been setup correctly.
+a service status to make sure everything has been set up correctly.
sudo gitlab-ctl reconfigure
sudo gitlab-rake gitlab:check
diff --git a/doc/university/support/README.md b/doc/university/support/README.md
index 0cbae71d1f5..805af253367 100644
--- a/doc/university/support/README.md
+++ b/doc/university/support/README.md
@@ -37,7 +37,7 @@ Continue to look over remaining portions of the [University Overview](../README.
Get your development machine ready to familiarize yourself with the codebase, the components, and to be prepared to reproduce issues that our users encounter
- Install the [GDK](https://gitlab.com/gitlab-org/gitlab-development-kit)
- - [Setup OpenLDAP as part of this](https://gitlab.com/gitlab-org/gitlab-development-kit#openldap)
+ - [Set up OpenLDAP as part of this](https://gitlab.com/gitlab-org/gitlab-development-kit#openldap)
#### Become comfortable with the Installation processes that we support
diff --git a/doc/university/training/end-user/README.md b/doc/university/training/end-user/README.md
index 9b8a8db58e2..e5eb5d97e3b 100644
--- a/doc/university/training/end-user/README.md
+++ b/doc/university/training/end-user/README.md
@@ -80,7 +80,7 @@ git config --global user.name "Your Name"
git config --global user.email you@example.com
```
-- If you don't use the global flag you can setup a different author for
+- If you don't use the global flag you can set up a different author for
each project
- Check settings with:
diff --git a/doc/update/4.2-to-5.0.md b/doc/update/4.2-to-5.0.md
index 311664b2bc1..d292327efbd 100644
--- a/doc/update/4.2-to-5.0.md
+++ b/doc/update/4.2-to-5.0.md
@@ -32,7 +32,7 @@ cd /home/git/
sudo -u git -H git clone https://github.com/gitlabhq/gitlab-shell.git /home/git/gitlab-shell
```
-## 3. setup gitlab-shell
+## 3. set up gitlab-shell
```bash
# chmod all repos and files under git
diff --git a/doc/update/7.5-to-7.6.md b/doc/update/7.5-to-7.6.md
index f0dfb177b79..0d45a9528b9 100644
--- a/doc/update/7.5-to-7.6.md
+++ b/doc/update/7.5-to-7.6.md
@@ -82,7 +82,7 @@ git diff origin/7-5-stable:config/gitlab.yml.example origin/7-6-stable:config/gi
* HTTP setups: Make `/etc/nginx/sites-available/gitlab` the same as [`lib/support/nginx/gitlab`][nginx] but with your settings
* HTTPS setups: Make `/etc/nginx/sites-available/gitlab-ssl` the same as [`lib/support/nginx/gitlab-ssl`][nginx-ssl] but with your setting
-#### Setup time zone (optional)
+#### Set up time zone (optional)
Consider setting the time zone in `gitlab.yml` otherwise GitLab will default to UTC. If you set a time zone previously in [`application.rb`][app] (unlikely), unset it.
diff --git a/doc/update/7.6-to-7.7.md b/doc/update/7.6-to-7.7.md
index 85de6b0c546..5e0b2ca7bcd 100644
--- a/doc/update/7.6-to-7.7.md
+++ b/doc/update/7.6-to-7.7.md
@@ -82,7 +82,7 @@ git diff origin/7-6-stable:config/gitlab.yml.example origin/7-7-stable:config/gi
* HTTP setups: Make `/etc/nginx/sites-available/gitlab` the same as [`lib/support/nginx/gitlab`][nginx] but with your settings
* HTTPS setups: Make `/etc/nginx/sites-available/gitlab-ssl` the same as [`lib/support/nginx/gitlab-ssl`][nginx-ssl] but with your setting
-#### Setup time zone (optional)
+#### Set up time zone (optional)
Consider setting the time zone in `gitlab.yml` otherwise GitLab will default to UTC. If you set a time zone previously in [`application.rb`][app] (unlikely), unset it.
diff --git a/doc/update/7.7-to-7.8.md b/doc/update/7.7-to-7.8.md
index 7cee5f79a13..f5b1ebf0a9c 100644
--- a/doc/update/7.7-to-7.8.md
+++ b/doc/update/7.7-to-7.8.md
@@ -83,7 +83,7 @@ git diff origin/7-7-stable:config/gitlab.yml.example origin/7-8-stable:config/gi
* HTTPS setups: Make `/etc/nginx/sites-available/gitlab-ssl` the same as [`lib/support/nginx/gitlab-ssl`][nginx-ssl] but with your settings.
* A new `location /uploads/` section has been added that needs to have the same content as the existing `location @gitlab` section.
-#### Setup time zone (optional)
+#### Set up time zone (optional)
Consider setting the time zone in `gitlab.yml` otherwise GitLab will default to UTC. If you set a time zone previously in [`application.rb`][app] (unlikely), unset it.
diff --git a/doc/update/7.8-to-7.9.md b/doc/update/7.8-to-7.9.md
index 5a8b689dbc1..0db7698936b 100644
--- a/doc/update/7.8-to-7.9.md
+++ b/doc/update/7.8-to-7.9.md
@@ -85,7 +85,7 @@ git diff origin/7-8-stable:config/gitlab.yml.example origin/7-9-stable:config/gi
* HTTPS setups: Make `/etc/nginx/sites-available/gitlab-ssl` the same as [`lib/support/nginx/gitlab-ssl`][nginx-ssl] but with your settings.
* A new `location /uploads/` section has been added that needs to have the same content as the existing `location @gitlab` section.
-#### Setup time zone (optional)
+#### Set up time zone (optional)
Consider setting the time zone in `gitlab.yml` otherwise GitLab will default to UTC. If you set a time zone previously in [`application.rb`][app] (unlikely), unset it.
diff --git a/doc/update/7.9-to-7.10.md b/doc/update/7.9-to-7.10.md
index 99df51dbb99..782fb0736e6 100644
--- a/doc/update/7.9-to-7.10.md
+++ b/doc/update/7.9-to-7.10.md
@@ -81,7 +81,7 @@ git diff origin/7-9-stable:config/gitlab.yml.example origin/7-10-stable:config/g
* HTTPS setups: Make `/etc/nginx/sites-available/gitlab-ssl` the same as [`lib/support/nginx/gitlab-ssl`][nginx-ssl] but with your settings.
* A new `location /uploads/` section has been added that needs to have the same content as the existing `location @gitlab` section.
-#### Setup time zone (optional)
+#### Set up time zone (optional)
Consider setting the time zone in `gitlab.yml` otherwise GitLab will default to UTC. If you set a time zone previously in [`application.rb`][app] (unlikely), unset it.
diff --git a/doc/update/9.4-to-9.5.md b/doc/update/9.4-to-9.5.md
index 1bfc1167c36..6a655f77a55 100644
--- a/doc/update/9.4-to-9.5.md
+++ b/doc/update/9.4-to-9.5.md
@@ -154,7 +154,7 @@ sudo -u git -H make
#### New Gitaly configuration options required
-In order to function Gitaly needs some additional configuration information. Below we assume you installed Gitaly in `/home/git/gitaly` and GitLab Shell in `/home/git/gitlab-shell'.
+In order to function Gitaly needs some additional configuration information. Below we assume you installed Gitaly in `/home/git/gitaly` and GitLab Shell in `/home/git/gitlab-shell`.
```shell
echo '
diff --git a/doc/update/9.5-to-10.0.md b/doc/update/9.5-to-10.0.md
index 8d1cf0f737b..7790d192a82 100644
--- a/doc/update/9.5-to-10.0.md
+++ b/doc/update/9.5-to-10.0.md
@@ -154,7 +154,7 @@ sudo -u git -H make
#### New Gitaly configuration options required
-In order to function Gitaly needs some additional configuration information. Below we assume you installed Gitaly in `/home/git/gitaly` and GitLab Shell in `/home/git/gitlab-shell'.
+In order to function Gitaly needs some additional configuration information. Below we assume you installed Gitaly in `/home/git/gitaly` and GitLab Shell in `/home/git/gitlab-shell`.
```shell
echo '
diff --git a/doc/update/README.md b/doc/update/README.md
index 2c1fbc15719..7d3c4c310a4 100644
--- a/doc/update/README.md
+++ b/doc/update/README.md
@@ -41,7 +41,8 @@ However, for this to work there are the following requirements:
1. You can only upgrade 1 minor release at a time. So from 9.1 to 9.2, not to
9.3.
2. You have to use [post-deployment
- migrations](../development/post_deployment_migrations.md).
+ migrations](../development/post_deployment_migrations.md) (included in
+ zero downtime update steps below)
3. You are using PostgreSQL. If you are using MySQL please look at the release
post to see if downtime is required.
diff --git a/doc/user/gitlab_com/index.md b/doc/user/gitlab_com/index.md
index 0b9395914f9..e14e716a5eb 100644
--- a/doc/user/gitlab_com/index.md
+++ b/doc/user/gitlab_com/index.md
@@ -221,7 +221,7 @@ and the following environment variables:
## Cron jobs
-Periodically executed jobs by Sidekiq, to self-heal Gitlab, do external
+Periodically executed jobs by Sidekiq, to self-heal GitLab, do external
synchronizations, run scheduled pipelines, etc.:
| Setting | GitLab.com | Default |
diff --git a/doc/user/group/subgroups/index.md b/doc/user/group/subgroups/index.md
index b55946a788f..8db36c4a0e8 100644
--- a/doc/user/group/subgroups/index.md
+++ b/doc/user/group/subgroups/index.md
@@ -1,9 +1,8 @@
# Subgroups
-> **Notes:**
-> - [Introduced][ce-2772] in GitLab 9.0.
-> - Not available when using MySQL as external database (support removed in
-> GitLab 9.3 [due to performance reasons][issue]).
+NOTE: **Note:**
+[Introduced][ce-2772] in GitLab 9.0. Not available when using MySQL as external
+database (support removed in GitLab 9.3 [due to performance reasons][issue]).
With subgroups (aka nested groups or hierarchical groups) you can have
up to 20 levels of nested groups, which among other things can help you to:
@@ -79,14 +78,14 @@ structure.
## Creating a subgroup
-> **Notes:**
-> - You need to be an Owner of a group in order to be able to create
-> a subgroup. For more information check the [permissions table][permissions].
-> - For a list of words that are not allowed to be used as group names see the
-> [reserved names][reserved].
-> - Users can always create subgroups if they are explicitly added as an Owner to
-> a parent group even if group creation is disabled by an administrator in their
-> settings.
+NOTE: **Note:**
+You need to be an Owner of a group in order to be able to create a subgroup. For
+more information check the [permissions table][permissions].
+For a list of words that are not allowed to be used as group names see the
+[reserved names][reserved].
+Users can always create subgroups if they are explicitly added as an Owner to
+a parent group even if group creation is disabled by an administrator in their
+settings.
To create a subgroup:
@@ -136,12 +135,15 @@ From the image above, we can deduct the following things:
### Overriding the ancestor group membership
->**Note:**
+NOTE: **Note:**
You need to be an Owner of a group in order to be able to add members to it.
+NOTE: **Note:**
+A user's permissions in a subgroup cannot be lower than in any of its ancestor groups.
+Therefore, you cannot reduce a user's permissions in a subgroup with respect to its ancestor groups.
+
To override a user's membership of an ancestor group (the first group they were
-added to), simply add the user in the new subgroup again, but with different
-permissions.
+added to), add the user to the new subgroup again with a higher set of permissions.
For example, if User0 was first added to group `group-1/group-1-1` with Developer
permissions, then they will inherit those permissions in every other subgroup
diff --git a/doc/user/index.md b/doc/user/index.md
index 649c0b664a5..08995032cb1 100644
--- a/doc/user/index.md
+++ b/doc/user/index.md
@@ -96,7 +96,7 @@ directly from GitLab. No third-party integrations needed.
- [GitLab Auto Deploy](../ci/autodeploy/index.md): Deploy your application out-of-the-box with GitLab Auto Deploy.
- [Review Apps](../ci/review_apps/index.md): Live-preview the changes introduced by a merge request with Review Apps.
- [GitLab Pages](project/pages/index.md): Publish your static site directly from
-GitLab with Gitlab Pages. You can build, test, and deploy any Static Site Generator with Pages.
+GitLab with GitLab Pages. You can build, test, and deploy any Static Site Generator with Pages.
- [GitLab Container Registry](project/container_registry.md): Build and deploy Docker
images with Container Registry.
diff --git a/doc/user/profile/account/delete_account.md b/doc/user/profile/account/delete_account.md
index 910bd20f882..49f0ce2cd79 100644
--- a/doc/user/profile/account/delete_account.md
+++ b/doc/user/profile/account/delete_account.md
@@ -1,5 +1,8 @@
# Deleting a User Account
+NOTE: **Note:**
+Deleting a user will delete all projects in that user namespace.
+
- As a user, you can delete your own account by navigating to **Settings** > **Account** and selecting **Delete account**
- As an admin, you can delete a user account by navigating to the **Admin Area**, selecting the **Users** tab, selecting a user, and clicking on **Delete user**
diff --git a/doc/user/profile/account/two_factor_authentication.md b/doc/user/profile/account/two_factor_authentication.md
index 8838efb18fe..e5411662511 100644
--- a/doc/user/profile/account/two_factor_authentication.md
+++ b/doc/user/profile/account/two_factor_authentication.md
@@ -69,7 +69,7 @@ of recovery codes.
1. Go to **Account**.
1. Click **Enable Two-Factor Authentication**.
1. Plug in your U2F device.
-1. Click on **Setup New U2F Device**.
+1. Click on **Set up New U2F Device**.
1. A light will start blinking on your device. Activate it by pressing its button.
You will see a message indicating that your device was successfully set up.
diff --git a/doc/user/project/clusters/index.md b/doc/user/project/clusters/index.md
index 1edc82ee9ef..41768998a59 100644
--- a/doc/user/project/clusters/index.md
+++ b/doc/user/project/clusters/index.md
@@ -127,8 +127,81 @@ applications running on the cluster.
When GitLab creates the cluster, it enables and uses the legacy
[Attribute-based access control (ABAC)](https://kubernetes.io/docs/admin/authorization/abac/).
The newer [RBAC](https://kubernetes.io/docs/admin/authorization/rbac/)
-authorization will be supported in a
-[future release](https://gitlab.com/gitlab-org/gitlab-ce/issues/29398).
+authorization is [experimental](#role-based-access-control-rbac).
+
+### Role-based access control (RBAC) **[CORE ONLY]**
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/21401) in GitLab 11.4.
+
+CAUTION: **Warning:**
+The RBAC authorization is experimental. To enable it you need access to the
+server where GitLab is installed.
+
+The support for RBAC-enabled clusters is hidden behind a feature flag. Once
+the feature flag is enabled, GitLab will create the necessary service accounts
+and privileges in order to install and run [GitLab managed applications](#installing-applications).
+
+To enable the feature flag:
+
+1. SSH into the server where GitLab is installed.
+1. Enter the Rails console:
+
+ **For Omnibus GitLab**
+
+ ```sh
+ sudo gitlab-rails console
+ ```
+
+ **For installations from source**
+
+ ```sh
+ sudo -u git -H bundle exec rails console
+ ```
+
+1. Enable the RBAC authorization:
+
+ ```ruby
+ Feature.enable('rbac_clusters')
+ ```
+
+If you are creating a [new GKE cluster via
+GitLab](#adding-and-creating-a-new-gke-cluster-via-gitlab), you will be
+asked if you would like to create an RBAC-enabled cluster. Enabling this
+setting will create a `gitlab` service account which will be used by
+GitLab to manage the newly created cluster. To enable this, this service
+account will have the `cluster-admin` privilege.
+
+If you are [adding an existing Kubernetes
+cluster](#adding-an-existing-kubernetes-cluster), you will be asked if
+the cluster you are adding is a RBAC-enabled cluster. Ensure the
+token of the account has administrator privileges for the cluster.
+
+In both cases above, when you install Helm Tiller into your cluster, an
+RBAC-enabled cluster will create a `tiller` service account, with `cluster-admin`
+privileges in the `gitlab-managed-apps` namespace. This service account will be
+added to the installed Helm Tiller and will be used by Helm to install and run
+[GitLab managed applications](#installing-applications).
+
+The table below summarizes which resources will be created in a
+RBAC-enabled cluster :
+
+| Name | Kind | Details | Created when |
+| --- | --- | --- | --- |
+| `gitlab` | `ServiceAccount` | `default` namespace | Creating a new GKE Cluster |
+| `gitlab-admin` | `ClusterRoleBinding` | `cluster-admin` roleRef | Creating a new GKE Cluster |
+| `gitlab-token` | `Secret` | Token for `gitlab` ServiceAccount | Creating a new GKE Cluster |
+| `tiller` | `ServiceAccount` | `gitlab-managed-apps` namespace | Installing Helm Tiller |
+| `tiller-admin` | `ClusterRoleBinding` | `cluster-admin` roleRef | Installing Helm Tiller |
+
+
+Helm Tiller will also create additional service accounts and other RBAC
+resources for each installed application. Consult the documentation for the
+Helm charts for each application for details.
+
+NOTE: **Note:**
+Auto DevOps will not successfully complete in a cluster that only has RBAC
+authorization enabled. RBAC support for Auto DevOps is planned in a
+[future release](https://gitlab.com/gitlab-org/gitlab-ce/issues/44597).
### Security of GitLab Runners
@@ -161,13 +234,13 @@ with Tiller already installed, you should be careful as GitLab cannot
detect it. By installing it via the applications will result into having it
twice, which can lead to confusion during deployments.
-| Application | GitLab version | Description |
-| ----------- | :------------: | ----------- |
-| [Helm Tiller](https://docs.helm.sh/) | 10.2+ | Helm is a package manager for Kubernetes and is required to install all the other applications. It is installed in its own pod inside the cluster which can run the `helm` CLI in a safe environment. |
-| [Ingress](https://kubernetes.io/docs/concepts/services-networking/ingress/) | 10.2+ | Ingress can provide load balancing, SSL termination, and name-based virtual hosting. It acts as a web proxy for your applications and is useful if you want to use [Auto DevOps] or deploy your own web apps. |
-| [Prometheus](https://prometheus.io/docs/introduction/overview/) | 10.4+ | Prometheus is an open-source monitoring and alerting system useful to supervise your deployed applications. |
-| [GitLab Runner](https://docs.gitlab.com/runner/) | 10.6+ | GitLab Runner is the open source project that is used to run your jobs and send the results back to GitLab. It is used in conjunction with [GitLab CI/CD](https://about.gitlab.com/features/gitlab-ci-cd/), the open-source continuous integration service included with GitLab that coordinates the jobs. When installing the GitLab Runner via the applications, it will run in **privileged mode** by default. Make sure you read the [security implications](#security-implications) before doing so. |
-| [JupyterHub](http://jupyter.org/) | 11.0+ | [JupyterHub](https://jupyterhub.readthedocs.io/en/stable/) is a multi-user service for managing notebooks across a team. [Jupyter Notebooks](https://jupyter-notebook.readthedocs.io/en/latest/) provide a web-based interactive programming environment used for data analysis, visualization, and machine learning. We use [this](https://gitlab.com/gitlab-org/jupyterhub-user-image/blob/master/Dockerfile) custom Jupyter image that installs additional useful packages on top of the base Jupyter. **Note**: Authentication will be enabled for any user of the GitLab server via OAuth2. HTTPS will be supported in a future release. |
+| Application | GitLab version | Description | Helm Chart |
+| ----------- | :------------: | ----------- | --------------- |
+| [Helm Tiller](https://docs.helm.sh/) | 10.2+ | Helm is a package manager for Kubernetes and is required to install all the other applications. It is installed in its own pod inside the cluster which can run the `helm` CLI in a safe environment. | n/a |
+| [Ingress](https://kubernetes.io/docs/concepts/services-networking/ingress/) | 10.2+ | Ingress can provide load balancing, SSL termination, and name-based virtual hosting. It acts as a web proxy for your applications and is useful if you want to use [Auto DevOps] or deploy your own web apps. | [stable/nginx-ingress](https://github.com/helm/charts/tree/master/stable/nginx-ingress) |
+| [Prometheus](https://prometheus.io/docs/introduction/overview/) | 10.4+ | Prometheus is an open-source monitoring and alerting system useful to supervise your deployed applications. | [stable/prometheus](https://github.com/helm/charts/tree/master/stable/prometheus) |
+| [GitLab Runner](https://docs.gitlab.com/runner/) | 10.6+ | GitLab Runner is the open source project that is used to run your jobs and send the results back to GitLab. It is used in conjunction with [GitLab CI/CD](https://about.gitlab.com/features/gitlab-ci-cd/), the open-source continuous integration service included with GitLab that coordinates the jobs. When installing the GitLab Runner via the applications, it will run in **privileged mode** by default. Make sure you read the [security implications](#security-implications) before doing so. | [runner/gitlab-runner](https://gitlab.com/charts/gitlab-runner) |
+| [JupyterHub](http://jupyter.org/) | 11.0+ | [JupyterHub](https://jupyterhub.readthedocs.io/en/stable/) is a multi-user service for managing notebooks across a team. [Jupyter Notebooks](https://jupyter-notebook.readthedocs.io/en/latest/) provide a web-based interactive programming environment used for data analysis, visualization, and machine learning. We use [this](https://gitlab.com/gitlab-org/jupyterhub-user-image/blob/master/Dockerfile) custom Jupyter image that installs additional useful packages on top of the base Jupyter. **Note**: Authentication will be enabled for any user of the GitLab server via OAuth2. HTTPS will be supported in a future release. | [jupyter/jupyterhub](https://jupyterhub.github.io/helm-chart/) |
## Getting the external IP address
diff --git a/doc/user/project/container_registry.md b/doc/user/project/container_registry.md
index df850d4f68d..2709ebb6f05 100644
--- a/doc/user/project/container_registry.md
+++ b/doc/user/project/container_registry.md
@@ -27,7 +27,7 @@ to enable it.
1. First, ask your system administrator to enable GitLab Container Registry
following the [administration documentation](../../administration/container_registry.md).
If you are using GitLab.com, this is enabled by default so you can start using
- the Registry immediately. Currently there is a soft (10GB) size restriction for
+ the Registry immediately. Currently there is a soft (10GB) size restriction for
registry on GitLab.com, as part of the [repository size limit](repository/index.html#repository-size).
1. Go to your [project's General settings](settings/index.md#sharing-and-permissions)
and enable the **Container Registry** feature on your project. For new
@@ -216,7 +216,7 @@ needs to trust the mitmproxy SSL certificates for this to work.
The following installation instructions assume you are running Ubuntu:
-1. Install mitmproxy (see http://docs.mitmproxy.org/en/stable/install.html)
+1. [Install mitmproxy](https://docs.mitmproxy.org/stable/overview-installation/).
1. Run `mitmproxy --port 9000` to generate its certificates.
Enter <kbd>CTRL</kbd>-<kbd>C</kbd> to quit.
1. Install the certificate from `~/.mitmproxy` to your system:
@@ -245,7 +245,7 @@ This will run mitmproxy on port `9000`. In another window, run:
curl --proxy http://localhost:9000 https://httpbin.org/status/200
```
-If everything is setup correctly, you will see information on the mitmproxy window and
+If everything is set up correctly, you will see information on the mitmproxy window and
no errors from the curl commands.
#### Running the Docker daemon with a proxy
@@ -293,4 +293,4 @@ Once the right permissions were set, the error will go away.
[docker-docs]: https://docs.docker.com/engine/userguide/intro/
[pat]: ../profile/personal_access_tokens.md
[pdt]: ../project/deploy_tokens/index.md
-[reconfigure]: ../../administration/restart_gitlab.md#omnibus-gitlab-reconfigure \ No newline at end of file
+[reconfigure]: ../../administration/restart_gitlab.md#omnibus-gitlab-reconfigure
diff --git a/doc/user/project/cycle_analytics.md b/doc/user/project/cycle_analytics.md
index 7e788ae6220..ea843054f8e 100644
--- a/doc/user/project/cycle_analytics.md
+++ b/doc/user/project/cycle_analytics.md
@@ -154,7 +154,7 @@ You can [read more about permissions][permissions] in general.
Learn more about Cycle Analytics in the following resources:
-- [Cycle Analytics feature page](https://about.gitlab.com/solutions/cycle-analytics/)
+- [Cycle Analytics feature page](https://about.gitlab.com/features/cycle-analytics/)
- [Cycle Analytics feature preview](https://about.gitlab.com/2016/09/16/feature-preview-introducing-cycle-analytics/)
- [Cycle Analytics feature highlight](https://about.gitlab.com/2016/09/21/cycle-analytics-feature-highlight/)
diff --git a/doc/user/project/deploy_tokens/index.md b/doc/user/project/deploy_tokens/index.md
index 0b9b49f326f..ff647b2f0a2 100644
--- a/doc/user/project/deploy_tokens/index.md
+++ b/doc/user/project/deploy_tokens/index.md
@@ -51,7 +51,7 @@ To download a repository using a Deploy Token, you just need to:
```bash
-git clone http://<username>:<deploy_token>@gitlab.example.com/tanuki/awesome_project.git
+git clone https://<username>:<deploy_token>@gitlab.example.com/tanuki/awesome_project.git
```
Just replace `<username>` and `<deploy_token>` with the proper values
diff --git a/doc/user/project/img/issue_board_milestone_lists.png b/doc/user/project/img/issue_board_milestone_lists.png
new file mode 100644
index 00000000000..91926f58f87
--- /dev/null
+++ b/doc/user/project/img/issue_board_milestone_lists.png
Binary files differ
diff --git a/doc/user/project/img/issue_board_summed_weights.png b/doc/user/project/img/issue_board_summed_weights.png
new file mode 100644
index 00000000000..2288d767d8c
--- /dev/null
+++ b/doc/user/project/img/issue_board_summed_weights.png
Binary files differ
diff --git a/doc/user/project/img/issue_boards_core.png b/doc/user/project/img/issue_boards_core.png
new file mode 100755
index 00000000000..9e819160861
--- /dev/null
+++ b/doc/user/project/img/issue_boards_core.png
Binary files differ
diff --git a/doc/user/project/img/issue_boards_premium.png b/doc/user/project/img/issue_boards_premium.png
new file mode 100755
index 00000000000..bd9164b2961
--- /dev/null
+++ b/doc/user/project/img/issue_boards_premium.png
Binary files differ
diff --git a/doc/user/project/integrations/hangouts_chat.md b/doc/user/project/integrations/hangouts_chat.md
index 47525617d95..20a71da927c 100644
--- a/doc/user/project/integrations/hangouts_chat.md
+++ b/doc/user/project/integrations/hangouts_chat.md
@@ -15,7 +15,7 @@ See also [the Hangouts Chat documentation for configuring incoming webhooks](htt
## On GitLab
-When you have the **Webhook URL** for your Hangouts Chat room webhook, you can setup the GitLab service.
+When you have the **Webhook URL** for your Hangouts Chat room webhook, you can set up the GitLab service.
1. Navigate to the [Integrations page](project_services.md#accessing-the-project-services) in your project's settings, i.e. **Project > Settings > Integrations**.
1. Select the **Hangouts Chat** project service to configure it.
diff --git a/doc/user/project/integrations/img/webhooks_ssl.png b/doc/user/project/integrations/img/webhooks_ssl.png
index f023e9665f2..e5777a2e99b 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/integrations/jira.md b/doc/user/project/integrations/jira.md
index b3821cf8391..ba8b79b911b 100644
--- a/doc/user/project/integrations/jira.md
+++ b/doc/user/project/integrations/jira.md
@@ -49,7 +49,7 @@ We have split this stage in steps so it is easier to follow.
1. The next step is to create a new user (e.g., `gitlab`) who has write access
to projects in JIRA. Enter the user's name and a _valid_ e-mail address
- since JIRA sends a verification e-mail to set-up the password.
+ since JIRA sends a verification e-mail to set up the password.
_**Note:** JIRA creates the username automatically by using the e-mail
prefix. You can change it later if you want._
diff --git a/doc/user/project/integrations/mattermost.md b/doc/user/project/integrations/mattermost.md
index 3e77823a6aa..89de1fe4dcb 100644
--- a/doc/user/project/integrations/mattermost.md
+++ b/doc/user/project/integrations/mattermost.md
@@ -38,7 +38,7 @@ At the end, fill in your Mattermost details:
| Field | Description |
| ----- | ----------- |
-| **Webhook** | The incoming webhook URL which you have to setup on Mattermost, it will be something like: http://mattermost.example/hooks/5xo… |
+| **Webhook** | The incoming webhook URL which you have to set up on Mattermost, it will be something like: http://mattermost.example/hooks/5xo… |
| **Username** | Optional username which can be on messages sent to Mattermost. Fill this in if you want to change the username of the bot. |
| **Notify only broken pipelines** | If you choose to enable the **Pipeline** event and you want to be only notified about failed pipelines. |
diff --git a/doc/user/project/integrations/mattermost_slash_commands.md b/doc/user/project/integrations/mattermost_slash_commands.md
index 488f61c77a3..e031dcad2c3 100644
--- a/doc/user/project/integrations/mattermost_slash_commands.md
+++ b/doc/user/project/integrations/mattermost_slash_commands.md
@@ -102,7 +102,7 @@ in a new slash command.
![Mattermost add command configuration](img/mattermost_slash_command_configuration.png)
-1. After you setup all the values, copy the token (we will use it below) and
+1. After you set up all the values, copy the token (we will use it below) and
click **Done**.
![Mattermost slash command token](img/mattermost_slash_command_token.png)
diff --git a/doc/user/project/integrations/microsoft_teams.md b/doc/user/project/integrations/microsoft_teams.md
index 140c6738a49..ca32689910c 100644
--- a/doc/user/project/integrations/microsoft_teams.md
+++ b/doc/user/project/integrations/microsoft_teams.md
@@ -25,7 +25,7 @@ At the end fill in your Microsoft Teams details:
| Field | Description |
| ----- | ----------- |
-| **Webhook** | The incoming webhook URL which you have to setup on Microsoft Teams. |
+| **Webhook** | The incoming webhook URL which you have to set up on Microsoft Teams. |
| **Notify only broken pipelines** | If you choose to enable the **Pipeline** event and you want to be only notified about failed pipelines. |
After you are all done, click **Save changes** for the changes to take effect.
diff --git a/doc/user/project/integrations/mock_ci.md b/doc/user/project/integrations/mock_ci.md
index 6aefe5dbded..8b1908c46fe 100644
--- a/doc/user/project/integrations/mock_ci.md
+++ b/doc/user/project/integrations/mock_ci.md
@@ -2,7 +2,7 @@
**NB: This service is only listed if you are in a development environment!**
-To setup the mock CI service server, respond to the following endpoints
+To set up the mock CI service server, respond to the following endpoints
- `commit_status`: `#{project.namespace.path}/#{project.path}/status/#{sha}.json`
- Have your service return `200 { status: ['failed'|'canceled'|'running'|'pending'|'success'|'success_with_warnings'|'skipped'|'not_found'] }`
diff --git a/doc/user/project/integrations/prometheus.md b/doc/user/project/integrations/prometheus.md
index f687027e8c8..0b61a41aab0 100644
--- a/doc/user/project/integrations/prometheus.md
+++ b/doc/user/project/integrations/prometheus.md
@@ -8,7 +8,7 @@ within the GitLab interface.
![Environment Dashboard](img/prometheus_dashboard.png)
-There are two ways to setup Prometheus integration, depending on where your apps are running:
+There are two ways to set up Prometheus integration, depending on where your apps are running:
* For deployments on Kubernetes, GitLab can automatically [deploy and manage Prometheus](#managed-prometheus-on-kubernetes)
* For other deployment targets, simply [specify the Prometheus server](#manual-configuration-of-prometheus).
diff --git a/doc/user/project/integrations/webhooks.md b/doc/user/project/integrations/webhooks.md
index 6104eadde35..5a38f5d8aed 100644
--- a/doc/user/project/integrations/webhooks.md
+++ b/doc/user/project/integrations/webhooks.md
@@ -57,6 +57,14 @@ You can turn this off in the webhook settings in your GitLab projects.
![SSL Verification](img/webhooks_ssl.png)
+## Branch filtering
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/20338) in GitLab 11.3.
+
+Push events can be filtered by branch using a branch name or wildcard pattern
+to limit which push events are sent to your webhook endpoint. By default the
+field is blank causing all push events to be sent to your webhook endpoint.
+
## Events
Below are described the supported events.
@@ -1162,7 +1170,7 @@ You can trigger the webhook manually. Sample data from the project will be used.
## Troubleshoot webhooks
-Gitlab stores each perform of the webhook.
+GitLab stores each perform of the webhook.
You can find records for last 2 days in "Recent Deliveries" section on the edit page of each webhook.
![Recent deliveries](img/webhook_logs.png)
diff --git a/doc/user/project/issue_board.md b/doc/user/project/issue_board.md
index 7c6d547d626..464fa5987c1 100644
--- a/doc/user/project/issue_board.md
+++ b/doc/user/project/issue_board.md
@@ -2,13 +2,44 @@
> [Introduced][ce-5554] in [GitLab 8.11](https://about.gitlab.com/2016/08/22/gitlab-8-11-released/#issue-board).
+## Overview
+
The GitLab Issue Board is a software project management tool used to plan,
organize, and visualize a workflow for a feature or product release.
It can be used as a [Kanban] or a [Scrum] board.
-![GitLab Issue Board](img/issue_board.png)
+It provides perfect pairing between issue tracking and project management,
+keeping everything in the same place, so that you don't need to jump
+between different platforms to organize your workflow.
-## Overview
+With GitLab Issue Boards, you organize your issues in lists that correspond to
+their assigned labels, visualizing issues designed as cards throughout that lists.
+
+You define your process and GitLab organizes it for you. You add your labels
+then create the corresponding list to pull in your existing issues. When
+you're ready, you can drag and drop your issue cards from one step to the next.
+
+![GitLab Issue Board - Core](img/issue_boards_core.png)
+
+**<i class="fa fa-youtube-play youtube" aria-hidden="true"></i>
+Watch a [video presentation](https://youtu.be/UWsJ8tkHAa8) of
+Issue Boards** (version introduced in GitLab 8.11 - August 2016).
+
+### Advanced features of Issue Boards
+
+With [GitLab Starter](https://about.gitlab.com/pricing/), you can create
+[multiple issue boards](#multiple-issue-boards) for a given project. **[STARTER]**
+
+With [GitLab Premium](https://about.gitlab.com/pricing/), you can also create multiple
+issue boards for your groups, and add lists for [assignees](#assignee-lists) and
+[milestones](#milestone-lists). **[PREMIUM]**
+
+Check all the [advanced features of Issue Boards](#gitlab-enterprise-features-for-issue-boards)
+below.
+
+![GitLab Issue Boards - Premium](img/issue_boards_premium.png)
+
+## How it works
The Issue Board builds on GitLab's existing
[issue tracking functionality](issues/index.md#issue-tracker) and
@@ -28,15 +59,12 @@ and deploy from one single platform. Issue Boards help you to visualize
and manage the entire process _in_ GitLab.
With [Multiple Issue Boards](#use-cases-for-multiple-issue-boards), available
-only in [GitLab Enterprise Edition](#features-per-tier),
+only in [different tiers of GitLab Enterprise Edition](#gitlab-enterprise-features-for-issue-boards),
you go even further, as you can not only keep yourself and your project
organized from a broader perspective with one Issue Board per project,
but also allow your team members to organize their own workflow by creating
multiple Issue Boards within the same project.
-For a visual overview, see our [Issue Board feature page](https://about.gitlab.com/features/issueboard/)
-on about.gitlab.com or our [video introduction to Issue Boards](https://www.youtube.com/watch?v=UWsJ8tkHAa8).
-
## Use cases
There are many ways to use GitLab Issue Boards tailored to your own preferred workflow.
@@ -111,11 +139,6 @@ to improve their workflow with multiple boards.
Create lists for each of your team members and quickly drag-and-drop issues onto each team member.
-## Permissions
-
-[Developers and up](../permissions.md) can use all the functionality of the
-Issue Board, that is, create or delete lists and drag issues from one list to another.
-
## Issue Board terminology
- **Issue Board** - Each board represents a unique view for your issues. It can have multiple lists with each list consisting of issues represented by cards.
@@ -126,6 +149,139 @@ Issue Board, that is, create or delete lists and drag issues from one list to an
- **Closed** (default): shows all closed issues. Always appears as the rightmost list.
- **Card** - A box in the list that represents an individual issue. The information you can see on a card consists of the issue number, the issue title, the assignee, and the labels associated with the issue. You can drag cards from one list to another to change their label or assignee from that of the source list to that of the destination list.
+## Permissions
+
+[Developers and up](../permissions.md) can use all the functionality of the
+Issue Board, that is, create or delete lists and drag issues from one list to another.
+
+## GitLab Enterprise features for Issue Boards
+
+GitLab Issue Boards are available on GitLab Core and GitLab.com Free, but some
+advanced functionalities are only present in higher tiers: GitLab.com Bronze,
+Silver, or Gold, or GitLab self-managed Starter, Premium, and Ultimate, as described
+on the following sections.
+
+For a collection of [features per tier](#summary-of-features-per-tier), check the summary below.
+
+### Multiple Issue Boards **[STARTER]**
+
+> Introduced in [GitLab Enterprise Edition 8.13](https://about.gitlab.com/2016/10/22/gitlab-8-13-released/#multiple-issue-boards-ee).
+
+Multiple Issue Boards, as the name suggests, allow for more than one Issue Board
+for a given project or group. This is great for large projects with more than one team
+or in situations where a repository is used to host the code of multiple
+products.
+
+Clicking on the current board name in the upper left corner will reveal a
+menu from where you can create another Issue Board and rename or delete the
+existing one.
+
+NOTE: **Note:**
+The Multiple Issue Boards feature is available for
+**projects in GitLab Starter Edition** and for **groups in GitLab Premium Edition**.
+
+![Multiple Issue Boards](img/issue_boards_multiple.png)
+
+### Configurable Issue Boards **[STARTER]**
+
+> Introduced in [GitLab Starter Edition 10.2](https://about.gitlab.com/2017/11/22/gitlab-10-2-released/#issue-boards-configuration).
+
+An Issue Board can be associated with a GitLab [Milestone](milestones/index.md#milestones),
+[Labels](labels.md), Assignee and Weight
+which will automatically filter the Board issues according to these fields.
+This allows you to create unique boards according to your team's need.
+
+![Create scoped board](img/issue_board_creation.png)
+
+You can define the scope of your board when creating it or by clicking on the "Edit board" button. Once a milestone, assignee or weight is assigned to an Issue Board, you will no longer be able to filter
+through these in the search bar. In order to do that, you need to remove the desired scope (e.g. milestone, assignee or weight) from the Issue Board.
+
+![Edit board configuration](img/issue_board_edit_button.png)
+
+If you don't have editing permission in a board, you're still able to see the configuration by clicking on "View scope".
+
+![Viewing board configuration](img/issue_board_view_scope.png)
+
+### Focus mode **[STARTER]**
+
+> Introduced in [GitLab Starter 9.1](https://about.gitlab.com/2017/04/22/gitlab-9-1-released/#issue-boards-focus-mode-ees-eep).
+
+Click the button at the top right to toggle focus mode on and off. In focus mode, the navigation UI is hidden, allowing you to focus on issues in the board.
+
+![Board focus mode](img/issue_board_focus_mode.gif)
+
+### Sum of Issue Weights **[STARTER]**
+
+The top of each list indicates the sum of issue weights for the issues that
+belong to that list. This is useful when using boards for capacity allocation,
+especially in combination with [assignee lists](#assignee-lists).
+
+![Issue Board summed weights](img/issue_board_summed_weights.png)
+
+### Group Issue Boards **[PREMIUM]**
+
+> Introduced in [GitLab Premium 10.0](https://about.gitlab.com/2017/09/22/gitlab-10-0-released/#group-issue-boards).
+
+Accessible at the group navigation level, a group issue board offers the same features as a project-level board,
+but it can display issues from all projects in that
+group and its descendant subgroups. Similarly, you can only filter by group labels for these
+boards. When updating milestones and labels for an issue through the sidebar update mechanism, again only
+group-level objects are available.
+
+NOTE: **Note:**
+Multiple group issue boards were originally introduced in [GitLab 10.0 Premium](https://about.gitlab.com/2017/09/22/gitlab-10-0-released/#group-issue-boards) and
+one group issue board per group was made available in GitLab 10.6 Core.
+
+![Group issue board](img/group_issue_board.png)
+
+### Assignee lists **[PREMIUM]**
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/5784) in GitLab 11.0 Premium.
+
+Like a regular list that shows all issues that have the list label, you can add
+an assignee list that shows all issues assigned to the given user.
+You can have a board with both label lists and assignee lists. To add an
+assignee list:
+
+1. Click **Add list**.
+1. Select the **Assignee list** tab.
+1. Search and click on the user you want to add as an assignee.
+
+Now that the assignee list is added, you can assign or unassign issues to that user
+by [dragging issues](#dragging-issues-between-lists) to and/or from an assignee list.
+To remove an assignee list, just as with a label list, click the trash icon.
+
+![Assignee lists](img/issue_board_assignee_lists.png)
+
+### Milestone lists **[PREMIUM]**
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/6469) in GitLab 11.2 Premium.
+
+As of 11.2, you're also able to create lists of a milestone. As the name states,
+these are lists that filter issues by the assigned milestone, giving you more
+freedom and visibility on the Issue Board. To do so:
+
+1. Click **Add list**.
+1. Select the **Milestone** tab.
+1. Search and click on the milestone.
+
+Similar to the assignee lists, you're now able to [drag issues](#dragging-issues-between-lists)
+to and/or from a milestone list to manipulate the milestone of the dragged issues.
+As on another list types, click on the trash icon to remove it.
+
+![Milestone lists](img/issue_board_milestone_lists.png)
+
+### Summary of features per tier
+
+Different issue board features are available in different [GitLab tiers](https://about.gitlab.com/pricing/), as shown in the following table:
+
+| Tier | Number of Project Issue Boards | Number of Group Issue Boards | Configurable Issue Boards | Assignee Lists |
+|----------|--------------------------------|------------------------------|---------------------------|----------------|
+| Core / Free | 1 | 1 | No | No |
+| Starter / Bronze | Multiple | 1 | Yes | No |
+| Premium / Silver | Multiple | Multiple | Yes | Yes |
+| Ultimate / Gold | Multiple | Multiple | Yes | Yes |
+
## Actions you can take on an Issue Board
- [Create a new list](#creating-a-new-list).
@@ -142,7 +298,7 @@ Issue Board, that is, create or delete lists and drag issues from one list to an
If you are not able to perform one or more of the things above, make sure you
have the right [permissions](#permissions).
-## First time using the Issue Board
+### First time using the Issue Board
The first time you navigate to your Issue Board, you will be presented with
a default list (**Done**) and a welcoming message that gives
@@ -157,7 +313,7 @@ which means the system has no way of populating them automatically. That's of
course if the predefined labels don't already exist. If any of them does exist,
the list will be created and filled with the issues that have that label.
-## Creating a new list
+### Creating a new list
Create a new list by clicking on the **Add list** button at the upper
right corner of the Issue Board.
@@ -172,7 +328,7 @@ To create a list for a label that doesn't yet exist, simply create the label by
choosing **Create new label**. The label will be created on-the-fly and it will
be immediately added to the dropdown. You can now choose it to create a list.
-## Deleting a list
+### Deleting a list
To delete a list from the Issue Board use the small trash icon that is present
in the list's heading. A confirmation dialog will appear for you to confirm.
@@ -180,7 +336,7 @@ in the list's heading. A confirmation dialog will appear for you to confirm.
Deleting a list doesn't have any effect in issues and labels, it's just the
list view that is removed. You can always add it back later if you need.
-## Adding issues to a list
+### Adding issues to a list
You can add issues to a list by clicking the **Add issues** button that is
present in the upper right corner of the Issue Board. This will open up a modal
@@ -192,7 +348,7 @@ the list by filtering by author, assignee, milestone and label.
![Bulk adding issues to lists](img/issue_boards_add_issues_modal.png)
-## Removing an issue from a list
+### Removing an issue from a list
Removing an issue from a list can be done by clicking on the issue card and then
clicking the **Remove from board** button in the sidebar. Under the hood, the
@@ -201,7 +357,7 @@ board itself.
![Remove issue from list](img/issue_boards_remove_issue.png)
-## Issue ordering in a list
+### Issue ordering in a list
When visiting a board, issues appear ordered in any list. You are able to change
that order simply by dragging and dropping the issues. The changed order will be saved
@@ -224,7 +380,7 @@ a given board inside your GitLab instance, any time those two issues are subsequ
loaded in any board in the same instance (could be a different project board or a different group board, for example),
that ordering will be maintained.
-## Filtering issues
+### Filtering issues
You should be able to use the filters on top of your Issue Board to show only
the results you want. This is similar to the filtering used in the issue tracker
@@ -232,7 +388,7 @@ since the metadata from the issues and labels are re-used in the Issue Board.
You can filter by author, assignee, milestone and label.
-## Creating workflows
+### Creating workflows
By reordering your lists, you can create workflows. As lists in Issue Boards are
based on labels, it works out of the box with your existing issues. So if you've
@@ -267,89 +423,7 @@ to another list the label changes and a system not is recorded.
![Issue Board system notes](img/issue_board_system_notes.png)
-## Multiple Issue Boards **[STARTER]**
-
-> Introduced in [GitLab Enterprise Edition 8.13](https://about.gitlab.com/2016/10/22/gitlab-8-13-released/#multiple-issue-boards-ee).
-
-Multiple Issue Boards, as the name suggests, allow for more than one Issue Board
-for a given project or group. This is great for large projects with more than one team
-or in situations where a repository is used to host the code of multiple
-products.
-
-Clicking on the current board name in the upper left corner will reveal a
-menu from where you can create another Issue Board and rename or delete the
-existing one.
-
-NOTE: **Note:**
-The Multiple Issue Boards feature is available for
-**projects in GitLab Starter Edition** and for **groups in GitLab Premium Edition**.
-
-![Multiple Issue Boards](img/issue_boards_multiple.png)
-
-## Configurable Issue Boards **[STARTER]**
-
-> Introduced in [GitLab Starter Edition 10.2](https://about.gitlab.com/2017/11/22/gitlab-10-2-released/#issue-boards-configuration).
-
-An Issue Board can be associated with GitLab [Milestone](milestones/index.md#milestones),
-[Labels](labels.md), Assignee and Weight
-which will automatically filter the Board issues according to these fields.
-This allows you to create unique boards according to your team's need.
-
-![Create scoped board](img/issue_board_creation.png)
-
-You can define the scope of your board when creating it or by clicking on the "Edit board" button. Once a milestone, assignee or weight is assigned to an Issue Board, you will no longer be able to filter
-through these in the search bar. In order to do that, you need to remove the desired scope (e.g. milestone, assignee or weight) from the Issue Board.
-
-![Edit board configuration](img/issue_board_edit_button.png)
-
-If you don't have editing permission in a board, you're still able to see the configuration by clicking on "View scope".
-
-![Viewing board configuration](img/issue_board_view_scope.png)
-
-## Focus mode **[STARTER]**
-
-> Introduced in [GitLab Starter 9.1](https://about.gitlab.com/2017/04/22/gitlab-9-1-released/#issue-boards-focus-mode-ees-eep).
-
-Click the button at the top right to toggle focus mode on and off. In focus mode, the navigation UI is hidden, allowing you to focus on issues in the board.
-
-![Board focus mode](img/issue_board_focus_mode.gif)
-
-## Group Issue Boards **[PREMIUM]**
-
-> Introduced in [GitLab Premium 10.0](https://about.gitlab.com/2017/09/22/gitlab-10-0-released/#group-issue-boards).
-
-Accessible at the group navigation level, a group issue board offers the same features as a project-level board,
-but it can display issues from all projects in that
-group and its descendant subgroups. Similarly, you can only filter by group labels for these
-boards. When updating milestones and labels for an issue through the sidebar update mechanism, again only
-group-level objects are available.
-
-NOTE: **Note:**
-Multiple group issue boards were originally introduced in [GitLab 10.0 Premium](https://about.gitlab.com/2017/09/22/gitlab-10-0-released/#group-issue-boards) and
-one group issue board per group was made available in GitLab 10.6 Core.
-
-![Group issue board](img/group_issue_board.png)
-
-## Assignee lists **[PREMIUM]**
-
-> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/5784) in GitLab 11.0 Premium.
-
-Like a regular list that shows all issues that have the list label, you can add
-an assignee list that shows all issues assigned to the given user.
-You can have a board with both label lists and assignee lists. To add an
-assignee list:
-
-1. Click **Add list**.
-1. Select the **Assignee list** tab.
-1. Search and click on the user you want to add as an assignee.
-
-Now that the assignee list is added, you can assign or unassign issues to that user
-by [dragging issues](#dragging-issues-between-lists) to and/or from an assignee list.
-To remove an assignee list, just as with a label list, click the trash icon.
-
-![Assignee lists](img/issue_board_assignee_lists.png)
-
-## Dragging issues between lists
+### Dragging issues between lists
When dragging issues between lists, different behavior occurs depending on the source list and the target list.
@@ -360,17 +434,6 @@ When dragging issues between lists, different behavior occurs depending on the s
| From label `A` list | `A` removed | Issue closed | `A` removed<br/>`B` added | `Bob` assigned |
| From assignee `Alice` list | `Alice` unassigned | Issue closed | `B` added | `Alice` unassigned<br/>`Bob` assigned |
-## Features per tier
-
-Different issue board features are available in different [GitLab tiers](https://about.gitlab.com/pricing/), as shown in the following table:
-
-| Tier | Number of Project Issue Boards | Number of Group Issue Boards | Configurable Issue Boards | Assignee Lists |
-|----------|--------------------------------|------------------------------|---------------------------|----------------|
-| Core | 1 | 1 | No | No |
-| Starter | Multiple | 1 | Yes | No |
-| Premium | Multiple | Multiple | Yes | Yes |
-| Ultimate | Multiple | Multiple | Yes | Yes |
-
## Tips
A few things to remember:
diff --git a/doc/user/project/issues/issues_functionalities.md b/doc/user/project/issues/issues_functionalities.md
index 46f25417fde..631f511b5fa 100644
--- a/doc/user/project/issues/issues_functionalities.md
+++ b/doc/user/project/issues/issues_functionalities.md
@@ -69,7 +69,7 @@ Learn more on the [Time Tracking documentation](../../../workflow/time_tracking.
#### 6. Due date
When you work on a tight schedule, and it's important to
-have a way to setup a deadline for implementations and for solving
+have a way to set up a deadline for implementations and for solving
problems. This can be facilitated by the [due date](due_dates.md)). Due dates
can be changed as many times as needed.
diff --git a/doc/user/project/pages/img/icons/click.png b/doc/user/project/pages/img/icons/click.png
new file mode 100644
index 00000000000..daaf760ec08
--- /dev/null
+++ b/doc/user/project/pages/img/icons/click.png
Binary files differ
diff --git a/doc/user/project/pages/img/icons/cogs.png b/doc/user/project/pages/img/icons/cogs.png
new file mode 100644
index 00000000000..a12da1b5e8c
--- /dev/null
+++ b/doc/user/project/pages/img/icons/cogs.png
Binary files differ
diff --git a/doc/user/project/pages/img/icons/fork.png b/doc/user/project/pages/img/icons/fork.png
new file mode 100644
index 00000000000..e2c9577e7ce
--- /dev/null
+++ b/doc/user/project/pages/img/icons/fork.png
Binary files differ
diff --git a/doc/user/project/pages/img/icons/free.png b/doc/user/project/pages/img/icons/free.png
new file mode 100644
index 00000000000..3b8f8f6863e
--- /dev/null
+++ b/doc/user/project/pages/img/icons/free.png
Binary files differ
diff --git a/doc/user/project/pages/img/icons/lock.png b/doc/user/project/pages/img/icons/lock.png
new file mode 100644
index 00000000000..1c1f0b4457b
--- /dev/null
+++ b/doc/user/project/pages/img/icons/lock.png
Binary files differ
diff --git a/doc/user/project/pages/img/icons/monitor.png b/doc/user/project/pages/img/icons/monitor.png
new file mode 100644
index 00000000000..7b99d430eef
--- /dev/null
+++ b/doc/user/project/pages/img/icons/monitor.png
Binary files differ
diff --git a/doc/user/project/pages/img/icons/terminal.png b/doc/user/project/pages/img/icons/terminal.png
new file mode 100644
index 00000000000..ab5ae11310c
--- /dev/null
+++ b/doc/user/project/pages/img/icons/terminal.png
Binary files differ
diff --git a/doc/user/project/pages/img/ssgs_pages.png b/doc/user/project/pages/img/ssgs_pages.png
new file mode 100644
index 00000000000..608881c8e31
--- /dev/null
+++ b/doc/user/project/pages/img/ssgs_pages.png
Binary files differ
diff --git a/doc/user/project/pages/index.md b/doc/user/project/pages/index.md
index 4f0774dba5c..60144fa1971 100644
--- a/doc/user/project/pages/index.md
+++ b/doc/user/project/pages/index.md
@@ -4,71 +4,180 @@ description: 'Learn how to use GitLab Pages to deploy a static website at no add
# GitLab Pages
-With GitLab Pages it's easy to publish your project website. GitLab Pages is a hosting service for static websites, at no additional cost.
-
-## Getting Started
-
-[Create a project from scratch](getting_started_part_two.md#create-a-project-from-scratch)
-to get you started quickly, or,
-alternatively, start from an existing project as follows:
-
-1. [Fork](../../../gitlab-basics/fork-project.md#how-to-fork-a-project) an [example project](https://gitlab.com/pages):
+**GitLab Pages is a feature that allows you to publish static websites
+directly from a repository in GitLab.**
+
+You can use it either for personal or business websites, such as
+portfolios, documentation, manifestos, and business presentations,
+and attribute any license to your content.
+
+<table class="borderless-table center fixed-table">
+ <tr>
+ <td style="width: 22%"><img src="img/icons/cogs.png" alt="SSGs" class="image-noshadow half-width"></td>
+ <td style="width: 4%">
+ <strong>
+ <i class="fa fa-angle-double-right" aria-hidden="true"></i>
+ </strong>
+ </td>
+ <td style="width: 22%"><img src="img/icons/monitor.png" alt="Websites" class="image-noshadow half-width"></td>
+ <td style="width: 4%">
+ <strong>
+ <i class="fa fa-angle-double-right" aria-hidden="true"></i>
+ </strong>
+ </td>
+ <td style="width: 22%"><img src="img/icons/free.png" alt="Pages is free" class="image-noshadow half-width"></td>
+ <td style="width: 4%">
+ <strong>
+ <i class="fa fa-angle-double-right" aria-hidden="true"></i>
+ </strong>
+ </td>
+ <td style="width: 22%"><img src="img/icons/lock.png" alt="Secure your website" class="image-noshadow half-width"></td>
+ </tr>
+ <tr>
+ <td><em>Use any static website generator or plain HTML</em></td>
+ <td></td>
+ <td><em>Create websites for your projects, groups, or user account</em></td>
+ <td></td>
+ <td><em>Host on GitLab.com for free, or on your own GitLab instance</em></td>
+ <td></td>
+ <td><em>Connect your custom domain(s) and TLS certificates</em></td>
+ </tr>
+</table>
+
+Pages is available for free for all GitLab.com users as well as for self-managed
+instances (GitLab Core, Starter, Premium, and Ultimate).
+
+## Overview
+
+<div class="row">
+<div class="col-md-9">
+<p style="margin-top: 18px;">
+To publish a website with Pages, you can use any Static Site Generator (SSG),
+such as Jekyll, Hugo, Middleman, Harp, Hexo, and Brunch, just to name a few. You can also
+publish any website written directly in plain HTML, CSS, and JavaScript.</p>
+<p>Pages does <strong>not</strong> support dynamic server-side processing, for instance, as <code>.php</code> and <code>.asp</code> requires. See this article to learn more about
+<a href="https://about.gitlab.com/2016/06/03/ssg-overview-gitlab-pages-part-1-dynamic-x-static/">static websites vs dynamic websites</a>.</p>
+</div>
+<div class="col-md-3"><img src="img/ssgs_pages.png" alt="Examples of SSGs supported by Pages" class="image-noshadow middle display-block"></div>
+</div>
+
+### Availability
+
+If you're using GitLab.com, your website will be publicly available to the internet.
+If you're using self-managed instances (Core, Starter, Premium, or Ultimate),
+your websites will be published on your own server, according to the
+[Pages admin settings](../../../administration/pages/index.md) chosen by your sysdamin,
+who can opt for making them public or internal to your server.
+
+### How it works
+
+To use GitLab Pages, first you need to create a project in GitLab to upload your website's
+files to. These projects can be either public, internal, or private, at your own choice.
+GitLab will always deploy your website from a very specific folder called `public` in your
+repository. Note that when you create a new project in GitLab, a [repository](../repository/index.md)
+becomes available automatically.
+
+To deploy your site, GitLab will use its built-in tool called [GitLab CI/CD](../../../ci/README.md),
+that will build your site and publish it to the GitLab Pages server. The sequence of
+scripts that GitLab CI/CD runs to accomplish this task is created from a file named
+`.gitlab-ci.yml`, which you can [create and modify](getting_started_part_four.md) at will.
+
+You can either use GitLab's [default domain for GitLab Pages websites](getting_started_part_one.md#gitlab-pages-domain),
+`*.gitlab.io`, or your own domain (`example.com`). In that case, you'll
+need admin access to your domain's registrar (or control panel) to set it up with Pages.
+
+Optionally, when adding your own domain, you can add an SSL/TLS certificate to secure your
+site under the HTTPS protocol.
+
+## Getting started
+
+To get started with GitLab Pages, you can either [create a project from scratch](getting_started_part_two.md#create-a-project-from-scratch)
+or quickly start from copying an existing example project, as follows:
+
+1. Choose an [example project](https://gitlab.com/pages) to [fork](../../../gitlab-basics/fork-project.md#how-to-fork-a-project):
by forking a project, you create a copy of the codebase you're forking from to start from a template instead of starting from scratch.
-2. Change a file to trigger a GitLab CI/CD pipeline: GitLab CI/CD will build and deploy your site to GitLab Pages.
-3. Visit your project's **Settings > Pages** to see your **website link**, and click on it. Bam! Your website is live! :)
-
- _Further steps (optional):_
-
-4. Remove the [fork relationship](getting_started_part_two.md#fork-a-project-to-get-started-from)
+1. From the left sidebar, navigate to your project's **CI/CD > Pipelines** and click
+**Run pipeline** so that GitLab CI/CD will build and deploy your site to the server.
+1. Once the pipeline has finished successfully, find the link to visit your website from your
+ project's **Settings > Pages**.
+
+<table class="borderless-table center fixed-table middle width-80">
+ <tr>
+ <td style="width: 30%"><img src="img/icons/fork.png" alt="Fork" class="image-noshadow half-width"></td>
+ <td style="width: 10%">
+ <strong>
+ <i class="fa fa-angle-double-right" aria-hidden="true"></i>
+ </strong>
+ </td>
+ <td style="width: 30%"><img src="img/icons/terminal.png" alt="Deploy" class="image-noshadow half-width"></td>
+ <td style="width: 10%">
+ <strong>
+ <i class="fa fa-angle-double-right" aria-hidden="true"></i>
+ </strong>
+ </td>
+ <td style="width: 30%"><img src="img/icons/click.png" alt="Visit" class="image-noshadow half-width"></td>
+ </tr>
+ <tr>
+ <td><em>Fork an example project</em></td>
+ <td></td>
+ <td><em>Deploy your website</em></td>
+ <td></td>
+ <td><em>Visit your website's URL</em></td>
+ </tr>
+</table>
+
+Your website is then visible on your domain, and you can modify your files
+as you wish. For every modification pushed to your repository, GitLab CI/CD will run
+a new pipeline to publish your changes to the server.
+
+You can also take some optional further steps:
+
+- Remove the [fork relationship](getting_started_part_two.md#fork-a-project-to-get-started-from)
(_You don't need the relationship unless you intent to contribute back to the example project you forked from_).
-5. Make it a [user/group website](getting_started_part_one.md#user-and-group-websites)
+- Make it a [user/group website](getting_started_part_one.md#user-and-group-websites)
-**Watch a video with the steps above: https://www.youtube.com/watch?v=TWqh9MtT4Bg**
+**<i class="fa fa-youtube-play youtube" aria-hidden="true"></i> Watch a [video tutorial](https://www.youtube.com/watch?v=TWqh9MtT4Bg) with all the steps above!**
_Advanced options:_
- [Use a custom domain](getting_started_part_three.md#adding-your-custom-domain-to-gitlab-pages)
- Apply [SSL/TLS certification](getting_started_part_three.md#ssl-tls-certificates) to your custom domain
-## How Does It Work?
-
-With GitLab Pages you can create [static websites](getting_started_part_one.md#what-you-need-to-know-before-getting-started)
-for your GitLab projects, groups, or user accounts.
-
-It supports plain static content, such as HTML, and **all** [static site generators (SSGs)](https://about.gitlab.com/2016/06/03/ssg-overview-gitlab-pages-part-1-dynamic-x-static/), such as Jekyll, Middleman, Hexo, Hugo, and Pelican.
-
-Connect as many custom domains as you like and bring your own TLS certificate
-to secure them.
-
-Your files live in a project [repository](../repository/index.md) on GitLab.
-[GitLab CI](../../../ci/README.md) picks up those files and makes them available at, typically,
-`https://<username>.gitlab.io/<projectname>`. Please read through the docs on
-[GitLab Pages domains](getting_started_part_one.md#gitlab-pages-domain) for more info.
-
## Explore GitLab Pages
-Read the following tutorials to know more about:
+To learn more about GitLab Pages, read the following tutorials:
- [Static websites and GitLab Pages domains](getting_started_part_one.md): Understand what is a static website, and how GitLab Pages default domains work
- [Projects for GitLab Pages and URL structure](getting_started_part_two.md): Forking projects and creating new ones from scratch, understanding URLs structure and baseurls
-- [GitLab Pages custom domains and SSL/TLS Certificates](getting_started_part_three.md): How to add custom domains and subdomains to your website, configure DNS records, and SSL/TLS certificates
+- [GitLab Pages custom domains and SSL/TLS Certificates](getting_started_part_three.md): How to add custom domains and subdomains to your website, configure DNS records and SSL/TLS certificates
- [Creating and Tweaking GitLab CI/CD for GitLab Pages](getting_started_part_four.md): Understand how to create your own `.gitlab-ci.yml` for your site
- [Technical aspects, custom 404 pages, limitations](introduction.md)
-- [Hosting on GitLab.com with GitLab Pages](https://about.gitlab.com/2016/04/07/gitlab-pages-setup/) (outdated)
-_Blog posts series about Static Site Generators (SSGs):_
+### GitLab Pages with Static Site Generators (SSGs)
+
+To understand more about SSGs, their advantages, and how to get the most from them
+with Pages, read through this series:
- [SSGs part 1: Static vs dynamic websites](https://about.gitlab.com/2016/06/03/ssg-overview-gitlab-pages-part-1-dynamic-x-static/)
- [SSGs part 2: Modern static site generators](https://about.gitlab.com/2016/06/10/ssg-overview-gitlab-pages-part-2/)
- [SSGs part 3: Build any SSG site with GitLab Pages](https://about.gitlab.com/2016/06/17/ssg-overview-gitlab-pages-part-3-examples-ci/)
-_Blog posts for securing GitLab Pages custom domains with SSL/TLS certificates:_
+### GitLab Pages with SSL/TLS certificates
+
+If you're using GitLab Pages default domain (`.gitlab.io`), your website will be
+automatically secure and available under HTTPS. If you're using your own domain, you can
+optionally secure it with with SSL/TLS certificates. You can read the following
+tutorials to learn how to use these third-party certificates with GitLab Pages:
- [CloudFlare](https://about.gitlab.com/2017/02/07/setting-up-gitlab-pages-with-cloudflare-certificates/)
-- [Let's Encrypt](https://about.gitlab.com/2016/04/11/tutorial-securing-your-gitlab-pages-with-tls-and-letsencrypt/) (outdated)
+- [Let's Encrypt](https://about.gitlab.com/2016/04/11/tutorial-securing-your-gitlab-pages-with-tls-and-letsencrypt/) (mind that although this article is out-of-date, it can still be useful to guide you through the basic steps)
## Advanced use
+There are quite some great examples of GitLab Pages websites built for some
+specific reasons. These examples can teach you some advanced techniques
+to use and adapt to your own needs:
+
- [Posting to your GitLab Pages blog from iOS](https://about.gitlab.com/2016/08/19/posting-to-your-gitlab-pages-blog-from-ios/)
- [GitLab CI: Run jobs sequentially, in parallel, or build a custom pipeline](https://about.gitlab.com/2016/07/29/the-basics-of-gitlab-ci/)
- [GitLab CI: Deployment & environments](https://about.gitlab.com/2016/08/26/ci-deployment-and-environments/)
@@ -80,10 +189,9 @@ _Blog posts for securing GitLab Pages custom domains with SSL/TLS certificates:_
Enable and configure GitLab Pages on your own instance (GitLab Community Edition and Enterprise Editions) with
the [admin guide](../../../administration/pages/index.md).
-**Watch the video: https://www.youtube.com/watch?v=dD8c7WNcc6s**
+**<i class="fa fa-youtube-play youtube" aria-hidden="true"></i> Watch a [video tutorial](https://www.youtube.com/watch?v=dD8c7WNcc6s) for getting started with GitLab Pages admin!**
## More information about GitLab Pages
-- For an overview, visit the [feature webpage](https://about.gitlab.com/features/pages/)
- Announcement (2016-12-24): ["We're bringing GitLab Pages to CE"](https://about.gitlab.com/2016/12/24/were-bringing-gitlab-pages-to-community-edition/)
- Announcement (2017-03-06): ["We are changing the IP of GitLab Pages on GitLab.com"](https://about.gitlab.com/2017/03/06/we-are-changing-the-ip-of-gitlab-pages-on-gitlab-com/)
diff --git a/doc/user/project/pipelines/job_artifacts.md b/doc/user/project/pipelines/job_artifacts.md
index fc3970e2014..a8b47558c99 100644
--- a/doc/user/project/pipelines/job_artifacts.md
+++ b/doc/user/project/pipelines/job_artifacts.md
@@ -151,6 +151,20 @@ For example:
https://gitlab.com/gitlab-org/gitlab-ce/-/jobs/artifacts/master/browse?job=coverage
```
+There is also a URL to specific files, including html files that
+are shown in [GitLab Pages](../../../administration/pages/index.md):
+
+```
+https://example.com/<namespace>/<project>/-/jobs/artifacts/<ref>/file/<path>?job=<job_name>
+```
+
+For example, when a job `coverage` creates the artifact `htmlcov/index.html`,
+you can access it at:
+
+```
+https://gitlab.com/gitlab-org/gitlab-ce/-/jobs/artifacts/master/file/htmlcov/index.html?job=coverage
+```
+
The latest builds are also exposed in the UI in various places. Specifically,
look for the download button in:
diff --git a/doc/user/project/repository/index.md b/doc/user/project/repository/index.md
index 1c3915a5fdd..4d016277824 100644
--- a/doc/user/project/repository/index.md
+++ b/doc/user/project/repository/index.md
@@ -158,7 +158,9 @@ Find it under your project's **Repository > Graph**.
## Repository Languages
For the default branch of each repository, GitLab will determine what programming languages
-were used and display this on the projects pages.
+were used and display this on the projects pages. If this information is missing, it will
+be added after updating the default branch on the project. This process can take up to 5
+minutes.
![Repository Languages bar](img/repository_languages.png)
diff --git a/doc/user/project/wiki/index.md b/doc/user/project/wiki/index.md
index ad0ef60373c..127a30d6669 100644
--- a/doc/user/project/wiki/index.md
+++ b/doc/user/project/wiki/index.md
@@ -40,11 +40,6 @@ support Markdown, RDoc and AsciiDoc. For Markdown based pages, all the
[Markdown features](../../markdown.md) are supported and for links there is
some [wiki specific](../../markdown.md#wiki-specific-markdown) behavior.
->**Note:**
-The wiki is based on a Git repository and contains only text files. Uploading
-files via the web interface will upload them in GitLab itself, and they will
-not be available if you clone the wiki repo locally.
-
In the web interface the commit message is optional, but the GitLab Wiki is
based on Git and needs a commit message, so one will be created for you if you
do not enter one.
@@ -53,6 +48,14 @@ When you're ready, click the **Create page** and the new page will be created.
![New page](img/wiki_create_new_page.png)
+> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/33475) in GitLab 11.3.
+
+Starting with GitLab 11.3, any file that is uploaded to the wiki via GitLab's
+interface will be stored in the wiki Git repository, and it will be available
+if you clone the wiki repository locally. All uploaded files prior to GitLab
+11.3 are stored in GitLab itself. If you want them to be part of the wiki's Git
+repository, you will have to upload them again.
+
## Editing a wiki page
To edit a page, simply click on the **Edit** button. From there on, you can
diff --git a/doc/workflow/lfs/lfs_administration.md b/doc/workflow/lfs/lfs_administration.md
index 3f9ffedd61a..ec5943fd51b 100644
--- a/doc/workflow/lfs/lfs_administration.md
+++ b/doc/workflow/lfs/lfs_administration.md
@@ -54,7 +54,7 @@ to offload local hard disk R/W operations, and free up disk space significantly.
GitLab is tightly integrated with `Fog`, so you can refer to its [documentation](http://fog.io/about/provider_documentation.html)
to check which storage services can be integrated with GitLab.
You can also use external object storage in a private local network. For example,
-[Minio](https://www.minio.io/) is a standalone object storage service, is easy to setup, and works well with GitLab instances.
+[Minio](https://www.minio.io/) is a standalone object storage service, is easy to set up, and works well with GitLab instances.
GitLab provides two different options for the uploading mechanism: "Direct upload" and "Background upload".
@@ -95,6 +95,7 @@ Here is a configuration example with S3.
| `host` | S3 compatible host for when not using AWS, e.g. `localhost` or `storage.example.com` | s3.amazonaws.com |
| `endpoint` | Can be used when configuring an S3 compatible service such as [Minio](https://www.minio.io), by entering a URL such as `http://127.0.0.1:9000` | (optional) |
| `path_style` | Set to true to use `host/bucket_name/object` style paths instead of `bucket_name.host/object`. Leave as false for AWS S3 | false |
+| `use_iam_profile` | Set to true to use IAM profile instead of access keys | false
Here is a configuration example with GCS.
diff --git a/lib/api/commits.rb b/lib/api/commits.rb
index fcaff35459e..5aeffc8fb99 100644
--- a/lib/api/commits.rb
+++ b/lib/api/commits.rb
@@ -73,7 +73,26 @@ module API
params do
requires :branch, type: String, desc: 'Name of the branch to commit into. To create a new branch, also provide `start_branch`.', allow_blank: false
requires :commit_message, type: String, desc: 'Commit message'
- requires :actions, type: Array[Hash], desc: 'Actions to perform in commit'
+ requires :actions, type: Array, desc: 'Actions to perform in commit' do
+ requires :action, type: String, desc: 'The action to perform, `create`, `delete`, `move`, `update`, `chmod`', values: %w[create update move delete chmod].freeze
+ requires :file_path, type: String, desc: 'Full path to the file. Ex. `lib/class.rb`'
+ given action: ->(action) { action == 'move' } do
+ requires :previous_path, type: String, desc: 'Original full path to the file being moved. Ex. `lib/class1.rb`'
+ end
+ given action: ->(action) { %w[create move].include? action } do
+ optional :content, type: String, desc: 'File content'
+ end
+ given action: ->(action) { action == 'update' } do
+ requires :content, type: String, desc: 'File content'
+ end
+ optional :encoding, type: String, desc: '`text` or `base64`', default: 'text', values: %w[text base64]
+ given action: ->(action) { %w[update move delete].include? action } do
+ optional :last_commit_id, type: String, desc: 'Last known file commit id'
+ end
+ given action: ->(action) { action == 'chmod' } do
+ requires :execute_filemode, type: Boolean, desc: 'When `true/false` enables/disables the execute flag on the file.'
+ end
+ end
optional :start_branch, type: String, desc: 'Name of the branch to start the new commit from'
optional :author_email, type: String, desc: 'Author email for commit'
optional :author_name, type: String, desc: 'Author name for commit'
diff --git a/lib/api/entities.rb b/lib/api/entities.rb
index 0fec3dc3dc4..12c4340c1ba 100644
--- a/lib/api/entities.rb
+++ b/lib/api/entities.rb
@@ -53,7 +53,7 @@ module API
class User < UserBasic
expose :created_at, if: ->(user, opts) { Ability.allowed?(opts[:current_user], :read_user_profile, user) }
- expose :bio, :location, :skype, :linkedin, :twitter, :website_url, :organization
+ expose :bio, :location, :public_email, :skype, :linkedin, :twitter, :website_url, :organization
end
class UserActivity < Grape::Entity
diff --git a/lib/api/protected_branches.rb b/lib/api/protected_branches.rb
index e569fad8663..804f6fa9b73 100644
--- a/lib/api/protected_branches.rb
+++ b/lib/api/protected_branches.rb
@@ -44,10 +44,10 @@ module API
params do
requires :name, type: String, desc: 'The name of the protected branch'
optional :push_access_level, type: Integer,
- values: ProtectedRefAccess::ALLOWED_ACCESS_LEVELS,
+ values: ProtectedBranch::PushAccessLevel.allowed_access_levels,
desc: 'Access levels allowed to push (defaults: `40`, maintainer access level)'
optional :merge_access_level, type: Integer,
- values: ProtectedRefAccess::ALLOWED_ACCESS_LEVELS,
+ values: ProtectedBranch::MergeAccessLevel.allowed_access_levels,
desc: 'Access levels allowed to merge (defaults: `40`, maintainer access level)'
end
# rubocop: disable CodeReuse/ActiveRecord
diff --git a/lib/api/protected_tags.rb b/lib/api/protected_tags.rb
index 219d51a2bc5..e406344e42d 100644
--- a/lib/api/protected_tags.rb
+++ b/lib/api/protected_tags.rb
@@ -47,7 +47,7 @@ module API
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,
+ values: ProtectedTag::CreateAccessLevel.allowed_access_levels,
desc: 'Access levels allowed to create (defaults: `40`, maintainer access level)'
end
post ':id/protected_tags' do
diff --git a/lib/api/runners.rb b/lib/api/runners.rb
index 30abd0b63e9..9bcdfc8cb15 100644
--- a/lib/api/runners.rb
+++ b/lib/api/runners.rb
@@ -11,10 +11,18 @@ module API
params do
optional :scope, type: String, values: Ci::Runner::AVAILABLE_STATUSES,
desc: 'The scope of specific runners to show'
+ optional :type, type: String, values: Ci::Runner::AVAILABLE_TYPES,
+ desc: 'The type of the runners to show'
+ optional :status, type: String, values: Ci::Runner::AVAILABLE_STATUSES,
+ desc: 'The status of the runners to show'
use :pagination
end
get do
- runners = filter_runners(current_user.ci_owned_runners, params[:scope], allowed_scopes: Ci::Runner::AVAILABLE_STATUSES)
+ runners = current_user.ci_owned_runners
+ runners = filter_runners(runners, params[:scope], allowed_scopes: Ci::Runner::AVAILABLE_STATUSES)
+ runners = filter_runners(runners, params[:type], allowed_scopes: Ci::Runner::AVAILABLE_TYPES)
+ runners = filter_runners(runners, params[:status], allowed_scopes: Ci::Runner::AVAILABLE_STATUSES)
+
present paginate(runners), with: Entities::Runner
end
@@ -24,11 +32,20 @@ module API
params do
optional :scope, type: String, values: Ci::Runner::AVAILABLE_SCOPES,
desc: 'The scope of specific runners to show'
+ optional :type, type: String, values: Ci::Runner::AVAILABLE_TYPES,
+ desc: 'The type of the runners to show'
+ optional :status, type: String, values: Ci::Runner::AVAILABLE_STATUSES,
+ desc: 'The status of the runners to show'
use :pagination
end
get 'all' do
authenticated_as_admin!
- runners = filter_runners(Ci::Runner.all, params[:scope])
+
+ runners = Ci::Runner.all
+ runners = filter_runners(runners, params[:scope])
+ runners = filter_runners(runners, params[:type], allowed_scopes: Ci::Runner::AVAILABLE_TYPES)
+ runners = filter_runners(runners, params[:status], allowed_scopes: Ci::Runner::AVAILABLE_STATUSES)
+
present paginate(runners), with: Entities::Runner
end
@@ -116,10 +133,18 @@ module API
params do
optional :scope, type: String, values: Ci::Runner::AVAILABLE_SCOPES,
desc: 'The scope of specific runners to show'
+ optional :type, type: String, values: Ci::Runner::AVAILABLE_TYPES,
+ desc: 'The type of the runners to show'
+ optional :status, type: String, values: Ci::Runner::AVAILABLE_STATUSES,
+ desc: 'The status of the runners to show'
use :pagination
end
get ':id/runners' do
- runners = filter_runners(Ci::Runner.owned_or_instance_wide(user_project.id), params[:scope])
+ runners = Ci::Runner.owned_or_instance_wide(user_project.id)
+ runners = filter_runners(runners, params[:scope])
+ runners = filter_runners(runners, params[:type], allowed_scopes: Ci::Runner::AVAILABLE_TYPES)
+ runners = filter_runners(runners, params[:status], allowed_scopes: Ci::Runner::AVAILABLE_STATUSES)
+
present paginate(runners), with: Entities::Runner
end
diff --git a/lib/api/settings.rb b/lib/api/settings.rb
index 897010217dc..8d71bd9dff1 100644
--- a/lib/api/settings.rb
+++ b/lib/api/settings.rb
@@ -102,7 +102,7 @@ module API
end
optional :repository_checks_enabled, type: Boolean, desc: "GitLab will periodically run 'git fsck' in all project and wiki repositories to look for silent disk corruption issues."
optional :repository_storages, type: Array[String], desc: 'Storage paths for new projects'
- optional :require_two_factor_authentication, type: Boolean, desc: 'Require all users to setup Two-factor authentication'
+ optional :require_two_factor_authentication, type: Boolean, desc: 'Require all users to set up Two-factor authentication'
given require_two_factor_authentication: ->(val) { val } do
requires :two_factor_grace_period, type: Integer, desc: 'Amount of time (in hours) that users are allowed to skip forced configuration of two-factor authentication'
end
@@ -117,11 +117,6 @@ module API
given shared_runners_enabled: ->(val) { val } do
requires :shared_runners_text, type: String, desc: 'Shared runners text '
end
- optional :sidekiq_throttling_enabled, type: Boolean, desc: 'Enable Sidekiq Job Throttling'
- given sidekiq_throttling_enabled: ->(val) { val } do
- requires :sidekiq_throttling_factor, type: Float, desc: 'The factor by which the queues should be throttled. A value between 0.0 and 1.0, exclusive.'
- requires :sidekiq_throttling_queues, type: Array[String], desc: 'Choose which queues you wish to throttle'
- end
optional :sign_in_text, type: String, desc: 'The sign in text of the GitLab application'
optional :signin_enabled, type: Boolean, desc: 'Flag indicating if password authentication is enabled for the web interface' # support legacy names, can be removed in v5
optional :signup_enabled, type: Boolean, desc: 'Flag indicating if sign up is enabled'
diff --git a/lib/banzai/filter/abstract_reference_filter.rb b/lib/banzai/filter/abstract_reference_filter.rb
index ad0806df8e6..4764f8e1e19 100644
--- a/lib/banzai/filter/abstract_reference_filter.rb
+++ b/lib/banzai/filter/abstract_reference_filter.rb
@@ -296,7 +296,7 @@ module Banzai
# Returns projects for the given paths.
def find_for_paths(paths)
- if RequestStore.active?
+ if Gitlab::SafeRequestStore.active?
cache = refs_cache
to_query = paths - cache.keys
@@ -340,7 +340,7 @@ module Banzai
end
def refs_cache
- RequestStore["banzai_#{parent_type}_refs".to_sym] ||= {}
+ Gitlab::SafeRequestStore["banzai_#{parent_type}_refs".to_sym] ||= {}
end
def parent_type
diff --git a/lib/banzai/filter/external_issue_reference_filter.rb b/lib/banzai/filter/external_issue_reference_filter.rb
index b4a7a44e109..8159dcfed72 100644
--- a/lib/banzai/filter/external_issue_reference_filter.rb
+++ b/lib/banzai/filter/external_issue_reference_filter.rb
@@ -97,9 +97,7 @@ module Banzai
private
def external_issues_cached(attribute)
- return project.public_send(attribute) unless RequestStore.active? # rubocop:disable GitlabSecurity/PublicSend
-
- cached_attributes = RequestStore[:banzai_external_issues_tracker_attributes] ||= Hash.new { |h, k| h[k] = {} }
+ cached_attributes = Gitlab::SafeRequestStore[:banzai_external_issues_tracker_attributes] ||= Hash.new { |h, k| h[k] = {} }
cached_attributes[project.id][attribute] = project.public_send(attribute) if cached_attributes[project.id][attribute].nil? # rubocop:disable GitlabSecurity/PublicSend
cached_attributes[project.id][attribute]
end
diff --git a/lib/banzai/filter/relative_link_filter.rb b/lib/banzai/filter/relative_link_filter.rb
index 8e838d04bad..7acbc933adc 100644
--- a/lib/banzai/filter/relative_link_filter.rb
+++ b/lib/banzai/filter/relative_link_filter.rb
@@ -60,7 +60,11 @@ module Banzai
path_parts.unshift(relative_url_root, project.full_path)
end
- path = Addressable::URI.escape(File.join(*path_parts))
+ begin
+ path = Addressable::URI.escape(File.join(*path_parts))
+ rescue Addressable::URI::InvalidURIError
+ return
+ end
html_attr.value =
if context[:only_path]
diff --git a/lib/banzai/reference_parser/base_parser.rb b/lib/banzai/reference_parser/base_parser.rb
index 68752f5bb5a..3ab154a7b1c 100644
--- a/lib/banzai/reference_parser/base_parser.rb
+++ b/lib/banzai/reference_parser/base_parser.rb
@@ -166,7 +166,7 @@ module Banzai
# objects that have not yet been queried. For objects that have already
# been queried the object is returned from the cache.
def collection_objects_for_ids(collection, ids)
- if RequestStore.active?
+ if Gitlab::SafeRequestStore.active?
ids = ids.map(&:to_i)
cache = collection_cache[collection_cache_key(collection)]
to_query = ids - cache.keys
@@ -248,7 +248,7 @@ module Banzai
end
def collection_cache
- RequestStore[:banzai_collection_cache] ||= Hash.new do |hash, key|
+ Gitlab::SafeRequestStore[:banzai_collection_cache] ||= Hash.new do |hash, key|
hash[key] = {}
end
end
diff --git a/lib/banzai/request_store_reference_cache.rb b/lib/banzai/request_store_reference_cache.rb
index 426131442a2..9a9704f9837 100644
--- a/lib/banzai/request_store_reference_cache.rb
+++ b/lib/banzai/request_store_reference_cache.rb
@@ -1,8 +1,8 @@
module Banzai
module RequestStoreReferenceCache
def cached_call(request_store_key, cache_key, path: [])
- if RequestStore.active?
- cache = RequestStore[request_store_key] ||= Hash.new do |hash, key|
+ if Gitlab::SafeRequestStore.active?
+ cache = Gitlab::SafeRequestStore[request_store_key] ||= Hash.new do |hash, key|
hash[key] = Hash.new { |h, k| h[k] = {} }
end
diff --git a/lib/event_filter.rb b/lib/event_filter.rb
index f756a211a12..24fdcd6fbb1 100644
--- a/lib/event_filter.rb
+++ b/lib/event_filter.rb
@@ -1,76 +1,42 @@
-class EventFilter
- attr_accessor :params
-
- class << self
- def all
- 'all'
- end
-
- def push
- 'push'
- end
-
- def merged
- 'merged'
- end
+# frozen_string_literal: true
- def issue
- 'issue'
- end
-
- def comments
- 'comments'
- end
-
- def team
- 'team'
- end
+class EventFilter
+ attr_accessor :filter
+
+ ALL = 'all'
+ PUSH = 'push'
+ MERGED = 'merged'
+ ISSUE = 'issue'
+ COMMENTS = 'comments'
+ TEAM = 'team'
+ FILTERS = [ALL, PUSH, MERGED, ISSUE, COMMENTS, TEAM].freeze
+
+ def initialize(filter)
+ # Split using comma to maintain backward compatibility Ex/ "filter1,filter2"
+ filter = filter.to_s.split(',')[0].to_s
+ @filter = FILTERS.include?(filter) ? filter : ALL
end
- def initialize(params)
- @params = if params
- params.dup
- else
- [] # EventFilter.default_filter
- end
+ def active?(key)
+ filter == key.to_s
end
# rubocop: disable CodeReuse/ActiveRecord
def apply_filter(events)
- return events if params.blank? || params == EventFilter.all
-
- case params
- when EventFilter.push
+ case filter
+ when PUSH
events.where(action: Event::PUSHED)
- when EventFilter.merged
+ when MERGED
events.where(action: Event::MERGED)
- when EventFilter.comments
+ when COMMENTS
events.where(action: Event::COMMENTED)
- when EventFilter.team
+ when TEAM
events.where(action: [Event::JOINED, Event::LEFT, Event::EXPIRED])
- when EventFilter.issue
+ when ISSUE
events.where(action: [Event::CREATED, Event::UPDATED, Event::CLOSED, Event::REOPENED])
- end
- end
- # rubocop: enable CodeReuse/ActiveRecord
-
- def options(key)
- filter = params.dup
-
- if filter.include? key
- filter.delete key
else
- filter << key
- end
-
- filter
- end
-
- def active?(key)
- if params.present?
- params.include? key
- else
- key == EventFilter.all
+ events
end
end
+ # rubocop: enable CodeReuse/ActiveRecord
end
diff --git a/lib/extracts_path.rb b/lib/extracts_path.rb
index e8dbde176ef..e02d403f7b1 100644
--- a/lib/extracts_path.rb
+++ b/lib/extracts_path.rb
@@ -54,7 +54,7 @@ module ExtractsPath
valid_refs = ref_names.select { |v| id.start_with?("#{v}/") }
- if valid_refs.length == 0
+ if valid_refs.empty?
# No exact ref match, so just try our best
pair = id.match(%r{([^/]+)(.*)}).captures
else
diff --git a/lib/feature.rb b/lib/feature.rb
index f4b57376313..0e90ad9a333 100644
--- a/lib/feature.rb
+++ b/lib/feature.rb
@@ -28,11 +28,7 @@ class Feature
end
def persisted_names
- if RequestStore.active?
- RequestStore[:flipper_persisted_names] ||= FlipperFeature.feature_names
- else
- FlipperFeature.feature_names
- end
+ Gitlab::SafeRequestStore[:flipper_persisted_names] ||= FlipperFeature.feature_names
end
def persisted?(feature)
@@ -76,11 +72,7 @@ class Feature
end
def flipper
- if RequestStore.active?
- RequestStore[:flipper] ||= build_flipper_instance
- else
- @flipper ||= build_flipper_instance
- end
+ @flipper ||= (Gitlab::SafeRequestStore[:flipper] ||= build_flipper_instance)
end
def build_flipper_instance
diff --git a/lib/gitlab/auth/ldap/access.rb b/lib/gitlab/auth/ldap/access.rb
index eeab7791643..f323d2e0f7a 100644
--- a/lib/gitlab/auth/ldap/access.rb
+++ b/lib/gitlab/auth/ldap/access.rb
@@ -92,12 +92,12 @@ module Gitlab
if provider
Gitlab::AppLogger.info(
"LDAP account \"#{ldap_identity.extern_uid}\" #{reason}, " \
- "blocking Gitlab user \"#{user.name}\" (#{user.email})"
+ "blocking GitLab user \"#{user.name}\" (#{user.email})"
)
else
Gitlab::AppLogger.info(
"Account is not provided by LDAP, " \
- "blocking Gitlab user \"#{user.name}\" (#{user.email})"
+ "blocking GitLab user \"#{user.name}\" (#{user.email})"
)
end
end
@@ -107,7 +107,7 @@ module Gitlab
Gitlab::AppLogger.info(
"LDAP account \"#{ldap_identity.extern_uid}\" #{reason}, " \
- "unblocking Gitlab user \"#{user.name}\" (#{user.email})"
+ "unblocking GitLab user \"#{user.name}\" (#{user.email})"
)
end
end
diff --git a/lib/gitlab/background_migration/populate_external_pipeline_source.rb b/lib/gitlab/background_migration/populate_external_pipeline_source.rb
new file mode 100644
index 00000000000..036fe641757
--- /dev/null
+++ b/lib/gitlab/background_migration/populate_external_pipeline_source.rb
@@ -0,0 +1,50 @@
+# frozen_string_literal: true
+# rubocop:disable Style/Documentation
+
+module Gitlab
+ module BackgroundMigration
+ class PopulateExternalPipelineSource
+ module Migratable
+ class Pipeline < ActiveRecord::Base
+ self.table_name = 'ci_pipelines'
+
+ def self.sources
+ {
+ unknown: nil,
+ push: 1,
+ web: 2,
+ trigger: 3,
+ schedule: 4,
+ api: 5,
+ external: 6
+ }
+ end
+ end
+
+ class CommitStatus < ActiveRecord::Base
+ self.table_name = 'ci_builds'
+ self.inheritance_column = :_type_disabled
+
+ scope :has_pipeline, -> { where('ci_builds.commit_id=ci_pipelines.id') }
+ scope :of_type, -> (type) { where('type=?', type) }
+ end
+ end
+
+ def perform(start_id, stop_id)
+ external_pipelines(start_id, stop_id)
+ .update_all(source: Migratable::Pipeline.sources[:external])
+ end
+
+ private
+
+ def external_pipelines(start_id, stop_id)
+ Migratable::Pipeline.where(id: (start_id..stop_id))
+ .where(
+ 'EXISTS (?) AND NOT EXISTS (?)',
+ Migratable::CommitStatus.of_type('GenericCommitStatus').has_pipeline.select(1),
+ Migratable::CommitStatus.of_type('Ci::Build').has_pipeline.select(1)
+ )
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/cache/request_cache.rb b/lib/gitlab/cache/request_cache.rb
index 671b8e7e1b1..b96e161a5b6 100644
--- a/lib/gitlab/cache/request_cache.rb
+++ b/lib/gitlab/cache/request_cache.rb
@@ -26,8 +26,8 @@ module Gitlab
define_method(method_name) do |*args|
store =
- if RequestStore.active?
- RequestStore.store
+ if Gitlab::SafeRequestStore.active?
+ Gitlab::SafeRequestStore.store
else
ivar_name = # ! and ? cannot be used as ivar name
"@cache_#{method_name.to_s.tr('!?', "\u2605\u2606")}"
diff --git a/lib/gitlab/ci/config/entry/reports.rb b/lib/gitlab/ci/config/entry/reports.rb
index 5963f3eb90c..7bc482a6f48 100644
--- a/lib/gitlab/ci/config/entry/reports.rb
+++ b/lib/gitlab/ci/config/entry/reports.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
module Gitlab
module Ci
class Config
@@ -9,7 +11,7 @@ module Gitlab
include Validatable
include Attributable
- ALLOWED_KEYS = %i[junit].freeze
+ ALLOWED_KEYS = %i[junit sast dependency_scanning container_scanning dast].freeze
attributes ALLOWED_KEYS
@@ -19,6 +21,10 @@ module Gitlab
with_options allow_nil: true do
validates :junit, array_of_strings_or_string: true
+ validates :sast, array_of_strings_or_string: true
+ validates :dependency_scanning, array_of_strings_or_string: true
+ validates :container_scanning, array_of_strings_or_string: true
+ validates :dast, array_of_strings_or_string: true
end
end
diff --git a/lib/gitlab/ci/parsers.rb b/lib/gitlab/ci/parsers.rb
deleted file mode 100644
index a4eccc08dfc..00000000000
--- a/lib/gitlab/ci/parsers.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-module Gitlab
- module Ci
- module Parsers
- def self.fabricate!(file_type)
- "Gitlab::Ci::Parsers::#{file_type.classify}".constantize.new
- end
- end
- end
-end
diff --git a/lib/gitlab/ci/parsers/junit.rb b/lib/gitlab/ci/parsers/junit.rb
deleted file mode 100644
index d1c136f2009..00000000000
--- a/lib/gitlab/ci/parsers/junit.rb
+++ /dev/null
@@ -1,66 +0,0 @@
-module Gitlab
- module Ci
- module Parsers
- class Junit
- JunitParserError = Class.new(StandardError)
-
- def parse!(xml_data, test_suite)
- root = Hash.from_xml(xml_data)
-
- all_cases(root) do |test_case|
- test_case = create_test_case(test_case)
- test_suite.add_test_case(test_case)
- end
- rescue REXML::ParseException => e
- raise JunitParserError, "XML parsing failed: #{e.message}"
- rescue => e
- raise JunitParserError, "JUnit parsing failed: #{e.message}"
- end
-
- private
-
- def all_cases(root, parent = nil, &blk)
- return unless root.present?
-
- [root].flatten.compact.map do |node|
- next unless node.is_a?(Hash)
-
- # we allow only one top-level 'testsuites'
- all_cases(node['testsuites'], root, &blk) unless parent
-
- # we require at least one level of testsuites or testsuite
- each_case(node['testcase'], &blk) if parent
-
- # we allow multiple nested 'testsuite' (eg. PHPUnit)
- all_cases(node['testsuite'], root, &blk)
- end
- end
-
- def each_case(testcase, &blk)
- return unless testcase.present?
-
- [testcase].flatten.compact.map(&blk)
- end
-
- def create_test_case(data)
- if data['failure']
- status = ::Gitlab::Ci::Reports::TestCase::STATUS_FAILED
- system_output = data['failure']
- else
- status = ::Gitlab::Ci::Reports::TestCase::STATUS_SUCCESS
- system_output = nil
- end
-
- ::Gitlab::Ci::Reports::TestCase.new(
- classname: data['classname'],
- name: data['name'],
- file: data['file'],
- execution_time: data['time'],
- status: status,
- system_output: system_output
- )
- end
- end
- end
- end
-end
diff --git a/lib/gitlab/ci/parsers/test.rb b/lib/gitlab/ci/parsers/test.rb
new file mode 100644
index 00000000000..c6bc9662b07
--- /dev/null
+++ b/lib/gitlab/ci/parsers/test.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Ci
+ module Parsers
+ module Test
+ ParserNotFoundError = Class.new(StandardError)
+
+ PARSERS = {
+ junit: ::Gitlab::Ci::Parsers::Test::Junit
+ }.freeze
+
+ def self.fabricate!(file_type)
+ PARSERS.fetch(file_type.to_sym).new
+ rescue KeyError
+ raise ParserNotFoundError, "Cannot find any parser matching file type '#{file_type}'"
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/ci/parsers/test/junit.rb b/lib/gitlab/ci/parsers/test/junit.rb
new file mode 100644
index 00000000000..5d7d9a751d8
--- /dev/null
+++ b/lib/gitlab/ci/parsers/test/junit.rb
@@ -0,0 +1,70 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Ci
+ module Parsers
+ module Test
+ class Junit
+ JunitParserError = Class.new(StandardError)
+
+ def parse!(xml_data, test_suite)
+ root = Hash.from_xml(xml_data)
+
+ all_cases(root) do |test_case|
+ test_case = create_test_case(test_case)
+ test_suite.add_test_case(test_case)
+ end
+ rescue REXML::ParseException => e
+ raise JunitParserError, "XML parsing failed: #{e.message}"
+ rescue => e
+ raise JunitParserError, "JUnit parsing failed: #{e.message}"
+ end
+
+ private
+
+ def all_cases(root, parent = nil, &blk)
+ return unless root.present?
+
+ [root].flatten.compact.map do |node|
+ next unless node.is_a?(Hash)
+
+ # we allow only one top-level 'testsuites'
+ all_cases(node['testsuites'], root, &blk) unless parent
+
+ # we require at least one level of testsuites or testsuite
+ each_case(node['testcase'], &blk) if parent
+
+ # we allow multiple nested 'testsuite' (eg. PHPUnit)
+ all_cases(node['testsuite'], root, &blk)
+ end
+ end
+
+ def each_case(testcase, &blk)
+ return unless testcase.present?
+
+ [testcase].flatten.compact.map(&blk)
+ end
+
+ def create_test_case(data)
+ if data['failure']
+ status = ::Gitlab::Ci::Reports::TestCase::STATUS_FAILED
+ system_output = data['failure']
+ else
+ status = ::Gitlab::Ci::Reports::TestCase::STATUS_SUCCESS
+ system_output = nil
+ end
+
+ ::Gitlab::Ci::Reports::TestCase.new(
+ classname: data['classname'],
+ name: data['name'],
+ file: data['file'],
+ execution_time: data['time'],
+ status: status,
+ system_output: system_output
+ )
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/vendor/gitlab-ci-yml/Android.gitlab-ci.yml b/lib/gitlab/ci/templates/Android.gitlab-ci.yml
index 5f9d54ff574..5f9d54ff574 100644
--- a/vendor/gitlab-ci-yml/Android.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Android.gitlab-ci.yml
diff --git a/vendor/gitlab-ci-yml/Auto-DevOps.gitlab-ci.yml b/lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml
index a191f1f59bf..aebaf2d6982 100644
--- a/vendor/gitlab-ci-yml/Auto-DevOps.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml
@@ -49,7 +49,7 @@ variables:
POSTGRES_DB: $CI_ENVIRONMENT_SLUG
KUBERNETES_VERSION: 1.8.6
- HELM_VERSION: 2.6.1
+ HELM_VERSION: 2.10.0
DOCKER_DRIVER: overlay2
@@ -122,6 +122,9 @@ license_management:
paths: [gl-license-management-report.json]
only:
- branches
+ only:
+ variables:
+ - $GITLAB_FEATURES =~ /\blicense_management\b/
except:
variables:
- $LICENSE_MANAGEMENT_DISABLED
@@ -159,7 +162,10 @@ sast:
artifacts:
paths: [gl-sast-report.json]
only:
- - branches
+ refs:
+ - branches
+ variables:
+ - $GITLAB_FEATURES =~ /\bsast\b/
except:
variables:
- $SAST_DISABLED
@@ -176,7 +182,10 @@ dependency_scanning:
artifacts:
paths: [gl-dependency-scanning-report.json]
only:
- - branches
+ refs:
+ - branches
+ variables:
+ - $GITLAB_FEATURES =~ /\bdependency_scanning\b/
except:
variables:
- $DEPENDENCY_SCANNING_DISABLED
@@ -193,7 +202,10 @@ container_scanning:
artifacts:
paths: [gl-container-scanning-report.json]
only:
- - branches
+ refs:
+ - branches
+ variables:
+ - $GITLAB_FEATURES =~ /\bsast_container\b/
except:
variables:
- $CONTAINER_SCANNING_DISABLED
@@ -212,6 +224,8 @@ dast:
refs:
- branches
kubernetes: active
+ variables:
+ - $GITLAB_FEATURES =~ /\bdast\b/
except:
refs:
- master
@@ -484,15 +498,11 @@ rollout 100%:
}
function license_management() {
- if echo $GITLAB_FEATURES |grep license_management > /dev/null ; then
- # Extract "MAJOR.MINOR" from CI_SERVER_VERSION and generate "MAJOR-MINOR-stable"
- LICENSE_MANAGEMENT_VERSION=$(echo "$CI_SERVER_VERSION" | sed 's/^\([0-9]*\)\.\([0-9]*\).*/\1-\2-stable/')
+ # Extract "MAJOR.MINOR" from CI_SERVER_VERSION and generate "MAJOR-MINOR-stable"
+ LICENSE_MANAGEMENT_VERSION=$(echo "$CI_SERVER_VERSION" | sed 's/^\([0-9]*\)\.\([0-9]*\).*/\1-\2-stable/')
- docker run --volume "$PWD:/code" \
- "registry.gitlab.com/gitlab-org/security-products/license-management:$LICENSE_MANAGEMENT_VERSION" analyze /code
- else
- echo "License management is not available in your subscription"
- fi
+ docker run --volume "$PWD:/code" \
+ "registry.gitlab.com/gitlab-org/security-products/license-management:$LICENSE_MANAGEMENT_VERSION" analyze /code
}
function sast() {
@@ -605,7 +615,6 @@ rollout 100%:
--set postgresql.postgresPassword="$POSTGRES_PASSWORD" \
--set postgresql.postgresDatabase="$POSTGRES_DB" \
--namespace="$KUBE_NAMESPACE" \
- --version="$CI_PIPELINE_ID-$CI_JOB_ID" \
"$name" \
chart/
@@ -635,8 +644,8 @@ rollout 100%:
function install_dependencies() {
apk add -U openssl curl tar gzip bash ca-certificates git
- wget -q -O /etc/apk/keys/sgerrand.rsa.pub https://alpine-pkgs.sgerrand.com/sgerrand.rsa.pub
- wget https://github.com/sgerrand/alpine-pkg-glibc/releases/download/2.28-r0/glibc-2.28-r0.apk
+ curl -L -o /etc/apk/keys/sgerrand.rsa.pub https://alpine-pkgs.sgerrand.com/sgerrand.rsa.pub
+ curl -L -O https://github.com/sgerrand/alpine-pkg-glibc/releases/download/2.28-r0/glibc-2.28-r0.apk
apk add glibc-2.28-r0.apk
rm glibc-2.28-r0.apk
diff --git a/vendor/gitlab-ci-yml/Bash.gitlab-ci.yml b/lib/gitlab/ci/templates/Bash.gitlab-ci.yml
index 2d218b2e164..2d218b2e164 100644
--- a/vendor/gitlab-ci-yml/Bash.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Bash.gitlab-ci.yml
diff --git a/vendor/gitlab-ci-yml/C++.gitlab-ci.yml b/lib/gitlab/ci/templates/C++.gitlab-ci.yml
index c83c49d8c95..c83c49d8c95 100644
--- a/vendor/gitlab-ci-yml/C++.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/C++.gitlab-ci.yml
diff --git a/vendor/gitlab-ci-yml/Chef.gitlab-ci.yml b/lib/gitlab/ci/templates/Chef.gitlab-ci.yml
index 4d5b6484d6e..4d5b6484d6e 100644
--- a/vendor/gitlab-ci-yml/Chef.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Chef.gitlab-ci.yml
diff --git a/vendor/gitlab-ci-yml/Clojure.gitlab-ci.yml b/lib/gitlab/ci/templates/Clojure.gitlab-ci.yml
index f066285b1ad..f066285b1ad 100644
--- a/vendor/gitlab-ci-yml/Clojure.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Clojure.gitlab-ci.yml
diff --git a/vendor/gitlab-ci-yml/Crystal.gitlab-ci.yml b/lib/gitlab/ci/templates/Crystal.gitlab-ci.yml
index 36386a19fdc..36386a19fdc 100644
--- a/vendor/gitlab-ci-yml/Crystal.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Crystal.gitlab-ci.yml
diff --git a/vendor/gitlab-ci-yml/Django.gitlab-ci.yml b/lib/gitlab/ci/templates/Django.gitlab-ci.yml
index 57afcbbe8b5..57afcbbe8b5 100644
--- a/vendor/gitlab-ci-yml/Django.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Django.gitlab-ci.yml
diff --git a/vendor/gitlab-ci-yml/Docker.gitlab-ci.yml b/lib/gitlab/ci/templates/Docker.gitlab-ci.yml
index eeefadaa019..eeefadaa019 100644
--- a/vendor/gitlab-ci-yml/Docker.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Docker.gitlab-ci.yml
diff --git a/vendor/gitlab-ci-yml/Elixir.gitlab-ci.yml b/lib/gitlab/ci/templates/Elixir.gitlab-ci.yml
index cf9c731637c..cf9c731637c 100644
--- a/vendor/gitlab-ci-yml/Elixir.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Elixir.gitlab-ci.yml
diff --git a/vendor/gitlab-ci-yml/Go.gitlab-ci.yml b/lib/gitlab/ci/templates/Go.gitlab-ci.yml
index d572d7a1edc..d572d7a1edc 100644
--- a/vendor/gitlab-ci-yml/Go.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Go.gitlab-ci.yml
diff --git a/vendor/gitlab-ci-yml/Gradle.gitlab-ci.yml b/lib/gitlab/ci/templates/Gradle.gitlab-ci.yml
index 48d98dddfad..48d98dddfad 100644
--- a/vendor/gitlab-ci-yml/Gradle.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Gradle.gitlab-ci.yml
diff --git a/vendor/gitlab-ci-yml/Grails.gitlab-ci.yml b/lib/gitlab/ci/templates/Grails.gitlab-ci.yml
index 7fc698d50cf..7fc698d50cf 100644
--- a/vendor/gitlab-ci-yml/Grails.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Grails.gitlab-ci.yml
diff --git a/vendor/gitlab-ci-yml/Julia.gitlab-ci.yml b/lib/gitlab/ci/templates/Julia.gitlab-ci.yml
index 140cb4635f3..04c21b4725d 100644
--- a/vendor/gitlab-ci-yml/Julia.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Julia.gitlab-ci.yml
@@ -1,4 +1,4 @@
-# An example .gitlab-ci.yml file to test (and optionally report the coverage
+# This is an example .gitlab-ci.yml file to test (and optionally report the coverage
# results of) your [Julia][1] packages. Please refer to the [documentation][2]
# for more information about package development in Julia.
#
@@ -6,7 +6,7 @@
# whatever name you have given to your package.
#
# [1]: http://julialang.org/
-# [2]: http://julia.readthedocs.org/
+# [2]: https://docs.julialang.org/en/v1/manual/documentation/index.html
# Below is the template to run your tests in Julia
.test_template: &test_definition
@@ -18,25 +18,30 @@
script:
# Let's run the tests. Substitute `coverage = false` below, if you do not
# want coverage results.
- - /opt/julia/bin/julia -e 'Pkg.clone(pwd()); Pkg.test("MyPackage",
- coverage = true)'
+ - julia -e 'using Pkg; Pkg.clone(pwd()); Pkg.build("MyPackage"); Pkg.test("MyPackage"; coverage = true)'
# Comment out below if you do not want coverage results.
- - /opt/julia/bin/julia -e 'Pkg.add("Coverage"); cd(Pkg.dir("MyPackage"));
+ - julia -e 'using Pkg; Pkg.add("Coverage");
+ import MyPackage; cd(joinpath(dirname(pathof(MyPackage)), ".."));
using Coverage; cl, tl = get_summary(process_folder());
println("(", cl/tl*100, "%) covered")'
# Name a test and select an appropriate image.
-test:0.4.6:
- image: julialang/julia:v0.4.6
+# images comes from Docker hub
+test:0.7:
+ image: julia:0.7
+ <<: *test_definition
+
+test:1.0:
+ image: julia:1.0
<<: *test_definition
# Maybe you would like to test your package against the development branch:
-test:0.5.0-dev:
- image: julialang/julia:v0.5.0-dev
- # ... allowing for failures, since we are testing against the development
- # branch:
- allow_failure: true
- <<: *test_definition
+# test:1.1-dev (not sure there is such an image in docker, so not tested yet):
+# image: julia:v1.1-dev
+# # ... allowing for failures, since we are testing against the development
+# # branch:
+# allow_failure: true
+# <<: *test_definition
# REMARK: Do not forget to enable the coverage feature for your project, if you
# are using code coverage reporting above. This can be done by
@@ -44,11 +49,28 @@ test:0.5.0-dev:
# - Navigating to the `CI/CD Pipelines` settings of your project,
# - Copying and pasting the default `Simplecov` regex example provided, i.e.,
# `\(\d+.\d+\%\) covered` in the `test coverage parsing` textfield.
-#
-# WARNING: This template is using the `julialang/julia` images from [Docker
+
+# Example documentation deployment
+pages:
+ image: julia:0.7
+ stage: deploy
+ script:
+ - apt-get update -qq && apt-get install -y git # needed by Documenter
+ - julia -e 'using Pkg; Pkg.clone(pwd()); Pkg.build("MyPackage");' # rebuild Julia (can be put somewhere else I'm sure
+ - julia -e 'using Pkg; import MyPackage; Pkg.add("Documenter")' # install Documenter
+ - julia --color=yes docs/make.jl # make documentation
+ - mv docs/build public # move to the directory picked up by Gitlab pages
+ artifacts:
+ paths:
+ - public
+ only:
+ - master
+
+
+# WARNING: This template is using the `julia` images from [Docker
# Hub][3]. One can use custom Julia images and/or the official ones found
# in the same place. However, care must be taken to correctly locate the binary
# file (`/opt/julia/bin/julia` above), which is usually given on the image's
# description page.
#
-# [3]: http://hub.docker.com/
+# [3]: https://hub.docker.com/_/julia/
diff --git a/vendor/gitlab-ci-yml/LaTeX.gitlab-ci.yml b/lib/gitlab/ci/templates/LaTeX.gitlab-ci.yml
index a4aed36889e..a4aed36889e 100644
--- a/vendor/gitlab-ci-yml/LaTeX.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/LaTeX.gitlab-ci.yml
diff --git a/vendor/gitlab-ci-yml/Laravel.gitlab-ci.yml b/lib/gitlab/ci/templates/Laravel.gitlab-ci.yml
index 0688f77a1d2..0688f77a1d2 100644
--- a/vendor/gitlab-ci-yml/Laravel.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Laravel.gitlab-ci.yml
diff --git a/vendor/gitlab-ci-yml/Maven.gitlab-ci.yml b/lib/gitlab/ci/templates/Maven.gitlab-ci.yml
index d61ff239e13..d61ff239e13 100644
--- a/vendor/gitlab-ci-yml/Maven.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Maven.gitlab-ci.yml
diff --git a/vendor/gitlab-ci-yml/Mono.gitlab-ci.yml b/lib/gitlab/ci/templates/Mono.gitlab-ci.yml
index 3585f99760f..3585f99760f 100644
--- a/vendor/gitlab-ci-yml/Mono.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Mono.gitlab-ci.yml
diff --git a/vendor/gitlab-ci-yml/Nodejs.gitlab-ci.yml b/lib/gitlab/ci/templates/Nodejs.gitlab-ci.yml
index 41de1458582..41de1458582 100644
--- a/vendor/gitlab-ci-yml/Nodejs.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Nodejs.gitlab-ci.yml
diff --git a/vendor/gitlab-ci-yml/OpenShift.gitlab-ci.yml b/lib/gitlab/ci/templates/OpenShift.gitlab-ci.yml
index 290b9997084..290b9997084 100644
--- a/vendor/gitlab-ci-yml/OpenShift.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/OpenShift.gitlab-ci.yml
diff --git a/vendor/gitlab-ci-yml/PHP.gitlab-ci.yml b/lib/gitlab/ci/templates/PHP.gitlab-ci.yml
index 33f44ee9222..33f44ee9222 100644
--- a/vendor/gitlab-ci-yml/PHP.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/PHP.gitlab-ci.yml
diff --git a/vendor/gitlab-ci-yml/Packer.gitlab-ci.yml b/lib/gitlab/ci/templates/Packer.gitlab-ci.yml
index fa296057c72..fa296057c72 100644
--- a/vendor/gitlab-ci-yml/Packer.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Packer.gitlab-ci.yml
diff --git a/vendor/gitlab-ci-yml/Pages/Brunch.gitlab-ci.yml b/lib/gitlab/ci/templates/Pages/Brunch.gitlab-ci.yml
index 7fcc0b436b5..7fcc0b436b5 100644
--- a/vendor/gitlab-ci-yml/Pages/Brunch.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Pages/Brunch.gitlab-ci.yml
diff --git a/vendor/gitlab-ci-yml/Pages/Doxygen.gitlab-ci.yml b/lib/gitlab/ci/templates/Pages/Doxygen.gitlab-ci.yml
index 791afdd23f1..791afdd23f1 100644
--- a/vendor/gitlab-ci-yml/Pages/Doxygen.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Pages/Doxygen.gitlab-ci.yml
diff --git a/vendor/gitlab-ci-yml/Pages/Gatsby.gitlab-ci.yml b/lib/gitlab/ci/templates/Pages/Gatsby.gitlab-ci.yml
index 9df2a4797b2..9df2a4797b2 100644
--- a/vendor/gitlab-ci-yml/Pages/Gatsby.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Pages/Gatsby.gitlab-ci.yml
diff --git a/vendor/gitlab-ci-yml/Pages/HTML.gitlab-ci.yml b/lib/gitlab/ci/templates/Pages/HTML.gitlab-ci.yml
index 249a168aa33..249a168aa33 100644
--- a/vendor/gitlab-ci-yml/Pages/HTML.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Pages/HTML.gitlab-ci.yml
diff --git a/vendor/gitlab-ci-yml/Pages/Harp.gitlab-ci.yml b/lib/gitlab/ci/templates/Pages/Harp.gitlab-ci.yml
index dd3ef149668..dd3ef149668 100644
--- a/vendor/gitlab-ci-yml/Pages/Harp.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Pages/Harp.gitlab-ci.yml
diff --git a/vendor/gitlab-ci-yml/Pages/Hexo.gitlab-ci.yml b/lib/gitlab/ci/templates/Pages/Hexo.gitlab-ci.yml
index 02d02250bbf..02d02250bbf 100644
--- a/vendor/gitlab-ci-yml/Pages/Hexo.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Pages/Hexo.gitlab-ci.yml
diff --git a/vendor/gitlab-ci-yml/Pages/Hugo.gitlab-ci.yml b/lib/gitlab/ci/templates/Pages/Hugo.gitlab-ci.yml
index b8cfb0f56f6..b8cfb0f56f6 100644
--- a/vendor/gitlab-ci-yml/Pages/Hugo.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Pages/Hugo.gitlab-ci.yml
diff --git a/vendor/gitlab-ci-yml/Pages/Hyde.gitlab-ci.yml b/lib/gitlab/ci/templates/Pages/Hyde.gitlab-ci.yml
index f5b40f2b9f1..f5b40f2b9f1 100644
--- a/vendor/gitlab-ci-yml/Pages/Hyde.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Pages/Hyde.gitlab-ci.yml
diff --git a/vendor/gitlab-ci-yml/Pages/JBake.gitlab-ci.yml b/lib/gitlab/ci/templates/Pages/JBake.gitlab-ci.yml
index 7abfaf53e8e..7abfaf53e8e 100644
--- a/vendor/gitlab-ci-yml/Pages/JBake.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Pages/JBake.gitlab-ci.yml
diff --git a/vendor/gitlab-ci-yml/Pages/Jekyll.gitlab-ci.yml b/lib/gitlab/ci/templates/Pages/Jekyll.gitlab-ci.yml
index 37f50554036..37f50554036 100644
--- a/vendor/gitlab-ci-yml/Pages/Jekyll.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Pages/Jekyll.gitlab-ci.yml
diff --git a/lib/gitlab/ci/templates/Pages/Jigsaw.gitlab-ci.yml b/lib/gitlab/ci/templates/Pages/Jigsaw.gitlab-ci.yml
new file mode 100644
index 00000000000..0e5fb410a4e
--- /dev/null
+++ b/lib/gitlab/ci/templates/Pages/Jigsaw.gitlab-ci.yml
@@ -0,0 +1,42 @@
+# Jigsaw is a simple static sites generator with Laravel's Blade.
+#
+# Full project: https://github.com/tightenco/jigsaw
+
+image: php:7.2
+
+# These folders are cached between builds
+cache:
+ paths:
+ - vendor/
+ - node_modules/
+
+before_script:
+ # Update packages
+ - apt-get update -yqq
+
+ # Install dependencies
+ - apt-get install -yqq gnupg zlib1g-dev libpng-dev
+
+ # Install Node 8
+ - curl -sL https://deb.nodesource.com/setup_8.x | bash -
+ - apt-get install -yqq nodejs
+
+ # Install php extensions
+ - docker-php-ext-install zip
+
+ # Install Composer and project dependencies.
+ - curl -sS https://getcomposer.org/installer | php
+ - php composer.phar install
+
+ # Install Node dependencies.
+ - npm install
+
+pages:
+ script:
+ - npm run production
+ - mv build_production public
+ artifacts:
+ paths:
+ - public
+ only:
+ - master
diff --git a/vendor/gitlab-ci-yml/Pages/Lektor.gitlab-ci.yml b/lib/gitlab/ci/templates/Pages/Lektor.gitlab-ci.yml
index c5c44a5d86c..c5c44a5d86c 100644
--- a/vendor/gitlab-ci-yml/Pages/Lektor.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Pages/Lektor.gitlab-ci.yml
diff --git a/vendor/gitlab-ci-yml/Pages/Metalsmith.gitlab-ci.yml b/lib/gitlab/ci/templates/Pages/Metalsmith.gitlab-ci.yml
index 50e8b7ccd46..50e8b7ccd46 100644
--- a/vendor/gitlab-ci-yml/Pages/Metalsmith.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Pages/Metalsmith.gitlab-ci.yml
diff --git a/vendor/gitlab-ci-yml/Pages/Middleman.gitlab-ci.yml b/lib/gitlab/ci/templates/Pages/Middleman.gitlab-ci.yml
index 9f4cc0574d6..9f4cc0574d6 100644
--- a/vendor/gitlab-ci-yml/Pages/Middleman.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Pages/Middleman.gitlab-ci.yml
diff --git a/vendor/gitlab-ci-yml/Pages/Nanoc.gitlab-ci.yml b/lib/gitlab/ci/templates/Pages/Nanoc.gitlab-ci.yml
index b469b316ba5..b469b316ba5 100644
--- a/vendor/gitlab-ci-yml/Pages/Nanoc.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Pages/Nanoc.gitlab-ci.yml
diff --git a/vendor/gitlab-ci-yml/Pages/Octopress.gitlab-ci.yml b/lib/gitlab/ci/templates/Pages/Octopress.gitlab-ci.yml
index 4762ec9acfd..4762ec9acfd 100644
--- a/vendor/gitlab-ci-yml/Pages/Octopress.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Pages/Octopress.gitlab-ci.yml
diff --git a/vendor/gitlab-ci-yml/Pages/Pelican.gitlab-ci.yml b/lib/gitlab/ci/templates/Pages/Pelican.gitlab-ci.yml
index c5f3154f587..c5f3154f587 100644
--- a/vendor/gitlab-ci-yml/Pages/Pelican.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Pages/Pelican.gitlab-ci.yml
diff --git a/vendor/gitlab-ci-yml/Python.gitlab-ci.yml b/lib/gitlab/ci/templates/Python.gitlab-ci.yml
index 2e0589de652..2e0589de652 100644
--- a/vendor/gitlab-ci-yml/Python.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Python.gitlab-ci.yml
diff --git a/vendor/gitlab-ci-yml/Ruby.gitlab-ci.yml b/lib/gitlab/ci/templates/Ruby.gitlab-ci.yml
index 93cb31f48c0..93cb31f48c0 100644
--- a/vendor/gitlab-ci-yml/Ruby.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Ruby.gitlab-ci.yml
diff --git a/vendor/gitlab-ci-yml/Rust.gitlab-ci.yml b/lib/gitlab/ci/templates/Rust.gitlab-ci.yml
index cab087c48c7..cab087c48c7 100644
--- a/vendor/gitlab-ci-yml/Rust.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Rust.gitlab-ci.yml
diff --git a/vendor/gitlab-ci-yml/Scala.gitlab-ci.yml b/lib/gitlab/ci/templates/Scala.gitlab-ci.yml
index b4208ed9d7d..b4208ed9d7d 100644
--- a/vendor/gitlab-ci-yml/Scala.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Scala.gitlab-ci.yml
diff --git a/vendor/gitlab-ci-yml/Swift.gitlab-ci.yml b/lib/gitlab/ci/templates/Swift.gitlab-ci.yml
index ba8a802ba4f..ba8a802ba4f 100644
--- a/vendor/gitlab-ci-yml/Swift.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Swift.gitlab-ci.yml
diff --git a/vendor/gitlab-ci-yml/Terraform.gitlab-ci.yml b/lib/gitlab/ci/templates/Terraform.gitlab-ci.yml
index 7160fce26a8..7160fce26a8 100644
--- a/vendor/gitlab-ci-yml/Terraform.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Terraform.gitlab-ci.yml
diff --git a/vendor/gitlab-ci-yml/dotNET.gitlab-ci.yml b/lib/gitlab/ci/templates/dotNET.gitlab-ci.yml
index fc3d4ecdbba..fc3d4ecdbba 100644
--- a/vendor/gitlab-ci-yml/dotNET.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/dotNET.gitlab-ci.yml
diff --git a/lib/gitlab/contributions_calendar.rb b/lib/gitlab/contributions_calendar.rb
index 3236abfa43f..1ffc2639237 100644
--- a/lib/gitlab/contributions_calendar.rb
+++ b/lib/gitlab/contributions_calendar.rb
@@ -30,8 +30,9 @@ module Gitlab
note_events = event_counts(date_from, :merge_requests)
.having(action: [Event::COMMENTED])
- union = Gitlab::SQL::Union.new([repo_events, issue_events, mr_events, note_events])
- events = Event.find_by_sql(union.to_sql).map(&:attributes)
+ events = Event
+ .from_union([repo_events, issue_events, mr_events, note_events])
+ .map(&:attributes)
@activity_dates = events.each_with_object(Hash.new {|h, k| h[k] = 0 }) do |event, activities|
activities[event["date"]] += event["total_amount"]
diff --git a/lib/gitlab/current_settings.rb b/lib/gitlab/current_settings.rb
index c9dbd2d2e5f..de7c959e706 100644
--- a/lib/gitlab/current_settings.rb
+++ b/lib/gitlab/current_settings.rb
@@ -2,11 +2,7 @@ module Gitlab
module CurrentSettings
class << self
def current_application_settings
- if RequestStore.active?
- RequestStore.fetch(:current_application_settings) { ensure_application_settings! }
- else
- ensure_application_settings!
- end
+ Gitlab::SafeRequestStore.fetch(:current_application_settings) { ensure_application_settings! }
end
def fake_application_settings(attributes = {})
diff --git a/lib/gitlab/database.rb b/lib/gitlab/database.rb
index 8eacad078c8..42f9605f5ac 100644
--- a/lib/gitlab/database.rb
+++ b/lib/gitlab/database.rb
@@ -249,5 +249,21 @@ module Gitlab
end
private_class_method :database_version
+
+ def self.add_post_migrate_path_to_rails(force: false)
+ return if ENV['SKIP_POST_DEPLOYMENT_MIGRATIONS'] && !force
+
+ Rails.application.config.paths['db'].each do |db_path|
+ path = Rails.root.join(db_path, 'post_migrate').to_s
+
+ unless Rails.application.config.paths['db/migrate'].include? path
+ Rails.application.config.paths['db/migrate'] << path
+
+ # Rails memoizes migrations at certain points where it won't read the above
+ # path just yet. As such we must also update the following list of paths.
+ ActiveRecord::Migrator.migrations_paths << path
+ end
+ end
+ end
end
end
diff --git a/lib/gitlab/database/grant.rb b/lib/gitlab/database/grant.rb
index d32837f5793..7d334a79009 100644
--- a/lib/gitlab/database/grant.rb
+++ b/lib/gitlab/database/grant.rb
@@ -2,6 +2,8 @@ module Gitlab
module Database
# Model that can be used for querying permissions of a SQL user.
class Grant < ActiveRecord::Base
+ include FromUnion
+
self.table_name =
if Database.postgresql?
'information_schema.role_table_grants'
@@ -42,9 +44,7 @@ module Gitlab
.where("GRANTEE = CONCAT('\\'', REPLACE(CURRENT_USER(), '@', '\\'@\\''), '\\'')")
]
- union = SQL::Union.new(queries).to_sql
-
- Grant.from("(#{union}) privs").any?
+ Grant.from_union(queries, alias_as: 'privs').any?
end
end
end
diff --git a/lib/gitlab/database/migration_helpers.rb b/lib/gitlab/database/migration_helpers.rb
index 7f012312819..30541ee3553 100644
--- a/lib/gitlab/database/migration_helpers.rb
+++ b/lib/gitlab/database/migration_helpers.rb
@@ -1073,6 +1073,10 @@ into similar problems in the future (e.g. when new tables are created).
connection.select_value(index_sql).to_i > 0
end
+
+ def mysql_compatible_index_length
+ Gitlab::Database.mysql? ? 20 : nil
+ end
end
end
end
diff --git a/lib/gitlab/database/subquery.rb b/lib/gitlab/database/subquery.rb
new file mode 100644
index 00000000000..36e4559b554
--- /dev/null
+++ b/lib/gitlab/database/subquery.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Database
+ module Subquery
+ class << self
+ def self_join(relation)
+ t = relation.arel_table
+ t2 = if !Gitlab.rails5?
+ relation.arel.as('t2')
+ else
+ # Work around a bug in Rails 5, where LIMIT causes trouble
+ # See https://gitlab.com/gitlab-org/gitlab-ce/issues/51729
+ r = relation.limit(nil).arel
+ r.take(relation.limit_value) if relation.limit_value
+ r.as('t2')
+ end
+
+ relation.unscoped.joins(t.join(t2).on(t[:id].eq(t2[:id])).join_sources.first)
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/diff/file.rb b/lib/gitlab/diff/file.rb
index d2ca7a070fa..fb117baca9e 100644
--- a/lib/gitlab/diff/file.rb
+++ b/lib/gitlab/diff/file.rb
@@ -20,8 +20,9 @@ module Gitlab
DiffViewer::Image
].sort_by { |v| v.binary? ? 0 : 1 }.freeze
- def initialize(diff, repository:, diff_refs: nil, fallback_diff_refs: nil)
+ def initialize(diff, repository:, diff_refs: nil, fallback_diff_refs: nil, stats: nil)
@diff = diff
+ @stats = stats
@repository = repository
@diff_refs = diff_refs
@fallback_diff_refs = fallback_diff_refs
@@ -165,11 +166,11 @@ module Gitlab
end
def added_lines
- diff_lines.count(&:added?)
+ @stats&.additions || diff_lines.count(&:added?)
end
def removed_lines
- diff_lines.count(&:removed?)
+ @stats&.deletions || diff_lines.count(&:removed?)
end
def file_identifier
diff --git a/lib/gitlab/diff/file_collection/base.rb b/lib/gitlab/diff/file_collection/base.rb
index 2acb0e43b69..b79ff771a2b 100644
--- a/lib/gitlab/diff/file_collection/base.rb
+++ b/lib/gitlab/diff/file_collection/base.rb
@@ -2,23 +2,27 @@ module Gitlab
module Diff
module FileCollection
class Base
+ include Gitlab::Utils::StrongMemoize
+
attr_reader :project, :diff_options, :diff_refs, :fallback_diff_refs, :diffable
delegate :count, :size, :real_size, to: :diff_files
def self.default_options
- ::Commit.max_diff_options.merge(ignore_whitespace_change: false, expanded: false)
+ ::Commit.max_diff_options.merge(ignore_whitespace_change: false, expanded: false, include_stats: true)
end
def initialize(diffable, project:, diff_options: nil, diff_refs: nil, fallback_diff_refs: nil)
diff_options = self.class.default_options.merge(diff_options || {})
@diffable = diffable
+ @include_stats = diff_options.delete(:include_stats)
@diffs = diffable.raw_diffs(diff_options)
@project = project
@diff_options = diff_options
@diff_refs = diff_refs
@fallback_diff_refs = fallback_diff_refs
+ @repository = project.repository
end
def diff_files
@@ -43,10 +47,27 @@ module Gitlab
private
+ def diff_stats_collection
+ strong_memoize(:diff_stats) do
+ # There are scenarios where we don't need to request Diff Stats,
+ # when caching for instance.
+ next unless @include_stats
+ next unless diff_refs
+
+ @repository.diff_stats(diff_refs.base_sha, diff_refs.head_sha)
+ end
+ end
+
def decorate_diff!(diff)
return diff if diff.is_a?(File)
- Gitlab::Diff::File.new(diff, repository: project.repository, diff_refs: diff_refs, fallback_diff_refs: fallback_diff_refs)
+ stats = diff_stats_collection&.find_by_path(diff.new_path)
+
+ Gitlab::Diff::File.new(diff,
+ repository: project.repository,
+ diff_refs: diff_refs,
+ fallback_diff_refs: fallback_diff_refs,
+ stats: stats)
end
end
end
diff --git a/lib/gitlab/diff/position.rb b/lib/gitlab/diff/position.rb
index 978962ab2eb..fc280f96ec1 100644
--- a/lib/gitlab/diff/position.rb
+++ b/lib/gitlab/diff/position.rb
@@ -101,21 +101,21 @@ module Gitlab
return @diff_file if defined?(@diff_file)
@diff_file = begin
- if RequestStore.active?
- key = {
- project_id: repository.project.id,
- start_sha: start_sha,
- head_sha: head_sha,
- path: file_path
- }
-
- RequestStore.fetch(key) { find_diff_file(repository) }
- else
- find_diff_file(repository)
- end
+ key = {
+ project_id: repository.project.id,
+ start_sha: start_sha,
+ head_sha: head_sha,
+ path: file_path
+ }
+
+ Gitlab::SafeRequestStore.fetch(key) { find_diff_file(repository) }
end
end
+ def diff_options
+ { paths: paths, expanded: true, include_stats: false }
+ end
+
def diff_line(repository)
@diff_line ||= diff_file(repository)&.line_for_position(self)
end
@@ -130,7 +130,7 @@ module Gitlab
return unless diff_refs.complete?
return unless comparison = diff_refs.compare_in(repository.project)
- comparison.diffs(paths: paths, expanded: true).diff_files.first
+ comparison.diffs(diff_options).diff_files.first
end
def get_formatter_class(type)
diff --git a/lib/gitlab/favicon.rb b/lib/gitlab/favicon.rb
index 4850a6c0430..050a1ad3a0b 100644
--- a/lib/gitlab/favicon.rb
+++ b/lib/gitlab/favicon.rb
@@ -47,7 +47,7 @@ module Gitlab
end
def appearance
- RequestStore.store[:appearance] ||= (Appearance.current || Appearance.new)
+ Gitlab::SafeRequestStore[:appearance] ||= (Appearance.current || Appearance.new)
end
def appearance_favicon
diff --git a/lib/gitlab/git/diff_stats_collection.rb b/lib/gitlab/git/diff_stats_collection.rb
new file mode 100644
index 00000000000..d4033f56387
--- /dev/null
+++ b/lib/gitlab/git/diff_stats_collection.rb
@@ -0,0 +1,30 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Git
+ class DiffStatsCollection
+ include Gitlab::Utils::StrongMemoize
+ include Enumerable
+
+ def initialize(diff_stats)
+ @collection = diff_stats
+ end
+
+ def each(&block)
+ @collection.each(&block)
+ end
+
+ def find_by_path(path)
+ indexed_by_path[path]
+ end
+
+ private
+
+ def indexed_by_path
+ strong_memoize(:indexed_by_path) do
+ index_by { |stats| stats.path }
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/git/hook_env.rb b/lib/gitlab/git/hook_env.rb
index 455e8451c10..620568d8817 100644
--- a/lib/gitlab/git/hook_env.rb
+++ b/lib/gitlab/git/hook_env.rb
@@ -17,18 +17,18 @@ module Gitlab
].freeze
def self.set(gl_repository, env)
- return unless RequestStore.active?
+ return unless Gitlab::SafeRequestStore.active?
raise "missing gl_repository" if gl_repository.blank?
- RequestStore.store[:gitlab_git_env] ||= {}
- RequestStore.store[:gitlab_git_env][gl_repository] = whitelist_git_env(env)
+ Gitlab::SafeRequestStore[:gitlab_git_env] ||= {}
+ Gitlab::SafeRequestStore[:gitlab_git_env][gl_repository] = whitelist_git_env(env)
end
def self.all(gl_repository)
- return {} unless RequestStore.active?
+ return {} unless Gitlab::SafeRequestStore.active?
- h = RequestStore.fetch(:gitlab_git_env) { {} }
+ h = Gitlab::SafeRequestStore.fetch(:gitlab_git_env) { {} }
h.fetch(gl_repository, {})
end
diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb
index 1b8d320ff3b..45d42c7078f 100644
--- a/lib/gitlab/git/repository.rb
+++ b/lib/gitlab/git/repository.rb
@@ -438,6 +438,16 @@ module Gitlab
Gitlab::Git::DiffCollection.new(iterator, options)
end
+ def diff_stats(left_id, right_id)
+ stats = wrapped_gitaly_errors do
+ gitaly_commit_client.diff_stats(left_id, right_id)
+ end
+
+ Gitlab::Git::DiffStatsCollection.new(stats)
+ rescue CommandError, TypeError
+ Gitlab::Git::DiffStatsCollection.new([])
+ end
+
# Returns a RefName for a given SHA
def ref_name_for_sha(ref_path, sha)
raise ArgumentError, "sha can't be empty" unless sha.present?
@@ -581,10 +591,6 @@ module Gitlab
end
end
- def user_to_committer(user)
- Gitlab::Git.committer_hash(email: user.email, name: user.name)
- end
-
# Delete the specified branch from the repository
def delete_branch(branch_name)
wrapped_gitaly_errors do
@@ -947,6 +953,12 @@ module Gitlab
end
end
+ def list_last_commits_for_tree(sha, path, offset: 0, limit: 25)
+ wrapped_gitaly_errors do
+ gitaly_commit_client.list_last_commits_for_tree(sha, path, offset: offset, limit: limit)
+ end
+ end
+
def last_commit_for_path(sha, path)
wrapped_gitaly_errors do
gitaly_commit_client.last_commit_for_path(sha, path)
diff --git a/lib/gitlab/git/storage/circuit_breaker.rb b/lib/gitlab/git/storage/circuit_breaker.rb
index 62427ac9cc4..fcee9ae566c 100644
--- a/lib/gitlab/git/storage/circuit_breaker.rb
+++ b/lib/gitlab/git/storage/circuit_breaker.rb
@@ -11,7 +11,7 @@ module Gitlab
to: :failure_info
def self.for_storage(storage)
- cached_circuitbreakers = RequestStore.fetch(:circuitbreaker_cache) do
+ cached_circuitbreakers = Gitlab::SafeRequestStore.fetch(:circuitbreaker_cache) do
Hash.new do |hash, storage_name|
hash[storage_name] = build(storage_name)
end
diff --git a/lib/gitlab/git/storage/failure_info.rb b/lib/gitlab/git/storage/failure_info.rb
index 387279c110d..1d28a850049 100644
--- a/lib/gitlab/git/storage/failure_info.rb
+++ b/lib/gitlab/git/storage/failure_info.rb
@@ -10,7 +10,7 @@ module Gitlab
redis.del(*all_storage_keys) unless all_storage_keys.empty?
end
- RequestStore.delete(:circuitbreaker_cache)
+ Gitlab::SafeRequestStore.delete(:circuitbreaker_cache)
end
def self.load(cache_key)
diff --git a/lib/gitlab/git/wiki.rb b/lib/gitlab/git/wiki.rb
index ae92a624e05..d2dc4f2e688 100644
--- a/lib/gitlab/git/wiki.rb
+++ b/lib/gitlab/git/wiki.rb
@@ -115,11 +115,7 @@ module Gitlab
def version(commit_id)
commit_find_proc = -> { Gitlab::Git::Commit.find(@repository, commit_id) }
- if RequestStore.active?
- RequestStore.fetch([:wiki_version_commit, commit_id]) { commit_find_proc.call }
- else
- commit_find_proc.call
- end
+ Gitlab::SafeRequestStore.fetch([:wiki_version_commit, commit_id]) { commit_find_proc.call }
end
def assert_type!(object, klass)
diff --git a/lib/gitlab/gitaly_client.rb b/lib/gitlab/gitaly_client.rb
index 12307338972..500aabcbbb8 100644
--- a/lib/gitlab/gitaly_client.rb
+++ b/lib/gitlab/gitaly_client.rb
@@ -174,10 +174,29 @@ module Gitlab
end
private_class_method :current_transaction_labels
+ # For some time related tasks we can't rely on `Time.now` since it will be
+ # affected by Timecop in some tests, and the clock of some gitaly-related
+ # components (grpc's c-core and gitaly server) use system time instead of
+ # timecop's time, so tests will fail.
+ # `Time.at(Process.clock_gettime(Process::CLOCK_REALTIME))` will circumvent
+ # timecop.
+ def self.real_time
+ Time.at(Process.clock_gettime(Process::CLOCK_REALTIME))
+ end
+ private_class_method :real_time
+
+ def self.authorization_token(storage)
+ token = token(storage).to_s
+ issued_at = real_time.to_i.to_s
+ hmac = OpenSSL::HMAC.hexdigest(OpenSSL::Digest::SHA256.new, token, issued_at)
+
+ "v2.#{hmac}.#{issued_at}"
+ end
+ private_class_method :authorization_token
+
def self.request_kwargs(storage, timeout, remote_storage: nil)
- encoded_token = Base64.strict_encode64(token(storage).to_s)
metadata = {
- 'authorization' => "Bearer #{encoded_token}",
+ 'authorization' => "Bearer #{authorization_token(storage)}",
'client_name' => CLIENT_NAME
}
@@ -195,12 +214,7 @@ module Gitlab
return result unless timeout > 0
- # Do not use `Time.now` for deadline calculation, since it
- # will be affected by Timecop in some tests, but grpc's c-core
- # uses system time instead of timecop's time, so tests will fail
- # `Time.at(Process.clock_gettime(Process::CLOCK_REALTIME))` will
- # circumvent timecop
- deadline = Time.at(Process.clock_gettime(Process::CLOCK_REALTIME)) + timeout
+ deadline = real_time + timeout
result[:deadline] = deadline
result
@@ -302,7 +316,7 @@ module Gitlab
# Ensures that Gitaly is not being abuse through n+1 misuse etc
def self.enforce_gitaly_request_limits(call_site)
# Only count limits in request-response environments (not sidekiq for example)
- return unless RequestStore.active?
+ return unless Gitlab::SafeRequestStore.active?
# This is this actual number of times this call was made. Used for information purposes only
actual_call_count = increment_call_count("gitaly_#{call_site}_actual")
@@ -326,7 +340,7 @@ module Gitlab
end
def self.allow_n_plus_1_calls
- return yield unless RequestStore.active?
+ return yield unless Gitlab::SafeRequestStore.active?
begin
increment_call_count(:gitaly_call_count_exception_block_depth)
@@ -337,25 +351,25 @@ module Gitlab
end
def self.get_call_count(key)
- RequestStore.store[key] || 0
+ Gitlab::SafeRequestStore[key] || 0
end
private_class_method :get_call_count
def self.increment_call_count(key)
- RequestStore.store[key] ||= 0
- RequestStore.store[key] += 1
+ Gitlab::SafeRequestStore[key] ||= 0
+ Gitlab::SafeRequestStore[key] += 1
end
private_class_method :increment_call_count
def self.decrement_call_count(key)
- RequestStore.store[key] -= 1
+ Gitlab::SafeRequestStore[key] -= 1
end
private_class_method :decrement_call_count
# Returns an estimate of the number of Gitaly calls made for this
# request
def self.get_request_count
- return 0 unless RequestStore.active?
+ return 0 unless Gitlab::SafeRequestStore.active?
gitaly_migrate_count = get_call_count("gitaly_migrate_actual")
gitaly_call_count = get_call_count("gitaly_call_actual")
@@ -372,28 +386,28 @@ module Gitlab
end
def self.reset_counts
- return unless RequestStore.active?
+ return unless Gitlab::SafeRequestStore.active?
%w[migrate call].each do |call_site|
- RequestStore.store["gitaly_#{call_site}_actual"] = 0
- RequestStore.store["gitaly_#{call_site}_permitted"] = 0
+ Gitlab::SafeRequestStore["gitaly_#{call_site}_actual"] = 0
+ Gitlab::SafeRequestStore["gitaly_#{call_site}_permitted"] = 0
end
end
def self.add_call_details(details)
id = details.delete(:id)
- return unless id && RequestStore.active? && RequestStore.store[:peek_enabled]
+ return unless id && Gitlab::SafeRequestStore[:peek_enabled]
- RequestStore.store['gitaly_call_details'] ||= {}
- RequestStore.store['gitaly_call_details'][id] ||= {}
- RequestStore.store['gitaly_call_details'][id].merge!(details)
+ Gitlab::SafeRequestStore['gitaly_call_details'] ||= {}
+ Gitlab::SafeRequestStore['gitaly_call_details'][id] ||= {}
+ Gitlab::SafeRequestStore['gitaly_call_details'][id].merge!(details)
end
def self.list_call_details
- return {} unless RequestStore.active? && RequestStore.store[:peek_enabled]
+ return {} unless Gitlab::SafeRequestStore[:peek_enabled]
- RequestStore.store['gitaly_call_details'] || {}
+ Gitlab::SafeRequestStore['gitaly_call_details'] || {}
end
def self.expected_server_version
@@ -431,22 +445,22 @@ module Gitlab
# Count a stack. Used for n+1 detection
def self.count_stack
- return unless RequestStore.active?
+ return unless Gitlab::SafeRequestStore.active?
stack_string = Gitlab::Profiler.clean_backtrace(caller).drop(1).join("\n")
- RequestStore.store[:stack_counter] ||= Hash.new
+ Gitlab::SafeRequestStore[:stack_counter] ||= Hash.new
- count = RequestStore.store[:stack_counter][stack_string] || 0
- RequestStore.store[:stack_counter][stack_string] = count + 1
+ count = Gitlab::SafeRequestStore[:stack_counter][stack_string] || 0
+ Gitlab::SafeRequestStore[:stack_counter][stack_string] = count + 1
end
private_class_method :count_stack
# Returns a count for the stack which called Gitaly the most times. Used for n+1 detection
def self.max_call_count
- return 0 unless RequestStore.active?
+ return 0 unless Gitlab::SafeRequestStore.active?
- stack_counter = RequestStore.store[:stack_counter]
+ stack_counter = Gitlab::SafeRequestStore[:stack_counter]
return 0 unless stack_counter
stack_counter.values.max
@@ -455,9 +469,9 @@ module Gitlab
# Returns the stacks that calls Gitaly the most times. Used for n+1 detection
def self.max_stacks
- return nil unless RequestStore.active?
+ return nil unless Gitlab::SafeRequestStore.active?
- stack_counter = RequestStore.store[:stack_counter]
+ stack_counter = Gitlab::SafeRequestStore[:stack_counter]
return nil unless stack_counter
max = max_call_count
diff --git a/lib/gitlab/gitaly_client/commit_service.rb b/lib/gitlab/gitaly_client/commit_service.rb
index f65d7383dc7..085b2a127a5 100644
--- a/lib/gitlab/gitaly_client/commit_service.rb
+++ b/lib/gitlab/gitaly_client/commit_service.rb
@@ -148,6 +148,24 @@ module Gitlab
GitalyClient.call(@repository.storage, :commit_service, :count_commits, request, timeout: GitalyClient.medium_timeout).count
end
+ def list_last_commits_for_tree(revision, path, offset: 0, limit: 25)
+ request = Gitaly::ListLastCommitsForTreeRequest.new(
+ repository: @gitaly_repo,
+ revision: encode_binary(revision),
+ path: encode_binary(path.to_s),
+ offset: offset,
+ limit: limit
+ )
+
+ response = GitalyClient.call(@repository.storage, :commit_service, :list_last_commits_for_tree, request, timeout: GitalyClient.medium_timeout)
+
+ response.each_with_object({}) do |gitaly_response, hsh|
+ gitaly_response.commits.each do |commit_for_tree|
+ hsh[commit_for_tree.path] = Gitlab::Git::Commit.new(@repository, commit_for_tree.commit)
+ end
+ end
+ end
+
def last_commit_for_path(revision, path)
request = Gitaly::LastCommitForPathRequest.new(
repository: @gitaly_repo,
@@ -172,6 +190,17 @@ module Gitlab
consume_commits_response(response)
end
+ def diff_stats(left_commit_sha, right_commit_sha)
+ request = Gitaly::DiffStatsRequest.new(
+ repository: @gitaly_repo,
+ left_commit_id: left_commit_sha,
+ right_commit_id: right_commit_sha
+ )
+
+ response = GitalyClient.call(@repository.storage, :diff_service, :diff_stats, request, timeout: GitalyClient.medium_timeout)
+ response.flat_map(&:stats)
+ end
+
def find_all_commits(opts = {})
request = Gitaly::FindAllCommitsRequest.new(
repository: @gitaly_repo,
@@ -229,22 +258,23 @@ module Gitlab
end
def find_commit(revision)
- if RequestStore.active?
- # We don't use RequeStstore.fetch(key) { ... } directly because `revision`
- # can be a branch name, so we can't use it as a key as it could point
- # to another commit later on (happens a lot in tests).
+ if Gitlab::SafeRequestStore.active?
+ # We don't use Gitlab::SafeRequestStore.fetch(key) { ... } directly
+ # because `revision` can be a branch name, so we can't use it as a key
+ # as it could point to another commit later on (happens a lot in
+ # tests).
key = {
storage: @gitaly_repo.storage_name,
relative_path: @gitaly_repo.relative_path,
commit_id: revision
}
- return RequestStore[key] if RequestStore.exist?(key)
+ return Gitlab::SafeRequestStore[key] if Gitlab::SafeRequestStore.exist?(key)
commit = call_find_commit(revision)
return unless commit
key[:commit_id] = commit.id
- RequestStore[key] = commit
+ Gitlab::SafeRequestStore[key] = commit
else
call_find_commit(revision)
end
diff --git a/lib/gitlab/gitaly_client/operation_service.rb b/lib/gitlab/gitaly_client/operation_service.rb
index 54c78fdb680..0f148614b20 100644
--- a/lib/gitlab/gitaly_client/operation_service.rb
+++ b/lib/gitlab/gitaly_client/operation_service.rb
@@ -333,7 +333,8 @@ module Gitlab
action: action[:action].upcase.to_sym,
file_path: encode_binary(action[:file_path]),
previous_path: encode_binary(action[:previous_path]),
- base64_content: action[:encoding] == 'base64'
+ base64_content: action[:encoding] == 'base64',
+ execute_filemode: !!action[:execute_filemode]
)
rescue RangeError
raise ArgumentError, "Unknown action '#{action[:action]}'"
diff --git a/lib/gitlab/gitaly_client/storage_settings.rb b/lib/gitlab/gitaly_client/storage_settings.rb
index 8e530de174d..26d1f53f26c 100644
--- a/lib/gitlab/gitaly_client/storage_settings.rb
+++ b/lib/gitlab/gitaly_client/storage_settings.rb
@@ -13,7 +13,7 @@ module Gitlab
Storage is invalid because it has no `path` key.
For source installations, update your config/gitlab.yml Refer to gitlab.yml.example for an updated example.
- If you're using the Gitlab Development Kit, you can update your configuration running `gdk reconfigure`.
+ If you're using the GitLab Development Kit, you can update your configuration running `gdk reconfigure`.
MSG
# This class will give easily recognizable NoMethodErrors
diff --git a/lib/gitlab/group_hierarchy.rb b/lib/gitlab/group_hierarchy.rb
index b74e7b10448..8fbfa1a86bf 100644
--- a/lib/gitlab/group_hierarchy.rb
+++ b/lib/gitlab/group_hierarchy.rb
@@ -89,14 +89,14 @@ module Gitlab
ancestors_table = ancestors.alias_to(groups_table)
descendants_table = descendants.alias_to(groups_table)
- union = SQL::Union.new([model.unscoped.from(ancestors_table),
- model.unscoped.from(descendants_table)])
-
relation = model
.unscoped
.with
.recursive(ancestors.to_arel, descendants.to_arel)
- .from("(#{union.to_sql}) #{model.table_name}")
+ .from_union([
+ model.unscoped.from(ancestors_table),
+ model.unscoped.from(descendants_table)
+ ])
read_only(relation)
end
diff --git a/lib/gitlab/import_export/project_tree_restorer.rb b/lib/gitlab/import_export/project_tree_restorer.rb
index 00ea4b833e2..3d693d23c99 100644
--- a/lib/gitlab/import_export/project_tree_restorer.rb
+++ b/lib/gitlab/import_export/project_tree_restorer.rb
@@ -136,9 +136,18 @@ module Gitlab
return if tree_hash[relation_key].blank?
tree_array = [tree_hash[relation_key]].flatten
+ null_iid_pipelines = []
# Avoid keeping a possible heavy object in memory once we are done with it
- while relation_item = tree_array.shift
+ while relation_item = (tree_array.shift || null_iid_pipelines.shift)
+ if nil_iid_pipeline?(relation_key, relation_item) && tree_array.any?
+ # Move pipelines with NULL IIDs to the end
+ # so they don't clash with existing IIDs.
+ null_iid_pipelines << relation_item
+
+ next
+ end
+
# The transaction at this level is less speedy than one single transaction
# But we can't have it in the upper level or GC won't get rid of the AR objects
# after we save the batch.
@@ -201,6 +210,10 @@ module Gitlab
def excluded_keys_for_relation(relation)
reader.attributes_finder.find_excluded_keys(relation)
end
+
+ def nil_iid_pipeline?(relation_key, relation_item)
+ relation_key == 'pipelines' && relation_item['iid'].nil?
+ end
end
end
end
diff --git a/lib/gitlab/import_export/relation_factory.rb b/lib/gitlab/import_export/relation_factory.rb
index 81807ed659c..2486b1e4921 100644
--- a/lib/gitlab/import_export/relation_factory.rb
+++ b/lib/gitlab/import_export/relation_factory.rb
@@ -86,7 +86,6 @@ module Gitlab
case @relation_name
when :merge_request_diff_files then setup_diff
when :notes then setup_note
- when 'Ci::Pipeline' then setup_pipeline
end
update_user_references
@@ -94,6 +93,8 @@ module Gitlab
update_group_references
remove_duplicate_assignees
+ setup_pipeline if @relation_name == 'Ci::Pipeline'
+
reset_tokens!
remove_encrypted_attributes!
end
diff --git a/lib/gitlab/issuables_count_for_state.rb b/lib/gitlab/issuables_count_for_state.rb
index 505810964bc..b5657a36998 100644
--- a/lib/gitlab/issuables_count_for_state.rb
+++ b/lib/gitlab/issuables_count_for_state.rb
@@ -1,7 +1,7 @@
module Gitlab
# Class for counting and caching the number of issuables per state.
class IssuablesCountForState
- # The name of the RequestStore cache key.
+ # The name of the Gitlab::SafeRequestStore cache key.
CACHE_KEY = :issuables_count_for_state
# The state values that can be safely casted to a Symbol.
@@ -10,12 +10,7 @@ module Gitlab
# finder - The finder class to use for retrieving the issuables.
def initialize(finder)
@finder = finder
- @cache =
- if RequestStore.active?
- RequestStore[CACHE_KEY] ||= initialize_cache
- else
- initialize_cache
- end
+ @cache = Gitlab::SafeRequestStore[CACHE_KEY] ||= initialize_cache
end
def for_state_or_opened(state = nil)
diff --git a/lib/gitlab/kubernetes/kube_client.rb b/lib/gitlab/kubernetes/kube_client.rb
index 8312b901524..588238de608 100644
--- a/lib/gitlab/kubernetes/kube_client.rb
+++ b/lib/gitlab/kubernetes/kube_client.rb
@@ -25,12 +25,14 @@ module Gitlab
:get_config_map,
:get_namespace,
:get_pod,
+ :get_secret,
:get_service,
:get_service_account,
:delete_pod,
:create_config_map,
:create_namespace,
:create_pod,
+ :create_secret,
:create_service_account,
:update_config_map,
:update_service_account,
diff --git a/lib/gitlab/kubernetes/service_account_token.rb b/lib/gitlab/kubernetes/service_account_token.rb
new file mode 100644
index 00000000000..2e912b26c09
--- /dev/null
+++ b/lib/gitlab/kubernetes/service_account_token.rb
@@ -0,0 +1,36 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Kubernetes
+ class ServiceAccountToken
+ attr_reader :name, :service_account_name, :namespace_name
+
+ def initialize(name, service_account_name, namespace_name)
+ @name = name
+ @service_account_name = service_account_name
+ @namespace_name = namespace_name
+ end
+
+ def generate
+ ::Kubeclient::Resource.new(metadata: metadata, type: service_acount_token_type)
+ end
+
+ private
+
+ # as per https://kubernetes.io/docs/reference/access-authn-authz/service-accounts-admin/#to-create-additional-api-tokens
+ def service_acount_token_type
+ 'kubernetes.io/service-account-token'
+ end
+
+ def metadata
+ {
+ name: name,
+ namespace: namespace_name,
+ annotations: {
+ "kubernetes.io/service-account.name": service_account_name
+ }
+ }
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/logger.rb b/lib/gitlab/logger.rb
index e58927a40b9..3d7c049c17f 100644
--- a/lib/gitlab/logger.rb
+++ b/lib/gitlab/logger.rb
@@ -30,7 +30,7 @@ module Gitlab
end
def self.build
- RequestStore[self.cache_key] ||= new(self.full_log_path)
+ Gitlab::SafeRequestStore[self.cache_key] ||= new(self.full_log_path)
end
def self.full_log_path
diff --git a/lib/gitlab/null_request_store.rb b/lib/gitlab/null_request_store.rb
new file mode 100644
index 00000000000..8db331dcb9f
--- /dev/null
+++ b/lib/gitlab/null_request_store.rb
@@ -0,0 +1,41 @@
+# frozen_string_literal: true
+
+# Used by Gitlab::SafeRequestStore
+module Gitlab
+ # The methods `begin!`, `clear!`, and `end!` are not defined because they
+ # should only be called directly on `RequestStore`.
+ class NullRequestStore
+ def store
+ {}
+ end
+
+ def active?
+ end
+
+ def read(key)
+ end
+
+ def [](key)
+ end
+
+ def write(key, value)
+ value
+ end
+
+ def []=(key, value)
+ value
+ end
+
+ def exist?(key)
+ false
+ end
+
+ def fetch(key, &block)
+ yield
+ end
+
+ def delete(key, &block)
+ yield(key) if block_given?
+ end
+ end
+end
diff --git a/lib/gitlab/performance_bar/peek_query_tracker.rb b/lib/gitlab/performance_bar/peek_query_tracker.rb
index f2825db59ae..37ff32b1296 100644
--- a/lib/gitlab/performance_bar/peek_query_tracker.rb
+++ b/lib/gitlab/performance_bar/peek_query_tracker.rb
@@ -23,7 +23,7 @@ module Gitlab
end
subscribe('sql.active_record') do |_, start, finish, _, data|
- if RequestStore.active? && RequestStore.store[:peek_enabled]
+ if Gitlab::SafeRequestStore.store[:peek_enabled]
# data[:cached] is only available starting from Rails 5.1.0
# https://github.com/rails/rails/blob/v5.1.0/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb#L113
# Before that, data[:name] was set to 'CACHE'
diff --git a/lib/gitlab/project_authorizations/with_nested_groups.rb b/lib/gitlab/project_authorizations/with_nested_groups.rb
index e3da1634fa5..448c3f3a7d8 100644
--- a/lib/gitlab/project_authorizations/with_nested_groups.rb
+++ b/lib/gitlab/project_authorizations/with_nested_groups.rb
@@ -49,13 +49,11 @@ module Gitlab
.where('p_ns.share_with_group_lock IS FALSE')
]
- union = Gitlab::SQL::Union.new(relations)
-
ProjectAuthorization
.unscoped
.with
.recursive(cte.to_arel)
- .select_from_union(union)
+ .select_from_union(relations)
end
private
diff --git a/lib/gitlab/project_authorizations/without_nested_groups.rb b/lib/gitlab/project_authorizations/without_nested_groups.rb
index 7d0c00c7f36..ed2287dcc7e 100644
--- a/lib/gitlab/project_authorizations/without_nested_groups.rb
+++ b/lib/gitlab/project_authorizations/without_nested_groups.rb
@@ -24,11 +24,9 @@ module Gitlab
user.groups.joins(:shared_projects).select_for_project_authorization
]
- union = Gitlab::SQL::Union.new(relations)
-
ProjectAuthorization
.unscoped
- .select_from_union(union)
+ .select_from_union(relations)
end
end
end
diff --git a/lib/gitlab/repository_cache.rb b/lib/gitlab/repository_cache.rb
index b1bf3ca4143..a03ce07b6a1 100644
--- a/lib/gitlab/repository_cache.rb
+++ b/lib/gitlab/repository_cache.rb
@@ -29,5 +29,21 @@ module Gitlab
def read(key)
backend.read(cache_key(key))
end
+
+ def write(key, value)
+ backend.write(cache_key(key), value)
+ end
+
+ def fetch_without_caching_false(key, &block)
+ value = read(key)
+ return value if value
+
+ value = yield
+
+ # Don't cache false values
+ write(key, value) if value
+
+ value
+ end
end
end
diff --git a/lib/gitlab/repository_cache_adapter.rb b/lib/gitlab/repository_cache_adapter.rb
index 2ec871f0754..d95024fccf7 100644
--- a/lib/gitlab/repository_cache_adapter.rb
+++ b/lib/gitlab/repository_cache_adapter.rb
@@ -1,23 +1,80 @@
module Gitlab
module RepositoryCacheAdapter
extend ActiveSupport::Concern
+ include Gitlab::Utils::StrongMemoize
class_methods do
- # Wraps around the given method and caches its output in Redis and an instance
- # variable.
+ # Caches and strongly memoizes the method.
#
# This only works for methods that do not take any arguments.
- def cache_method(name, fallback: nil, memoize_only: false)
- original = :"_uncached_#{name}"
+ #
+ # name - The name of the method to be cached.
+ # fallback - A value to fall back to if the repository does not exist, or
+ # in case of a Git error. Defaults to nil.
+ def cache_method(name, fallback: nil)
+ uncached_name = alias_uncached_method(name)
+
+ define_method(name) do
+ cache_method_output(name, fallback: fallback) do
+ __send__(uncached_name) # rubocop:disable GitlabSecurity/PublicSend
+ end
+ end
+ end
- alias_method(original, name)
+ # Caches truthy values from the method. All values are strongly memoized,
+ # and cached in RequestStore.
+ #
+ # Currently only used to cache `exists?` since stale false values are
+ # particularly troublesome. This can occur, for example, when an NFS mount
+ # is temporarily down.
+ #
+ # This only works for methods that do not take any arguments.
+ #
+ # name - The name of the method to be cached.
+ def cache_method_asymmetrically(name)
+ uncached_name = alias_uncached_method(name)
define_method(name) do
- cache_method_output(name, fallback: fallback, memoize_only: memoize_only) do
- __send__(original) # rubocop:disable GitlabSecurity/PublicSend
+ cache_method_output_asymmetrically(name) do
+ __send__(uncached_name) # rubocop:disable GitlabSecurity/PublicSend
end
end
end
+
+ # Strongly memoizes the method.
+ #
+ # This only works for methods that do not take any arguments.
+ #
+ # name - The name of the method to be memoized.
+ # fallback - A value to fall back to if the repository does not exist, or
+ # in case of a Git error. Defaults to nil. The fallback value
+ # is not memoized.
+ def memoize_method(name, fallback: nil)
+ uncached_name = alias_uncached_method(name)
+
+ define_method(name) do
+ memoize_method_output(name, fallback: fallback) do
+ __send__(uncached_name) # rubocop:disable GitlabSecurity/PublicSend
+ end
+ end
+ end
+
+ # Prepends "_uncached_" to the target method name
+ #
+ # Returns the uncached method name
+ def alias_uncached_method(name)
+ uncached_name = :"_uncached_#{name}"
+
+ alias_method(uncached_name, name)
+
+ uncached_name
+ end
+ end
+
+ # RequestStore-backed RepositoryCache to be used. Should be overridden by
+ # the including class
+ def request_store_cache
+ raise NotImplementedError
end
# RepositoryCache to be used. Should be overridden by the including class
@@ -30,65 +87,93 @@ module Gitlab
raise NotImplementedError
end
- # Caches the supplied block both in a cache and in an instance variable.
+ # Caches and strongly memoizes the supplied block.
#
- # The cache key and instance variable are named the same way as the value of
- # the `key` argument.
+ # name - The name of the method to be cached.
+ # fallback - A value to fall back to if the repository does not exist, or
+ # in case of a Git error. Defaults to nil.
+ def cache_method_output(name, fallback: nil, &block)
+ memoize_method_output(name, fallback: fallback) do
+ cache.fetch(name, &block)
+ end
+ end
+
+ # Caches truthy values from the supplied block. All values are strongly
+ # memoized, and cached in RequestStore.
#
- # This method will return `nil` if the corresponding instance variable is also
- # set to `nil`. This ensures we don't keep yielding the block when it returns
- # `nil`.
+ # Currently only used to cache `exists?` since stale false values are
+ # particularly troublesome. This can occur, for example, when an NFS mount
+ # is temporarily down.
#
- # key - The name of the key to cache the data in.
- # fallback - A value to fall back to in the event of a Git error.
- def cache_method_output(key, fallback: nil, memoize_only: false, &block)
- ivar = cache_instance_variable_name(key)
-
- if instance_variable_defined?(ivar)
- instance_variable_get(ivar)
- else
- # If the repository doesn't exist and a fallback was specified we return
- # that value inmediately. This saves us Rugged/gRPC invocations.
- return fallback unless fallback.nil? || cache.repository.exists?
-
- begin
- value =
- if memoize_only
- yield
- else
- cache.fetch(key, &block)
- end
-
- instance_variable_set(ivar, value)
- rescue Gitlab::Git::Repository::NoRepository
- # Even if the above `#exists?` check passes these errors might still
- # occur (for example because of a non-existing HEAD). We want to
- # gracefully handle this and not cache anything
- fallback
+ # name - The name of the method to be cached.
+ def cache_method_output_asymmetrically(name, &block)
+ memoize_method_output(name) do
+ request_store_cache.fetch(name) do
+ cache.fetch_without_caching_false(name, &block)
end
end
end
+ # Strongly memoizes the supplied block.
+ #
+ # name - The name of the method to be memoized.
+ # fallback - A value to fall back to if the repository does not exist, or
+ # in case of a Git error. Defaults to nil. The fallback value is
+ # not memoized.
+ def memoize_method_output(name, fallback: nil, &block)
+ no_repository_fallback(name, fallback: fallback) do
+ strong_memoize(memoizable_name(name), &block)
+ end
+ end
+
+ # Returns the fallback value if the repository does not exist
+ def no_repository_fallback(name, fallback: nil, &block)
+ # Avoid unnecessary gRPC invocations
+ return fallback if fallback && fallback_early?(name)
+
+ yield
+ rescue Gitlab::Git::Repository::NoRepository
+ # Even if the `#exists?` check in `fallback_early?` passes, these errors
+ # might still occur (for example because of a non-existing HEAD). We
+ # want to gracefully handle this and not memoize anything.
+ fallback
+ end
+
# Expires the caches of a specific set of methods
def expire_method_caches(methods)
- methods.each do |key|
- unless cached_methods.include?(key.to_sym)
- Rails.logger.error "Requested to expire non-existent method '#{key}' for Repository"
+ methods.each do |name|
+ unless cached_methods.include?(name.to_sym)
+ Rails.logger.error "Requested to expire non-existent method '#{name}' for Repository"
next
end
- cache.expire(key)
+ cache.expire(name)
- ivar = cache_instance_variable_name(key)
-
- remove_instance_variable(ivar) if instance_variable_defined?(ivar)
+ clear_memoization(memoizable_name(name))
end
+
+ expire_request_store_method_caches(methods)
end
private
- def cache_instance_variable_name(key)
- :"@#{key.to_s.tr('?!', '')}"
+ def memoizable_name(name)
+ "#{name.to_s.tr('?!', '')}"
+ end
+
+ def expire_request_store_method_caches(methods)
+ methods.each do |name|
+ request_store_cache.expire(name)
+ end
+ end
+
+ # All cached repository methods depend on the existence of a Git repository,
+ # so if the repository doesn't exist, we already know not to call it.
+ def fallback_early?(method_name)
+ # Avoid infinite loop
+ return false if method_name == :exists?
+
+ !exists?
end
end
end
diff --git a/lib/gitlab/request_context.rb b/lib/gitlab/request_context.rb
index fef536ecb0b..8562d4515aa 100644
--- a/lib/gitlab/request_context.rb
+++ b/lib/gitlab/request_context.rb
@@ -2,7 +2,7 @@ module Gitlab
class RequestContext
class << self
def client_ip
- RequestStore[:client_ip]
+ Gitlab::SafeRequestStore[:client_ip]
end
end
@@ -13,7 +13,7 @@ module Gitlab
def call(env)
req = Rack::Request.new(env)
- RequestStore[:client_ip] = req.ip
+ Gitlab::SafeRequestStore[:client_ip] = req.ip
@app.call(env)
end
diff --git a/lib/gitlab/safe_request_store.rb b/lib/gitlab/safe_request_store.rb
new file mode 100644
index 00000000000..4e82353adb6
--- /dev/null
+++ b/lib/gitlab/safe_request_store.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module SafeRequestStore
+ NULL_STORE = Gitlab::NullRequestStore.new
+
+ class << self
+ # These methods should always run directly against RequestStore
+ delegate :clear!, :begin!, :end!, :active?, to: :RequestStore
+
+ # These methods will run against NullRequestStore if RequestStore is disabled
+ delegate :read, :[], :write, :[]=, :exist?, :fetch, :delete, to: :store
+ end
+
+ def self.store
+ if RequestStore.active?
+ RequestStore
+ else
+ NULL_STORE
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/sidekiq_throttler.rb b/lib/gitlab/sidekiq_throttler.rb
deleted file mode 100644
index 5512afa45a8..00000000000
--- a/lib/gitlab/sidekiq_throttler.rb
+++ /dev/null
@@ -1,25 +0,0 @@
-module Gitlab
- class SidekiqThrottler
- class << self
- def execute!
- if Gitlab::CurrentSettings.sidekiq_throttling_enabled?
- require 'sidekiq-limit_fetch'
-
- Gitlab::CurrentSettings.current_application_settings.sidekiq_throttling_queues.each do |queue|
- Sidekiq::Queue[queue].limit = queue_limit
- end
- end
- end
-
- private
-
- def queue_limit
- @queue_limit ||=
- begin
- factor = Gitlab::CurrentSettings.current_application_settings.sidekiq_throttling_factor
- (factor * Sidekiq.options[:concurrency]).ceil
- end
- end
- end
- end
-end
diff --git a/lib/gitlab/template/finders/global_template_finder.rb b/lib/gitlab/template/finders/global_template_finder.rb
index 831da45191f..b08d9a99e99 100644
--- a/lib/gitlab/template/finders/global_template_finder.rb
+++ b/lib/gitlab/template/finders/global_template_finder.rb
@@ -1,4 +1,4 @@
-# Searches and reads file present on Gitlab installation directory
+# Searches and reads file present on GitLab installation directory
module Gitlab
module Template
module Finders
diff --git a/lib/gitlab/template/finders/repo_template_finder.rb b/lib/gitlab/template/finders/repo_template_finder.rb
index 29bc2393ff9..9140ace879f 100644
--- a/lib/gitlab/template/finders/repo_template_finder.rb
+++ b/lib/gitlab/template/finders/repo_template_finder.rb
@@ -1,4 +1,4 @@
-# Searches and reads files present on each Gitlab project repository
+# Searches and reads files present on each GitLab project repository
module Gitlab
module Template
module Finders
diff --git a/lib/gitlab/template/gitlab_ci_yml_template.rb b/lib/gitlab/template/gitlab_ci_yml_template.rb
index fd040148a1e..deae53cc61b 100644
--- a/lib/gitlab/template/gitlab_ci_yml_template.rb
+++ b/lib/gitlab/template/gitlab_ci_yml_template.rb
@@ -20,7 +20,7 @@ module Gitlab
end
def base_dir
- Rails.root.join('vendor/gitlab-ci-yml')
+ Rails.root.join('lib/gitlab/ci/templates')
end
def finder(project = nil)
diff --git a/lib/gitlab/temporarily_allow.rb b/lib/gitlab/temporarily_allow.rb
index 880e55f71df..8d7dacc6c54 100644
--- a/lib/gitlab/temporarily_allow.rb
+++ b/lib/gitlab/temporarily_allow.rb
@@ -10,7 +10,7 @@ module Gitlab
end
def temporarily_allowed?(key)
- if RequestStore.active?
+ if Gitlab::SafeRequestStore.active?
temporarily_allow_request_store[key] > 0
else
TEMPORARILY_ALLOW_MUTEX.synchronize do
@@ -26,11 +26,11 @@ module Gitlab
end
def temporarily_allow_request_store
- RequestStore[:temporarily_allow] ||= Hash.new(0)
+ Gitlab::SafeRequestStore[:temporarily_allow] ||= Hash.new(0)
end
def temporarily_allow_add(key, value)
- if RequestStore.active?
+ if Gitlab::SafeRequestStore.active?
temporarily_allow_request_store[key] += value
else
TEMPORARILY_ALLOW_MUTEX.synchronize do
diff --git a/lib/gitlab/testing/request_inspector_middleware.rb b/lib/gitlab/testing/request_inspector_middleware.rb
index e387667480d..c251e78f5c5 100644
--- a/lib/gitlab/testing/request_inspector_middleware.rb
+++ b/lib/gitlab/testing/request_inspector_middleware.rb
@@ -35,11 +35,15 @@ module Gitlab
request_headers = env_http_headers(env)
status, headers, body = @app.call(env)
+ full_body = ''
+ body.each { |b| full_body << b }
+
request = OpenStruct.new(
url: url,
status_code: status,
request_headers: request_headers,
- response_headers: headers
+ response_headers: headers,
+ body: full_body
)
log_request request
diff --git a/lib/gitlab/tree_summary.rb b/lib/gitlab/tree_summary.rb
index b05d408b1c0..c2955cd374c 100644
--- a/lib/gitlab/tree_summary.rb
+++ b/lib/gitlab/tree_summary.rb
@@ -73,25 +73,29 @@ module Gitlab
end
def fill_last_commits!(entries)
- # n+1: https://gitlab.com/gitlab-org/gitlab-ce/issues/37433
- Gitlab::GitalyClient.allow_n_plus_1_calls do
- entries.each do |entry|
- raw_commit = repository.last_commit_for_path(commit.id, entry_path(entry))
+ # Ensure the path is in "path/" format
+ ensured_path =
+ if path
+ File.join(*[path, ""])
+ end
+
+ commits_hsh = repository.list_last_commits_for_tree(commit.id, ensured_path, offset: offset, limit: limit)
- if raw_commit
- commit = resolve_commit(raw_commit)
+ entries.each do |entry|
+ path_key = entry_path(entry)
+ commit = cache_commit(commits_hsh[path_key])
- entry[:commit] = commit
- entry[:commit_path] = commit_path(commit)
- end
+ if commit
+ entry[:commit] = commit
+ entry[:commit_path] = commit_path(commit)
end
end
end
- def resolve_commit(raw_commit)
- return nil unless raw_commit.present?
+ def cache_commit(commit)
+ return nil unless commit.present?
- resolved_commits[raw_commit.id] ||= ::Commit.new(raw_commit, project)
+ resolved_commits[commit.id] ||= commit
end
def commit_path(commit)
diff --git a/lib/gitlab/user_extractor.rb b/lib/gitlab/user_extractor.rb
index 09652a4fb5e..bd0d24e4369 100644
--- a/lib/gitlab/user_extractor.rb
+++ b/lib/gitlab/user_extractor.rb
@@ -18,7 +18,7 @@ module Gitlab
def users
return User.none unless @text.present?
- @users ||= User.from("(#{union.to_sql}) users")
+ @users ||= User.from_union(union_relations)
end
# rubocop: enable CodeReuse/ActiveRecord
@@ -43,13 +43,13 @@ module Gitlab
private
- def union
+ def union_relations
relations = []
relations << User.by_any_email(emails) if emails.any?
relations << User.by_username(usernames) if usernames.any?
- Gitlab::SQL::Union.new(relations)
+ relations
end
end
end
diff --git a/lib/google_api/cloud_platform/client.rb b/lib/google_api/cloud_platform/client.rb
index 36859b4d025..77b6610286f 100644
--- a/lib/google_api/cloud_platform/client.rb
+++ b/lib/google_api/cloud_platform/client.rb
@@ -50,7 +50,7 @@ module GoogleApi
service.get_zone_cluster(project_id, zone, cluster_id, options: user_agent_header)
end
- def projects_zones_clusters_create(project_id, zone, cluster_name, cluster_size, machine_type:)
+ def projects_zones_clusters_create(project_id, zone, cluster_name, cluster_size, machine_type:, legacy_abac:)
service = Google::Apis::ContainerV1::ContainerService.new
service.authorization = access_token
@@ -63,7 +63,7 @@ module GoogleApi
"machine_type": machine_type
},
"legacy_abac": {
- "enabled": true
+ "enabled": legacy_abac
}
}
}
diff --git a/lib/quality/helm_client.rb b/lib/quality/helm_client.rb
new file mode 100644
index 00000000000..49d953da681
--- /dev/null
+++ b/lib/quality/helm_client.rb
@@ -0,0 +1,47 @@
+# frozen_string_literal: true
+
+require 'time'
+require_relative '../gitlab/popen' unless defined?(Gitlab::Popen)
+
+module Quality
+ class HelmClient
+ attr_reader :namespace
+
+ Release = Struct.new(:name, :revision, :last_update, :status, :chart, :namespace) do
+ def revision
+ @revision ||= self[:revision].to_i
+ end
+
+ def last_update
+ @last_update ||= Time.parse(self[:last_update])
+ end
+ end
+
+ def initialize(namespace: ENV['KUBE_NAMESPACE'])
+ @namespace = namespace
+ end
+
+ def releases(args: [])
+ command = ['list', %(--namespace "#{namespace}"), *args]
+
+ run_command(command)
+ .stdout
+ .lines
+ .select { |line| line.include?(namespace) }
+ .map { |line| Release.new(*line.split(/\t/).map(&:strip)) }
+ end
+
+ def delete(release_name:)
+ run_command(['delete', '--purge', release_name])
+ end
+
+ private
+
+ def run_command(command)
+ final_command = ['helm', *command].join(' ')
+ puts "Running command: `#{final_command}`" # rubocop:disable Rails/Output
+
+ Gitlab::Popen.popen_with_detail([final_command])
+ end
+ end
+end
diff --git a/lib/quality/kubernetes_client.rb b/lib/quality/kubernetes_client.rb
new file mode 100644
index 00000000000..e366a688e3e
--- /dev/null
+++ b/lib/quality/kubernetes_client.rb
@@ -0,0 +1,32 @@
+# frozen_string_literal: true
+
+require_relative '../gitlab/popen' unless defined?(Gitlab::Popen)
+
+module Quality
+ class KubernetesClient
+ attr_reader :namespace
+
+ def initialize(namespace: ENV['KUBE_NAMESPACE'])
+ @namespace = namespace
+ end
+
+ def cleanup(release_name:)
+ command = ['kubectl']
+ command << %(-n "#{namespace}" get ingress,svc,pdb,hpa,deploy,statefulset,job,pod,secret,configmap,pvc,secret,clusterrole,clusterrolebinding,role,rolebinding,sa 2>&1)
+ command << '|' << %(grep "#{release_name}")
+ command << '|' << "awk '{print $1}'"
+ command << '|' << %(xargs kubectl -n "#{namespace}" delete)
+ command << '||' << 'true'
+
+ run_command(command)
+ end
+
+ private
+
+ def run_command(command)
+ puts "Running command: `#{command.join(' ')}`" # rubocop:disable Rails/Output
+
+ Gitlab::Popen.popen_with_detail(command)
+ end
+ end
+end
diff --git a/lib/support/nginx/gitlab b/lib/support/nginx/gitlab
index 72eb8adcce2..fc984d737d5 100644
--- a/lib/support/nginx/gitlab
+++ b/lib/support/nginx/gitlab
@@ -17,7 +17,7 @@
## See installation.md#using-https for additional HTTPS configuration details.
upstream gitlab-workhorse {
- # Gitlab socket file,
+ # GitLab socket file,
# for Omnibus this would be: unix:/var/opt/gitlab/gitlab-workhorse/socket
server unix:/home/git/gitlab/tmp/sockets/gitlab-workhorse.socket fail_timeout=0;
}
@@ -112,7 +112,7 @@ server {
error_page 502 /502.html;
error_page 503 /503.html;
location ~ ^/(404|422|500|502|503)\.html$ {
- # Location to the Gitlab's public directory,
+ # Location to the GitLab's public directory,
# for Omnibus this would be: /opt/gitlab/embedded/service/gitlab-rails/public.
root /home/git/gitlab/public;
internal;
diff --git a/lib/support/nginx/gitlab-ssl b/lib/support/nginx/gitlab-ssl
index 2e3799d5e1b..ba01e250bbb 100644
--- a/lib/support/nginx/gitlab-ssl
+++ b/lib/support/nginx/gitlab-ssl
@@ -21,7 +21,7 @@
## See installation.md#using-https for additional HTTPS configuration details.
upstream gitlab-workhorse {
- # Gitlab socket file,
+ # GitLab socket file,
# for Omnibus this would be: unix:/var/opt/gitlab/gitlab-workhorse/socket
server unix:/home/git/gitlab/tmp/sockets/gitlab-workhorse.socket fail_timeout=0;
}
@@ -162,7 +162,7 @@ server {
error_page 502 /502.html;
error_page 503 /503.html;
location ~ ^/(404|422|500|502|503)\.html$ {
- # Location to the Gitlab's public directory,
+ # Location to the GitLab's public directory,
# for Omnibus this would be: /opt/gitlab/embedded/service/gitlab-rails/public
root /home/git/gitlab/public;
internal;
diff --git a/lib/system_check/incoming_email/imap_authentication_check.rb b/lib/system_check/incoming_email/imap_authentication_check.rb
index e55bea86d3f..3550c5796b0 100644
--- a/lib/system_check/incoming_email/imap_authentication_check.rb
+++ b/lib/system_check/incoming_email/imap_authentication_check.rb
@@ -7,7 +7,7 @@ module SystemCheck
if config
try_connect_imap
else
- @error = "#{mail_room_config_path} does not have mailboxes setup"
+ @error = "#{mail_room_config_path} does not have mailboxes set up"
false
end
end
diff --git a/lib/tasks/gemojione.rake b/lib/tasks/gemojione.rake
index c6942d22926..560a52053d8 100644
--- a/lib/tasks/gemojione.rake
+++ b/lib/tasks/gemojione.rake
@@ -86,7 +86,7 @@ namespace :gemojione do
SPRITESHEET_WIDTH = 860
SPRITESHEET_HEIGHT = 840
- # Setup a map to rename image files
+ # Set up a map to rename image files
emoji_unicode_string_to_name_map = {}
Gitlab::Emoji.emojis.each do |name, emoji_hash|
# Ignore aliases
diff --git a/lib/tasks/gitlab/artifacts/migrate.rake b/lib/tasks/gitlab/artifacts/migrate.rake
index bfca4bfb3f7..e7634d2ed4f 100644
--- a/lib/tasks/gitlab/artifacts/migrate.rake
+++ b/lib/tasks/gitlab/artifacts/migrate.rake
@@ -15,7 +15,7 @@ namespace :gitlab do
build.artifacts_file.migrate!(ObjectStorage::Store::REMOTE)
build.artifacts_metadata.migrate!(ObjectStorage::Store::REMOTE)
- logger.info("Transferred artifacts of #{build.id} of #{build.artifacts_size} to object storage")
+ logger.info("Transferred artifact ID #{build.id} with size #{build.artifacts_size} to object storage")
rescue => e
logger.error("Failed to transfer artifacts of #{build.id} with error: #{e.message}")
end
diff --git a/lib/tasks/gitlab/db.rake b/lib/tasks/gitlab/db.rake
index 69166851816..74cd70c6e9f 100644
--- a/lib/tasks/gitlab/db.rake
+++ b/lib/tasks/gitlab/db.rake
@@ -51,6 +51,8 @@ namespace :gitlab do
if ActiveRecord::Base.connection.tables.count > 1
Rake::Task['db:migrate'].invoke
else
+ # Add post-migrate paths to ensure we mark all migrations as up
+ Gitlab::Database.add_post_migrate_path_to_rails(force: true)
Rake::Task['db:schema:load'].invoke
Rake::Task['db:seed_fu'].invoke
end
diff --git a/lib/tasks/gitlab/shell.rake b/lib/tasks/gitlab/shell.rake
index 4fcbbbf8c9d..0ebc6f00793 100644
--- a/lib/tasks/gitlab/shell.rake
+++ b/lib/tasks/gitlab/shell.rake
@@ -92,9 +92,11 @@ namespace :gitlab do
def setup
warn_user_is_not_gitlab
+ ensure_write_to_authorized_keys_is_enabled
+
unless ENV['force'] == 'yes'
- puts "This will rebuild an authorized_keys file."
- puts "You will lose any data stored in authorized_keys file."
+ puts "This task will now rebuild the authorized_keys file."
+ puts "You will lose any data stored in the authorized_keys file."
ask_to_continue
puts ""
end
@@ -118,4 +120,44 @@ namespace :gitlab do
puts "Quitting...".color(:red)
exit 1
end
+
+ def ensure_write_to_authorized_keys_is_enabled
+ return if Gitlab::CurrentSettings.current_application_settings.authorized_keys_enabled
+
+ puts authorized_keys_is_disabled_warning
+
+ unless ENV['force'] == 'yes'
+ puts 'Do you want to permanently enable the "Write to authorized_keys file" setting now?'
+ ask_to_continue
+ end
+
+ puts 'Enabling the "Write to authorized_keys file" setting...'
+ Gitlab::CurrentSettings.current_application_settings.update!(authorized_keys_enabled: true)
+
+ puts 'Successfully enabled "Write to authorized_keys file"!'
+ puts ''
+ end
+
+ def authorized_keys_is_disabled_warning
+ <<-MSG.strip_heredoc
+ WARNING
+
+ The "Write to authorized_keys file" setting is disabled, which prevents
+ the file from being rebuilt!
+
+ It should be enabled for most GitLab installations. Large installations
+ may wish to disable it as part of speeding up SSH operations.
+
+ See https://docs.gitlab.com/ee/administration/operations/fast_ssh_key_lookup.html
+
+ If you did not intentionally disable this option in Admin Area > Settings,
+ then you may have been affected by the 9.3.0 bug in which the new setting
+ was disabled by default.
+
+ https://gitlab.com/gitlab-org/gitlab-ee/issues/2738
+
+ It was reverted in 9.3.1 and fixed in 9.3.3, however, if Settings were
+ saved while the setting was unchecked, then it is still disabled.
+ MSG
+ end
end
diff --git a/lib/tasks/gitlab/site_statistics.rake b/lib/tasks/gitlab/site_statistics.rake
index 7d24ec72a9d..d97f11b2ed5 100644
--- a/lib/tasks/gitlab/site_statistics.rake
+++ b/lib/tasks/gitlab/site_statistics.rake
@@ -10,14 +10,6 @@ namespace :gitlab do
SiteStatistic.update_all('repositories_count = (SELECT COUNT(*) FROM projects)')
end
puts 'OK!'.color(:green)
-
- print '* Wikis... '
- SiteStatistic.transaction do
- # see https://gitlab.com/gitlab-org/gitlab-ce/issues/48967
- ActiveRecord::Base.connection.execute('SET LOCAL statement_timeout TO 0') if Gitlab::Database.postgresql?
- SiteStatistic.update_all('wikis_count = (SELECT COUNT(*) FROM project_features WHERE wiki_access_level != 0)')
- end
- puts 'OK!'.color(:green)
puts
end
end
diff --git a/lib/tasks/gitlab/update_templates.rake b/lib/tasks/gitlab/update_templates.rake
index ef6a32d6730..abe10f5580e 100644
--- a/lib/tasks/gitlab/update_templates.rake
+++ b/lib/tasks/gitlab/update_templates.rake
@@ -100,10 +100,6 @@ namespace :gitlab do
/(\.{1,2}|LICENSE|Global|\.gitignore)\z/
),
Template.new(
- "https://gitlab.com/gitlab-org/gitlab-ci-yml.git",
- /(\.{1,2}|LICENSE|CONTRIBUTING.md|Pages|autodeploy|\.gitlab-ci.yml)\z/
- ),
- Template.new(
"https://gitlab.com/gitlab-org/Dockerfile.git",
/(\.{1,2}|LICENSE|CONTRIBUTING.md|\.Dockerfile)\z/
)
diff --git a/lib/tasks/gitlab/uploads/migrate.rake b/lib/tasks/gitlab/uploads/migrate.rake
index f548a266b99..1c93609a006 100644
--- a/lib/tasks/gitlab/uploads/migrate.rake
+++ b/lib/tasks/gitlab/uploads/migrate.rake
@@ -1,6 +1,30 @@
namespace :gitlab do
namespace :uploads do
- desc 'GitLab | Uploads | Migrate the uploaded files to object storage'
+ namespace :migrate do
+ desc "GitLab | Uploads | Migrate all uploaded files to object storage"
+ task all: :environment do
+ categories = [%w(AvatarUploader Project :avatar),
+ %w(AvatarUploader Group :avatar),
+ %w(AvatarUploader User :avatar),
+ %w(AttachmentUploader Note :attachment),
+ %w(AttachmentUploader Appearance :logo),
+ %w(AttachmentUploader Appearance :header_logo),
+ %w(FaviconUploader Appearance :favicon),
+ %w(FileUploader Project),
+ %w(PersonalFileUploader Snippet),
+ %w(NamespaceFileUploader Snippet),
+ %w(FileUploader MergeRequest)]
+
+ categories.each do |args|
+ Rake::Task["gitlab:uploads:migrate"].invoke(*args)
+ Rake::Task["gitlab:uploads:migrate"].reenable
+ end
+ end
+ end
+
+ # The following is the actual rake task that migrates uploads of specified
+ # category to object storage
+ desc 'GitLab | Uploads | Migrate the uploaded files of specified type to object storage'
task :migrate, [:uploader_class, :model_class, :mounted_as] => :environment do |task, args|
batch_size = ENV.fetch('BATCH', 200).to_i
@to_store = ObjectStorage::Store::REMOTE
diff --git a/locale/ar_SA/gitlab.po b/locale/ar_SA/gitlab.po
index a9a1e87c479..662e69e27c6 100644
--- a/locale/ar_SA/gitlab.po
+++ b/locale/ar_SA/gitlab.po
@@ -444,7 +444,7 @@ msgstr ""
msgid "<strong>Removes</strong> source branch"
msgstr ""
-msgid "A 'Runner' is a process which runs a job. You can setup as many Runners as you need."
+msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr ""
msgid "A collection of graphs regarding Continuous Integration"
@@ -891,7 +891,7 @@ msgstr ""
msgid "Ascending"
msgstr ""
-msgid "Ask your group maintainer to setup a group Runner."
+msgid "Ask your group maintainer to set up a group Runner."
msgstr ""
msgid "Assertion consumer service URL"
@@ -6702,10 +6702,10 @@ msgstr ""
msgid "Settings"
msgstr ""
-msgid "Setup a %{type} Runner manually"
+msgid "Set up a %{type} Runner manually"
msgstr ""
-msgid "Setup a specific Runner automatically"
+msgid "Set up a specific Runner automatically"
msgstr ""
msgid "Share"
@@ -8316,7 +8316,7 @@ msgstr ""
msgid "You can resolve the merge conflict using either the Interactive mode, by choosing %{use_ours} or %{use_theirs} buttons, or by editing the files directly. Commit these changes into %{branch_name}"
msgstr ""
-msgid "You can setup jobs to only use Runners with specific tags. Separate tags with commas."
+msgid "You can set up jobs to only use Runners with specific tags. Separate tags with commas."
msgstr ""
msgid "You cannot write to a read-only secondary GitLab Geo instance. Please use %{link_to_primary_node} instead."
diff --git a/locale/bg/gitlab.po b/locale/bg/gitlab.po
index 8aae50168be..c33fa2084a6 100644
--- a/locale/bg/gitlab.po
+++ b/locale/bg/gitlab.po
@@ -308,7 +308,7 @@ msgstr ""
msgid "<strong>Removes</strong> source branch"
msgstr ""
-msgid "A 'Runner' is a process which runs a job. You can setup as many Runners as you need."
+msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr ""
msgid "A collection of graphs regarding Continuous Integration"
@@ -755,7 +755,7 @@ msgstr ""
msgid "Ascending"
msgstr ""
-msgid "Ask your group maintainer to setup a group Runner."
+msgid "Ask your group maintainer to set up a group Runner."
msgstr ""
msgid "Assertion consumer service URL"
@@ -6510,10 +6510,10 @@ msgstr "зададете парола"
msgid "Settings"
msgstr ""
-msgid "Setup a %{type} Runner manually"
+msgid "Set up a %{type} Runner manually"
msgstr ""
-msgid "Setup a specific Runner automatically"
+msgid "Set up a specific Runner automatically"
msgstr ""
msgid "Share"
@@ -7109,7 +7109,7 @@ msgid "The tabs below will be removed in a future version"
msgstr ""
msgid "The testing stage shows the time GitLab CI takes to run every pipeline for the related merge request. The data will automatically be added after your first pipeline finishes running."
-msgstr "Етапът на теÑтване показва времето, което е нужно на „Gitlab CI“ да изпълни вÑÑка Ñхема от задачи за Ñвързаната заÑвка за Ñливане. Данните ще бъдат добавени автоматично Ñлед като приключи изпълнението на първата Ви Ñхема."
+msgstr "Етапът на теÑтване показва времето, което е нужно на „GitLab CI“ да изпълни вÑÑка Ñхема от задачи за Ñвързаната заÑвка за Ñливане. Данните ще бъдат добавени автоматично Ñлед като приключи изпълнението на първата Ви Ñхема."
msgid "The time in seconds GitLab will keep failure information. When no failures occur during this time, information about the mount is reset."
msgstr ""
@@ -8108,7 +8108,7 @@ msgstr ""
msgid "You can resolve the merge conflict using either the Interactive mode, by choosing %{use_ours} or %{use_theirs} buttons, or by editing the files directly. Commit these changes into %{branch_name}"
msgstr ""
-msgid "You can setup jobs to only use Runners with specific tags. Separate tags with commas."
+msgid "You can set up jobs to only use Runners with specific tags. Separate tags with commas."
msgstr ""
msgid "You cannot write to a read-only secondary GitLab Geo instance. Please use %{link_to_primary_node} instead."
diff --git a/locale/ca_ES/gitlab.po b/locale/ca_ES/gitlab.po
index 2bdf9db1fb5..6bfe59669b5 100644
--- a/locale/ca_ES/gitlab.po
+++ b/locale/ca_ES/gitlab.po
@@ -308,7 +308,7 @@ msgstr ""
msgid "<strong>Removes</strong> source branch"
msgstr ""
-msgid "A 'Runner' is a process which runs a job. You can setup as many Runners as you need."
+msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr ""
msgid "A collection of graphs regarding Continuous Integration"
@@ -755,7 +755,7 @@ msgstr ""
msgid "Ascending"
msgstr ""
-msgid "Ask your group maintainer to setup a group Runner."
+msgid "Ask your group maintainer to set up a group Runner."
msgstr ""
msgid "Assertion consumer service URL"
@@ -6510,10 +6510,10 @@ msgstr ""
msgid "Settings"
msgstr ""
-msgid "Setup a %{type} Runner manually"
+msgid "Set up a %{type} Runner manually"
msgstr ""
-msgid "Setup a specific Runner automatically"
+msgid "Set up a specific Runner automatically"
msgstr ""
msgid "Share"
@@ -8108,7 +8108,7 @@ msgstr ""
msgid "You can resolve the merge conflict using either the Interactive mode, by choosing %{use_ours} or %{use_theirs} buttons, or by editing the files directly. Commit these changes into %{branch_name}"
msgstr ""
-msgid "You can setup jobs to only use Runners with specific tags. Separate tags with commas."
+msgid "You can set up jobs to only use Runners with specific tags. Separate tags with commas."
msgstr ""
msgid "You cannot write to a read-only secondary GitLab Geo instance. Please use %{link_to_primary_node} instead."
diff --git a/locale/cs_CZ/gitlab.po b/locale/cs_CZ/gitlab.po
index 98eb5b1aba6..0e349d2b12a 100644
--- a/locale/cs_CZ/gitlab.po
+++ b/locale/cs_CZ/gitlab.po
@@ -376,7 +376,7 @@ msgstr ""
msgid "<strong>Removes</strong> source branch"
msgstr ""
-msgid "A 'Runner' is a process which runs a job. You can setup as many Runners as you need."
+msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr ""
msgid "A collection of graphs regarding Continuous Integration"
@@ -823,7 +823,7 @@ msgstr "Artefakty"
msgid "Ascending"
msgstr ""
-msgid "Ask your group maintainer to setup a group Runner."
+msgid "Ask your group maintainer to set up a group Runner."
msgstr ""
msgid "Assertion consumer service URL"
@@ -6606,10 +6606,10 @@ msgstr ""
msgid "Settings"
msgstr ""
-msgid "Setup a %{type} Runner manually"
+msgid "Set up a %{type} Runner manually"
msgstr ""
-msgid "Setup a specific Runner automatically"
+msgid "Set up a specific Runner automatically"
msgstr ""
msgid "Share"
@@ -8212,7 +8212,7 @@ msgstr ""
msgid "You can resolve the merge conflict using either the Interactive mode, by choosing %{use_ours} or %{use_theirs} buttons, or by editing the files directly. Commit these changes into %{branch_name}"
msgstr ""
-msgid "You can setup jobs to only use Runners with specific tags. Separate tags with commas."
+msgid "You can set up jobs to only use Runners with specific tags. Separate tags with commas."
msgstr ""
msgid "You cannot write to a read-only secondary GitLab Geo instance. Please use %{link_to_primary_node} instead."
diff --git a/locale/da_DK/gitlab.po b/locale/da_DK/gitlab.po
index d1757972cfe..c32bf9eb38d 100644
--- a/locale/da_DK/gitlab.po
+++ b/locale/da_DK/gitlab.po
@@ -308,7 +308,7 @@ msgstr ""
msgid "<strong>Removes</strong> source branch"
msgstr ""
-msgid "A 'Runner' is a process which runs a job. You can setup as many Runners as you need."
+msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr ""
msgid "A collection of graphs regarding Continuous Integration"
@@ -755,7 +755,7 @@ msgstr ""
msgid "Ascending"
msgstr ""
-msgid "Ask your group maintainer to setup a group Runner."
+msgid "Ask your group maintainer to set up a group Runner."
msgstr ""
msgid "Assertion consumer service URL"
@@ -6510,10 +6510,10 @@ msgstr ""
msgid "Settings"
msgstr ""
-msgid "Setup a %{type} Runner manually"
+msgid "Set up a %{type} Runner manually"
msgstr ""
-msgid "Setup a specific Runner automatically"
+msgid "Set up a specific Runner automatically"
msgstr ""
msgid "Share"
@@ -8108,7 +8108,7 @@ msgstr ""
msgid "You can resolve the merge conflict using either the Interactive mode, by choosing %{use_ours} or %{use_theirs} buttons, or by editing the files directly. Commit these changes into %{branch_name}"
msgstr ""
-msgid "You can setup jobs to only use Runners with specific tags. Separate tags with commas."
+msgid "You can set up jobs to only use Runners with specific tags. Separate tags with commas."
msgstr ""
msgid "You cannot write to a read-only secondary GitLab Geo instance. Please use %{link_to_primary_node} instead."
diff --git a/locale/de/gitlab.po b/locale/de/gitlab.po
index 562251fa483..25a041c94f4 100644
--- a/locale/de/gitlab.po
+++ b/locale/de/gitlab.po
@@ -308,7 +308,7 @@ msgstr ""
msgid "<strong>Removes</strong> source branch"
msgstr ""
-msgid "A 'Runner' is a process which runs a job. You can setup as many Runners as you need."
+msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr ""
msgid "A collection of graphs regarding Continuous Integration"
@@ -755,7 +755,7 @@ msgstr ""
msgid "Ascending"
msgstr ""
-msgid "Ask your group maintainer to setup a group Runner."
+msgid "Ask your group maintainer to set up a group Runner."
msgstr ""
msgid "Assertion consumer service URL"
@@ -3571,7 +3571,7 @@ msgid "Git revision"
msgstr ""
msgid "Git storage health information has been reset"
-msgstr "Informationen über den Speicherzustand von Gitlab wurden zurückgesetzt."
+msgstr "Informationen über den Speicherzustand von GitLab wurden zurückgesetzt."
msgid "Git strategy for pipelines"
msgstr ""
@@ -6510,10 +6510,10 @@ msgstr "ein Passwort festlegst"
msgid "Settings"
msgstr "Einstellungen"
-msgid "Setup a %{type} Runner manually"
+msgid "Set up a %{type} Runner manually"
msgstr ""
-msgid "Setup a specific Runner automatically"
+msgid "Set up a specific Runner automatically"
msgstr ""
msgid "Share"
@@ -8108,7 +8108,7 @@ msgstr ""
msgid "You can resolve the merge conflict using either the Interactive mode, by choosing %{use_ours} or %{use_theirs} buttons, or by editing the files directly. Commit these changes into %{branch_name}"
msgstr ""
-msgid "You can setup jobs to only use Runners with specific tags. Separate tags with commas."
+msgid "You can set up jobs to only use Runners with specific tags. Separate tags with commas."
msgstr ""
msgid "You cannot write to a read-only secondary GitLab Geo instance. Please use %{link_to_primary_node} instead."
diff --git a/locale/eo/gitlab.po b/locale/eo/gitlab.po
index 8aff5c0a62b..456235b2fa6 100644
--- a/locale/eo/gitlab.po
+++ b/locale/eo/gitlab.po
@@ -308,7 +308,7 @@ msgstr ""
msgid "<strong>Removes</strong> source branch"
msgstr ""
-msgid "A 'Runner' is a process which runs a job. You can setup as many Runners as you need."
+msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr ""
msgid "A collection of graphs regarding Continuous Integration"
@@ -755,7 +755,7 @@ msgstr ""
msgid "Ascending"
msgstr ""
-msgid "Ask your group maintainer to setup a group Runner."
+msgid "Ask your group maintainer to set up a group Runner."
msgstr ""
msgid "Assertion consumer service URL"
@@ -6510,10 +6510,10 @@ msgstr "kreos pasvorton"
msgid "Settings"
msgstr ""
-msgid "Setup a %{type} Runner manually"
+msgid "Set up a %{type} Runner manually"
msgstr ""
-msgid "Setup a specific Runner automatically"
+msgid "Set up a specific Runner automatically"
msgstr ""
msgid "Share"
@@ -8108,7 +8108,7 @@ msgstr ""
msgid "You can resolve the merge conflict using either the Interactive mode, by choosing %{use_ours} or %{use_theirs} buttons, or by editing the files directly. Commit these changes into %{branch_name}"
msgstr ""
-msgid "You can setup jobs to only use Runners with specific tags. Separate tags with commas."
+msgid "You can set up jobs to only use Runners with specific tags. Separate tags with commas."
msgstr ""
msgid "You cannot write to a read-only secondary GitLab Geo instance. Please use %{link_to_primary_node} instead."
diff --git a/locale/es/gitlab.po b/locale/es/gitlab.po
index ef26024bd48..648b323bed0 100644
--- a/locale/es/gitlab.po
+++ b/locale/es/gitlab.po
@@ -308,7 +308,7 @@ msgstr ""
msgid "<strong>Removes</strong> source branch"
msgstr ""
-msgid "A 'Runner' is a process which runs a job. You can setup as many Runners as you need."
+msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr ""
msgid "A collection of graphs regarding Continuous Integration"
@@ -755,7 +755,7 @@ msgstr "Artefactos"
msgid "Ascending"
msgstr ""
-msgid "Ask your group maintainer to setup a group Runner."
+msgid "Ask your group maintainer to set up a group Runner."
msgstr ""
msgid "Assertion consumer service URL"
@@ -2130,7 +2130,7 @@ msgid "ContainerRegistry|First log in to GitLab&rsquo;s Container Registry using
msgstr ""
msgid "ContainerRegistry|GitLab supports up to 3 levels of image names. The following examples of images are valid for your project:"
-msgstr "Gitlab soporta hasta 3 niveles para nombres de imágenes. Los siguientes ejemplos de imágenes son válidos para tu proyecto:"
+msgstr "GitLab soporta hasta 3 niveles para nombres de imágenes. Los siguientes ejemplos de imágenes son válidos para tu proyecto:"
msgid "ContainerRegistry|How to use the Container Registry"
msgstr ""
@@ -6510,10 +6510,10 @@ msgstr "establecer una contraseña"
msgid "Settings"
msgstr "Configuración"
-msgid "Setup a %{type} Runner manually"
+msgid "Set up a %{type} Runner manually"
msgstr ""
-msgid "Setup a specific Runner automatically"
+msgid "Set up a specific Runner automatically"
msgstr ""
msgid "Share"
@@ -8108,7 +8108,7 @@ msgstr ""
msgid "You can resolve the merge conflict using either the Interactive mode, by choosing %{use_ours} or %{use_theirs} buttons, or by editing the files directly. Commit these changes into %{branch_name}"
msgstr ""
-msgid "You can setup jobs to only use Runners with specific tags. Separate tags with commas."
+msgid "You can set up jobs to only use Runners with specific tags. Separate tags with commas."
msgstr ""
msgid "You cannot write to a read-only secondary GitLab Geo instance. Please use %{link_to_primary_node} instead."
diff --git a/locale/et_EE/gitlab.po b/locale/et_EE/gitlab.po
index 2fdb8197acd..dbaff32f1b5 100644
--- a/locale/et_EE/gitlab.po
+++ b/locale/et_EE/gitlab.po
@@ -308,7 +308,7 @@ msgstr ""
msgid "<strong>Removes</strong> source branch"
msgstr ""
-msgid "A 'Runner' is a process which runs a job. You can setup as many Runners as you need."
+msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr ""
msgid "A collection of graphs regarding Continuous Integration"
@@ -755,7 +755,7 @@ msgstr ""
msgid "Ascending"
msgstr ""
-msgid "Ask your group maintainer to setup a group Runner."
+msgid "Ask your group maintainer to set up a group Runner."
msgstr ""
msgid "Assertion consumer service URL"
@@ -6510,10 +6510,10 @@ msgstr ""
msgid "Settings"
msgstr ""
-msgid "Setup a %{type} Runner manually"
+msgid "Set up a %{type} Runner manually"
msgstr ""
-msgid "Setup a specific Runner automatically"
+msgid "Set up a specific Runner automatically"
msgstr ""
msgid "Share"
@@ -8108,7 +8108,7 @@ msgstr ""
msgid "You can resolve the merge conflict using either the Interactive mode, by choosing %{use_ours} or %{use_theirs} buttons, or by editing the files directly. Commit these changes into %{branch_name}"
msgstr ""
-msgid "You can setup jobs to only use Runners with specific tags. Separate tags with commas."
+msgid "You can set up jobs to only use Runners with specific tags. Separate tags with commas."
msgstr ""
msgid "You cannot write to a read-only secondary GitLab Geo instance. Please use %{link_to_primary_node} instead."
diff --git a/locale/fil_PH/gitlab.po b/locale/fil_PH/gitlab.po
index 58254366594..20943d89ea0 100644
--- a/locale/fil_PH/gitlab.po
+++ b/locale/fil_PH/gitlab.po
@@ -308,7 +308,7 @@ msgstr ""
msgid "<strong>Removes</strong> source branch"
msgstr ""
-msgid "A 'Runner' is a process which runs a job. You can setup as many Runners as you need."
+msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr ""
msgid "A collection of graphs regarding Continuous Integration"
@@ -755,7 +755,7 @@ msgstr ""
msgid "Ascending"
msgstr ""
-msgid "Ask your group maintainer to setup a group Runner."
+msgid "Ask your group maintainer to set up a group Runner."
msgstr ""
msgid "Assertion consumer service URL"
@@ -6510,10 +6510,10 @@ msgstr ""
msgid "Settings"
msgstr ""
-msgid "Setup a %{type} Runner manually"
+msgid "Set up a %{type} Runner manually"
msgstr ""
-msgid "Setup a specific Runner automatically"
+msgid "Set up a specific Runner automatically"
msgstr ""
msgid "Share"
@@ -8108,7 +8108,7 @@ msgstr ""
msgid "You can resolve the merge conflict using either the Interactive mode, by choosing %{use_ours} or %{use_theirs} buttons, or by editing the files directly. Commit these changes into %{branch_name}"
msgstr ""
-msgid "You can setup jobs to only use Runners with specific tags. Separate tags with commas."
+msgid "You can set up jobs to only use Runners with specific tags. Separate tags with commas."
msgstr ""
msgid "You cannot write to a read-only secondary GitLab Geo instance. Please use %{link_to_primary_node} instead."
diff --git a/locale/fr/gitlab.po b/locale/fr/gitlab.po
index 84bc10a9cd2..463c30cccfb 100644
--- a/locale/fr/gitlab.po
+++ b/locale/fr/gitlab.po
@@ -308,7 +308,7 @@ msgstr "<strong>%{pushes}</strong> poussées Git, plus de <strong>%{commits}</s
msgid "<strong>Removes</strong> source branch"
msgstr "<strong>Supprime</strong> la branche source"
-msgid "A 'Runner' is a process which runs a job. You can setup as many Runners as you need."
+msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr "Un « exécuteur » est un processus qui exécute une tâche. Vous pouvez configurer autant d’exécuteurs que nécessaire."
msgid "A collection of graphs regarding Continuous Integration"
@@ -546,7 +546,7 @@ msgid "An application called %{link_to_client} is requesting access to your GitL
msgstr "Une application appelée %{link_to_client} demande l’accès à votre compte GitLab."
msgid "An empty GitLab User field will add the FogBugz user's full name (e.g. \"By John Smith\") in the description of all issues and comments. It will also associate and/or assign these issues and comments with the project creator."
-msgstr "Un champ utilisateur Gitlab vide ajoutera le nom complet de l’utilisateur FogBugz (p. ex., « Par John Smith ») dans la description de tous les tickets et commentaires. Il associera ou assignera ces tickets et commentaires au créateur du projet."
+msgstr "Un champ utilisateur GitLab vide ajoutera le nom complet de l’utilisateur FogBugz (p. ex., « Par John Smith ») dans la description de tous les tickets et commentaires. Il associera ou assignera ces tickets et commentaires au créateur du projet."
msgid "An error accured whilst committing your changes."
msgstr "Une erreur est survenue lors du commit de vos modifications."
@@ -755,7 +755,7 @@ msgstr "Artéfacts"
msgid "Ascending"
msgstr "Croissant"
-msgid "Ask your group maintainer to setup a group Runner."
+msgid "Ask your group maintainer to set up a group Runner."
msgstr "Demandez au responsable du groupe de configurer un exécuteur de groupe."
msgid "Assertion consumer service URL"
@@ -4020,7 +4020,7 @@ msgid "ImportButtons|Connect repositories from"
msgstr "Connecter des dépôts provenant de"
msgid "Improve Issue boards with GitLab Enterprise Edition."
-msgstr "Améliorez le tableau des tickets avec Gitlab Entreprise Edition."
+msgstr "Améliorez le tableau des tickets avec GitLab Entreprise Edition."
msgid "Improve issues management with Issue weight and GitLab Enterprise Edition."
msgstr "Améliorez la gestion des tickets grâce à la pondération disponible dans la version Entreprise Edition de GitLab."
@@ -6510,10 +6510,10 @@ msgstr "définir un mot de passe"
msgid "Settings"
msgstr "Paramètres"
-msgid "Setup a %{type} Runner manually"
+msgid "Set up a %{type} Runner manually"
msgstr ""
-msgid "Setup a specific Runner automatically"
+msgid "Set up a specific Runner automatically"
msgstr "Configurer automatiquement un exécuteur spécifique"
msgid "Share"
@@ -7004,7 +7004,7 @@ msgid "Thanks! Don't show me this again"
msgstr "Merci ! Ne plus afficher ce message"
msgid "The Advanced Global Search in GitLab is a powerful search service that saves you time. Instead of creating duplicate code and wasting time, you can now search for code within other teams that can help your own project."
-msgstr "La recherche globale avancée de Gitlab est un outil puissant qui vous fait gagner du temps. Au lieu de perdre du temps à recréer du code existant, vous pouvez maintenant faire des recherches dans le code d’autres équipes afin de vous aider sur votre projet."
+msgstr "La recherche globale avancée de GitLab est un outil puissant qui vous fait gagner du temps. Au lieu de perdre du temps à recréer du code existant, vous pouvez maintenant faire des recherches dans le code d’autres équipes afin de vous aider sur votre projet."
msgid "The Git LFS objects will <strong>not</strong> be synced."
msgstr ""
@@ -8108,7 +8108,7 @@ msgstr "Vous ne pouvez modifier des fichiers que dans une branche"
msgid "You can resolve the merge conflict using either the Interactive mode, by choosing %{use_ours} or %{use_theirs} buttons, or by editing the files directly. Commit these changes into %{branch_name}"
msgstr "Vous pouvez résoudre le conflit de fusion Git soit en mode interactif, en cliquant sur les boutons « %{use_ours} » ou « %{use_theirs} », soit en modifiant directement les fichiers. Valider ces modifications dans la branche « %{branch_name} »"
-msgid "You can setup jobs to only use Runners with specific tags. Separate tags with commas."
+msgid "You can set up jobs to only use Runners with specific tags. Separate tags with commas."
msgstr ""
msgid "You cannot write to a read-only secondary GitLab Geo instance. Please use %{link_to_primary_node} instead."
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index db372811db3..a9c5e45f9fa 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -107,6 +107,9 @@ msgstr ""
msgid "%{group_docs_link_start}Groups%{group_docs_link_end} allow you to manage and collaborate across multiple projects. Members of a group have access to all of its projects."
msgstr ""
+msgid "%{issuableType} will be removed! Are you sure?"
+msgstr ""
+
msgid "%{loadingIcon} Started"
msgstr ""
@@ -250,7 +253,7 @@ msgstr ""
msgid "<strong>Removes</strong> source branch"
msgstr ""
-msgid "A 'Runner' is a process which runs a job. You can setup as many Runners as you need."
+msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr ""
msgid "A collection of graphs regarding Continuous Integration"
@@ -355,6 +358,9 @@ msgstr ""
msgid "Add users to group"
msgstr ""
+msgid "Adding new applications is disabled in your GitLab instance. Please contact your GitLab administrator to get the permission"
+msgstr ""
+
msgid "Admin Area"
msgstr ""
@@ -637,7 +643,7 @@ msgstr ""
msgid "Artifacts"
msgstr ""
-msgid "Ask your group maintainer to setup a group Runner."
+msgid "Ask your group maintainer to set up a group Runner."
msgstr ""
msgid "Assign custom color like #FF0000"
@@ -784,9 +790,6 @@ msgstr ""
msgid "Background color"
msgstr ""
-msgid "Background jobs"
-msgstr ""
-
msgid "Badges"
msgstr ""
@@ -1050,6 +1053,9 @@ msgstr ""
msgid "CI / CD Settings"
msgstr ""
+msgid "CI/CD"
+msgstr ""
+
msgid "CI/CD configuration"
msgstr ""
@@ -1353,6 +1359,9 @@ msgstr ""
msgid "ClusterIntegration|Certificate Authority bundle (PEM format)"
msgstr ""
+msgid "ClusterIntegration|Choose which applications to install on your Kubernetes cluster. Helm Tiller is required to install any of the following applications."
+msgstr ""
+
msgid "ClusterIntegration|Choose which of your environments will use this cluster."
msgstr ""
@@ -1443,9 +1452,6 @@ msgstr ""
msgid "ClusterIntegration|Install"
msgstr ""
-msgid "ClusterIntegration|Install applications on your Kubernetes cluster. Read more about %{helpLink}"
-msgstr ""
-
msgid "ClusterIntegration|Installed"
msgstr ""
@@ -1653,6 +1659,9 @@ msgstr ""
msgid "ClusterIntegration|With a Kubernetes cluster associated to this project, you can use review apps, deploy your applications, run your pipelines, and much more in an easy way."
msgstr ""
+msgid "ClusterIntegration|You must first install Helm Tiller before installing the applications below"
+msgstr ""
+
msgid "ClusterIntegration|Your account must have %{link_to_kubernetes_engine}"
msgstr ""
@@ -1671,9 +1680,6 @@ msgstr ""
msgid "ClusterIntegration|help page"
msgstr ""
-msgid "ClusterIntegration|installing applications"
-msgstr ""
-
msgid "ClusterIntegration|meets the requirements"
msgstr ""
@@ -1732,6 +1738,9 @@ msgstr ""
msgid "CommitMessage|Add %{file_name}"
msgstr ""
+msgid "CommitWidget|authored"
+msgstr ""
+
msgid "Commits"
msgstr ""
@@ -1804,9 +1813,6 @@ msgstr ""
msgid "Configure Gitaly timeouts."
msgstr ""
-msgid "Configure Sidekiq job throttling."
-msgstr ""
-
msgid "Configure automatic git checks and housekeeping on repositories."
msgstr ""
@@ -2553,6 +2559,9 @@ msgstr ""
msgid "Environments|You don't have any environments right now."
msgstr ""
+msgid "Epic"
+msgstr ""
+
msgid "Error"
msgstr ""
@@ -2841,6 +2850,9 @@ msgstr ""
msgid "Generate a default set of labels"
msgstr ""
+msgid "Geo"
+msgstr ""
+
msgid "Git"
msgstr ""
@@ -3293,6 +3305,9 @@ msgstr ""
msgid "Invite"
msgstr ""
+msgid "Issue"
+msgstr ""
+
msgid "Issue Boards"
msgstr ""
@@ -3323,9 +3338,6 @@ msgstr ""
msgid "Jobs"
msgstr ""
-msgid "Job|Are you sure you want to erase this job?"
-msgstr ""
-
msgid "Job|Browse"
msgstr ""
@@ -3362,7 +3374,7 @@ msgstr ""
msgid "Job|The artifacts were removed"
msgstr ""
-msgid "Job|The artifacts will be removed"
+msgid "Job|The artifacts will be removed in"
msgstr ""
msgid "Job|This job is stuck, because the project doesn't have any runners online assigned to it."
@@ -3681,9 +3693,6 @@ msgstr ""
msgid "MergeRequests|Toggle comments for this file"
msgstr ""
-msgid "MergeRequests|Updating discussions failed"
-msgstr ""
-
msgid "MergeRequests|View file @ %{commitId}"
msgstr ""
@@ -3708,6 +3717,9 @@ msgstr ""
msgid "Metrics - Prometheus"
msgstr ""
+msgid "Metrics and profiling"
+msgstr ""
+
msgid "Metrics|Check out the CI/CD documentation on deploying to an environment"
msgstr ""
@@ -4995,6 +5007,9 @@ msgstr ""
msgid "Reply to this email directly or %{view_it_on_gitlab}."
msgstr ""
+msgid "Reporting"
+msgstr ""
+
msgid "Reports|%{failedString} and %{resolvedString}"
msgstr ""
@@ -5363,19 +5378,19 @@ msgstr ""
msgid "Set up Koding"
msgstr ""
-msgid "Set up your project to automatically push and/or pull changes to/from another repository. Branches, tags, and commits will be synced automatically."
+msgid "Set up a %{type} Runner manually"
msgstr ""
-msgid "SetPasswordToCloneLink|set a password"
+msgid "Set up a specific Runner automatically"
msgstr ""
-msgid "Settings"
+msgid "Set up your project to automatically push and/or pull changes to/from another repository. Branches, tags, and commits will be synced automatically."
msgstr ""
-msgid "Setup a %{type} Runner manually"
+msgid "SetPasswordToCloneLink|set a password"
msgstr ""
-msgid "Setup a specific Runner automatically"
+msgid "Settings"
msgstr ""
msgid "Share"
@@ -5536,6 +5551,9 @@ msgstr ""
msgid "SortOptions|Most popular"
msgstr ""
+msgid "SortOptions|Most stars"
+msgstr ""
+
msgid "SortOptions|Name"
msgstr ""
@@ -5796,6 +5814,9 @@ msgstr ""
msgid "Template"
msgstr ""
+msgid "Templates"
+msgstr ""
+
msgid "Terms of Service Agreement and Privacy Policy"
msgstr ""
@@ -6334,6 +6355,9 @@ msgstr ""
msgid "Toggle Sidebar"
msgstr ""
+msgid "Toggle commit description"
+msgstr ""
+
msgid "Toggle discussion"
msgstr ""
@@ -6799,7 +6823,7 @@ msgstr ""
msgid "You can resolve the merge conflict using either the Interactive mode, by choosing %{use_ours} or %{use_theirs} buttons, or by editing the files directly. Commit these changes into %{branch_name}"
msgstr ""
-msgid "You can setup jobs to only use Runners with specific tags. Separate tags with commas."
+msgid "You can set up jobs to only use Runners with specific tags. Separate tags with commas."
msgstr ""
msgid "You cannot write to this read-only GitLab instance."
diff --git a/locale/gl_ES/gitlab.po b/locale/gl_ES/gitlab.po
index 5caaba0ee8f..5574ed0613f 100644
--- a/locale/gl_ES/gitlab.po
+++ b/locale/gl_ES/gitlab.po
@@ -308,7 +308,7 @@ msgstr ""
msgid "<strong>Removes</strong> source branch"
msgstr ""
-msgid "A 'Runner' is a process which runs a job. You can setup as many Runners as you need."
+msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr ""
msgid "A collection of graphs regarding Continuous Integration"
@@ -755,7 +755,7 @@ msgstr ""
msgid "Ascending"
msgstr ""
-msgid "Ask your group maintainer to setup a group Runner."
+msgid "Ask your group maintainer to set up a group Runner."
msgstr ""
msgid "Assertion consumer service URL"
@@ -6510,10 +6510,10 @@ msgstr ""
msgid "Settings"
msgstr ""
-msgid "Setup a %{type} Runner manually"
+msgid "Set up a %{type} Runner manually"
msgstr ""
-msgid "Setup a specific Runner automatically"
+msgid "Set up a specific Runner automatically"
msgstr ""
msgid "Share"
@@ -8108,7 +8108,7 @@ msgstr ""
msgid "You can resolve the merge conflict using either the Interactive mode, by choosing %{use_ours} or %{use_theirs} buttons, or by editing the files directly. Commit these changes into %{branch_name}"
msgstr ""
-msgid "You can setup jobs to only use Runners with specific tags. Separate tags with commas."
+msgid "You can set up jobs to only use Runners with specific tags. Separate tags with commas."
msgstr ""
msgid "You cannot write to a read-only secondary GitLab Geo instance. Please use %{link_to_primary_node} instead."
diff --git a/locale/he_IL/gitlab.po b/locale/he_IL/gitlab.po
index 308d138a534..4eeac683e67 100644
--- a/locale/he_IL/gitlab.po
+++ b/locale/he_IL/gitlab.po
@@ -376,7 +376,7 @@ msgstr ""
msgid "<strong>Removes</strong> source branch"
msgstr ""
-msgid "A 'Runner' is a process which runs a job. You can setup as many Runners as you need."
+msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr ""
msgid "A collection of graphs regarding Continuous Integration"
@@ -823,7 +823,7 @@ msgstr ""
msgid "Ascending"
msgstr ""
-msgid "Ask your group maintainer to setup a group Runner."
+msgid "Ask your group maintainer to set up a group Runner."
msgstr ""
msgid "Assertion consumer service URL"
@@ -6606,10 +6606,10 @@ msgstr ""
msgid "Settings"
msgstr ""
-msgid "Setup a %{type} Runner manually"
+msgid "Set up a %{type} Runner manually"
msgstr ""
-msgid "Setup a specific Runner automatically"
+msgid "Set up a specific Runner automatically"
msgstr ""
msgid "Share"
@@ -8212,7 +8212,7 @@ msgstr ""
msgid "You can resolve the merge conflict using either the Interactive mode, by choosing %{use_ours} or %{use_theirs} buttons, or by editing the files directly. Commit these changes into %{branch_name}"
msgstr ""
-msgid "You can setup jobs to only use Runners with specific tags. Separate tags with commas."
+msgid "You can set up jobs to only use Runners with specific tags. Separate tags with commas."
msgstr ""
msgid "You cannot write to a read-only secondary GitLab Geo instance. Please use %{link_to_primary_node} instead."
diff --git a/locale/id_ID/gitlab.po b/locale/id_ID/gitlab.po
index ee5305c8ec8..e185f4f71b7 100644
--- a/locale/id_ID/gitlab.po
+++ b/locale/id_ID/gitlab.po
@@ -274,7 +274,7 @@ msgstr ""
msgid "<strong>Removes</strong> source branch"
msgstr ""
-msgid "A 'Runner' is a process which runs a job. You can setup as many Runners as you need."
+msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr ""
msgid "A collection of graphs regarding Continuous Integration"
@@ -721,7 +721,7 @@ msgstr ""
msgid "Ascending"
msgstr ""
-msgid "Ask your group maintainer to setup a group Runner."
+msgid "Ask your group maintainer to set up a group Runner."
msgstr ""
msgid "Assertion consumer service URL"
@@ -6462,10 +6462,10 @@ msgstr ""
msgid "Settings"
msgstr ""
-msgid "Setup a %{type} Runner manually"
+msgid "Set up a %{type} Runner manually"
msgstr ""
-msgid "Setup a specific Runner automatically"
+msgid "Set up a specific Runner automatically"
msgstr ""
msgid "Share"
@@ -8056,7 +8056,7 @@ msgstr ""
msgid "You can resolve the merge conflict using either the Interactive mode, by choosing %{use_ours} or %{use_theirs} buttons, or by editing the files directly. Commit these changes into %{branch_name}"
msgstr ""
-msgid "You can setup jobs to only use Runners with specific tags. Separate tags with commas."
+msgid "You can set up jobs to only use Runners with specific tags. Separate tags with commas."
msgstr ""
msgid "You cannot write to a read-only secondary GitLab Geo instance. Please use %{link_to_primary_node} instead."
diff --git a/locale/it/gitlab.po b/locale/it/gitlab.po
index 50d627ea6de..8d7bc9aff91 100644
--- a/locale/it/gitlab.po
+++ b/locale/it/gitlab.po
@@ -143,7 +143,7 @@ msgid "%{number_of_failures} of %{maximum_failures} failures. GitLab will allow
msgstr "%{number_of_failures} di %{maximum_failures} fallimenti. GitLab consentirà l'accesso al prossimo tentativo."
msgid "%{number_of_failures} of %{maximum_failures} failures. GitLab will not retry automatically. Reset storage information when the problem is resolved."
-msgstr "%{number_of_failures} di %{maximum_failures} fallimenti. Gitlab non ritenterà automaticamente. Ripristina l'informazioni d'archiviazione quando il problema è risolto."
+msgstr "%{number_of_failures} di %{maximum_failures} fallimenti. GitLab non ritenterà automaticamente. Ripristina l'informazioni d'archiviazione quando il problema è risolto."
msgid "%{openOrClose} %{noteable}"
msgstr ""
@@ -308,7 +308,7 @@ msgstr ""
msgid "<strong>Removes</strong> source branch"
msgstr ""
-msgid "A 'Runner' is a process which runs a job. You can setup as many Runners as you need."
+msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr ""
msgid "A collection of graphs regarding Continuous Integration"
@@ -755,7 +755,7 @@ msgstr "Artefatti"
msgid "Ascending"
msgstr ""
-msgid "Ask your group maintainer to setup a group Runner."
+msgid "Ask your group maintainer to set up a group Runner."
msgstr ""
msgid "Assertion consumer service URL"
@@ -1091,7 +1091,7 @@ msgstr[0] ""
msgstr[1] ""
msgid "Branch <strong>%{branch_name}</strong> was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}"
-msgstr "La branch <strong>%{branch_name}</strong> è stata creata. Per impostare un rilascio automatico scegli un template CI di Gitlab e committa le tue modifiche %{link_to_autodeploy_doc}"
+msgstr "La branch <strong>%{branch_name}</strong> è stata creata. Per impostare un rilascio automatico scegli un template CI di GitLab e committa le tue modifiche %{link_to_autodeploy_doc}"
msgid "Branch has changed"
msgstr "La branche è cambiata"
@@ -1661,7 +1661,7 @@ msgid "ClusterIntegration|GitLab Integration"
msgstr ""
msgid "ClusterIntegration|GitLab Runner"
-msgstr "Gitlab Runner"
+msgstr "GitLab Runner"
msgid "ClusterIntegration|GitLab Runner connects to this project's repository and executes CI/CD jobs, pushing results back and deploying, applications to production."
msgstr ""
@@ -2163,7 +2163,7 @@ msgid "ContainerRegistry|Use different image names"
msgstr "Utilizza nomi d'immagine differenti"
msgid "ContainerRegistry|With the Docker Container Registry integrated into GitLab, every project can have its own space to store its Docker images."
-msgstr "Con il Docker Container Registry integrato in Gitlab, ogni progetto può avere il suo spazio d'archiviazione sulle immagini Docker."
+msgstr "Con il Docker Container Registry integrato in GitLab, ogni progetto può avere il suo spazio d'archiviazione sulle immagini Docker."
msgid "ContainerRegistry|You can also use a %{deploy_token} for read-only access to the registry images."
msgstr ""
@@ -3652,7 +3652,7 @@ msgid "Google Takeout"
msgstr ""
msgid "Google authentication is not %{link_to_documentation}. Ask your GitLab administrator if you want to use this service."
-msgstr "L'autenticazione Google non è %{link_to_documentation}. Richiedi al tuo amministratore Gitlab se desideri utilizzare il servizio."
+msgstr "L'autenticazione Google non è %{link_to_documentation}. Richiedi al tuo amministratore GitLab se desideri utilizzare il servizio."
msgid "Got it!"
msgstr ""
@@ -6510,10 +6510,10 @@ msgstr "imposta una password"
msgid "Settings"
msgstr "Impostazioni"
-msgid "Setup a %{type} Runner manually"
+msgid "Set up a %{type} Runner manually"
msgstr ""
-msgid "Setup a specific Runner automatically"
+msgid "Set up a specific Runner automatically"
msgstr ""
msgid "Share"
@@ -8108,7 +8108,7 @@ msgstr ""
msgid "You can resolve the merge conflict using either the Interactive mode, by choosing %{use_ours} or %{use_theirs} buttons, or by editing the files directly. Commit these changes into %{branch_name}"
msgstr ""
-msgid "You can setup jobs to only use Runners with specific tags. Separate tags with commas."
+msgid "You can set up jobs to only use Runners with specific tags. Separate tags with commas."
msgstr ""
msgid "You cannot write to a read-only secondary GitLab Geo instance. Please use %{link_to_primary_node} instead."
diff --git a/locale/ja/gitlab.po b/locale/ja/gitlab.po
index 9864aded546..f1d84529a25 100644
--- a/locale/ja/gitlab.po
+++ b/locale/ja/gitlab.po
@@ -274,7 +274,7 @@ msgstr "<strong>%{pushes}</strong>回ã®ãƒ—ッシュã€<strong>%{commits}</stron
msgid "<strong>Removes</strong> source branch"
msgstr "ソースブランãƒã‚’<strong>削除</strong>"
-msgid "A 'Runner' is a process which runs a job. You can setup as many Runners as you need."
+msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr "「Runnerã€ã¯ã‚¸ãƒ§ãƒ–を実行ã™ã‚‹ãƒ—ロセスã§ã™ã€‚å¿…è¦ãªæ•°ã® Runner ã‚’ä»»æ„ã«ã‚»ãƒƒãƒˆã‚¢ãƒƒãƒ—ã§ãã¾ã™ã€‚"
msgid "A collection of graphs regarding Continuous Integration"
@@ -721,7 +721,7 @@ msgstr "アーティファクト"
msgid "Ascending"
msgstr "昇順"
-msgid "Ask your group maintainer to setup a group Runner."
+msgid "Ask your group maintainer to set up a group Runner."
msgstr "グループ Runner ã®è¨­å®šã¯ã€ã‚°ãƒ«ãƒ¼ãƒ—ã® Maintainer ã«ä¾é ¼ã—ã¦ãã ã•ã„。"
msgid "Assertion consumer service URL"
@@ -6462,10 +6462,10 @@ msgstr "パスワードを設定"
msgid "Settings"
msgstr "設定"
-msgid "Setup a %{type} Runner manually"
+msgid "Set up a %{type} Runner manually"
msgstr ""
-msgid "Setup a specific Runner automatically"
+msgid "Set up a specific Runner automatically"
msgstr ""
msgid "Share"
@@ -8056,7 +8056,7 @@ msgstr "ファイルを編集ã™ã‚‹ã«ã¯ã€ã©ã“ã‹ã®ãƒ–ランãƒã«ã„ãªã‘
msgid "You can resolve the merge conflict using either the Interactive mode, by choosing %{use_ours} or %{use_theirs} buttons, or by editing the files directly. Commit these changes into %{branch_name}"
msgstr ""
-msgid "You can setup jobs to only use Runners with specific tags. Separate tags with commas."
+msgid "You can set up jobs to only use Runners with specific tags. Separate tags with commas."
msgstr ""
msgid "You cannot write to a read-only secondary GitLab Geo instance. Please use %{link_to_primary_node} instead."
diff --git a/locale/ko/gitlab.po b/locale/ko/gitlab.po
index 6528dd0235a..416e0712a75 100644
--- a/locale/ko/gitlab.po
+++ b/locale/ko/gitlab.po
@@ -274,7 +274,7 @@ msgstr ""
msgid "<strong>Removes</strong> source branch"
msgstr ""
-msgid "A 'Runner' is a process which runs a job. You can setup as many Runners as you need."
+msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr "'러너(Runner)'는 ìž‘ì—…ì„ ì‹¤í–‰í•˜ëŠ” 프로세스입니다. 필요한 ë§Œí¼ ëŸ¬ë„ˆë¥¼ ì…‹ì—…í•  수 있습니다."
msgid "A collection of graphs regarding Continuous Integration"
@@ -721,7 +721,7 @@ msgstr ""
msgid "Ascending"
msgstr ""
-msgid "Ask your group maintainer to setup a group Runner."
+msgid "Ask your group maintainer to set up a group Runner."
msgstr "그룹 관리ìžì—게 그룹 Runner 를 설정하ë„ë¡ ìš”ì²­í•˜ì„¸ìš”"
msgid "Assertion consumer service URL"
@@ -6462,10 +6462,10 @@ msgstr "패스워드 설정"
msgid "Settings"
msgstr "설정"
-msgid "Setup a %{type} Runner manually"
+msgid "Set up a %{type} Runner manually"
msgstr ""
-msgid "Setup a specific Runner automatically"
+msgid "Set up a specific Runner automatically"
msgstr "특정 Runner ìžë™ 설정"
msgid "Share"
@@ -8056,7 +8056,7 @@ msgstr ""
msgid "You can resolve the merge conflict using either the Interactive mode, by choosing %{use_ours} or %{use_theirs} buttons, or by editing the files directly. Commit these changes into %{branch_name}"
msgstr ""
-msgid "You can setup jobs to only use Runners with specific tags. Separate tags with commas."
+msgid "You can set up jobs to only use Runners with specific tags. Separate tags with commas."
msgstr ""
msgid "You cannot write to a read-only secondary GitLab Geo instance. Please use %{link_to_primary_node} instead."
diff --git a/locale/nl_NL/gitlab.po b/locale/nl_NL/gitlab.po
index e210fbb6acb..8234f120676 100644
--- a/locale/nl_NL/gitlab.po
+++ b/locale/nl_NL/gitlab.po
@@ -308,7 +308,7 @@ msgstr ""
msgid "<strong>Removes</strong> source branch"
msgstr ""
-msgid "A 'Runner' is a process which runs a job. You can setup as many Runners as you need."
+msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr ""
msgid "A collection of graphs regarding Continuous Integration"
@@ -755,7 +755,7 @@ msgstr ""
msgid "Ascending"
msgstr ""
-msgid "Ask your group maintainer to setup a group Runner."
+msgid "Ask your group maintainer to set up a group Runner."
msgstr ""
msgid "Assertion consumer service URL"
@@ -6510,10 +6510,10 @@ msgstr ""
msgid "Settings"
msgstr ""
-msgid "Setup a %{type} Runner manually"
+msgid "Set up a %{type} Runner manually"
msgstr ""
-msgid "Setup a specific Runner automatically"
+msgid "Set up a specific Runner automatically"
msgstr ""
msgid "Share"
@@ -8108,7 +8108,7 @@ msgstr ""
msgid "You can resolve the merge conflict using either the Interactive mode, by choosing %{use_ours} or %{use_theirs} buttons, or by editing the files directly. Commit these changes into %{branch_name}"
msgstr ""
-msgid "You can setup jobs to only use Runners with specific tags. Separate tags with commas."
+msgid "You can set up jobs to only use Runners with specific tags. Separate tags with commas."
msgstr ""
msgid "You cannot write to a read-only secondary GitLab Geo instance. Please use %{link_to_primary_node} instead."
diff --git a/locale/pl_PL/gitlab.po b/locale/pl_PL/gitlab.po
index c619c74fa81..6cc1b4472c7 100644
--- a/locale/pl_PL/gitlab.po
+++ b/locale/pl_PL/gitlab.po
@@ -376,7 +376,7 @@ msgstr ""
msgid "<strong>Removes</strong> source branch"
msgstr ""
-msgid "A 'Runner' is a process which runs a job. You can setup as many Runners as you need."
+msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr ""
msgid "A collection of graphs regarding Continuous Integration"
@@ -823,7 +823,7 @@ msgstr ""
msgid "Ascending"
msgstr ""
-msgid "Ask your group maintainer to setup a group Runner."
+msgid "Ask your group maintainer to set up a group Runner."
msgstr ""
msgid "Assertion consumer service URL"
@@ -6606,10 +6606,10 @@ msgstr ""
msgid "Settings"
msgstr ""
-msgid "Setup a %{type} Runner manually"
+msgid "Set up a %{type} Runner manually"
msgstr ""
-msgid "Setup a specific Runner automatically"
+msgid "Set up a specific Runner automatically"
msgstr ""
msgid "Share"
@@ -8212,7 +8212,7 @@ msgstr ""
msgid "You can resolve the merge conflict using either the Interactive mode, by choosing %{use_ours} or %{use_theirs} buttons, or by editing the files directly. Commit these changes into %{branch_name}"
msgstr ""
-msgid "You can setup jobs to only use Runners with specific tags. Separate tags with commas."
+msgid "You can set up jobs to only use Runners with specific tags. Separate tags with commas."
msgstr ""
msgid "You cannot write to a read-only secondary GitLab Geo instance. Please use %{link_to_primary_node} instead."
diff --git a/locale/pt_BR/gitlab.po b/locale/pt_BR/gitlab.po
index 9eb6ac8906b..516b85f0016 100644
--- a/locale/pt_BR/gitlab.po
+++ b/locale/pt_BR/gitlab.po
@@ -308,7 +308,7 @@ msgstr "<strong>%{pushes}</strong> pushes, mais que <strong>%{commits}</strong>
msgid "<strong>Removes</strong> source branch"
msgstr "<strong>Remover</strong> branch de origem"
-msgid "A 'Runner' is a process which runs a job. You can setup as many Runners as you need."
+msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr "'Runner' é um processo que executa um job. Você pode configurar quantos Runners você precisar."
msgid "A collection of graphs regarding Continuous Integration"
@@ -755,7 +755,7 @@ msgstr "Artefatos"
msgid "Ascending"
msgstr "Ascendente"
-msgid "Ask your group maintainer to setup a group Runner."
+msgid "Ask your group maintainer to set up a group Runner."
msgstr "Solicite a um mantenedor do grupo para configurar um Runner de grupo."
msgid "Assertion consumer service URL"
@@ -1646,7 +1646,7 @@ msgid "ClusterIntegration|Environment scope"
msgstr "Escopo de ambiente"
msgid "ClusterIntegration|Every new Google Cloud Platform (GCP) account receives $300 in credit upon %{sign_up_link}. In partnership with Google, GitLab is able to offer an additional $200 for both new and existing GCP accounts to get started with GitLab's Google Kubernetes Engine Integration."
-msgstr "Cada nova conta no Google Cloud Plataform (GCP) recebe US$300 em créditos por se %{sign_up_link}. Em parceria com o Google, o Gitlab pode oferecer um adicional de US$200 para novas contas do GCP para começar a usar a integração GKE do GitLab."
+msgstr "Cada nova conta no Google Cloud Plataform (GCP) recebe US$300 em créditos por se %{sign_up_link}. Em parceria com o Google, o GitLab pode oferecer um adicional de US$200 para novas contas do GCP para começar a usar a integração GKE do GitLab."
msgid "ClusterIntegration|Fetching machine types"
msgstr "Recuperando tipos de máquina"
@@ -1661,7 +1661,7 @@ msgid "ClusterIntegration|GitLab Integration"
msgstr "Integração GitLab"
msgid "ClusterIntegration|GitLab Runner"
-msgstr "Gitlab Runner"
+msgstr "GitLab Runner"
msgid "ClusterIntegration|GitLab Runner connects to this project's repository and executes CI/CD jobs, pushing results back and deploying, applications to production."
msgstr ""
@@ -2127,10 +2127,10 @@ msgid "ContainerRegistry|Created"
msgstr "Criado"
msgid "ContainerRegistry|First log in to GitLab&rsquo;s Container Registry using your GitLab username and password. If you have %{link_2fa} you need to use a %{link_token}:"
-msgstr "Primeiro faça login no Container Registry do Gitlab usando seu nome de usuário e senha. Se você tiver %{link_2fa}, será necessário usar um %{link_token}:"
+msgstr "Primeiro faça login no Container Registry do GitLab usando seu nome de usuário e senha. Se você tiver %{link_2fa}, será necessário usar um %{link_token}:"
msgid "ContainerRegistry|GitLab supports up to 3 levels of image names. The following examples of images are valid for your project:"
-msgstr "Gitlab suporta até três níveis de nomes de imagens. Os exemplos a seguir são de imagens válidas para seu projeto:"
+msgstr "GitLab suporta até três níveis de nomes de imagens. Os exemplos a seguir são de imagens válidas para seu projeto:"
msgid "ContainerRegistry|How to use the Container Registry"
msgstr "Como usar o Container Registry"
@@ -2163,7 +2163,7 @@ msgid "ContainerRegistry|Use different image names"
msgstr "Use nomes de imagem diferentes"
msgid "ContainerRegistry|With the Docker Container Registry integrated into GitLab, every project can have its own space to store its Docker images."
-msgstr "Com o Container Registry do Docker integrado ao Gitlab, todo projeto pode ter seu próprio espaço para guardar suas imagens."
+msgstr "Com o Container Registry do Docker integrado ao GitLab, todo projeto pode ter seu próprio espaço para guardar suas imagens."
msgid "ContainerRegistry|You can also use a %{deploy_token} for read-only access to the registry images."
msgstr "Você pode usar também um %{deploy_token} para acesso somente-leitura às imagens do registry."
@@ -3652,7 +3652,7 @@ msgid "Google Takeout"
msgstr "Google Takeout"
msgid "Google authentication is not %{link_to_documentation}. Ask your GitLab administrator if you want to use this service."
-msgstr "Autenticação do Google não está %{link_to_documentation}. Peça ao administrador do Gitlab se você deseja usar esse serviço."
+msgstr "Autenticação do Google não está %{link_to_documentation}. Peça ao administrador do GitLab se você deseja usar esse serviço."
msgid "Got it!"
msgstr "Entendi!"
@@ -5812,7 +5812,7 @@ msgid "PrometheusService|Automatically deploy and configure Prometheus on your c
msgstr "Fazer deploy automático e configurar o Prometheus nos seus clusters para monitorar o ambiente do seu projeto"
msgid "PrometheusService|By default, Prometheus listens on ‘http://localhost:9090’. It’s not recommended to change the default address and port as this might affect or conflict with other services running on the GitLab server."
-msgstr "Por padrão, Prometheus escuta em 'http://localhost:9090'. Não é recomendado mudar o endereço padrão e sua porta, porque pode conflitar com outros serviços que estão executando no sevidor do Gitlab."
+msgstr "Por padrão, Prometheus escuta em 'http://localhost:9090'. Não é recomendado mudar o endereço padrão e sua porta, porque pode conflitar com outros serviços que estão executando no sevidor do GitLab."
msgid "PrometheusService|Common metrics"
msgstr "Métricas comuns"
@@ -6510,10 +6510,10 @@ msgstr "defina uma senha"
msgid "Settings"
msgstr "Configurações"
-msgid "Setup a %{type} Runner manually"
+msgid "Set up a %{type} Runner manually"
msgstr ""
-msgid "Setup a specific Runner automatically"
+msgid "Set up a specific Runner automatically"
msgstr "Configurar um Runner específico automaticamente"
msgid "Share"
@@ -8108,7 +8108,7 @@ msgstr "Você só pode editar arquivos quando estiver em um branch"
msgid "You can resolve the merge conflict using either the Interactive mode, by choosing %{use_ours} or %{use_theirs} buttons, or by editing the files directly. Commit these changes into %{branch_name}"
msgstr "Você pode resolver o conflito de merge usando o modo Interativo, escolhendo os botões %{use_ours} ou %{use_theirs} ou editando os arquivos diretamente. Confirme essas alterações em %{branch_name}"
-msgid "You can setup jobs to only use Runners with specific tags. Separate tags with commas."
+msgid "You can set up jobs to only use Runners with specific tags. Separate tags with commas."
msgstr ""
msgid "You cannot write to a read-only secondary GitLab Geo instance. Please use %{link_to_primary_node} instead."
diff --git a/locale/ro_RO/gitlab.po b/locale/ro_RO/gitlab.po
index 4ac7b482d51..f333a5aeba1 100644
--- a/locale/ro_RO/gitlab.po
+++ b/locale/ro_RO/gitlab.po
@@ -342,7 +342,7 @@ msgstr ""
msgid "<strong>Removes</strong> source branch"
msgstr ""
-msgid "A 'Runner' is a process which runs a job. You can setup as many Runners as you need."
+msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr ""
msgid "A collection of graphs regarding Continuous Integration"
@@ -789,7 +789,7 @@ msgstr ""
msgid "Ascending"
msgstr ""
-msgid "Ask your group maintainer to setup a group Runner."
+msgid "Ask your group maintainer to set up a group Runner."
msgstr ""
msgid "Assertion consumer service URL"
@@ -6558,10 +6558,10 @@ msgstr ""
msgid "Settings"
msgstr ""
-msgid "Setup a %{type} Runner manually"
+msgid "Set up a %{type} Runner manually"
msgstr ""
-msgid "Setup a specific Runner automatically"
+msgid "Set up a specific Runner automatically"
msgstr ""
msgid "Share"
@@ -8160,7 +8160,7 @@ msgstr ""
msgid "You can resolve the merge conflict using either the Interactive mode, by choosing %{use_ours} or %{use_theirs} buttons, or by editing the files directly. Commit these changes into %{branch_name}"
msgstr ""
-msgid "You can setup jobs to only use Runners with specific tags. Separate tags with commas."
+msgid "You can set up jobs to only use Runners with specific tags. Separate tags with commas."
msgstr ""
msgid "You cannot write to a read-only secondary GitLab Geo instance. Please use %{link_to_primary_node} instead."
diff --git a/locale/ru/gitlab.po b/locale/ru/gitlab.po
index 8fd8001f30c..75a291be637 100644
--- a/locale/ru/gitlab.po
+++ b/locale/ru/gitlab.po
@@ -376,7 +376,7 @@ msgstr ""
msgid "<strong>Removes</strong> source branch"
msgstr "<strong>УдалÑет</strong> иÑходную ветку"
-msgid "A 'Runner' is a process which runs a job. You can setup as many Runners as you need."
+msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr "«Runner» - Ñто процеÑÑ, который выполнÑет задание (обработчиков заданий). Ð’Ñ‹ можете наÑтроить Ñтолько таких процеÑÑов, Ñколько вам нужно."
msgid "A collection of graphs regarding Continuous Integration"
@@ -823,7 +823,7 @@ msgstr "Ðртефакты"
msgid "Ascending"
msgstr ""
-msgid "Ask your group maintainer to setup a group Runner."
+msgid "Ask your group maintainer to set up a group Runner."
msgstr ""
msgid "Assertion consumer service URL"
@@ -6606,10 +6606,10 @@ msgstr "уÑтановите пароль"
msgid "Settings"
msgstr "ÐаÑтройки"
-msgid "Setup a %{type} Runner manually"
+msgid "Set up a %{type} Runner manually"
msgstr ""
-msgid "Setup a specific Runner automatically"
+msgid "Set up a specific Runner automatically"
msgstr "ÐаÑтроить конкретный обработчик заданий автоматичеÑки"
msgid "Share"
@@ -6884,7 +6884,7 @@ msgid "Specify an e-mail address regex pattern to identify default internal user
msgstr ""
msgid "Specify the following URL during the Runner setup:"
-msgstr "Укажите Ñледующий URL во Ð²Ñ€ÐµÐ¼Ñ Ð½Ð°Ñтройки Gitlab Runner:"
+msgstr "Укажите Ñледующий URL во Ð²Ñ€ÐµÐ¼Ñ Ð½Ð°Ñтройки GitLab Runner:"
msgid "Squash commits"
msgstr ""
@@ -8212,7 +8212,7 @@ msgstr ""
msgid "You can resolve the merge conflict using either the Interactive mode, by choosing %{use_ours} or %{use_theirs} buttons, or by editing the files directly. Commit these changes into %{branch_name}"
msgstr ""
-msgid "You can setup jobs to only use Runners with specific tags. Separate tags with commas."
+msgid "You can set up jobs to only use Runners with specific tags. Separate tags with commas."
msgstr ""
msgid "You cannot write to a read-only secondary GitLab Geo instance. Please use %{link_to_primary_node} instead."
diff --git a/locale/sq_AL/gitlab.po b/locale/sq_AL/gitlab.po
index 6fe5001d729..762d4ef53a7 100644
--- a/locale/sq_AL/gitlab.po
+++ b/locale/sq_AL/gitlab.po
@@ -308,7 +308,7 @@ msgstr ""
msgid "<strong>Removes</strong> source branch"
msgstr ""
-msgid "A 'Runner' is a process which runs a job. You can setup as many Runners as you need."
+msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr ""
msgid "A collection of graphs regarding Continuous Integration"
@@ -755,7 +755,7 @@ msgstr ""
msgid "Ascending"
msgstr ""
-msgid "Ask your group maintainer to setup a group Runner."
+msgid "Ask your group maintainer to set up a group Runner."
msgstr ""
msgid "Assertion consumer service URL"
@@ -6510,10 +6510,10 @@ msgstr ""
msgid "Settings"
msgstr ""
-msgid "Setup a %{type} Runner manually"
+msgid "Set up a %{type} Runner manually"
msgstr ""
-msgid "Setup a specific Runner automatically"
+msgid "Set up a specific Runner automatically"
msgstr ""
msgid "Share"
@@ -8108,7 +8108,7 @@ msgstr ""
msgid "You can resolve the merge conflict using either the Interactive mode, by choosing %{use_ours} or %{use_theirs} buttons, or by editing the files directly. Commit these changes into %{branch_name}"
msgstr ""
-msgid "You can setup jobs to only use Runners with specific tags. Separate tags with commas."
+msgid "You can set up jobs to only use Runners with specific tags. Separate tags with commas."
msgstr ""
msgid "You cannot write to a read-only secondary GitLab Geo instance. Please use %{link_to_primary_node} instead."
diff --git a/locale/tr_TR/gitlab.po b/locale/tr_TR/gitlab.po
index a3dd9cb738e..e7e44caf077 100644
--- a/locale/tr_TR/gitlab.po
+++ b/locale/tr_TR/gitlab.po
@@ -308,7 +308,7 @@ msgstr ""
msgid "<strong>Removes</strong> source branch"
msgstr ""
-msgid "A 'Runner' is a process which runs a job. You can setup as many Runners as you need."
+msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr ""
msgid "A collection of graphs regarding Continuous Integration"
@@ -755,7 +755,7 @@ msgstr ""
msgid "Ascending"
msgstr ""
-msgid "Ask your group maintainer to setup a group Runner."
+msgid "Ask your group maintainer to set up a group Runner."
msgstr ""
msgid "Assertion consumer service URL"
@@ -6510,10 +6510,10 @@ msgstr ""
msgid "Settings"
msgstr ""
-msgid "Setup a %{type} Runner manually"
+msgid "Set up a %{type} Runner manually"
msgstr ""
-msgid "Setup a specific Runner automatically"
+msgid "Set up a specific Runner automatically"
msgstr ""
msgid "Share"
@@ -8108,7 +8108,7 @@ msgstr ""
msgid "You can resolve the merge conflict using either the Interactive mode, by choosing %{use_ours} or %{use_theirs} buttons, or by editing the files directly. Commit these changes into %{branch_name}"
msgstr ""
-msgid "You can setup jobs to only use Runners with specific tags. Separate tags with commas."
+msgid "You can set up jobs to only use Runners with specific tags. Separate tags with commas."
msgstr ""
msgid "You cannot write to a read-only secondary GitLab Geo instance. Please use %{link_to_primary_node} instead."
diff --git a/locale/uk/gitlab.po b/locale/uk/gitlab.po
index 2f965fc0ff0..7757f421b1f 100644
--- a/locale/uk/gitlab.po
+++ b/locale/uk/gitlab.po
@@ -376,7 +376,7 @@ msgstr "<strong>%{pushes}</strong> відправок (push), більше ніÐ
msgid "<strong>Removes</strong> source branch"
msgstr "<strong>ВидалÑÑ”</strong> гілку-джерело"
-msgid "A 'Runner' is a process which runs a job. You can setup as many Runners as you need."
+msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr "'Runner' — це процеÑ, Ñкий виконує завданнÑ. Ви можете Ñтворити потрібну кількіÑÑ‚ÑŒ Runner'ів."
msgid "A collection of graphs regarding Continuous Integration"
@@ -431,7 +431,7 @@ msgid "Access to failing storages has been temporarily disabled to allow the mou
msgstr "ДоÑтуп до Ñховищ, що вийшли з ладу, тимчаÑово прибраний Ð·Ð°Ð´Ð»Ñ Ð²Ñ–Ð´Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ð¼Ð¾Ð½Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ. ПіÑÐ»Ñ Ð²Ð¸Ñ€Ñ–ÑˆÐµÐ½Ð½Ñ Ð¿Ñ€Ð¾Ð±Ð»ÐµÐ¼Ð¸ обнуліть інформацію Ñховища Ð´Ð»Ñ Ð²Ñ–Ð´Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ð´Ð¾Ñтупу."
msgid "Access your runner token, customize your pipeline configuration, and view your pipeline status and coverage report."
-msgstr "Отримайте доÑтуп до Gitlab Runner токену, налаштуйте конфігурацію конвеєра та переглÑньте його ÑтатуÑ, а також звіт про покриттÑ."
+msgstr "Отримайте доÑтуп до GitLab Runner токену, налаштуйте конфігурацію конвеєра та переглÑньте його ÑтатуÑ, а також звіт про покриттÑ."
msgid "Account"
msgstr "Обліковий запиÑ"
@@ -614,7 +614,7 @@ msgid "An application called %{link_to_client} is requesting access to your GitL
msgstr "Додаток під назвою %{link_to_client} запитує доÑтуп до вашого GitLab аккаунту."
msgid "An empty GitLab User field will add the FogBugz user's full name (e.g. \"By John Smith\") in the description of all issues and comments. It will also associate and/or assign these issues and comments with the project creator."
-msgstr "Порожнє поле Gitlab-кориÑтувача буде заповнено іменем кориÑтувача з FogBugz (наприклад \"John Smith\") в опиÑÑ– вÑÑ–Ñ… проблем та коментарів. Крім того ці проблеми та коментарі будуть аÑоційовані з та/або призначені на автора проекту."
+msgstr "Порожнє поле GitLab-кориÑтувача буде заповнено іменем кориÑтувача з FogBugz (наприклад \"John Smith\") в опиÑÑ– вÑÑ–Ñ… проблем та коментарів. Крім того ці проблеми та коментарі будуть аÑоційовані з та/або призначені на автора проекту."
msgid "An error accured whilst committing your changes."
msgstr "ТрапилаÑÑ Ð¿Ð¾Ð¼Ð¸Ð»ÐºÐ° при коміті ваших змін."
@@ -823,7 +823,7 @@ msgstr "Ðртефакти"
msgid "Ascending"
msgstr "За зроÑтаннÑм"
-msgid "Ask your group maintainer to setup a group Runner."
+msgid "Ask your group maintainer to set up a group Runner."
msgstr "ПопроÑÑ–Ñ‚ÑŒ керівника групи, щоб налаштувати груповий Runner."
msgid "Assertion consumer service URL"
@@ -3667,7 +3667,7 @@ msgid "GitLab Geo"
msgstr "GitLab Geo"
msgid "GitLab Group Runners can execute code for all the projects in this group."
-msgstr "Групові Runner'и Gitlab можуть виконувати код Ð´Ð»Ñ ÑƒÑÑ–Ñ… проектів у цій групі."
+msgstr "Групові Runner'и GitLab можуть виконувати код Ð´Ð»Ñ ÑƒÑÑ–Ñ… проектів у цій групі."
msgid "GitLab Import"
msgstr "Імпорт з GitLab"
@@ -6541,7 +6541,7 @@ msgid "Select the custom project template source group."
msgstr ""
msgid "Selecting a GitLab user will add a link to the GitLab user in the descriptions of issues and comments (e.g. \"By <a href=\"#\">@johnsmith</a>\"). It will also associate and/or assign these issues and comments with the selected user."
-msgstr "При виборі кориÑтувача Gitlab поÑÐ¸Ð»Ð°Ð½Ð½Ñ Ð½Ð° нього буде додане до опиÑу проблем та коментарів (напр. \"<a href=\"#\"> @johnsmith</a>\"). Також це призведе до аÑоціації та/або Ð¿Ñ€Ð¸Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ñ†Ð¸Ñ… проблем та коментарів на вибраного кориÑтувача."
+msgstr "При виборі кориÑтувача GitLab поÑÐ¸Ð»Ð°Ð½Ð½Ñ Ð½Ð° нього буде додане до опиÑу проблем та коментарів (напр. \"<a href=\"#\"> @johnsmith</a>\"). Також це призведе до аÑоціації та/або Ð¿Ñ€Ð¸Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ñ†Ð¸Ñ… проблем та коментарів на вибраного кориÑтувача."
msgid "Selective synchronization"
msgstr "Вибіркова ÑинхронізаціÑ"
@@ -6606,10 +6606,10 @@ msgstr "вÑтановити пароль"
msgid "Settings"
msgstr "ÐалаштуваннÑ"
-msgid "Setup a %{type} Runner manually"
+msgid "Set up a %{type} Runner manually"
msgstr ""
-msgid "Setup a specific Runner automatically"
+msgid "Set up a specific Runner automatically"
msgstr "Ðвтоматично налаштувати Ñпецифічний runner"
msgid "Share"
@@ -7149,7 +7149,7 @@ msgid "The number of attempts GitLab will make to access a storage."
msgstr "КількіÑÑ‚ÑŒ Ñпроб, Ñкі зробить GitLab Ð´Ð»Ñ Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ð½Ð½Ñ Ð´Ð¾Ñтупу до Ñховища даних."
msgid "The number of failures after which GitLab will completely prevent access to the storage. The number of failures can be reset in the admin interface: %{link_to_health_page} or using the %{api_documentation_link}."
-msgstr "КількіÑÑ‚ÑŒ збоїв піÑÐ»Ñ Ñ‡Ð¾Ð³Ð¾ Gitlab повніÑÑ‚ÑŽ заблокує доÑтуп до Ñховища данних. Лічильник кількоÑÑ‚Ñ– збоїв може бути Ñкинутий в інтерфейÑÑ– адмініÑтратора %{link_to_health_page}, або через %{api_documentation_link}."
+msgstr "КількіÑÑ‚ÑŒ збоїв піÑÐ»Ñ Ñ‡Ð¾Ð³Ð¾ GitLab повніÑÑ‚ÑŽ заблокує доÑтуп до Ñховища данних. Лічильник кількоÑÑ‚Ñ– збоїв може бути Ñкинутий в інтерфейÑÑ– адмініÑтратора %{link_to_health_page}, або через %{api_documentation_link}."
msgid "The passphrase required to decrypt the private key. This is optional and the value is encrypted at rest."
msgstr "Пароль, Ñкий потрібен Ð´Ð»Ñ Ð´ÐµÑˆÐ¸Ñ„Ñ€ÑƒÐ²Ð°Ð½Ð½Ñ Ð¿Ñ€Ð¸Ð²Ð°Ñ‚Ð½Ð¾Ð³Ð¾ ключа. Він Ñ” необов’Ñзковим Ñ– зберігаєтьÑÑ Ñƒ зашифрованому виглÑді."
@@ -7230,7 +7230,7 @@ msgid "The user map is a JSON document mapping the Google Code users that partic
msgstr "Мапа кориÑтувачів — це JSON-документ, Ñкий задає Ñк адреÑи електронної пошти та імена кориÑтувачів Google Code, що приймали учаÑÑ‚ÑŒ у ваших проектах будуть імпортовані у GitLab. Ви можете змінити його шлÑхом зміни значень, що ÑтоÑÑ‚ÑŒ Ñправа від <code>:</code>. Ðе видалÑйте лапки та інші знаки пунктуації, а також не змінюйте адреÑи електронної пошти чи імена кориÑтувачів зліва."
msgid "The user map is a mapping of the FogBugz users that participated on your projects to the way their email address and usernames will be imported into GitLab. You can change this by populating the table below."
-msgstr "Мапа кориÑтувачів — це правила Ñ–Ð¼Ð¿Ð¾Ñ€Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ ÐºÐ¾Ñ€Ð¸Ñтувачів FogBugz, Ñкі приймали учаÑÑ‚ÑŒ у ваших проектах до Gitlab (зокрема Ñ—Ñ… імен та Ð°Ð´Ñ€ÐµÑ ÐµÐ»ÐµÐºÑ‚Ñ€Ð¾Ð½Ð½Ð¾Ñ— пошти). Ви можете вноÑити зміни шлÑхом Ð·Ð°Ð¿Ð¾Ð²Ð½ÐµÐ½Ð½Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ– нижче."
+msgstr "Мапа кориÑтувачів — це правила Ñ–Ð¼Ð¿Ð¾Ñ€Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ ÐºÐ¾Ñ€Ð¸Ñтувачів FogBugz, Ñкі приймали учаÑÑ‚ÑŒ у ваших проектах до GitLab (зокрема Ñ—Ñ… імен та Ð°Ð´Ñ€ÐµÑ ÐµÐ»ÐµÐºÑ‚Ñ€Ð¾Ð½Ð½Ð¾Ñ— пошти). Ви можете вноÑити зміни шлÑхом Ð·Ð°Ð¿Ð¾Ð²Ð½ÐµÐ½Ð½Ñ Ñ‚Ð°Ð±Ð»Ð¸Ñ†Ñ– нижче."
msgid "The value lying at the midpoint of a series of observed values. E.g., between 3, 5, 9, the median is 5. Between 3, 5, 7, 8, the median is (5+7)/2 = 6."
msgstr "Середнє Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð² Ñ€Ñдку. Приклад: між 3, 5, 9, Ñередніми 5, між 3, 5, 7, 8, Ñередніми (5 + 7) / 2 = 6."
@@ -7625,7 +7625,7 @@ msgid "To connect GitHub repositories, you can use a %{personal_access_token_lin
msgstr "Ð”Ð»Ñ Ð¿Ñ–Ð´ÐºÐ»ÑŽÑ‡ÐµÐ½Ð½Ñ Ñ€ÐµÐ¿Ð¾Ð·Ð¸Ñ‚Ð¾Ñ€Ñ–Ñ—Ð² з GitHub, ви можете викориÑтовувати %{personal_access_token_link}. Коли ви Ñтворюватимете ваш перÑональний токен доÑтупу, вам потрібно буде вибрати облаÑÑ‚ÑŒ дії <code>repo</code>, щоб ми могли відобразити ÑпиÑок ваших публічних та приватних репозиторіїв, доÑтупних Ð´Ð»Ñ Ð¿Ñ–Ð´ÐºÐ»ÑŽÑ‡ÐµÐ½Ð½Ñ."
msgid "To connect GitHub repositories, you first need to authorize GitLab to access the list of your GitHub repositories:"
-msgstr "Ð”Ð»Ñ Ð¿Ñ–Ð´ÐºÐ»ÑŽÑ‡ÐµÐ½Ð½Ñ Ñ€ÐµÐ¿Ð¾Ð·Ð¸Ñ‚Ð¾Ñ€Ñ–Ñ—Ð² з GitHub, ви Ñпочатку повинні дозволити Gitlab доÑтуп до ÑпиÑку ваших репозиторіїв на GitHub:"
+msgstr "Ð”Ð»Ñ Ð¿Ñ–Ð´ÐºÐ»ÑŽÑ‡ÐµÐ½Ð½Ñ Ñ€ÐµÐ¿Ð¾Ð·Ð¸Ñ‚Ð¾Ñ€Ñ–Ñ—Ð² з GitHub, ви Ñпочатку повинні дозволити GitLab доÑтуп до ÑпиÑку ваших репозиторіїв на GitHub:"
msgid "To connect an SVN repository, check out %{svn_link}."
msgstr "Ð”Ð»Ñ Ð¿Ñ€Ð¸Ñ”Ð´Ð½Ð°Ð½Ð½Ñ SVN-репозиторію, переглÑньте %{svn_link}."
@@ -7643,7 +7643,7 @@ msgid "To import GitHub repositories, you can use a %{personal_access_token_link
msgstr "Ð”Ð»Ñ Ñ–Ð¼Ð¿Ð¾Ñ€Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ñ€ÐµÐ¿Ð¾Ð·Ð¸Ñ‚Ð¾Ñ€Ñ–Ñ—Ð² з GitHub, ви можете викориÑтовувати %{personal_access_token_link}. Коли ви Ñтворюватимете ваш перÑональний токен доÑтупу, вам потрібно буде вибрати облаÑÑ‚ÑŒ дії <code>repo</code>, щоб ми могли відобразити ÑпиÑок ваших публічних та приватних репозиторіїв, доÑтупних Ð´Ð»Ñ Ð¿Ñ–Ð´ÐºÐ»ÑŽÑ‡ÐµÐ½Ð½Ñ."
msgid "To import GitHub repositories, you first need to authorize GitLab to access the list of your GitHub repositories:"
-msgstr "Ð”Ð»Ñ Ñ–Ð¼Ð¿Ð¾Ñ€Ñ‚Ñƒ репозиторіїв з GitHub, ви Ñпочатку повинні дозволити Gitlab доÑтуп до ÑпиÑку ваших репозиторіїв на GitHub:"
+msgstr "Ð”Ð»Ñ Ñ–Ð¼Ð¿Ð¾Ñ€Ñ‚Ñƒ репозиторіїв з GitHub, ви Ñпочатку повинні дозволити GitLab доÑтуп до ÑпиÑку ваших репозиторіїв на GitHub:"
msgid "To import an SVN repository, check out %{svn_link}."
msgstr "Ð”Ð»Ñ Ñ–Ð¼Ð¿Ð¾Ñ€Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ SVN-репозиторію, переглÑньте %{svn_link}."
@@ -8177,7 +8177,7 @@ msgid "You are going to transfer %{project_full_name} to another owner. Are you
msgstr "Ви збираєтеÑÑ Ð¿ÐµÑ€ÐµÐ´Ð°Ñ‚Ð¸ проект %{project_full_name} іншому влаÑнику. Ви ÐБСОЛЮТÐО впевнені?"
msgid "You are on a read-only GitLab instance."
-msgstr "Ви знаходитеÑÑ Ð½Ð° інÑтанÑÑ– Gitlab \"тільки Ð´Ð»Ñ Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ\"."
+msgstr "Ви знаходитеÑÑ Ð½Ð° інÑтанÑÑ– GitLab \"тільки Ð´Ð»Ñ Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ\"."
msgid "You are on a secondary, <b>read-only</b> Geo node. If you want to make changes, you must visit this page on the %{primary_node}."
msgstr "Ви знаходитеÑÑŒ на вторинному <b>лише Ð´Ð»Ñ Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ</b> Geo-вузлі. Якщо ви хочете внеÑти будь-Ñкі зміни, ви повинні відвідати %{primary_node}."
@@ -8212,7 +8212,7 @@ msgstr "Ви можете редагувати файли, лише перебу
msgid "You can resolve the merge conflict using either the Interactive mode, by choosing %{use_ours} or %{use_theirs} buttons, or by editing the files directly. Commit these changes into %{branch_name}"
msgstr "Ви можете розв’Ñзати цей конфлікт Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ð·Ð° допомогою інтерактивного режиму (викориÑтовуючи кнопки %{use_ours} та %{use_theirs}), або безпоÑередньо редагуючи файли. Закомітити зміни у %{branch_name}"
-msgid "You can setup jobs to only use Runners with specific tags. Separate tags with commas."
+msgid "You can set up jobs to only use Runners with specific tags. Separate tags with commas."
msgstr ""
msgid "You cannot write to a read-only secondary GitLab Geo instance. Please use %{link_to_primary_node} instead."
diff --git a/locale/zh_CN/gitlab.po b/locale/zh_CN/gitlab.po
index 969ce34ac5c..5f72eee83d8 100644
--- a/locale/zh_CN/gitlab.po
+++ b/locale/zh_CN/gitlab.po
@@ -274,7 +274,7 @@ msgstr "<strong>%{pushes}</strong> 个推é€ï¼Œè¶…å‰ <strong>%{people}</strong>
msgid "<strong>Removes</strong> source branch"
msgstr "<strong>删除</strong>æºåˆ†æ”¯"
-msgid "A 'Runner' is a process which runs a job. You can setup as many Runners as you need."
+msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr "Runner是一个执行任务的进程。您å¯ä»¥æ ¹æ®éœ€è¦é…置任æ„æ•°é‡çš„Runner。"
msgid "A collection of graphs regarding Continuous Integration"
@@ -721,7 +721,7 @@ msgstr "产物"
msgid "Ascending"
msgstr "å‡åºæŽ’列"
-msgid "Ask your group maintainer to setup a group Runner."
+msgid "Ask your group maintainer to set up a group Runner."
msgstr "请群组维护者é…置一个群组级 Runner。"
msgid "Assertion consumer service URL"
@@ -2078,7 +2078,7 @@ msgid "Connect repositories from GitHub"
msgstr "从 Github 中导入代ç ä»“库"
msgid "Connect your external repositories, and CI/CD pipelines will run for new commits. A GitLab project will be created with only CI/CD features enabled."
-msgstr "连接外部仓库åŽï¼Œæ–°æ交将会å¯åŠ¨CI/CDæµæ°´çº¿ã€‚ä»…å¯ç”¨CI/CD功能的Gitlab项目将会被创建。"
+msgstr "连接外部仓库åŽï¼Œæ–°æ交将会å¯åŠ¨CI/CDæµæ°´çº¿ã€‚ä»…å¯ç”¨CI/CD功能的GitLab项目将会被创建。"
msgid "Connecting..."
msgstr "正在连接..."
@@ -3550,7 +3550,7 @@ msgid "GitLab Geo"
msgstr "GitLab Geo"
msgid "GitLab Group Runners can execute code for all the projects in this group."
-msgstr "Gitlab群组Runnerå¯ä»¥ç”¨æ¥è¿è¡Œç¾¤ç»„内所有项目的代ç ã€‚"
+msgstr "GitLab群组Runnerå¯ä»¥ç”¨æ¥è¿è¡Œç¾¤ç»„内所有项目的代ç ã€‚"
msgid "GitLab Import"
msgstr "GitLab导入"
@@ -6462,10 +6462,10 @@ msgstr "设置密ç "
msgid "Settings"
msgstr "设置"
-msgid "Setup a %{type} Runner manually"
+msgid "Set up a %{type} Runner manually"
msgstr ""
-msgid "Setup a specific Runner automatically"
+msgid "Set up a specific Runner automatically"
msgstr "自动创建专用Runner"
msgid "Share"
@@ -8056,7 +8056,7 @@ msgstr "åªèƒ½åœ¨åˆ†æ”¯ä¸Šç¼–辑文件"
msgid "You can resolve the merge conflict using either the Interactive mode, by choosing %{use_ours} or %{use_theirs} buttons, or by editing the files directly. Commit these changes into %{branch_name}"
msgstr "您å¯ä»¥ä½¿ç”¨äº¤äº’模å¼ï¼Œé€šè¿‡é€‰æ‹© %{use_ours} 或 %{use_theirs} 按钮æ¥è§£å†³åˆå¹¶å†²çªã€‚也å¯ä»¥é€šè¿‡ç›´æŽ¥ç¼–辑文件æ¥è§£å†³åˆå¹¶å†²çªã€‚然åŽå°†è¿™äº›æ›´æ”¹æ交到 %{branch_name}"
-msgid "You can setup jobs to only use Runners with specific tags. Separate tags with commas."
+msgid "You can set up jobs to only use Runners with specific tags. Separate tags with commas."
msgstr ""
msgid "You cannot write to a read-only secondary GitLab Geo instance. Please use %{link_to_primary_node} instead."
diff --git a/locale/zh_HK/gitlab.po b/locale/zh_HK/gitlab.po
index 424ca95d24c..49fbfc224e4 100644
--- a/locale/zh_HK/gitlab.po
+++ b/locale/zh_HK/gitlab.po
@@ -274,7 +274,7 @@ msgstr ""
msgid "<strong>Removes</strong> source branch"
msgstr ""
-msgid "A 'Runner' is a process which runs a job. You can setup as many Runners as you need."
+msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr ""
msgid "A collection of graphs regarding Continuous Integration"
@@ -721,7 +721,7 @@ msgstr ""
msgid "Ascending"
msgstr ""
-msgid "Ask your group maintainer to setup a group Runner."
+msgid "Ask your group maintainer to set up a group Runner."
msgstr ""
msgid "Assertion consumer service URL"
@@ -6462,10 +6462,10 @@ msgstr "設置密碼"
msgid "Settings"
msgstr ""
-msgid "Setup a %{type} Runner manually"
+msgid "Set up a %{type} Runner manually"
msgstr ""
-msgid "Setup a specific Runner automatically"
+msgid "Set up a specific Runner automatically"
msgstr ""
msgid "Share"
@@ -8056,7 +8056,7 @@ msgstr ""
msgid "You can resolve the merge conflict using either the Interactive mode, by choosing %{use_ours} or %{use_theirs} buttons, or by editing the files directly. Commit these changes into %{branch_name}"
msgstr ""
-msgid "You can setup jobs to only use Runners with specific tags. Separate tags with commas."
+msgid "You can set up jobs to only use Runners with specific tags. Separate tags with commas."
msgstr ""
msgid "You cannot write to a read-only secondary GitLab Geo instance. Please use %{link_to_primary_node} instead."
diff --git a/locale/zh_TW/gitlab.po b/locale/zh_TW/gitlab.po
index d7ca7996926..534e1f64ea1 100644
--- a/locale/zh_TW/gitlab.po
+++ b/locale/zh_TW/gitlab.po
@@ -274,7 +274,7 @@ msgstr "æŽ¨é€ <strong>%{pushes}</strong> 個,<strong>%{people}</strong> 個è²
msgid "<strong>Removes</strong> source branch"
msgstr "<strong>刪除</strong>來æºåˆ†æ”¯"
-msgid "A 'Runner' is a process which runs a job. You can setup as many Runners as you need."
+msgid "A 'Runner' is a process which runs a job. You can set up as many Runners as you need."
msgstr "一個「執行器ã€æ˜¯ä¸€å€‹åŸ·è¡Œå·¥ä½œçš„進程。你å¯ä»¥å®‰è£ä½ éœ€è¦çš„多個執行器。"
msgid "A collection of graphs regarding Continuous Integration"
@@ -721,7 +721,7 @@ msgstr "產物"
msgid "Ascending"
msgstr "é †åº"
-msgid "Ask your group maintainer to setup a group Runner."
+msgid "Ask your group maintainer to set up a group Runner."
msgstr "è©¢å•æ‚¨çš„群組維護者以安è£ç¾¤çµ„執行器。"
msgid "Assertion consumer service URL"
@@ -1626,7 +1626,7 @@ msgid "ClusterIntegration|GitLab Integration"
msgstr "GitLab æ•´åˆ"
msgid "ClusterIntegration|GitLab Runner"
-msgstr "Gitlab Runner"
+msgstr "GitLab Runner"
msgid "ClusterIntegration|GitLab Runner connects to this project's repository and executes CI/CD jobs, pushing results back and deploying, applications to production."
msgstr ""
@@ -2090,7 +2090,7 @@ msgid "ContainerRegistry|Created"
msgstr "已建立"
msgid "ContainerRegistry|First log in to GitLab&rsquo;s Container Registry using your GitLab username and password. If you have %{link_2fa} you need to use a %{link_token}:"
-msgstr "請先使用你的 Gitlab 帳號來登入 Gitlab 的 Container Registry。如果你有 %{link_2fa} ,你必須使用 %{link_token}:"
+msgstr "請先使用你的 GitLab 帳號來登入 GitLab 的 Container Registry。如果你有 %{link_2fa} ,你必須使用 %{link_token}:"
msgid "ContainerRegistry|GitLab supports up to 3 levels of image names. The following examples of images are valid for your project:"
msgstr "GitLab 支æ´å¤šé” 3 級的映åƒæª”å稱。以下映åƒæª”範例å°æ‚¨çš„專案有幫助:"
@@ -6462,10 +6462,10 @@ msgstr "設定密碼"
msgid "Settings"
msgstr "設定"
-msgid "Setup a %{type} Runner manually"
+msgid "Set up a %{type} Runner manually"
msgstr ""
-msgid "Setup a specific Runner automatically"
+msgid "Set up a specific Runner automatically"
msgstr "自動設置特定的執行器"
msgid "Share"
@@ -6897,7 +6897,7 @@ msgid "TagsPage|Optionally, add a message to the tag."
msgstr "增加標籤的說明(å¯é¸ï¼‰"
msgid "TagsPage|Optionally, add release notes to the tag. They will be stored in the GitLab database and displayed on the tags page."
-msgstr "增加標籤的發佈說明,這將會被儲存在Gitlab資料庫中,並顯示於標籤é ã€‚(å¯é¸ï¼‰"
+msgstr "增加標籤的發佈說明,這將會被儲存在GitLab資料庫中,並顯示於標籤é ã€‚(å¯é¸ï¼‰"
msgid "TagsPage|Release notes"
msgstr "發佈說明"
@@ -8056,7 +8056,7 @@ msgstr "您åªèƒ½åœ¨åˆ†æ”¯ä¸Šç·¨è¼¯æ–‡ä»¶"
msgid "You can resolve the merge conflict using either the Interactive mode, by choosing %{use_ours} or %{use_theirs} buttons, or by editing the files directly. Commit these changes into %{branch_name}"
msgstr "您å¯ä»¥é€éŽä½¿ç”¨äº’動模å¼é¸æ“‡ %{use_ours} 或 %{use_theirs} 按鈕ã€æˆ–者是直接編輯檔案來解決åˆä½µè¡çªï¼Œä¸¦å°‡é€™äº›è®Šæ›´æ交到 %{branch_name}。"
-msgid "You can setup jobs to only use Runners with specific tags. Separate tags with commas."
+msgid "You can set up jobs to only use Runners with specific tags. Separate tags with commas."
msgstr ""
msgid "You cannot write to a read-only secondary GitLab Geo instance. Please use %{link_to_primary_node} instead."
diff --git a/package.json b/package.json
index 4a479b6fb2a..714bdb285fe 100644
--- a/package.json
+++ b/package.json
@@ -19,7 +19,7 @@
},
"dependencies": {
"@gitlab-org/gitlab-svgs": "^1.29.0",
- "@gitlab-org/gitlab-ui": "^1.5.0",
+ "@gitlab-org/gitlab-ui": "^1.7.1",
"autosize": "^4.0.0",
"axios": "^0.17.1",
"babel-core": "^6.26.3",
@@ -35,7 +35,7 @@
"classlist-polyfill": "^1.2.0",
"clipboard": "^1.7.1",
"codesandbox-api": "^0.0.18",
- "compression-webpack-plugin": "^1.1.11",
+ "compression-webpack-plugin": "^2.0.0",
"core-js": "^2.4.1",
"cropper": "^2.3.0",
"css-loader": "^1.0.0",
@@ -55,7 +55,7 @@
"dropzone": "^4.2.0",
"emoji-unicode-version": "^0.2.1",
"exports-loader": "^0.7.0",
- "file-loader": "^1.1.11",
+ "file-loader": "^2.0.0",
"formdata-polyfill": "^3.0.11",
"fuzzaldrin-plus": "^0.5.0",
"glob": "^7.1.2",
@@ -70,7 +70,7 @@
"katex": "^0.9.0",
"marked": "^0.3.12",
"monaco-editor": "^0.14.3",
- "monaco-editor-webpack-plugin": "^1.5.2",
+ "monaco-editor-webpack-plugin": "^1.5.4",
"mousetrap": "^1.4.6",
"pikaday": "^1.6.1",
"popper.js": "^1.14.3",
@@ -85,47 +85,47 @@
"sortablejs": "^1.7.0",
"sql.js": "^0.4.0",
"stickyfilljs": "^2.0.5",
- "style-loader": "^0.21.0",
+ "style-loader": "^0.23.0",
"svg4everybody": "2.1.9",
"three": "^0.84.0",
"three-orbit-controls": "^82.1.0",
"three-stl-loader": "^1.0.4",
"timeago.js": "^3.0.2",
"underscore": "^1.9.0",
- "url-loader": "^1.0.1",
+ "url-loader": "^1.1.1",
"visibilityjs": "^1.2.4",
- "vue": "^2.5.16",
- "vue-loader": "^15.2.4",
+ "vue": "^2.5.17",
+ "vue-loader": "^15.4.2",
"vue-resource": "^1.5.0",
"vue-router": "^3.0.1",
- "vue-template-compiler": "^2.5.16",
+ "vue-template-compiler": "^2.5.17",
"vue-virtual-scroll-list": "^1.2.5",
"vuex": "^3.0.1",
- "webpack": "^4.16.0",
- "webpack-bundle-analyzer": "^2.13.1",
- "webpack-cli": "^3.0.8",
+ "webpack": "^4.19.1",
+ "webpack-bundle-analyzer": "^3.0.2",
+ "webpack-cli": "^3.1.0",
"webpack-stats-plugin": "^0.2.1",
"worker-loader": "^2.0.0",
"xterm": "^3.5.0"
},
"devDependencies": {
"axios-mock-adapter": "^1.15.0",
- "babel-eslint": "^8.2.3",
- "babel-plugin-istanbul": "^4.1.6",
- "babel-plugin-rewire": "^1.1.0",
+ "babel-eslint": "^9.0.0",
+ "babel-plugin-istanbul": "^5.0.1",
+ "babel-plugin-rewire": "^1.2.0",
"babel-template": "^6.26.0",
"babel-types": "^6.26.0",
"chalk": "^2.4.1",
- "commander": "^2.15.1",
- "eslint": "~4.12.1",
- "eslint-config-airbnb-base": "^12.1.0",
- "eslint-import-resolver-webpack": "^0.10.0",
- "eslint-plugin-filenames": "^1.2.0",
- "eslint-plugin-html": "4.0.3",
- "eslint-plugin-import": "^2.12.0",
- "eslint-plugin-jasmine": "^2.1.0",
- "eslint-plugin-promise": "^3.8.0",
- "eslint-plugin-vue": "^4.5.0",
+ "commander": "^2.18.0",
+ "eslint": "~5.6.0",
+ "eslint-config-airbnb-base": "^13.1.0",
+ "eslint-import-resolver-webpack": "^0.10.1",
+ "eslint-plugin-filenames": "^1.3.2",
+ "eslint-plugin-html": "4.0.5",
+ "eslint-plugin-import": "^2.14.0",
+ "eslint-plugin-jasmine": "^2.10.1",
+ "eslint-plugin-promise": "^4.0.1",
+ "eslint-plugin-vue": "^5.0.0-beta.3",
"gettext-extractor": "^3.3.2",
"gettext-extractor-vue": "^4.0.1",
"ignore": "^3.3.7",
@@ -141,8 +141,8 @@
"karma-mocha-reporter": "^2.2.5",
"karma-sourcemap-loader": "^0.3.7",
"karma-webpack": "^4.0.0-beta.0",
- "nodemon": "^1.18.2",
+ "nodemon": "^1.18.4",
"prettier": "1.12.1",
- "webpack-dev-server": "^3.1.4"
+ "webpack-dev-server": "^3.1.8"
}
}
diff --git a/qa/qa.rb b/qa/qa.rb
index cb3202c8e1c..952084085d5 100644
--- a/qa/qa.rb
+++ b/qa/qa.rb
@@ -57,6 +57,7 @@ module QA
autoload :Wiki, 'qa/factory/resource/wiki'
autoload :File, 'qa/factory/resource/file'
autoload :Fork, 'qa/factory/resource/fork'
+ autoload :SSHKey, 'qa/factory/resource/ssh_key'
end
module Repository
@@ -217,6 +218,7 @@ module QA
module Profile
autoload :PersonalAccessTokens, 'qa/page/profile/personal_access_tokens'
+ autoload :SSHKeys, 'qa/page/profile/ssh_keys'
end
module Issuable
diff --git a/qa/qa/factory/repository/project_push.rb b/qa/qa/factory/repository/project_push.rb
index 4f78098d348..167f47c9141 100644
--- a/qa/qa/factory/repository/project_push.rb
+++ b/qa/qa/factory/repository/project_push.rb
@@ -11,7 +11,9 @@ module QA
factory.output
end
- product(:project) { |factory| factory.project }
+ product :project do |factory|
+ factory.project
+ end
def initialize
@file_name = 'file.txt'
@@ -21,8 +23,8 @@ module QA
@new_branch = true
end
- def repository_uri
- @repository_uri ||= begin
+ def repository_http_uri
+ @repository_http_uri ||= begin
project.visit!
Page::Project::Show.act do
choose_repository_clone_http
@@ -30,6 +32,16 @@ module QA
end
end
end
+
+ def repository_ssh_uri
+ @repository_ssh_uri ||= begin
+ project.visit!
+ Page::Project::Show.act do
+ choose_repository_clone_ssh
+ repository_location.uri
+ end
+ end
+ end
end
end
end
diff --git a/qa/qa/factory/repository/push.rb b/qa/qa/factory/repository/push.rb
index 5b7ebf6c41f..6c5088f1da5 100644
--- a/qa/qa/factory/repository/push.rb
+++ b/qa/qa/factory/repository/push.rb
@@ -5,8 +5,8 @@ module QA
module Repository
class Push < Factory::Base
attr_accessor :file_name, :file_content, :commit_message,
- :branch_name, :new_branch, :output, :repository_uri,
- :user
+ :branch_name, :new_branch, :output, :repository_http_uri,
+ :repository_ssh_uri, :ssh_key, :user
attr_writer :remote_branch
@@ -16,7 +16,8 @@ module QA
@commit_message = "This is a test commit"
@branch_name = 'master'
@new_branch = true
- @repository_uri = ""
+ @repository_http_uri = ""
+ @ssh_key = nil
end
def remote_branch
@@ -31,9 +32,14 @@ module QA
def fabricate!
Git::Repository.perform do |repository|
- repository.uri = repository_uri
+ if ssh_key
+ repository.uri = repository_ssh_uri
+ repository.use_ssh_key(ssh_key)
+ else
+ repository.uri = repository_http_uri
+ repository.use_default_credentials
+ end
- repository.use_default_credentials
username = 'GitLab QA'
email = 'root@gitlab.com'
@@ -63,6 +69,8 @@ module QA
repository.commit(commit_message)
@output = repository.push_changes("#{branch_name}:#{remote_branch}")
+
+ repository.delete_ssh_key
end
end
end
diff --git a/qa/qa/factory/repository/wiki_push.rb b/qa/qa/factory/repository/wiki_push.rb
index fb7c2bb660d..ecc6cc18c88 100644
--- a/qa/qa/factory/repository/wiki_push.rb
+++ b/qa/qa/factory/repository/wiki_push.rb
@@ -16,8 +16,8 @@ module QA
@new_branch = false
end
- def repository_uri
- @repository_uri ||= begin
+ def repository_http_uri
+ @repository_http_uri ||= begin
wiki.visit!
Page::Project::Wiki::Show.act do
go_to_clone_repository
diff --git a/qa/qa/factory/resource/branch.rb b/qa/qa/factory/resource/branch.rb
index bc252bf3148..60539992073 100644
--- a/qa/qa/factory/resource/branch.rb
+++ b/qa/qa/factory/resource/branch.rb
@@ -64,7 +64,7 @@ module QA
end
page.wait(reload: false) do
- !page.first('.btn-create').disabled?
+ !page.first('.btn-success').disabled?
end
page.protect_branch
diff --git a/qa/qa/factory/resource/fork.rb b/qa/qa/factory/resource/fork.rb
index 01969c31438..92050eaba2a 100644
--- a/qa/qa/factory/resource/fork.rb
+++ b/qa/qa/factory/resource/fork.rb
@@ -13,8 +13,43 @@ module QA
product(:user) { |factory| factory.user }
+ def visit_project_with_retry
+ # The user intermittently fails to stay signed in after visiting the
+ # project page. The new user is registered and then signs in and a
+ # screenshot shows that signing in was successful. Then the project
+ # page is visited but a screenshot shows the user is no longer signed
+ # in. It's difficult to reproduce locally but GDK logs don't seem to
+ # show anything unexpected. This method attempts to work around the
+ # problem and capture data to help troubleshoot.
+
+ Capybara::Screenshot.screenshot_and_save_page
+
+ start = Time.now
+
+ while Time.now - start < 20
+ push.project.visit!
+
+ puts "Visited project page"
+ Capybara::Screenshot.screenshot_and_save_page
+
+ return if Page::Menu::Main.act { has_personal_area?(wait: 0) }
+
+ puts "Not signed in. Attempting to sign in again."
+ Capybara::Screenshot.screenshot_and_save_page
+
+ Page::Menu::Main.act { sign_out }
+
+ Page::Main::Login.perform do |login|
+ login.sign_in_using_credentials(user)
+ end
+ end
+
+ raise "Failed to load project page and stay logged in"
+ end
+
def fabricate!
- push.project.visit!
+ visit_project_with_retry
+
Page::Project::Show.act { fork_project }
Page::Project::Fork::New.perform do |fork_new|
diff --git a/qa/qa/factory/resource/kubernetes_cluster.rb b/qa/qa/factory/resource/kubernetes_cluster.rb
index ef2ea72b170..94d7df7128b 100644
--- a/qa/qa/factory/resource/kubernetes_cluster.rb
+++ b/qa/qa/factory/resource/kubernetes_cluster.rb
@@ -36,7 +36,7 @@ module QA
if @install_helm_tiller
Page::Project::Operations::Kubernetes::Show.perform do |page|
- # We must wait a few seconds for permissions to be setup correctly for new cluster
+ # We must wait a few seconds for permissions to be set up correctly for new cluster
sleep 10
# Helm must be installed before everything else
diff --git a/qa/qa/factory/resource/project.rb b/qa/qa/factory/resource/project.rb
index 7fff22b5468..90db26ab3ab 100644
--- a/qa/qa/factory/resource/project.rb
+++ b/qa/qa/factory/resource/project.rb
@@ -20,6 +20,13 @@ module QA
end
end
+ product :repository_http_location do
+ Page::Project::Show.act do
+ choose_repository_clone_http
+ repository_location
+ end
+ end
+
def initialize
@description = 'My awesome project'
end
diff --git a/qa/qa/factory/resource/ssh_key.rb b/qa/qa/factory/resource/ssh_key.rb
new file mode 100644
index 00000000000..6c872f32d16
--- /dev/null
+++ b/qa/qa/factory/resource/ssh_key.rb
@@ -0,0 +1,40 @@
+# frozen_string_literal: true
+
+module QA
+ module Factory
+ module Resource
+ class SSHKey < Factory::Base
+ extend Forwardable
+
+ attr_accessor :title
+ attr_reader :private_key, :public_key, :fingerprint
+ def_delegators :key, :private_key, :public_key, :fingerprint
+
+ product :private_key do |factory|
+ factory.private_key
+ end
+
+ product :title do |factory|
+ factory.title
+ end
+
+ product :fingerprint do |factory|
+ factory.fingerprint
+ end
+
+ def key
+ @key ||= Runtime::Key::RSA.new
+ end
+
+ def fabricate!
+ Page::Menu::Main.act { go_to_profile_settings }
+ Page::Menu::Profile.act { click_ssh_keys }
+
+ Page::Profile::SSHKeys.perform do |page|
+ page.add_key(public_key, title)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/factory/resource/user.rb b/qa/qa/factory/resource/user.rb
index eac2a873bd5..34b52223b2d 100644
--- a/qa/qa/factory/resource/user.rb
+++ b/qa/qa/factory/resource/user.rb
@@ -37,7 +37,10 @@ module QA
product(:password) { |factory| factory.password }
def fabricate!
- Page::Menu::Main.perform { |main| main.sign_out }
+ # Don't try to log-out if we're not logged-in
+ if Page::Menu::Main.act { has_personal_area?(wait: 0) }
+ Page::Menu::Main.perform { |main| main.sign_out }
+ end
if credentials_given?
Page::Main::Login.perform do |login|
diff --git a/qa/qa/git/repository.rb b/qa/qa/git/repository.rb
index faecacd45ec..14cb8125fdb 100644
--- a/qa/qa/git/repository.rb
+++ b/qa/qa/git/repository.rb
@@ -7,6 +7,10 @@ module QA
class Repository
include Scenario::Actable
+ def initialize
+ @ssh_cmd = ""
+ end
+
def self.perform(*args)
Dir.mktmpdir do |dir|
Dir.chdir(dir) { super }
@@ -38,7 +42,7 @@ module QA
end
def clone(opts = '')
- run_and_redact_credentials("git clone #{opts} #{@uri} ./")
+ run_and_redact_credentials(build_git_command("git clone #{opts} #{@uri} ./"))
end
def checkout(branch_name)
@@ -58,6 +62,10 @@ module QA
`git config user.email #{email}`
end
+ def configure_ssh_command(command)
+ @ssh_cmd = "GIT_SSH_COMMAND='#{command}'"
+ end
+
def commit_file(name, contents, message)
add_file(name, contents)
commit(message)
@@ -74,7 +82,7 @@ module QA
end
def push_changes(branch = 'master')
- output, _ = run_and_redact_credentials("git push #{@uri} #{branch}")
+ output, _ = run_and_redact_credentials(build_git_command("git push #{@uri} #{branch}"))
output
end
@@ -83,6 +91,31 @@ module QA
`git log --oneline`.split("\n")
end
+ def use_ssh_key(key)
+ @private_key_file = Tempfile.new("id_#{SecureRandom.hex(8)}")
+ File.binwrite(@private_key_file, key.private_key)
+ File.chmod(0700, @private_key_file)
+
+ @known_hosts_file = Tempfile.new("known_hosts_#{SecureRandom.hex(8)}")
+ keyscan_params = ['-H']
+ keyscan_params << "-p #{@uri.port}" if @uri.port
+ keyscan_params << @uri.host
+ run_and_redact_credentials("ssh-keyscan #{keyscan_params.join(' ')} >> #{@known_hosts_file.path}")
+
+ configure_ssh_command("ssh -i #{@private_key_file.path} -o UserKnownHostsFile=#{@known_hosts_file.path}")
+ end
+
+ def delete_ssh_key
+ return unless @private_key_file
+
+ @private_key_file.close(true)
+ @known_hosts_file.close(true)
+ end
+
+ def build_git_command(command_str)
+ [@ssh_cmd, command_str].compact.join(' ')
+ end
+
private
# Since the remote URL contains the credentials, and git occasionally
diff --git a/qa/qa/page/admin/settings/main.rb b/qa/qa/page/admin/settings/main.rb
index db3387b4557..73034ffe0d8 100644
--- a/qa/qa/page/admin/settings/main.rb
+++ b/qa/qa/page/admin/settings/main.rb
@@ -6,11 +6,11 @@ module QA
include QA::Page::Settings::Common
view 'app/views/admin/application_settings/show.html.haml' do
- element :repository_storage_settings
+ element :terms_settings
end
def expand_repository_storage(&block)
- expand_section(:repository_storage_settings) do
+ expand_section(:terms_settings) do
RepositoryStorage.perform(&block)
end
end
diff --git a/qa/qa/page/base.rb b/qa/qa/page/base.rb
index 30e35bf7abb..a87536671c6 100644
--- a/qa/qa/page/base.rb
+++ b/qa/qa/page/base.rb
@@ -76,6 +76,10 @@ module QA
find_element(name).set(content)
end
+ def has_element?(name)
+ has_css?(element_selector_css(name))
+ end
+
def within_element(name)
page.within(element_selector_css(name)) do
yield
diff --git a/qa/qa/page/group/show.rb b/qa/qa/page/group/show.rb
index 6747f7f10b6..74d20df76ba 100644
--- a/qa/qa/page/group/show.rb
+++ b/qa/qa/page/group/show.rb
@@ -5,14 +5,11 @@ module QA
include Page::Component::GroupsFilter
view 'app/views/groups/show.html.haml' do
- element :new_project_or_subgroup_dropdown, '.new-project-subgroup'
- element :new_project_or_subgroup_dropdown_toggle, '.dropdown-toggle'
- element :new_project_option, /%li.*data:.*value: "new-project"/
- element :new_project_button, /%input.*data:.*action: "new-project"/
- element :new_subgroup_option, /%li.*data:.*value: "new-subgroup"/
-
- # data-value and data-action get modified by JS for subgroup
- element :new_subgroup_button, /%input.*\.js-new-group-child/
+ element :new_project_or_subgroup_dropdown
+ element :new_project_or_subgroup_dropdown_toggle
+ element :new_project_option
+ element :new_subgroup_option
+ element :new_in_group_button
end
view 'app/assets/javascripts/groups/constants.js' do
@@ -24,7 +21,7 @@ module QA
end
def has_new_project_or_subgroup_dropdown?
- page.has_css?(element_selector_css(:new_project_or_subgroup_dropdown))
+ has_element?(:new_project_or_subgroup_dropdown)
end
def has_subgroup?(name)
@@ -36,31 +33,29 @@ module QA
end
def go_to_new_subgroup
- click_new('subgroup')
+ select_kind :new_subgroup_option
- find("input[data-action='new-subgroup']").click
+ click_element :new_in_group_button
end
def go_to_new_project
- click_new('project')
+ select_kind :new_project_option
- find("input[data-action='new-project']").click
+ click_element :new_in_group_button
end
private
- def click_new(kind)
- within '.new-project-subgroup' do
- css = "li[data-value='new-#{kind}']"
-
+ def select_kind(kind)
+ within_element(:new_project_or_subgroup_dropdown) do
# May need to click again because it is possible to click the button quicker than the JS is bound
wait(reload: false) do
- find('.dropdown-toggle').click
+ click_element :new_project_or_subgroup_dropdown_toggle
- page.has_css?(css)
+ has_element?(kind)
end
- find(css).click
+ click_element kind
end
end
end
diff --git a/qa/qa/page/main/login.rb b/qa/qa/page/main/login.rb
index 08cf8da34fd..9b3183ba328 100644
--- a/qa/qa/page/main/login.rb
+++ b/qa/qa/page/main/login.rb
@@ -3,31 +3,32 @@ module QA
module Main
class Login < Page::Base
view 'app/views/devise/passwords/edit.html.haml' do
- element :password_field, 'password_field :password'
- element :password_confirmation, 'password_field :password_confirmation'
- element :change_password_button, 'submit "Change your password"'
+ element :password_field
+ element :password_confirmation
+ element :change_password_button
end
view 'app/views/devise/sessions/_new_base.html.haml' do
- element :login_field, 'text_field :login'
- element :password_field, 'password_field :password'
- element :sign_in_button, 'submit "Sign in"'
+ element :login_field
+ element :password_field
+ element :sign_in_button
end
view 'app/views/devise/sessions/_new_ldap.html.haml' do
- element :username_field, 'text_field_tag :username'
- element :password_field, 'password_field_tag :password'
- element :sign_in_button, 'submit_tag "Sign in"'
+ element :username_field
+ element :password_field
+ element :sign_in_button
end
view 'app/views/devise/shared/_tabs_ldap.html.haml' do
- element :ldap_tab, "link_to server['label']"
- element :standard_tab, "link_to 'Standard'"
+ element :ldap_tab
+ element :standard_tab
+ element :register_tab
end
view 'app/views/devise/shared/_tabs_normal.html.haml' do
- element :sign_in_tab, /nav-link.*login-pane.*Sign in/
- element :register_tab, /nav-link.*register-pane.*Register/
+ element :sign_in_tab
+ element :register_tab
end
def initialize
@@ -35,7 +36,7 @@ module QA
# we need to wait for the instance to start. That said, in some cases
# we are already logged-in so we check both cases here.
wait(max: 500) do
- page.has_css?('.login-page') ||
+ has_css?('.login-page') ||
Page::Menu::Main.act { has_personal_area?(wait: 0) }
end
end
@@ -66,6 +67,8 @@ module QA
end
using_wait_time 0 do
+ set_initial_password_if_present
+
sign_in_using_gitlab_credentials(admin)
end
@@ -76,28 +79,45 @@ module QA
'/users/sign_in'
end
+ def has_sign_in_tab?
+ has_element?(:sign_in_tab)
+ end
+
+ def has_ldap_tab?
+ has_element?(:ldap_tab)
+ end
+
+ def has_standard_tab?
+ has_element?(:standard_tab)
+ end
+
def sign_in_tab?
- page.has_button?('Sign in')
+ has_css?(".active", text: 'Sign in')
end
def ldap_tab?
- page.has_link?('LDAP')
+ has_css?(".active", text: 'LDAP')
+ end
+
+ def standard_tab?
+ has_css?(".active", text: 'Standard')
end
def switch_to_sign_in_tab
- click_on 'Sign in'
+ click_element :sign_in_tab
end
def switch_to_register_tab
- click_on 'Register'
+ set_initial_password_if_present
+ click_element :register_tab
end
def switch_to_ldap_tab
- click_on 'LDAP'
+ click_element :ldap_tab
end
def switch_to_standard_tab
- click_on 'Standard'
+ click_element :standard_tab
end
private
@@ -105,26 +125,26 @@ module QA
def sign_in_using_ldap_credentials
switch_to_ldap_tab
- fill_in :username, with: Runtime::User.ldap_username
- fill_in :password, with: Runtime::User.ldap_password
- click_button 'Sign in'
+ fill_element :username_field, Runtime::User.ldap_username
+ fill_element :password_field, Runtime::User.ldap_password
+ click_element :sign_in_button
end
def sign_in_using_gitlab_credentials(user)
- switch_to_sign_in_tab unless sign_in_tab?
- switch_to_standard_tab if ldap_tab?
+ switch_to_sign_in_tab if has_sign_in_tab?
+ switch_to_standard_tab if has_standard_tab?
- fill_in :user_login, with: user.username
- fill_in :user_password, with: user.password
- click_button 'Sign in'
+ fill_element :login_field, user.username
+ fill_element :password_field, user.password
+ click_element :sign_in_button
end
def set_initial_password_if_present
- return unless page.has_content?('Change your password')
+ return unless has_content?('Change your password')
- fill_in :user_password, with: Runtime::User.password
- fill_in :user_password_confirmation, with: Runtime::User.password
- click_button 'Change your password'
+ fill_element :password_field, Runtime::User.password
+ fill_element :password_confirmation, Runtime::User.password
+ click_element :change_password_button
end
end
end
diff --git a/qa/qa/page/main/sign_up.rb b/qa/qa/page/main/sign_up.rb
index 33ab56236f4..64cd395de78 100644
--- a/qa/qa/page/main/sign_up.rb
+++ b/qa/qa/page/main/sign_up.rb
@@ -19,7 +19,7 @@ module QA
fill_in :new_user_password, with: user.password
click_button 'Register'
- Page::Menu::Main.act { has_personal_area? }
+ Page::Menu::Main.act { assert_has_personal_area }
end
end
end
diff --git a/qa/qa/page/menu/main.rb b/qa/qa/page/menu/main.rb
index 36e7285f7b7..2ae86bbc7dc 100644
--- a/qa/qa/page/menu/main.rb
+++ b/qa/qa/page/menu/main.rb
@@ -61,8 +61,13 @@ module QA
end
def has_personal_area?(wait: Capybara.default_max_wait_time)
- # No need to wait, either we're logged-in, or not.
- using_wait_time(wait) { page.has_selector?('.qa-user-avatar') }
+ using_wait_time(wait) do
+ page.has_selector?(element_selector_css(:user_avatar))
+ end
+ end
+
+ def assert_has_personal_area
+ raise "Failed to sign in" unless has_personal_area?
end
private
diff --git a/qa/qa/page/menu/profile.rb b/qa/qa/page/menu/profile.rb
index 95e88d863e4..7e24fa85c33 100644
--- a/qa/qa/page/menu/profile.rb
+++ b/qa/qa/page/menu/profile.rb
@@ -6,6 +6,7 @@ module QA
element :access_token_link, 'link_to profile_personal_access_tokens_path'
element :access_token_title, 'Access Tokens'
element :top_level_items, '.sidebar-top-level-items'
+ element :ssh_keys, 'SSH Keys'
end
def click_access_tokens
@@ -14,6 +15,12 @@ module QA
end
end
+ def click_ssh_keys
+ within_sidebar do
+ click_link('SSH Keys')
+ end
+ end
+
private
def within_sidebar
diff --git a/qa/qa/page/menu/side.rb b/qa/qa/page/menu/side.rb
index 354ccec2a5a..a1eedfea42e 100644
--- a/qa/qa/page/menu/side.rb
+++ b/qa/qa/page/menu/side.rb
@@ -6,6 +6,7 @@ module QA
element :settings_item
element :settings_link, 'link_to edit_project_path'
element :repository_link, "title: _('Repository')"
+ element :link_pipelines
element :pipelines_settings_link, "title: _('CI / CD')"
element :operations_kubernetes_link, "title: _('Kubernetes')"
element :issues_link, /link_to.*shortcuts-issues/
@@ -49,7 +50,7 @@ module QA
def click_ci_cd_pipelines
within_sidebar do
- click_link('CI / CD')
+ click_element :link_pipelines
end
end
diff --git a/qa/qa/page/merge_request/show.rb b/qa/qa/page/merge_request/show.rb
index c200f14f4fb..d9254d89541 100644
--- a/qa/qa/page/merge_request/show.rb
+++ b/qa/qa/page/merge_request/show.rb
@@ -5,6 +5,9 @@ module QA
view 'app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue' do
element :merge_button
element :fast_forward_message, 'Fast-forward merge without a merge commit'
+ element :merge_moment_dropdown
+ element :merge_when_pipeline_succeeds_option
+ element :merge_immediately_option
end
view 'app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merged.vue' do
@@ -16,7 +19,7 @@ module QA
element :no_fast_forward_message, 'Fast-forward merge is not possible'
end
- view 'app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_squash_before_merge.vue' do
+ view 'app/assets/javascripts/vue_merge_request_widget/components/states/squash_before_merge.vue' do
element :squash_checkbox
end
@@ -27,7 +30,20 @@ module QA
def has_merge_button?
refresh
- has_selector?('.accept-merge-request')
+ has_css?(element_selector_css(:merge_button))
+ end
+
+ def has_merge_options?
+ has_css?(element_selector_css(:merge_moment_dropdown))
+ end
+
+ def merge_immediately
+ if has_merge_options?
+ click_element :merge_moment_dropdown
+ click_element :merge_immediately_option
+ else
+ click_element :merge_button
+ end
end
def rebase!
@@ -59,7 +75,7 @@ module QA
!first(element_selector_css(:merge_button)).disabled?
end
- click_element :merge_button
+ merge_immediately
wait(reload: false) do
has_text?('The changes were merged into')
diff --git a/qa/qa/page/profile/ssh_keys.rb b/qa/qa/page/profile/ssh_keys.rb
new file mode 100644
index 00000000000..ce1813b14d0
--- /dev/null
+++ b/qa/qa/page/profile/ssh_keys.rb
@@ -0,0 +1,34 @@
+# frozen_string_literal: true
+
+module QA
+ module Page
+ module Profile
+ class SSHKeys < Page::Base
+ view 'app/views/profiles/keys/_form.html.haml' do
+ element :key_title_field
+ element :key_public_key_field
+ element :add_key_button
+ end
+
+ view 'app/views/profiles/keys/_key_details.html.haml' do
+ element :delete_key_button
+ end
+
+ def add_key(public_key, title)
+ fill_element :key_public_key_field, public_key
+ fill_element :key_title_field, title
+
+ click_element :add_key_button
+ end
+
+ def remove_key(title)
+ click_link(title)
+
+ accept_alert do
+ click_element :delete_key_button
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/page/project/activity.rb b/qa/qa/page/project/activity.rb
index 0196922c889..a0500b4d31a 100644
--- a/qa/qa/page/project/activity.rb
+++ b/qa/qa/page/project/activity.rb
@@ -3,7 +3,7 @@ module QA
module Project
class Activity < Page::Base
view 'app/views/shared/_event_filter.html.haml' do
- element :push_events, "event_filter_link EventFilter.push, _('Push events')"
+ element :push_events, "event_filter_link EventFilter::PUSH, _('Push events')"
end
def go_to_push_events
diff --git a/qa/qa/specs/features/browser_ui/1_manage/login/register_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/login/register_spec.rb
new file mode 100644
index 00000000000..478a5cb9c4c
--- /dev/null
+++ b/qa/qa/specs/features/browser_ui/1_manage/login/register_spec.rb
@@ -0,0 +1,30 @@
+# frozen_string_literal: true
+
+module QA
+ shared_examples 'registration and login' do
+ it 'user registers and logs in' do
+ Runtime::Browser.visit(:gitlab, Page::Main::Login)
+
+ Factory::Resource::User.fabricate!
+
+ # 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
+
+ context :manage do
+ describe 'standard' do
+ it_behaves_like 'registration and login'
+ end
+ end
+
+ context :manage, :orchestrated, :ldap do
+ describe 'while LDAP is enabled' do
+ it_behaves_like 'registration and login'
+ end
+ end
+end
diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/add_ssh_key_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/add_ssh_key_spec.rb
new file mode 100644
index 00000000000..84f663c4866
--- /dev/null
+++ b/qa/qa/specs/features/browser_ui/3_create/repository/add_ssh_key_spec.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+module QA
+ context :create do
+ describe 'SSH keys support' do
+ let(:key_title) { "key for ssh tests #{Time.now.to_f}" }
+
+ it 'user adds and then removes an SSH key' do
+ Runtime::Browser.visit(:gitlab, Page::Main::Login)
+ Page::Main::Login.act { sign_in_using_credentials }
+
+ key = Factory::Resource::SSHKey.fabricate! do |resource|
+ resource.title = key_title
+ end
+
+ expect(page).to have_content("Title: #{key_title}")
+ expect(page).to have_content(key.fingerprint)
+
+ Page::Menu::Main.act { go_to_profile_settings }
+ Page::Menu::Profile.act { click_ssh_keys }
+
+ Page::Profile::SSHKeys.perform do |ssh_keys|
+ ssh_keys.remove_key(key_title)
+ end
+
+ expect(page).not_to have_content("Title: #{key_title}")
+ expect(page).not_to have_content(key.fingerprint)
+ end
+ end
+ end
+end
diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/use_ssh_key_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/use_ssh_key_spec.rb
new file mode 100644
index 00000000000..7c989bfd8cc
--- /dev/null
+++ b/qa/qa/specs/features/browser_ui/3_create/repository/use_ssh_key_spec.rb
@@ -0,0 +1,40 @@
+# frozen_string_literal: true
+
+module QA
+ context :create do
+ describe 'SSH key support' do
+ # Note: If you run this test against GDK make sure you've enabled sshd
+ # See: https://gitlab.com/gitlab-org/gitlab-qa/blob/master/docs/run_qa_against_gdk.md
+
+ let(:key_title) { "key for ssh tests #{Time.now.to_f}" }
+
+ it 'user adds an ssh key and pushes code to the repository' do
+ Runtime::Browser.visit(:gitlab, Page::Main::Login)
+ Page::Main::Login.act { sign_in_using_credentials }
+
+ key = Factory::Resource::SSHKey.fabricate! do |resource|
+ resource.title = key_title
+ end
+
+ Factory::Repository::ProjectPush.fabricate! do |push|
+ push.ssh_key = key
+ push.file_name = 'README.md'
+ push.file_content = '# Test Use SSH Key'
+ push.commit_message = 'Add README.md'
+ end
+
+ Page::Project::Show.act { wait_for_push }
+
+ expect(page).to have_content('README.md')
+ expect(page).to have_content('Test Use SSH Key')
+
+ Page::Menu::Main.act { go_to_profile_settings }
+ Page::Menu::Profile.act { click_ssh_keys }
+
+ Page::Profile::SSHKeys.perform do |ssh_keys|
+ ssh_keys.remove_key(key_title)
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/specs/features/sanity/framework_spec.rb b/qa/qa/specs/features/sanity/framework_spec.rb
index ee9d068eb3a..aae0f0ade71 100644
--- a/qa/qa/specs/features/sanity/framework_spec.rb
+++ b/qa/qa/specs/features/sanity/framework_spec.rb
@@ -6,9 +6,7 @@ module QA
it 'succeeds' do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
- Page::Main::Login.perform do |main_login|
- expect(main_login.sign_in_tab?).to be(true)
- end
+ expect(page).to have_text('Open source software to collaborate on code')
end
end
diff --git a/rubocop/cop/avoid_route_redirect_leading_slash.rb b/rubocop/cop/avoid_route_redirect_leading_slash.rb
new file mode 100644
index 00000000000..7ac1c881269
--- /dev/null
+++ b/rubocop/cop/avoid_route_redirect_leading_slash.rb
@@ -0,0 +1,52 @@
+# frozen_string_literal: true
+
+module RuboCop
+ module Cop
+ # Checks for a leading '/' in route redirects
+ # For more information see: https://gitlab.com/gitlab-org/gitlab-ce/issues/50645
+ #
+ # @example
+ # # bad
+ # root to: redirect('/-/instance/statistics/conversational_development_index')
+ #
+ # # good
+ # root to: redirect('-/instance/statistics/conversational_development_index')
+ #
+
+ class AvoidRouteRedirectLeadingSlash < RuboCop::Cop::Cop
+ MSG = 'Do not use a leading "/" in route redirects'
+
+ def_node_matcher :leading_slash_in_redirect?, <<~PATTERN
+ (send nil? :redirect (str #has_leading_slash?))
+ PATTERN
+
+ def on_send(node)
+ return unless in_routes?(node)
+ return unless leading_slash_in_redirect?(node)
+
+ add_offense(node)
+ end
+
+ def has_leading_slash?(str)
+ str.start_with?("/")
+ end
+
+ def in_routes?(node)
+ path = node.location.expression.source_buffer.name
+ dirname = File.dirname(path)
+ filename = File.basename(path)
+ dirname.end_with?('config/routes') || filename.end_with?('routes.rb')
+ end
+
+ def autocorrect(node)
+ lambda do |corrector|
+ corrector.replace(node.loc.expression, remove_leading_slash(node))
+ end
+ end
+
+ def remove_leading_slash(node)
+ node.source.sub('/', '')
+ end
+ end
+ end
+end
diff --git a/rubocop/cop/gitlab/union.rb b/rubocop/cop/gitlab/union.rb
new file mode 100644
index 00000000000..09541d8af3b
--- /dev/null
+++ b/rubocop/cop/gitlab/union.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+require_relative '../../spec_helpers'
+
+module RuboCop
+ module Cop
+ module Gitlab
+ # Cop that disallows the use of `Gitlab::SQL::Union`, in favour of using
+ # the `FromUnion` module.
+ class Union < RuboCop::Cop::Cop
+ include SpecHelpers
+
+ MSG = 'Use the `FromUnion` concern, instead of using `Gitlab::SQL::Union` directly'
+
+ def_node_matcher :raw_union?, <<~PATTERN
+ (send (const (const (const nil? :Gitlab) :SQL) :Union) :new ...)
+ PATTERN
+
+ def on_send(node)
+ return unless raw_union?(node)
+ return if in_spec?(node)
+
+ add_offense(node, location: :expression)
+ end
+ end
+ end
+ end
+end
diff --git a/rubocop/cop/ruby_interpolation_in_translation.rb b/rubocop/cop/ruby_interpolation_in_translation.rb
index b9411fcfd6c..c431b4a1977 100644
--- a/rubocop/cop/ruby_interpolation_in_translation.rb
+++ b/rubocop/cop/ruby_interpolation_in_translation.rb
@@ -6,7 +6,6 @@ module RuboCop
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 ...)
diff --git a/rubocop/rubocop.rb b/rubocop/rubocop.rb
index 46bd7d3bec6..ff929c7b6ce 100644
--- a/rubocop/rubocop.rb
+++ b/rubocop/rubocop.rb
@@ -3,9 +3,11 @@ require_relative 'cop/gitlab/module_with_instance_variables'
require_relative 'cop/gitlab/predicate_memoization'
require_relative 'cop/gitlab/httparty'
require_relative 'cop/gitlab/finder_with_find_by'
+require_relative 'cop/gitlab/union'
require_relative 'cop/include_sidekiq_worker'
require_relative 'cop/avoid_return_from_blocks'
require_relative 'cop/avoid_break_from_strong_memoize'
+require_relative 'cop/avoid_route_redirect_leading_slash'
require_relative 'cop/line_break_around_conditional_block'
require_relative 'cop/prefer_class_methods_over_module'
require_relative 'cop/migration/add_column'
diff --git a/scripts/review_apps/automated_cleanup.rb b/scripts/review_apps/automated_cleanup.rb
new file mode 100755
index 00000000000..a5f0ec372d8
--- /dev/null
+++ b/scripts/review_apps/automated_cleanup.rb
@@ -0,0 +1,109 @@
+# frozen_string_literal: true
+
+require 'gitlab'
+require_relative File.expand_path('../../lib/quality/helm_client.rb', __dir__)
+require_relative File.expand_path('../../lib/quality/kubernetes_client.rb', __dir__)
+
+class AutomatedCleanup
+ attr_reader :project_path, :gitlab_token, :cleaned_up_releases
+
+ def initialize(project_path: ENV['CI_PROJECT_PATH'], gitlab_token: ENV['GITLAB_BOT_REVIEW_APPS_CLEANUP_TOKEN'])
+ @project_path = project_path
+ @gitlab_token = gitlab_token
+ @cleaned_up_releases = []
+ end
+
+ def gitlab
+ @gitlab ||= begin
+ Gitlab.configure do |config|
+ config.endpoint = 'https://gitlab.com/api/v4'
+ # gitlab-bot's token "GitLab review apps cleanup"
+ config.private_token = gitlab_token
+ end
+
+ Gitlab
+ end
+ end
+
+ def helm
+ @helm ||= Quality::HelmClient.new
+ end
+
+ def kubernetes
+ @kubernetes ||= Quality::KubernetesClient.new
+ end
+
+ def perform_gitlab_environment_cleanup!(days_for_stop:, days_for_delete:)
+ puts "Checking for review apps not updated in the last #{days_for_stop} days..."
+
+ checked_environments = []
+ delete_threshold = threshold_time(days: days_for_delete)
+ stop_threshold = threshold_time(days: days_for_stop)
+ gitlab.deployments(project_path, per_page: 50).auto_paginate do |deployment|
+ next unless deployment.environment.name.start_with?('review/')
+ next if checked_environments.include?(deployment.environment.slug)
+
+ puts
+
+ checked_environments << deployment.environment.slug
+ deployed_at = Time.parse(deployment.created_at)
+
+ if deployed_at < delete_threshold
+ print_release_state(subject: 'Review app', release_name: deployment.environment.slug, release_date: deployment.created_at, action: 'deleting')
+ gitlab.delete_environment(project_path, deployment.environment.id)
+ cleaned_up_releases << deployment.environment.slug
+ elsif deployed_at < stop_threshold
+ print_release_state(subject: 'Review app', release_name: deployment.environment.slug, release_date: deployment.created_at, action: 'stopping')
+ gitlab.stop_environment(project_path, deployment.environment.id)
+ cleaned_up_releases << deployment.environment.slug
+ else
+ print_release_state(subject: 'Review app', release_name: deployment.environment.slug, release_date: deployment.created_at, action: 'leaving')
+ end
+ end
+ end
+
+ def perform_helm_releases_cleanup!(days:)
+ puts "Checking for Helm releases not updated in the last #{days} days..."
+
+ threshold_day = threshold_time(days: days)
+ helm.releases(args: ['--deployed', '--failed', '--date', '--reverse', '--max 25']).each do |release|
+ next if cleaned_up_releases.include?(release.name)
+
+ if release.last_update < threshold_day
+ print_release_state(subject: 'Release', release_name: release.name, release_date: release.last_update, action: 'cleaning')
+ helm.delete(release_name: release.name)
+ kubernetes.cleanup(release_name: release.name)
+ else
+ print_release_state(subject: 'Release', release_name: release.name, release_date: release.last_update, action: 'leaving')
+ end
+ end
+ end
+
+ def threshold_time(days:)
+ Time.now - days * 24 * 3600
+ end
+
+ def print_release_state(subject:, release_name:, release_date:, action:)
+ puts "\n#{subject} '#{release_name}' was last deployed on #{release_date}: #{action} it."
+ end
+end
+
+def timed(task)
+ start = Time.now
+ yield(self)
+ puts "#{task} finished in #{Time.now - start} seconds.\n"
+end
+
+automated_cleanup = AutomatedCleanup.new
+
+timed('Review apps cleanup') do
+ automated_cleanup.perform_gitlab_environment_cleanup!(days_for_stop: 2, days_for_delete: 3)
+end
+
+puts
+
+timed('Helm releases cleanup') do
+ automated_cleanup.perform_helm_releases_cleanup!(days: 3)
+end
+
+exit(0)
diff --git a/scripts/review_apps/review-apps.sh b/scripts/review_apps/review-apps.sh
new file mode 100755
index 00000000000..78293464265
--- /dev/null
+++ b/scripts/review_apps/review-apps.sh
@@ -0,0 +1,184 @@
+[[ "$TRACE" ]] && set -x
+export TILLER_NAMESPACE="$KUBE_NAMESPACE"
+
+function check_kube_domain() {
+ if [ -z ${REVIEW_APPS_DOMAIN+x} ]; then
+ echo "In order to deploy or use Review Apps, REVIEW_APPS_DOMAIN variable must be set"
+ echo "You can do it in Auto DevOps project settings or defining a variable at group or project level"
+ echo "You can also manually add it in .gitlab-ci.yml"
+ false
+ else
+ true
+ fi
+}
+
+function download_gitlab_chart() {
+ curl -o gitlab.tar.bz2 https://gitlab.com/charts/gitlab/-/archive/$GITLAB_HELM_CHART_REF/gitlab-$GITLAB_HELM_CHART_REF.tar.bz2
+ tar -xjf gitlab.tar.bz2
+ cd gitlab-$GITLAB_HELM_CHART_REF
+
+ helm init --client-only
+ helm repo add gitlab https://charts.gitlab.io
+ helm dependency update
+ helm dependency build
+}
+
+function ensure_namespace() {
+ kubectl describe namespace "$KUBE_NAMESPACE" || kubectl create namespace "$KUBE_NAMESPACE"
+}
+
+function install_tiller() {
+ echo "Checking Tiller..."
+ helm init --upgrade
+ kubectl rollout status -n "$TILLER_NAMESPACE" -w "deployment/tiller-deploy"
+ if ! helm version --debug; then
+ echo "Failed to init Tiller."
+ return 1
+ fi
+ echo ""
+}
+
+function create_secret() {
+ echo "Create secret..."
+
+ kubectl create secret generic -n "$KUBE_NAMESPACE" \
+ $CI_ENVIRONMENT_SLUG-gitlab-initial-root-password \
+ --from-literal=password=$REVIEW_APPS_ROOT_PASSWORD \
+ --dry-run -o json | kubectl apply -f -
+}
+
+function previousDeployFailed() {
+ set +e
+ echo "Checking for previous deployment of $CI_ENVIRONMENT_SLUG"
+ deployment_status=$(helm status $CI_ENVIRONMENT_SLUG >/dev/null 2>&1)
+ status=$?
+ # if `status` is `0`, deployment exists, has a status
+ if [ $status -eq 0 ]; then
+ echo "Previous deployment found, checking status"
+ deployment_status=$(helm status $CI_ENVIRONMENT_SLUG | grep ^STATUS | cut -d' ' -f2)
+ echo "Previous deployment state: $deployment_status"
+ if [[ "$deployment_status" == "FAILED" || "$deployment_status" == "PENDING_UPGRADE" || "$deployment_status" == "PENDING_INSTALL" ]]; then
+ status=0;
+ else
+ status=1;
+ fi
+ else
+ echo "Previous deployment NOT found."
+ fi
+ set -e
+ return $status
+}
+
+function deploy() {
+ track="${1-stable}"
+ name="$CI_ENVIRONMENT_SLUG"
+
+ if [[ "$track" != "stable" ]]; then
+ name="$name-$track"
+ fi
+
+ replicas="1"
+ service_enabled="false"
+ postgres_enabled="$POSTGRES_ENABLED"
+ gitlab_migrations_image_repository="registry.gitlab.com/gitlab-org/build/cng-mirror/gitlab-rails-ce"
+ gitlab_sidekiq_image_repository="registry.gitlab.com/gitlab-org/build/cng-mirror/gitlab-sidekiq-ce"
+ gitlab_unicorn_image_repository="registry.gitlab.com/gitlab-org/build/cng-mirror/gitlab-unicorn-ce"
+ gitlab_gitaly_image_repository="registry.gitlab.com/gitlab-org/build/cng-mirror/gitaly"
+ gitlab_shell_image_repository="registry.gitlab.com/gitlab-org/build/cng-mirror/gitlab-shell"
+ gitlab_workhorse_image_repository="registry.gitlab.com/gitlab-org/build/cng-mirror/gitlab-workhorse-ce"
+
+ if [[ "$CI_PROJECT_NAME" == "gitlab-ee" ]]; then
+ gitlab_migrations_image_repository="registry.gitlab.com/gitlab-org/build/cng-mirror/gitlab-rails-ee"
+ gitlab_sidekiq_image_repository="registry.gitlab.com/gitlab-org/build/cng-mirror/gitlab-sidekiq-ee"
+ gitlab_unicorn_image_repository="registry.gitlab.com/gitlab-org/build/cng-mirror/gitlab-unicorn-ee"
+ gitlab_workhorse_image_repository="registry.gitlab.com/gitlab-org/build/cng-mirror/gitlab-workhorse-ee"
+ fi
+
+ # canary uses stable db
+ [[ "$track" == "canary" ]] && postgres_enabled="false"
+
+ env_track=$( echo $track | tr -s '[:lower:]' '[:upper:]' )
+ env_slug=$( echo ${CI_ENVIRONMENT_SLUG//-/_} | tr -s '[:lower:]' '[:upper:]' )
+
+ if [[ "$track" == "stable" ]]; then
+ # for stable track get number of replicas from `PRODUCTION_REPLICAS`
+ eval new_replicas=\$${env_slug}_REPLICAS
+ service_enabled="true"
+ else
+ # for all tracks get number of replicas from `CANARY_PRODUCTION_REPLICAS`
+ eval new_replicas=\$${env_track}_${env_slug}_REPLICAS
+ fi
+ if [[ -n "$new_replicas" ]]; then
+ replicas="$new_replicas"
+ fi
+
+ # Cleanup and previous installs, as FAILED and PENDING_UPGRADE will cause errors with `upgrade`
+ if [ "$CI_ENVIRONMENT_SLUG" != "production" ] && previousDeployFailed ; then
+ echo "Deployment in bad state, cleaning up $CI_ENVIRONMENT_SLUG"
+ delete
+ cleanup
+ fi
+ helm repo add gitlab https://charts.gitlab.io/
+ helm dep update .
+
+HELM_CMD=$(cat << EOF
+ helm upgrade --install \
+ --wait \
+ --timeout 600 \
+ --set releaseOverride="$CI_ENVIRONMENT_SLUG" \
+ --set global.hosts.hostSuffix="$HOST_SUFFIX" \
+ --set global.hosts.domain="$REVIEW_APPS_DOMAIN" \
+ --set certmanager.install=false \
+ --set global.ingress.configureCertmanager=false \
+ --set global.ingress.tls.secretName=tls-cert \
+ --set global.ingress.annotations."external-dns\.alpha\.kubernetes\.io/ttl"="10"
+ --set gitlab.unicorn.resources.requests.cpu=200m \
+ --set gitlab.sidekiq.resources.requests.cpu=100m \
+ --set gitlab.gitlab-shell.resources.requests.cpu=100m \
+ --set redis.resources.requests.cpu=100m \
+ --set minio.resources.requests.cpu=100m \
+ --set gitlab.migrations.image.repository="$gitlab_migrations_image_repository" \
+ --set gitlab.migrations.image.tag="$CI_COMMIT_REF_NAME" \
+ --set gitlab.sidekiq.image.repository="$gitlab_sidekiq_image_repository" \
+ --set gitlab.sidekiq.image.tag="$CI_COMMIT_REF_NAME" \
+ --set gitlab.unicorn.image.repository="$gitlab_unicorn_image_repository" \
+ --set gitlab.unicorn.image.tag="$CI_COMMIT_REF_NAME" \
+ --set gitlab.gitaly.image.repository="registry.gitlab.com/gitlab-org/build/cng-mirror/gitaly" \
+ --set gitlab.gitaly.image.tag="v$GITALY_VERSION" \
+ --set gitlab.gitlab-shell.image.repository="registry.gitlab.com/gitlab-org/build/cng-mirror/gitlab-shell" \
+ --set gitlab.gitlab-shell.image.tag="v$GITLAB_SHELL_VERSION" \
+ --set gitlab.unicorn.workhorse.image="$gitlab_workhorse_image_repository" \
+ --set gitlab.unicorn.workhorse.tag="$CI_COMMIT_REF_NAME" \
+ --namespace="$KUBE_NAMESPACE" \
+ --version="$CI_PIPELINE_ID-$CI_JOB_ID" \
+ "$name" \
+ .
+EOF
+)
+
+ echo "Deploying with:"
+ echo $HELM_CMD
+
+ eval $HELM_CMD
+}
+
+function delete() {
+ track="${1-stable}"
+ name="$CI_ENVIRONMENT_SLUG"
+
+ if [[ "$track" != "stable" ]]; then
+ name="$name-$track"
+ fi
+
+ echo "Deleting release '$name'..."
+ helm delete --purge "$name" || true
+}
+
+function cleanup() {
+ echo "Cleaning up $CI_ENVIRONMENT_SLUG..."
+ kubectl -n "$KUBE_NAMESPACE" get ingress,svc,pdb,hpa,deploy,statefulset,job,pod,secret,configmap,pvc,secret,clusterrole,clusterrolebinding,role,rolebinding,sa 2>&1 \
+ | grep "$CI_ENVIRONMENT_SLUG" \
+ | awk '{print $1}' \
+ | xargs kubectl -n "$KUBE_NAMESPACE" delete \
+ || true
+}
diff --git a/scripts/trigger-build b/scripts/trigger-build
index 798bf1e82b7..0b5fd5995dd 100755
--- a/scripts/trigger-build
+++ b/scripts/trigger-build
@@ -1,122 +1,144 @@
#!/usr/bin/env ruby
-require 'net/http'
-require 'json'
-require 'cgi'
+require 'gitlab'
+
+#
+# Configure credentials to be used with gitlab gem
+#
+Gitlab.configure do |config|
+ config.endpoint = 'https://gitlab.com/api/v4'
+ config.private_token = ENV['GITLAB_QA_ACCESS_TOKEN'] # gitlab-qa bot access token
+end
module Trigger
- OMNIBUS_PROJECT_PATH = 'gitlab-org/omnibus-gitlab'.freeze
- CNG_PROJECT_PATH = 'gitlab-org/build/CNG'.freeze
TOKEN = ENV['BUILD_TRIGGER_TOKEN']
def self.ee?
ENV['CI_PROJECT_NAME'] == 'gitlab-ee' || File.exist?('CHANGELOG-EE.md')
end
- class Omnibus
- def initialize
- @uri = URI("https://gitlab.com/api/v4/projects/#{CGI.escape(Trigger::OMNIBUS_PROJECT_PATH)}/trigger/pipeline")
- @params = env_params.merge(file_params).merge(token: Trigger::TOKEN)
+ class Base
+ def initialize(api_token)
+ Gitlab.private_token = api_token
end
- def invoke!
- res = Net::HTTP.post_form(@uri, @params)
- id = JSON.parse(res.body)['id']
- project = Trigger::OMNIBUS_PROJECT_PATH
+ def invoke!(post_comment: false)
+ pipeline = Gitlab.run_trigger(
+ downstream_project_path,
+ Trigger::TOKEN,
+ ref,
+ variables)
- if id
- puts "Triggered https://gitlab.com/#{project}/pipelines/#{id}"
- puts "Waiting for downstream pipeline status"
- else
- raise "Trigger failed! The response from the trigger is: #{res.body}"
- end
+ puts "Triggered #{pipeline.web_url}"
+ puts "Waiting for downstream pipeline status"
- Trigger::Pipeline.new(project, id)
+ begin
+ Trigger::CommitComment.post!(downstream_project_path, pipeline) if post_comment
+ rescue Gitlab::Error::Error => error
+ puts "Ignoring the following error: #{error}"
+ end
+ Trigger::Pipeline.new(downstream_project_path, pipeline.id)
end
private
- def env_params
+ # Must be overriden
+ def downstream_project_path
+ raise NotImplementedError
+ end
+
+ # Must be overriden
+ def ref
+ raise NotImplementedError
+ end
+
+ # Can be overriden
+ def extra_variables
+ {}
+ end
+
+ # Can be overriden
+ def version_param_value(version_file)
+ File.read(version_file).strip
+ end
+
+ def variables
+ base_variables.merge(extra_variables).merge(version_file_variables)
+ end
+
+ def base_variables
{
- "ref" => ENV["OMNIBUS_BRANCH"] || "master",
- "variables[GITLAB_VERSION]" => ENV["CI_COMMIT_SHA"],
- "variables[ALTERNATIVE_SOURCES]" => true,
- "variables[ee]" => Trigger.ee? ? 'true' : 'false',
- "variables[TRIGGERED_USER]" => ENV["GITLAB_USER_NAME"],
- "variables[TRIGGER_SOURCE]" => "https://gitlab.com/gitlab-org/#{ENV['CI_PROJECT_NAME']}/-/jobs/#{ENV['CI_JOB_ID']}"
+ 'TRIGGERED_USER' => ENV['GITLAB_USER_NAME'],
+ 'TRIGGER_SOURCE' => ENV['CI_JOB_URL']
}
end
- def file_params
- Hash.new.tap do |params|
- Dir.glob("*_VERSION").each do |version_file|
- params["variables[#{version_file}]"] = File.read(version_file).strip
- end
+ # Read version files from all components
+ def version_file_variables
+ Dir.glob("*_VERSION").each_with_object({}) do |version_file, params|
+ params[version_file] = version_param_value(version_file)
end
end
end
- class CNG
- def initialize
- @uri = URI("https://gitlab.com/api/v4/projects/#{CGI.escape(Trigger::CNG_PROJECT_PATH)}/trigger/pipeline")
- @ref_name = ENV['CI_COMMIT_REF_NAME']
- @username = ENV['GITLAB_USER_NAME']
- @project_name = ENV['CI_PROJECT_NAME']
- @job_id = ENV['CI_JOB_ID']
- @params = env_params.merge(file_params).merge(token: Trigger::TOKEN)
- end
-
- #
- # Trigger a pipeline
- #
- def invoke!
- res = Net::HTTP.post_form(@uri, @params)
- id = JSON.parse(res.body)['id']
- project = Trigger::CNG_PROJECT_PATH
-
- if id
- puts "Triggered https://gitlab.com/#{project}/pipelines/#{id}"
- puts "Waiting for downstream pipeline status"
- else
- raise "Trigger failed! The response from the trigger is: #{res.body}"
- end
+ class Omnibus < Base
+ private
- Trigger::Pipeline.new(project, id)
+ def downstream_project_path
+ 'gitlab-org/omnibus-gitlab'.freeze
end
+ def ref
+ ENV['OMNIBUS_BRANCH'] || 'master'
+ end
+
+ def extra_variables
+ {
+ 'GITLAB_VERSION' => ENV['CI_COMMIT_SHA'],
+ 'ALTERNATIVE_SOURCES' => 'true',
+ 'ee' => Trigger.ee? ? 'true' : 'false'
+ }
+ end
+ end
+
+ class CNG < Base
private
- def env_params
- params = {
- "ref" => ENV["CNG_BRANCH"] || "master",
- "variables[TRIGGERED_USER]" => @username,
- "variables[TRIGGER_SOURCE]" => "https://gitlab.com/gitlab-org/#{@project_name}/-/jobs/#{@job_id}"
+ def downstream_project_path
+ ENV['CNG_PROJECT_PATH'] || 'gitlab-org/build/CNG-mirror'
+ end
+
+ def ref
+ ENV['CNG_BRANCH'] || 'master'
+ end
+
+ def extra_variables
+ edition = Trigger.ee? ? 'EE' : 'CE'
+
+ {
+ "GITLAB_#{edition}_VERSION" => ENV['CI_COMMIT_REF_NAME'],
+ "#{edition}_PIPELINE" => 'true'
}
+ end
- if Trigger.ee?
- params["variables[GITLAB_EE_VERSION]"] = @ref_name
- params["variables[EE_PIPELINE]"] = 'true'
+ def version_param_value(_version_file)
+ raw_version = super
+
+ # if the version matches semver format, treat it as a tag and prepend `v`
+ if raw_version =~ Regexp.compile(/^\d+\.\d+\.\d+(-rc\d+)?(-ee)?$/)
+ "v#{raw_version}"
else
- params["variables[GITLAB_CE_VERSION]"] = @ref_name
- params["variables[CE_PIPELINE]"] = 'true'
+ raw_version
end
-
- params
end
+ end
- # Read version files from all components
- def file_params
- Dir.glob("*_VERSION").each_with_object({}) do |version_file, params|
- raw_version = File.read(version_file).strip
- # if the version matches semver format, treat it as a tag and prepend `v`
- version = if raw_version =~ Regexp.compile(/^\d+\.\d+\.\d+(-rc\d+)?(-ee)?$/)
- "v#{raw_version}"
- else
- raw_version
- end
-
- params["variables[#{version_file}]"] = version
- end
+ class CommitComment
+ def self.post!(downstream_project_path, downstream_pipeline)
+ Gitlab.create_commit_comment(
+ ENV['CI_PROJECT_PATH'],
+ ENV['CI_COMMIT_SHA'],
+ "The [`#{ENV['CI_JOB_NAME']}`](#{ENV['CI_JOB_URL']}) job from pipeline #{ENV['CI_PIPELINE_URL']} triggered #{downstream_pipeline.web_url} downstream.")
end
end
@@ -124,9 +146,15 @@ module Trigger
INTERVAL = 60 # seconds
MAX_DURATION = 3600 * 3 # 3 hours
+ attr_reader :project, :id
+
def initialize(project, id)
+ @project = project
+ @id = id
@start = Time.now.to_i
- @uri = URI("https://gitlab.com/api/v4/projects/#{CGI.escape(project)}/pipelines/#{id}")
+
+ # gitlab-bot's token "GitLab multi-project pipeline polling"
+ Gitlab.private_token = ENV['GITLAB_BOT_MULTI_PROJECT_PIPELINE_POLLING_TOKEN']
end
def wait!
@@ -157,15 +185,9 @@ module Trigger
end
def status
- req = Net::HTTP::Get.new(@uri)
- req['PRIVATE-TOKEN'] = ENV['GITLAB_QA_ACCESS_TOKEN']
-
- res = Net::HTTP.start(@uri.hostname, @uri.port, use_ssl: true) do |http|
- http.request(req)
- end
-
- JSON.parse(res.body)['status'].to_s.to_sym
- rescue JSON::ParserError
+ Gitlab.pipeline(project, id).status.to_sym
+ rescue Gitlab::Error::Error => error
+ puts "Ignoring the following error: #{error}"
# Ignore GitLab API hiccups. If GitLab is really down, we'll hit the job
# timeout anyway.
:running
@@ -175,9 +197,9 @@ end
case ARGV[0]
when 'omnibus'
- Trigger::Omnibus.new.invoke!.wait!
+ Trigger::Omnibus.new(ENV['GITLAB_QA_ACCESS_TOKEN']).invoke!(post_comment: true).wait!
when 'cng'
- Trigger::CNG.new.invoke!.wait!
+ Trigger::CNG.new(ENV['GITLAB_QA_ACCESS_TOKEN']).invoke!.wait!
else
puts "Please provide a valid option:
omnibus - Triggers a pipeline that builds the omnibus-gitlab package
diff --git a/scripts/trigger-build-docs b/scripts/trigger-build-docs
index 9ee35684509..dfc8ee6050a 100755
--- a/scripts/trigger-build-docs
+++ b/scripts/trigger-build-docs
@@ -6,8 +6,8 @@ require 'gitlab'
# Configure credentials to be used with gitlab gem
#
Gitlab.configure do |config|
- config.endpoint = 'https://gitlab.com/api/v4'
- config.private_token = ENV["DOCS_API_TOKEN"] # GitLab Docs bot access token with Developer access to gitlab-docs
+ config.endpoint = 'https://gitlab.com/api/v4'
+ config.private_token = ENV["DOCS_API_TOKEN"] # GitLab Docs bot access token with Developer access to gitlab-docs
end
#
@@ -99,7 +99,7 @@ def trigger_pipeline
puts "=> Follow the status of the triggered pipeline:"
puts ""
- puts "https://gitlab.com/gitlab-com/gitlab-docs/pipelines/#{pipeline.id}"
+ puts pipeline.web_url
puts ""
puts "=> In a few minutes, you will be able to preview your changes under the following URL:"
puts ""
diff --git a/spec/controllers/application_controller_spec.rb b/spec/controllers/application_controller_spec.rb
index fbf116e533b..7202cee04ea 100644
--- a/spec/controllers/application_controller_spec.rb
+++ b/spec/controllers/application_controller_spec.rb
@@ -694,4 +694,38 @@ describe ApplicationController do
expect(response).to have_gitlab_http_status(403)
end
end
+
+ context 'when invalid UTF-8 parameters are received' do
+ controller(described_class) do
+ def index
+ params[:text].split(' ')
+
+ render json: :ok
+ end
+ end
+
+ before do
+ sign_in user
+ end
+
+ context 'html' do
+ it 'renders 412' do
+ get :index, text: "hi \255"
+
+ expect(response).to have_gitlab_http_status(412)
+ expect(response).to render_template :precondition_failed
+ end
+ end
+
+ context 'js' do
+ it 'renders 412' do
+ get :index, text: "hi \255", format: :js
+
+ json_response = JSON.parse(response.body)
+
+ expect(response).to have_gitlab_http_status(412)
+ expect(json_response['error']).to eq('Invalid UTF-8')
+ end
+ end
+ end
end
diff --git a/spec/controllers/import/gitlab_projects_controller_spec.rb b/spec/controllers/import/gitlab_projects_controller_spec.rb
index d624659bce9..cbd1a112602 100644
--- a/spec/controllers/import/gitlab_projects_controller_spec.rb
+++ b/spec/controllers/import/gitlab_projects_controller_spec.rb
@@ -3,7 +3,7 @@ require 'spec_helper'
describe Import::GitlabProjectsController do
set(:namespace) { create(:namespace) }
set(:user) { namespace.owner }
- let(:file) { fixture_file_upload('spec/fixtures/doc_sample.txt', 'text/plain') }
+ let(:file) { fixture_file_upload('spec/fixtures/project_export.tar.gz', 'text/plain') }
before do
sign_in(user)
diff --git a/spec/controllers/oauth/applications_controller_spec.rb b/spec/controllers/oauth/applications_controller_spec.rb
index 1195f44f37d..ace8a954e92 100644
--- a/spec/controllers/oauth/applications_controller_spec.rb
+++ b/spec/controllers/oauth/applications_controller_spec.rb
@@ -15,14 +15,44 @@ describe Oauth::ApplicationsController do
expect(response).to have_gitlab_http_status(200)
end
- it 'redirects back to profile page if OAuth applications are disabled' do
- allow(Gitlab::CurrentSettings.current_application_settings).to receive(:user_oauth_applications?).and_return(false)
+ it 'shows list of applications' do
+ disable_user_oauth
get :index
+ expect(response).to have_gitlab_http_status(200)
+ end
+ end
+
+ describe 'POST #create' do
+ it 'creates an application' do
+ post :create, oauth_params
+
+ expect(response).to have_gitlab_http_status(302)
+ expect(response).to redirect_to(oauth_application_path(Doorkeeper::Application.last))
+ end
+
+ it 'redirects back to profile page if OAuth applications are disabled' do
+ disable_user_oauth
+
+ post :create, oauth_params
+
expect(response).to have_gitlab_http_status(302)
expect(response).to redirect_to(profile_path)
end
end
end
+
+ def disable_user_oauth
+ allow(Gitlab::CurrentSettings.current_application_settings).to receive(:user_oauth_applications?).and_return(false)
+ end
+
+ def oauth_params
+ {
+ doorkeeper_application: {
+ name: 'foo',
+ redirect_uri: 'http://example.org'
+ }
+ }
+ end
end
diff --git a/spec/controllers/projects/clusters_controller_spec.rb b/spec/controllers/projects/clusters_controller_spec.rb
index 26a532ee01d..97ac11fd171 100644
--- a/spec/controllers/projects/clusters_controller_spec.rb
+++ b/spec/controllers/projects/clusters_controller_spec.rb
@@ -170,12 +170,14 @@ describe Projects::ClustersController do
end
describe 'POST create for new cluster' do
+ let(:legacy_abac_param) { 'true' }
let(:params) do
{
cluster: {
name: 'new-cluster',
provider_gcp_attributes: {
- gcp_project_id: 'gcp-project-12345'
+ gcp_project_id: 'gcp-project-12345',
+ legacy_abac: legacy_abac_param
}
}
}
@@ -201,6 +203,18 @@ describe Projects::ClustersController do
expect(response).to redirect_to(project_cluster_path(project, project.clusters.first))
expect(project.clusters.first).to be_gcp
expect(project.clusters.first).to be_kubernetes
+ expect(project.clusters.first.provider_gcp).to be_legacy_abac
+ end
+
+ context 'when legacy_abac param is false' do
+ let(:legacy_abac_param) { 'false' }
+
+ it 'creates a new cluster with legacy_abac_disabled' do
+ expect(ClusterProvisionWorker).to receive(:perform_async)
+ expect { go }.to change { Clusters::Cluster.count }
+ .and change { Clusters::Providers::Gcp.count }
+ expect(project.clusters.first.provider_gcp).not_to be_legacy_abac
+ end
end
end
diff --git a/spec/controllers/projects/jobs_controller_spec.rb b/spec/controllers/projects/jobs_controller_spec.rb
index b42f6419922..fd11cb31a2a 100644
--- a/spec/controllers/projects/jobs_controller_spec.rb
+++ b/spec/controllers/projects/jobs_controller_spec.rb
@@ -86,7 +86,7 @@ describe Projects::JobsController, :clean_gitlab_redis_shared_state do
def create_job(name, status)
pipeline = create(:ci_pipeline, project: project)
create(:ci_build, :tags, :triggered, :artifacts,
- pipeline: pipeline, name: name, status: status)
+ pipeline: pipeline, name: name, status: status)
end
end
@@ -206,6 +206,153 @@ describe Projects::JobsController, :clean_gitlab_redis_shared_state do
expect(json_response['status']['illustration']).to have_key('title')
end
end
+
+ context 'with no deployment' do
+ let(:job) { create(:ci_build, :success, pipeline: pipeline) }
+
+ it 'does not exposes the deployment information' do
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response['deployment_status']).to be_nil
+ end
+ end
+
+ context 'with deployment' do
+ let(:merge_request) { create(:merge_request, source_project: project) }
+ let(:environment) { create(:environment, project: project, name: 'staging', state: :available) }
+ let(:job) { create(:ci_build, :success, environment: environment.name, pipeline: pipeline) }
+
+ it 'exposes the deployment information' do
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response).to match_schema('job/job_details')
+ expect(json_response['deployment_status']["status"]).to eq 'creating'
+ expect(json_response['deployment_status']["icon"]).to eq 'passed'
+ expect(json_response['deployment_status']["environment"]).not_to be_nil
+ end
+ end
+
+ context 'when user can edit runner' do
+ context 'that belongs to the project' do
+ let(:runner) { create(:ci_runner, :project, projects: [project]) }
+ let(:job) { create(:ci_build, :success, pipeline: pipeline, runner: runner) }
+
+ before do
+ project.add_maintainer(user)
+ sign_in(user)
+
+ get_show(id: job.id, format: :json)
+ end
+
+ it 'user can edit runner' do
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to match_response_schema('job/job_details')
+ expect(json_response['runner']).to have_key('edit_path')
+ end
+ end
+
+ context 'that belongs to group' do
+ let(:group) { create(:group) }
+ let(:runner) { create(:ci_runner, :group, groups: [group]) }
+ let(:job) { create(:ci_build, :success, pipeline: pipeline, runner: runner) }
+ let(:user) { create(:user, :admin) }
+
+ before do
+ project.add_maintainer(user)
+ sign_in(user)
+
+ get_show(id: job.id, format: :json)
+ end
+
+ it 'user can not edit runner' do
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to match_response_schema('job/job_details')
+ expect(json_response['runner']).not_to have_key('edit_path')
+ end
+ end
+
+ context 'that belongs to instance' do
+ let(:runner) { create(:ci_runner, :instance) }
+ let(:job) { create(:ci_build, :success, pipeline: pipeline, runner: runner) }
+ let(:user) { create(:user, :admin) }
+
+ before do
+ project.add_maintainer(user)
+ sign_in(user)
+
+ get_show(id: job.id, format: :json)
+ end
+
+ it 'user can not edit runner' do
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to match_response_schema('job/job_details')
+ expect(json_response['runner']).not_to have_key('edit_path')
+ end
+ end
+ end
+
+ context 'when no runners are available' do
+ let(:runner) { create(:ci_runner, :instance, active: false) }
+ let(:job) { create(:ci_build, :pending, pipeline: pipeline, runner: runner) }
+
+ it 'exposes needed information' do
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to match_response_schema('job/job_details')
+ expect(json_response['runners']['online']).to be false
+ expect(json_response['runners']['available']).to be false
+ end
+ end
+
+ context 'when no runner is online' do
+ let(:runner) { create(:ci_runner, :instance) }
+ let(:job) { create(:ci_build, :pending, pipeline: pipeline, runner: runner) }
+
+ it 'exposes needed information' do
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to match_response_schema('job/job_details')
+ expect(json_response['runners']['online']).to be false
+ expect(json_response['runners']['available']).to be true
+ end
+ end
+
+ context 'settings_path' do
+ context 'when user is developer' do
+ it 'settings_path is not available' do
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to match_response_schema('job/job_details')
+ expect(json_response['runners']).not_to have_key('settings_path')
+ end
+ end
+
+ context 'when user is maintainer' do
+ let(:user) { create(:user, :admin) }
+
+ before do
+ project.add_maintainer(user)
+ sign_in(user)
+ end
+
+ it 'settings_path is available' do
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to match_response_schema('job/job_details')
+ expect(json_response['runners']['settings_path']).to match(/runners/)
+ end
+ end
+ end
+
+ context 'when no trace is available' do
+ it 'has_trace is false' do
+ expect(response).to match_response_schema('job/job_details')
+ expect(json_response['has_trace']).to be false
+ end
+ end
+
+ context 'when job has trace' do
+ let(:job) { create(:ci_build, :running, :trace_live, pipeline: pipeline) }
+
+ it "has_trace is true" do
+ expect(response).to match_response_schema('job/job_details')
+ expect(json_response['has_trace']).to be true
+ end
+ end
end
context 'when requesting JSON job is triggered' do
diff --git a/spec/controllers/projects/notes_controller_spec.rb b/spec/controllers/projects/notes_controller_spec.rb
index 81badaac76b..e48c9dea976 100644
--- a/spec/controllers/projects/notes_controller_spec.rb
+++ b/spec/controllers/projects/notes_controller_spec.rb
@@ -207,6 +207,14 @@ describe Projects::NotesController do
expect(response).to have_gitlab_http_status(200)
end
+ it 'returns discussion JSON when the return_discussion param is set' do
+ post :create, request_params.merge(format: :json, return_discussion: 'true')
+
+ expect(response).to have_gitlab_http_status(200)
+ expect(json_response).to have_key 'discussion'
+ expect(json_response['discussion']['notes'][0]['note']).to eq(request_params[:note][:note])
+ end
+
context 'when merge_request_diff_head_sha present' do
before do
service_params = {
diff --git a/spec/controllers/projects/pipelines_controller_spec.rb b/spec/controllers/projects/pipelines_controller_spec.rb
index d89716b1b50..5c7415a318d 100644
--- a/spec/controllers/projects/pipelines_controller_spec.rb
+++ b/spec/controllers/projects/pipelines_controller_spec.rb
@@ -90,6 +90,11 @@ describe Projects::PipelinesController do
context 'when performing gitaly calls', :request_store do
it 'limits the Gitaly requests' do
+ # Isolate from test preparation (Repository#exists? is also cached in RequestStore)
+ RequestStore.end!
+ RequestStore.clear!
+ RequestStore.begin!
+
expect { get_pipelines_index_json }
.to change { Gitlab::GitalyClient.get_request_count }.by(2)
end
@@ -193,14 +198,34 @@ describe Projects::PipelinesController do
context 'when accessing existing stage' do
before do
+ create(:ci_build, :retried, :failed, pipeline: pipeline, stage: 'build')
create(:ci_build, pipeline: pipeline, stage: 'build')
+ end
+
+ context 'without retried' do
+ before do
+ get_stage('build')
+ end
- get_stage('build')
+ it 'returns pipeline jobs without the retried builds' do
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to match_response_schema('pipeline_stage')
+ expect(json_response['latest_statuses'].length).to eq 1
+ expect(json_response).not_to have_key('retried')
+ end
end
- it 'returns html source for stage dropdown' do
- expect(response).to have_gitlab_http_status(:ok)
- expect(response).to match_response_schema('pipeline_stage')
+ context 'with retried' do
+ before do
+ get_stage('build', retried: true)
+ end
+
+ it 'returns pipelines jobs with the retried builds' do
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to match_response_schema('pipeline_stage')
+ expect(json_response['latest_statuses'].length).to eq 1
+ expect(json_response['retried'].length).to eq 1
+ end
end
end
@@ -214,12 +239,13 @@ describe Projects::PipelinesController do
end
end
- def get_stage(name)
- get :stage, namespace_id: project.namespace,
- project_id: project,
- id: pipeline.id,
- stage: name,
- format: :json
+ def get_stage(name, params = {})
+ get :stage, **params.merge(
+ namespace_id: project.namespace,
+ project_id: project,
+ id: pipeline.id,
+ stage: name,
+ format: :json)
end
end
diff --git a/spec/factories/ci/job_artifacts.rb b/spec/factories/ci/job_artifacts.rb
index f028803ca74..ee79f0ae5fd 100644
--- a/spec/factories/ci/job_artifacts.rb
+++ b/spec/factories/ci/job_artifacts.rb
@@ -14,6 +14,33 @@ FactoryBot.define do
artifact.project ||= artifact.job.project
end
+ trait :raw do
+ file_format :raw
+
+ after(:build) do |artifact, _|
+ artifact.file = fixture_file_upload(
+ Rails.root.join('spec/fixtures/trace/sample_trace'), 'text/plain')
+ end
+ end
+
+ trait :zip do
+ file_format :zip
+
+ after(:build) do |artifact, _|
+ artifact.file = fixture_file_upload(
+ Rails.root.join('spec/fixtures/ci_build_artifacts.zip'), 'application/zip')
+ end
+ end
+
+ trait :gzip do
+ file_format :gzip
+
+ after(:build) do |artifact, _|
+ artifact.file = fixture_file_upload(
+ Rails.root.join('spec/fixtures/ci_build_artifacts_metadata.gz'), 'application/x-gzip')
+ end
+ end
+
trait :archive do
file_type :archive
file_format :zip
diff --git a/spec/factories/events.rb b/spec/factories/events.rb
index 5798b81ecad..bf8411b1894 100644
--- a/spec/factories/events.rb
+++ b/spec/factories/events.rb
@@ -24,7 +24,7 @@ FactoryBot.define do
factory :push_event, class: PushEvent do
project factory: :project_empty_repo
- author factory: :user
+ author(factory: :user) { project.creator }
action Event::PUSHED
end
diff --git a/spec/factories/site_statistics.rb b/spec/factories/site_statistics.rb
index dd8c795515a..2533d0eecc2 100644
--- a/spec/factories/site_statistics.rb
+++ b/spec/factories/site_statistics.rb
@@ -2,6 +2,5 @@ FactoryBot.define do
factory :site_statistics, class: 'SiteStatistic' do
id 1
repositories_count 999
- wikis_count 555
end
end
diff --git a/spec/factories/users.rb b/spec/factories/users.rb
index 59db8cdc34b..a47bd7cafca 100644
--- a/spec/factories/users.rb
+++ b/spec/factories/users.rb
@@ -58,6 +58,14 @@ FactoryBot.define do
project_view :readme
end
+ trait :commit_email do
+ after(:create) do |user, evaluator|
+ additional = create(:email, :confirmed, user: user, email: "commit-#{user.email}")
+
+ user.update!(commit_email: additional.email)
+ end
+ end
+
factory :omniauth_user do
transient do
extern_uid '123456'
diff --git a/spec/features/admin/admin_runners_spec.rb b/spec/features/admin/admin_runners_spec.rb
index 026dea8d22c..ed9c0ea9ac0 100644
--- a/spec/features/admin/admin_runners_spec.rb
+++ b/spec/features/admin/admin_runners_spec.rb
@@ -19,7 +19,7 @@ describe "Admin Runners" do
create(:ci_build, pipeline: pipeline, runner_id: runner.id)
visit admin_runners_path
- expect(page).to have_text "Setup a shared Runner manually"
+ expect(page).to have_text "Set up a shared Runner manually"
expect(page).to have_text "Runners currently online: 1"
end
@@ -73,24 +73,72 @@ describe "Admin Runners" do
expect(page).to have_text 'No runners found'
end
+
+ it 'shows correct runner when status is selected and search term is entered' do
+ create(:ci_runner, description: 'runner-a-1', active: true)
+ create(:ci_runner, description: 'runner-a-2', active: false)
+ create(:ci_runner, description: 'runner-b-1', active: true)
+
+ visit admin_runners_path
+
+ input_filtered_search_keys('status:active')
+ expect(page).to have_content 'runner-a-1'
+ expect(page).to have_content 'runner-b-1'
+ expect(page).not_to have_content 'runner-a-2'
+
+ input_filtered_search_keys('status:active runner-a')
+ expect(page).to have_content 'runner-a-1'
+ expect(page).not_to have_content 'runner-b-1'
+ expect(page).not_to have_content 'runner-a-2'
+ end
end
- it 'shows correct runner when status is selected and search term is entered', :js do
- create(:ci_runner, description: 'runner-a-1', active: true)
- create(:ci_runner, description: 'runner-a-2', active: false)
- create(:ci_runner, description: 'runner-b-1', active: true)
+ describe 'filter by type', :js do
+ it 'shows correct runner when type matches' do
+ create :ci_runner, :project, description: 'runner-project'
+ create :ci_runner, :group, description: 'runner-group'
- visit admin_runners_path
+ visit admin_runners_path
+
+ expect(page).to have_content 'runner-project'
+ expect(page).to have_content 'runner-group'
- input_filtered_search_keys('status:active')
- expect(page).to have_content 'runner-a-1'
- expect(page).to have_content 'runner-b-1'
- expect(page).not_to have_content 'runner-a-2'
+ input_filtered_search_keys('type:project_type')
+ expect(page).to have_content 'runner-project'
+ expect(page).not_to have_content 'runner-group'
+ end
+
+ it 'shows no runner when type does not match' do
+ create :ci_runner, :project, description: 'runner-project'
+ create :ci_runner, :group, description: 'runner-group'
- input_filtered_search_keys('status:active runner-a')
- expect(page).to have_content 'runner-a-1'
- expect(page).not_to have_content 'runner-b-1'
- expect(page).not_to have_content 'runner-a-2'
+ visit admin_runners_path
+
+ input_filtered_search_keys('type:instance_type')
+
+ expect(page).not_to have_content 'runner-project'
+ expect(page).not_to have_content 'runner-group'
+
+ expect(page).to have_text 'No runners found'
+ end
+
+ it 'shows correct runner when type is selected and search term is entered' do
+ create :ci_runner, :project, description: 'runner-a-1'
+ create :ci_runner, :instance, description: 'runner-a-2'
+ create :ci_runner, :project, description: 'runner-b-1'
+
+ visit admin_runners_path
+
+ input_filtered_search_keys('type:project_type')
+ expect(page).to have_content 'runner-a-1'
+ expect(page).to have_content 'runner-b-1'
+ expect(page).not_to have_content 'runner-a-2'
+
+ input_filtered_search_keys('type:project_type runner-a')
+ expect(page).to have_content 'runner-a-1'
+ expect(page).not_to have_content 'runner-b-1'
+ expect(page).not_to have_content 'runner-a-2'
+ end
end
it 'sorts by last contact date', :js do
@@ -125,7 +173,7 @@ describe "Admin Runners" do
end
it 'has all necessary texts including no runner message' do
- expect(page).to have_text "Setup a shared Runner manually"
+ expect(page).to have_text "Set up a shared Runner manually"
expect(page).to have_text "Runners currently online: 0"
expect(page).to have_text 'No runners found'
end
diff --git a/spec/features/admin/admin_settings_spec.rb b/spec/features/admin/admin_settings_spec.rb
index 3c65b5898b4..0a69a26eb3e 100644
--- a/spec/features/admin/admin_settings_spec.rb
+++ b/spec/features/admin/admin_settings_spec.rb
@@ -9,340 +9,365 @@ describe 'Admin updates settings' do
before do
stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false')
sign_in(admin)
- visit admin_application_settings_path
end
- it 'Change visibility settings' do
- page.within('.as-visibility-access') do
- choose "application_setting_default_project_visibility_20"
- click_button 'Save changes'
+ context 'General page' do
+ before do
+ visit admin_application_settings_path
end
- expect(page).to have_content "Application settings saved successfully"
- end
+ it 'Change visibility settings' do
+ page.within('.as-visibility-access') do
+ choose "application_setting_default_project_visibility_20"
+ click_button 'Save changes'
+ end
- it 'Uncheck all restricted visibility levels' do
- page.within('.as-visibility-access') do
- find('#application_setting_visibility_level_0').set(false)
- find('#application_setting_visibility_level_10').set(false)
- find('#application_setting_visibility_level_20').set(false)
- click_button 'Save changes'
+ expect(page).to have_content "Application settings saved successfully"
end
- expect(page).to have_content "Application settings saved successfully"
- expect(find('#application_setting_visibility_level_0')).not_to be_checked
- expect(find('#application_setting_visibility_level_10')).not_to be_checked
- expect(find('#application_setting_visibility_level_20')).not_to be_checked
- end
+ it 'Uncheck all restricted visibility levels' do
+ page.within('.as-visibility-access') do
+ find('#application_setting_visibility_level_0').set(false)
+ find('#application_setting_visibility_level_10').set(false)
+ find('#application_setting_visibility_level_20').set(false)
+ click_button 'Save changes'
+ end
- it 'Modify import sources' do
- expect(Gitlab::CurrentSettings.import_sources).not_to be_empty
+ expect(page).to have_content "Application settings saved successfully"
+ expect(find('#application_setting_visibility_level_0')).not_to be_checked
+ expect(find('#application_setting_visibility_level_10')).not_to be_checked
+ expect(find('#application_setting_visibility_level_20')).not_to be_checked
+ end
- page.within('.as-visibility-access') do
- Gitlab::ImportSources.options.map do |name, _|
- uncheck name
+ it 'Modify import sources' do
+ expect(Gitlab::CurrentSettings.import_sources).not_to be_empty
+
+ page.within('.as-visibility-access') do
+ Gitlab::ImportSources.options.map do |name, _|
+ uncheck name
+ end
+
+ click_button 'Save changes'
end
- click_button 'Save changes'
+ expect(page).to have_content "Application settings saved successfully"
+ expect(Gitlab::CurrentSettings.import_sources).to be_empty
+
+ page.within('.as-visibility-access') do
+ check "Repo by URL"
+ click_button 'Save changes'
+ end
+
+ expect(page).to have_content "Application settings saved successfully"
+ expect(Gitlab::CurrentSettings.import_sources).to eq(['git'])
end
- expect(page).to have_content "Application settings saved successfully"
- expect(Gitlab::CurrentSettings.import_sources).to be_empty
+ it 'Change Visibility and Access Controls' do
+ page.within('.as-visibility-access') do
+ uncheck 'Project export enabled'
+ click_button 'Save changes'
+ end
- page.within('.as-visibility-access') do
- check "Repo by URL"
- click_button 'Save changes'
+ expect(Gitlab::CurrentSettings.project_export_enabled).to be_falsey
+ expect(page).to have_content "Application settings saved successfully"
end
- expect(page).to have_content "Application settings saved successfully"
- expect(Gitlab::CurrentSettings.import_sources).to eq(['git'])
- end
+ it 'Change Keys settings' do
+ page.within('.as-visibility-access') do
+ select 'Are forbidden', from: 'RSA SSH keys'
+ select 'Are allowed', from: 'DSA SSH keys'
+ select 'Must be at least 384 bits', from: 'ECDSA SSH keys'
+ select 'Are forbidden', from: 'ED25519 SSH keys'
+ click_on 'Save changes'
+ end
- it 'Change Visibility and Access Controls' do
- page.within('.as-visibility-access') do
- uncheck 'Project export enabled'
- click_button 'Save changes'
+ forbidden = ApplicationSetting::FORBIDDEN_KEY_VALUE.to_s
+
+ expect(page).to have_content 'Application settings saved successfully'
+ expect(find_field('RSA SSH keys').value).to eq(forbidden)
+ expect(find_field('DSA SSH keys').value).to eq('0')
+ expect(find_field('ECDSA SSH keys').value).to eq('384')
+ expect(find_field('ED25519 SSH keys').value).to eq(forbidden)
end
- expect(Gitlab::CurrentSettings.project_export_enabled).to be_falsey
- expect(page).to have_content "Application settings saved successfully"
- end
+ it 'Change Account and Limit Settings' do
+ page.within('.as-account-limit') do
+ uncheck 'Gravatar enabled'
+ click_button 'Save changes'
+ end
- it 'Change Account and Limit Settings' do
- page.within('.as-account-limit') do
- uncheck 'Gravatar enabled'
- click_button 'Save changes'
+ expect(Gitlab::CurrentSettings.gravatar_enabled).to be_falsey
+ expect(page).to have_content "Application settings saved successfully"
end
- expect(Gitlab::CurrentSettings.gravatar_enabled).to be_falsey
- expect(page).to have_content "Application settings saved successfully"
- end
+ it 'Change New users set to external', :js do
+ user_internal_regex = find('#application_setting_user_default_internal_regex', visible: :all)
- it 'Change New users set to external', :js do
- user_internal_regex = find('#application_setting_user_default_internal_regex', visible: :all)
+ expect(user_internal_regex).to be_readonly
+ expect(user_internal_regex['placeholder']).to eq 'To define internal users, first enable new users set to external'
- expect(user_internal_regex).to be_readonly
- expect(user_internal_regex['placeholder']).to eq 'To define internal users, first enable new users set to external'
+ check 'application_setting_user_default_external'
- check 'application_setting_user_default_external'
+ expect(user_internal_regex).not_to be_readonly
+ expect(user_internal_regex['placeholder']).to eq 'Regex pattern'
+ end
- expect(user_internal_regex).not_to be_readonly
- expect(user_internal_regex['placeholder']).to eq 'Regex pattern'
- end
+ it 'Change Sign-in restrictions' do
+ page.within('.as-signin') do
+ fill_in 'Home page URL', with: 'https://about.gitlab.com/'
+ click_button 'Save changes'
+ end
- it 'Change Sign-in restrictions' do
- page.within('.as-signin') do
- fill_in 'Home page URL', with: 'https://about.gitlab.com/'
- click_button 'Save changes'
+ expect(Gitlab::CurrentSettings.home_page_url).to eq "https://about.gitlab.com/"
+ expect(page).to have_content "Application settings saved successfully"
end
- expect(Gitlab::CurrentSettings.home_page_url).to eq "https://about.gitlab.com/"
- expect(page).to have_content "Application settings saved successfully"
- end
+ it 'Terms of Service' do
+ # Already have the admin accept terms, so they don't need to accept in this spec.
+ _existing_terms = create(:term)
+ accept_terms(admin)
- it 'Terms of Service' do
- # Already have the admin accept terms, so they don't need to accept in this spec.
- _existing_terms = create(:term)
- accept_terms(admin)
+ page.within('.as-terms') do
+ check 'Require all users to accept Terms of Service and Privacy Policy when they access GitLab.'
+ fill_in 'Terms of Service Agreement', with: 'Be nice!'
+ click_button 'Save changes'
+ end
- page.within('.as-terms') do
- check 'Require all users to accept Terms of Service and Privacy Policy when they access GitLab.'
- fill_in 'Terms of Service Agreement', with: 'Be nice!'
- click_button 'Save changes'
+ expect(Gitlab::CurrentSettings.enforce_terms).to be(true)
+ expect(Gitlab::CurrentSettings.terms).to eq 'Be nice!'
+ expect(page).to have_content 'Application settings saved successfully'
end
- expect(Gitlab::CurrentSettings.enforce_terms).to be(true)
- expect(Gitlab::CurrentSettings.terms).to eq 'Be nice!'
- expect(page).to have_content 'Application settings saved successfully'
- end
+ it 'Modify oauth providers' do
+ expect(Gitlab::CurrentSettings.disabled_oauth_sign_in_sources).to be_empty
- it 'Modify oauth providers' do
- expect(Gitlab::CurrentSettings.disabled_oauth_sign_in_sources).to be_empty
+ page.within('.as-signin') do
+ uncheck 'Google'
+ click_button 'Save changes'
+ end
- page.within('.as-signin') do
- uncheck 'Google'
- click_button 'Save changes'
- end
+ expect(page).to have_content "Application settings saved successfully"
+ expect(Gitlab::CurrentSettings.disabled_oauth_sign_in_sources).to include('google_oauth2')
- expect(page).to have_content "Application settings saved successfully"
- expect(Gitlab::CurrentSettings.disabled_oauth_sign_in_sources).to include('google_oauth2')
+ page.within('.as-signin') do
+ check "Google"
+ click_button 'Save changes'
+ end
- page.within('.as-signin') do
- check "Google"
- click_button 'Save changes'
+ expect(page).to have_content "Application settings saved successfully"
+ expect(Gitlab::CurrentSettings.disabled_oauth_sign_in_sources).not_to include('google_oauth2')
end
- expect(page).to have_content "Application settings saved successfully"
- expect(Gitlab::CurrentSettings.disabled_oauth_sign_in_sources).not_to include('google_oauth2')
- end
+ it 'Oauth providers do not raise validation errors when saving unrelated changes' do
+ expect(Gitlab::CurrentSettings.disabled_oauth_sign_in_sources).to be_empty
- it 'Oauth providers do not raise validation errors when saving unrelated changes' do
- expect(Gitlab::CurrentSettings.disabled_oauth_sign_in_sources).to be_empty
+ page.within('.as-signin') do
+ uncheck 'Google'
+ click_button 'Save changes'
+ end
- page.within('.as-signin') do
- uncheck 'Google'
- click_button 'Save changes'
- end
+ expect(page).to have_content "Application settings saved successfully"
+ expect(Gitlab::CurrentSettings.disabled_oauth_sign_in_sources).to include('google_oauth2')
- expect(page).to have_content "Application settings saved successfully"
- expect(Gitlab::CurrentSettings.disabled_oauth_sign_in_sources).to include('google_oauth2')
+ # Remove google_oauth2 from the Omniauth strategies
+ allow(Devise).to receive(:omniauth_providers).and_return([])
- # Remove google_oauth2 from the Omniauth strategies
- allow(Devise).to receive(:omniauth_providers).and_return([])
+ # Save an unrelated setting
+ page.within('.as-terms') do
+ click_button 'Save changes'
+ end
- # Save an unrelated setting
- page.within('.as-ci-cd') do
- click_button 'Save changes'
+ expect(page).to have_content "Application settings saved successfully"
+ expect(Gitlab::CurrentSettings.disabled_oauth_sign_in_sources).to include('google_oauth2')
end
- expect(page).to have_content "Application settings saved successfully"
- expect(Gitlab::CurrentSettings.disabled_oauth_sign_in_sources).to include('google_oauth2')
- end
+ it 'Configure web terminal' do
+ page.within('.as-terminal') do
+ fill_in 'Max session time', with: 15
+ click_button 'Save changes'
+ end
- it 'Change Help page' do
- page.within('.as-help-page') do
- fill_in 'Help page text', with: 'Example text'
- check 'Hide marketing-related entries from help'
- fill_in 'Support page URL', with: 'http://example.com/help'
- click_button 'Save changes'
+ expect(page).to have_content "Application settings saved successfully"
+ expect(Gitlab::CurrentSettings.terminal_max_session_time).to eq(15)
end
-
- expect(Gitlab::CurrentSettings.help_page_text).to eq "Example text"
- expect(Gitlab::CurrentSettings.help_page_hide_commercial_content).to be_truthy
- expect(Gitlab::CurrentSettings.help_page_support_url).to eq "http://example.com/help"
- expect(page).to have_content "Application settings saved successfully"
end
- it 'Change Pages settings' do
- page.within('.as-pages') do
- fill_in 'Maximum size of pages (MB)', with: 15
- check 'Require users to prove ownership of custom domains'
- click_button 'Save changes'
+ context 'Integrations page' do
+ before do
+ visit integrations_admin_application_settings_path
end
- expect(Gitlab::CurrentSettings.max_pages_size).to eq 15
- expect(Gitlab::CurrentSettings.pages_domain_verification_enabled?).to be_truthy
- expect(page).to have_content "Application settings saved successfully"
- end
+ it 'Enable hiding third party offers' do
+ page.within('.as-third-party-offers') do
+ check 'Do not display offers from third parties within GitLab'
+ click_button 'Save changes'
+ end
- it 'Change CI/CD settings' do
- page.within('.as-ci-cd') do
- check 'Default to Auto DevOps pipeline for all projects'
- fill_in 'Auto devops domain', with: 'domain.com'
- click_button 'Save changes'
+ expect(page).to have_content "Application settings saved successfully"
+ expect(Gitlab::CurrentSettings.hide_third_party_offers).to be true
end
- expect(Gitlab::CurrentSettings.auto_devops_enabled?).to be true
- expect(Gitlab::CurrentSettings.auto_devops_domain).to eq('domain.com')
- expect(page).to have_content "Application settings saved successfully"
- end
+ it 'Change Slack Notifications Service template settings' do
+ first(:link, 'Service Templates').click
+ click_link 'Slack notifications'
+ fill_in 'Webhook', with: 'http://localhost'
+ fill_in 'Username', with: 'test_user'
+ fill_in 'service_push_channel', with: '#test_channel'
+ page.check('Notify only broken pipelines')
+ page.check('Notify only default branch')
- it 'Change Influx settings' do
- page.within('.as-influx') do
- check 'Enable InfluxDB Metrics'
- click_button 'Save changes'
- end
+ check_all_events
+ click_on 'Save'
- expect(Gitlab::CurrentSettings.metrics_enabled?).to be true
- expect(page).to have_content "Application settings saved successfully"
- end
+ expect(page).to have_content 'Application settings saved successfully'
- it 'Change Prometheus settings' do
- page.within('.as-prometheus') do
- check 'Enable Prometheus Metrics'
- click_button 'Save changes'
- end
+ click_link 'Slack notifications'
- expect(Gitlab::CurrentSettings.prometheus_metrics_enabled?).to be true
- expect(page).to have_content "Application settings saved successfully"
+ page.all('input[type=checkbox]').each do |checkbox|
+ expect(checkbox).to be_checked
+ end
+ expect(find_field('Webhook').value).to eq 'http://localhost'
+ expect(find_field('Username').value).to eq 'test_user'
+ expect(find('#service_push_channel').value).to eq '#test_channel'
+ end
end
- it 'Change Performance bar settings' do
- group = create(:group)
+ context 'CI/CD page' do
+ it 'Change CI/CD settings' do
+ visit ci_cd_admin_application_settings_path
+
+ page.within('.as-ci-cd') do
+ check 'Default to Auto DevOps pipeline for all projects'
+ fill_in 'Auto devops domain', with: 'domain.com'
+ click_button 'Save changes'
+ end
- page.within('.as-performance-bar') do
- check 'Enable the Performance Bar'
- fill_in 'Allowed group', with: group.path
- click_on 'Save changes'
+ expect(Gitlab::CurrentSettings.auto_devops_enabled?).to be true
+ expect(Gitlab::CurrentSettings.auto_devops_domain).to eq('domain.com')
+ expect(page).to have_content "Application settings saved successfully"
end
+ end
- expect(page).to have_content "Application settings saved successfully"
- expect(find_field('Enable the Performance Bar')).to be_checked
- expect(find_field('Allowed group').value).to eq group.path
+ context 'Reporting page' do
+ it 'Change Spam settings' do
+ visit reporting_admin_application_settings_path
- page.within('.as-performance-bar') do
- uncheck 'Enable the Performance Bar'
- click_on 'Save changes'
- end
+ page.within('.as-spam') do
+ check 'Enable reCAPTCHA'
+ fill_in 'reCAPTCHA Site Key', with: 'key'
+ fill_in 'reCAPTCHA Private Key', with: 'key'
+ fill_in 'IPs per user', with: 15
+ click_button 'Save changes'
+ end
- expect(page).to have_content 'Application settings saved successfully'
- expect(find_field('Enable the Performance Bar')).not_to be_checked
- expect(find_field('Allowed group').value).to be_nil
+ expect(page).to have_content "Application settings saved successfully"
+ expect(Gitlab::CurrentSettings.recaptcha_enabled).to be true
+ expect(Gitlab::CurrentSettings.unique_ips_limit_per_user).to eq(15)
+ end
end
- it 'Change Background jobs settings' do
- page.within('.as-background') do
- fill_in 'Throttling Factor', with: 1
- click_button 'Save changes'
+ context 'Metrics and profiling page' do
+ before do
+ visit metrics_and_profiling_admin_application_settings_path
end
- expect(Gitlab::CurrentSettings.sidekiq_throttling_factor).to eq(1)
- expect(page).to have_content "Application settings saved successfully"
- end
+ it 'Change Influx settings' do
+ page.within('.as-influx') do
+ check 'Enable InfluxDB Metrics'
+ click_button 'Save changes'
+ end
- it 'Change Spam settings' do
- page.within('.as-spam') do
- check 'Enable reCAPTCHA'
- fill_in 'reCAPTCHA Site Key', with: 'key'
- fill_in 'reCAPTCHA Private Key', with: 'key'
- fill_in 'IPs per user', with: 15
- click_button 'Save changes'
+ expect(Gitlab::CurrentSettings.metrics_enabled?).to be true
+ expect(page).to have_content "Application settings saved successfully"
end
- expect(page).to have_content "Application settings saved successfully"
- expect(Gitlab::CurrentSettings.recaptcha_enabled).to be true
- expect(Gitlab::CurrentSettings.unique_ips_limit_per_user).to eq(15)
- end
+ it 'Change Prometheus settings' do
+ page.within('.as-prometheus') do
+ check 'Enable Prometheus Metrics'
+ click_button 'Save changes'
+ end
- it 'Configure web terminal' do
- page.within('.as-terminal') do
- fill_in 'Max session time', with: 15
- click_button 'Save changes'
+ expect(Gitlab::CurrentSettings.prometheus_metrics_enabled?).to be true
+ expect(page).to have_content "Application settings saved successfully"
end
- expect(page).to have_content "Application settings saved successfully"
- expect(Gitlab::CurrentSettings.terminal_max_session_time).to eq(15)
- end
+ it 'Change Performance bar settings' do
+ group = create(:group)
- it 'Enable outbound requests' do
- page.within('.as-outbound') do
- check 'Allow requests to the local network from hooks and services'
- click_button 'Save changes'
- end
+ page.within('.as-performance-bar') do
+ check 'Enable the Performance Bar'
+ fill_in 'Allowed group', with: group.path
+ click_on 'Save changes'
+ end
- expect(page).to have_content "Application settings saved successfully"
- expect(Gitlab::CurrentSettings.allow_local_requests_from_hooks_and_services).to be true
- end
+ expect(page).to have_content "Application settings saved successfully"
+ expect(find_field('Enable the Performance Bar')).to be_checked
+ expect(find_field('Allowed group').value).to eq group.path
- it 'Enable hiding third party offers' do
- page.within('.as-third-party-offers') do
- check 'Do not display offers from third parties within GitLab'
- click_button 'Save changes'
+ page.within('.as-performance-bar') do
+ uncheck 'Enable the Performance Bar'
+ click_on 'Save changes'
+ end
+
+ expect(page).to have_content 'Application settings saved successfully'
+ expect(find_field('Enable the Performance Bar')).not_to be_checked
+ expect(find_field('Allowed group').value).to be_nil
end
- expect(page).to have_content "Application settings saved successfully"
- expect(Gitlab::CurrentSettings.hide_third_party_offers).to be true
- end
+ it 'loads usage ping payload on click', :js do
+ expect(page).to have_button 'Preview payload'
- it 'Change Slack Notifications Service template settings' do
- first(:link, 'Service Templates').click
- click_link 'Slack notifications'
- fill_in 'Webhook', with: 'http://localhost'
- fill_in 'Username', with: 'test_user'
- fill_in 'service_push_channel', with: '#test_channel'
- page.check('Notify only broken pipelines')
- page.check('Notify only default branch')
+ find('.js-usage-ping-payload-trigger').click
- check_all_events
- click_on 'Save'
+ expect(page).to have_selector '.js-usage-ping-payload'
+ expect(page).to have_button 'Hide payload'
+ end
+ end
- expect(page).to have_content 'Application settings saved successfully'
+ context 'Network page' do
+ it 'Enable outbound requests' do
+ visit network_admin_application_settings_path
- click_link 'Slack notifications'
+ page.within('.as-outbound') do
+ check 'Allow requests to the local network from hooks and services'
+ click_button 'Save changes'
+ end
- page.all('input[type=checkbox]').each do |checkbox|
- expect(checkbox).to be_checked
+ expect(page).to have_content "Application settings saved successfully"
+ expect(Gitlab::CurrentSettings.allow_local_requests_from_hooks_and_services).to be true
end
- expect(find_field('Webhook').value).to eq 'http://localhost'
- expect(find_field('Username').value).to eq 'test_user'
- expect(find('#service_push_channel').value).to eq '#test_channel'
end
- it 'Change Keys settings' do
- page.within('.as-visibility-access') do
- select 'Are forbidden', from: 'RSA SSH keys'
- select 'Are allowed', from: 'DSA SSH keys'
- select 'Must be at least 384 bits', from: 'ECDSA SSH keys'
- select 'Are forbidden', from: 'ED25519 SSH keys'
- click_on 'Save changes'
+ context 'Preferences page' do
+ before do
+ visit preferences_admin_application_settings_path
end
- forbidden = ApplicationSetting::FORBIDDEN_KEY_VALUE.to_s
-
- expect(page).to have_content 'Application settings saved successfully'
- expect(find_field('RSA SSH keys').value).to eq(forbidden)
- expect(find_field('DSA SSH keys').value).to eq('0')
- expect(find_field('ECDSA SSH keys').value).to eq('384')
- expect(find_field('ED25519 SSH keys').value).to eq(forbidden)
- end
+ it 'Change Help page' do
+ page.within('.as-help-page') do
+ fill_in 'Help page text', with: 'Example text'
+ check 'Hide marketing-related entries from help'
+ fill_in 'Support page URL', with: 'http://example.com/help'
+ click_button 'Save changes'
+ end
- it 'loads usage ping payload on click', :js do
- expect(page).to have_button 'Preview payload'
+ expect(Gitlab::CurrentSettings.help_page_text).to eq "Example text"
+ expect(Gitlab::CurrentSettings.help_page_hide_commercial_content).to be_truthy
+ expect(Gitlab::CurrentSettings.help_page_support_url).to eq "http://example.com/help"
+ expect(page).to have_content "Application settings saved successfully"
+ end
- find('.js-usage-ping-payload-trigger').click
+ it 'Change Pages settings' do
+ page.within('.as-pages') do
+ fill_in 'Maximum size of pages (MB)', with: 15
+ check 'Require users to prove ownership of custom domains'
+ click_button 'Save changes'
+ end
- expect(page).to have_selector '.js-usage-ping-payload'
- expect(page).to have_button 'Hide payload'
+ expect(Gitlab::CurrentSettings.max_pages_size).to eq 15
+ expect(Gitlab::CurrentSettings.pages_domain_verification_enabled?).to be_truthy
+ expect(page).to have_content "Application settings saved successfully"
+ end
end
def check_all_events
diff --git a/spec/features/admin/admin_uses_repository_checks_spec.rb b/spec/features/admin/admin_uses_repository_checks_spec.rb
index e658f1b6738..d04bb9acd9e 100644
--- a/spec/features/admin/admin_uses_repository_checks_spec.rb
+++ b/spec/features/admin/admin_uses_repository_checks_spec.rb
@@ -33,7 +33,7 @@ describe 'Admin uses repository checks' do
end
it 'to clear all repository checks', :js do
- visit admin_application_settings_path
+ visit repository_admin_application_settings_path
expect(RepositoryCheck::ClearWorker).to receive(:perform_async)
diff --git a/spec/features/dashboard/group_spec.rb b/spec/features/dashboard/group_spec.rb
index 1c7932e7964..e57fcde8b2c 100644
--- a/spec/features/dashboard/group_spec.rb
+++ b/spec/features/dashboard/group_spec.rb
@@ -13,7 +13,7 @@ RSpec.describe 'Dashboard Group' do
it 'creates new group', :js do
visit dashboard_groups_path
- find('.btn-new').click
+ find('.btn-success').click
new_path = 'Samurai'
new_description = 'Tokugawa Shogunate'
diff --git a/spec/features/dashboard/projects_spec.rb b/spec/features/dashboard/projects_spec.rb
index 4daacc61d85..975b7944741 100644
--- a/spec/features/dashboard/projects_spec.rb
+++ b/spec/features/dashboard/projects_spec.rb
@@ -103,6 +103,14 @@ describe 'Dashboard Projects' do
expect(page).not_to have_content(project.name)
expect(page).to have_content(project3.name)
end
+
+ it 'sorts projects by most stars when sorting by most stars' do
+ project_with_most_stars = create(:project, namespace: user.namespace, star_count: 10)
+
+ visit dashboard_projects_path(sort: :stars_desc)
+
+ expect(first('.project-row')).to have_content(project_with_most_stars.title)
+ end
end
context 'when on Starred projects tab' do
diff --git a/spec/features/issues/filtered_search/filter_issues_spec.rb b/spec/features/issues/filtered_search/filter_issues_spec.rb
index d4949de3f27..35d57b3896d 100644
--- a/spec/features/issues/filtered_search/filter_issues_spec.rb
+++ b/spec/features/issues/filtered_search/filter_issues_spec.rb
@@ -265,7 +265,7 @@ describe 'Filter issues', :js do
context 'issue label clicked' do
it 'filters and displays in search bar' do
- find('.issues-list .issue .issue-main-info .issuable-info a .badge', text: multiple_words_label.title).click
+ find('.issues-list .issue .issuable-main-info .issuable-info a .badge', text: multiple_words_label.title).click
expect_issues_list_count(1)
expect_tokens([label_token("\"#{multiple_words_label.title}\"")])
diff --git a/spec/features/labels_hierarchy_spec.rb b/spec/features/labels_hierarchy_spec.rb
index 6f917f522bc..09904cb907f 100644
--- a/spec/features/labels_hierarchy_spec.rb
+++ b/spec/features/labels_hierarchy_spec.rb
@@ -156,7 +156,7 @@ describe 'Labels Hierarchy', :js, :nested_groups do
find('a.label-item', text: parent_group_label.title).click
find('a.label-item', text: project_label_1.title).click
- find('.btn-create').click
+ find('.btn-success').click
expect(page.find('.issue-details h2.title')).to have_content('new created issue')
expect(page).to have_selector('span.badge', text: grandparent_group_label.title)
diff --git a/spec/features/merge_request/user_posts_diff_notes_spec.rb b/spec/features/merge_request/user_posts_diff_notes_spec.rb
index b6ed3686de2..fa148715855 100644
--- a/spec/features/merge_request/user_posts_diff_notes_spec.rb
+++ b/spec/features/merge_request/user_posts_diff_notes_spec.rb
@@ -200,23 +200,20 @@ describe 'Merge request > User posts diff notes', :js do
end
context 'with a new line' do
- # TODO: https://gitlab.com/gitlab-org/gitlab-ce/issues/48034
- xit 'allows commenting' do
- should_allow_commenting(find('[id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd_10_9"]').find(:xpath, '..'))
+ it 'allows commenting' do
+ should_allow_commenting(find('[id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd_10_9"]'))
end
end
context 'with an old line' do
- # TODO: https://gitlab.com/gitlab-org/gitlab-ce/issues/48034
- xit 'allows commenting' do
- should_allow_commenting(find('[id="6eb14e00385d2fb284765eb1cd8d420d33d63fc9_22_22"]').find(:xpath, '..'))
+ it 'allows commenting' do
+ should_allow_commenting(find('[id="6eb14e00385d2fb284765eb1cd8d420d33d63fc9_22_22"]'))
end
end
context 'with an unchanged line' do
- # TODO: https://gitlab.com/gitlab-org/gitlab-ce/issues/48034
- xit 'allows commenting' do
- should_allow_commenting(find('[id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd_7_7"]').find(:xpath, '..'))
+ it 'allows commenting' do
+ should_allow_commenting(find('[id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd_7_7"]'))
end
end
diff --git a/spec/features/merge_request/user_posts_notes_spec.rb b/spec/features/merge_request/user_posts_notes_spec.rb
index 260c5f9c28b..ee5f5377ca6 100644
--- a/spec/features/merge_request/user_posts_notes_spec.rb
+++ b/spec/features/merge_request/user_posts_notes_spec.rb
@@ -111,7 +111,7 @@ describe 'Merge request > User posts notes', :js do
it 'allows using markdown buttons after saving a note and then trying to edit it again' do
page.within('.current-note-edit-form') do
fill_in 'note[note]', with: 'This is the new content'
- find('.btn-save').click
+ find('.btn-success').click
end
find('.note').hover
@@ -129,7 +129,7 @@ describe 'Merge request > User posts notes', :js do
it 'appends the edited at time to the note' do
page.within('.current-note-edit-form') do
fill_in 'note[note]', with: 'Some new content'
- find('.btn-save').click
+ find('.btn-success').click
end
page.within("#note_#{note.id}") do
diff --git a/spec/features/merge_request/user_resolves_conflicts_spec.rb b/spec/features/merge_request/user_resolves_conflicts_spec.rb
index 629052442b4..50c723776a3 100644
--- a/spec/features/merge_request/user_resolves_conflicts_spec.rb
+++ b/spec/features/merge_request/user_resolves_conflicts_spec.rb
@@ -44,9 +44,7 @@ describe 'Merge request > User resolves conflicts', :js do
within find('.diff-file', text: 'files/ruby/regex.rb') do
expect(page).to have_selector('.line_content.new', text: "def username_regexp")
- expect(page).not_to have_selector('.line_content.new', text: "def username_regex")
expect(page).to have_selector('.line_content.new', text: "def project_name_regexp")
- expect(page).not_to have_selector('.line_content.new', text: "def project_name_regex")
expect(page).to have_selector('.line_content.new', text: "def path_regexp")
expect(page).to have_selector('.line_content.new', text: "def archive_formats_regexp")
expect(page).to have_selector('.line_content.new', text: "def git_reference_regexp")
@@ -110,12 +108,8 @@ describe 'Merge request > User resolves conflicts', :js do
click_link('conflicts', href: %r{/conflicts\Z})
end
- # TODO: https://gitlab.com/gitlab-org/gitlab-ce/issues/48034
- # include_examples "conflicts are resolved in Interactive mode"
- # include_examples "conflicts are resolved in Edit inline mode"
-
- it 'prevents RSpec/EmptyExampleGroup' do
- end
+ include_examples "conflicts are resolved in Interactive mode"
+ include_examples "conflicts are resolved in Edit inline mode"
end
context 'in Parallel view mode' do
@@ -124,12 +118,8 @@ describe 'Merge request > User resolves conflicts', :js do
click_button 'Side-by-side'
end
- # TODO: https://gitlab.com/gitlab-org/gitlab-ce/issues/48034
- # include_examples "conflicts are resolved in Interactive mode"
- # include_examples "conflicts are resolved in Edit inline mode"
-
- it 'prevents RSpec/EmptyExampleGroup' do
- end
+ include_examples "conflicts are resolved in Interactive mode"
+ include_examples "conflicts are resolved in Edit inline mode"
end
end
diff --git a/spec/features/merge_request/user_resolves_diff_notes_and_discussions_resolve_spec.rb b/spec/features/merge_request/user_resolves_diff_notes_and_discussions_resolve_spec.rb
index 2d268ecab58..8a16c011067 100644
--- a/spec/features/merge_request/user_resolves_diff_notes_and_discussions_resolve_spec.rb
+++ b/spec/features/merge_request/user_resolves_diff_notes_and_discussions_resolve_spec.rb
@@ -139,44 +139,64 @@ describe 'Merge request > User resolves diff notes and discussions', :js do
expect(find('.diffs .diff-file .notes_holder')).to be_visible
end
end
- end
- it 'allows user to resolve from reply form without a comment' do
- page.within '.diff-content' do
- click_button 'Reply...'
+ describe 'reply form' do
+ before do
+ click_button 'Toggle discussion'
- click_button 'Resolve discussion'
- end
+ page.within '.diff-content' do
+ click_button 'Reply...'
+ end
+ end
- page.within '.line-resolve-all-container' do
- expect(page).to have_content('1/1 discussion resolved')
- expect(page).to have_selector('.line-resolve-btn.is-active')
- end
- end
+ it 'allows user to comment' do
+ page.within '.diff-content' do
+ find('.js-note-text').set 'testing'
- it 'allows user to unresolve from reply form without a comment' do
- page.within '.diff-content' do
- click_button 'Resolve discussion'
- sleep 1
+ click_button 'Comment'
- click_button 'Reply...'
+ wait_for_requests
+ end
- click_button 'Unresolve discussion'
- end
+ page.within '.line-resolve-all-container' do
+ expect(page).to have_content('1/1 discussion resolved')
+ end
+ end
- page.within '.line-resolve-all-container' do
- expect(page).to have_content('0/1 discussion resolved')
- expect(page).not_to have_selector('.line-resolve-btn.is-active')
+ it 'allows user to unresolve from reply form without a comment' do
+ page.within '.diff-content' do
+ click_button 'Unresolve discussion'
+
+ wait_for_requests
+ end
+
+ page.within '.line-resolve-all-container' do
+ expect(page).to have_content('0/1 discussion resolved')
+ expect(page).not_to have_selector('.line-resolve-btn.is-active')
+ end
+ end
+
+ it 'allows user to comment & unresolve discussion' do
+ page.within '.diff-content' do
+ find('.js-note-text').set 'testing'
+
+ click_button 'Comment & unresolve discussion'
+
+ wait_for_requests
+ end
+
+ page.within '.line-resolve-all-container' do
+ expect(page).to have_content('0/1 discussion resolved')
+ end
+ end
end
end
- it 'allows user to comment & resolve discussion' do
+ it 'allows user to resolve from reply form without a comment' do
page.within '.diff-content' do
click_button 'Reply...'
- find('.js-note-text').set 'testing'
-
- click_button 'Comment & resolve discussion'
+ click_button 'Resolve discussion'
end
page.within '.line-resolve-all-container' do
@@ -185,19 +205,18 @@ describe 'Merge request > User resolves diff notes and discussions', :js do
end
end
- it 'allows user to comment & unresolve discussion' do
+ it 'allows user to comment & resolve discussion' do
page.within '.diff-content' do
- click_button 'Resolve discussion'
-
click_button 'Reply...'
find('.js-note-text').set 'testing'
- click_button 'Comment & unresolve discussion'
+ click_button 'Comment & resolve discussion'
end
page.within '.line-resolve-all-container' do
- expect(page).to have_content('0/1 discussion resolved')
+ expect(page).to have_content('1/1 discussion resolved')
+ expect(page).to have_selector('.line-resolve-btn.is-active')
end
end
diff --git a/spec/features/merge_request/user_sees_merge_widget_spec.rb b/spec/features/merge_request/user_sees_merge_widget_spec.rb
index b285cd7a7ac..a5dc9017699 100644
--- a/spec/features/merge_request/user_sees_merge_widget_spec.rb
+++ b/spec/features/merge_request/user_sees_merge_widget_spec.rb
@@ -160,7 +160,7 @@ describe 'Merge request > User sees merge widget', :js do
end
end
- context 'view merge request where project has CI setup but no CI status' do
+ context 'view merge request where project has CI set up but no CI status' do
before do
pipeline = create(:ci_pipeline, project: project,
sha: merge_request.diff_head_sha,
@@ -178,7 +178,7 @@ describe 'Merge request > User sees merge widget', :js do
end
end
- context 'view merge request in project with only-mwps setting enabled but no CI is setup' do
+ context 'view merge request in project with only-mwps setting enabled but no CI is set up' do
before do
visit project_merge_request_path(project_only_mwps, merge_request_in_only_mwps_project)
end
diff --git a/spec/features/projects/activity/user_sees_activity_spec.rb b/spec/features/projects/activity/user_sees_activity_spec.rb
index e0248911b5f..ebaa137772d 100644
--- a/spec/features/projects/activity/user_sees_activity_spec.rb
+++ b/spec/features/projects/activity/user_sees_activity_spec.rb
@@ -3,8 +3,10 @@ require 'spec_helper'
describe 'Projects > Activity > User sees activity' do
let(:project) { create(:project, :repository, :public) }
let(:user) { project.creator }
+ let(:issue) { create(:issue, project: project) }
before do
+ create(:event, :created, project: project, target: issue, author: user)
event = create(:push_event, project: project, author: user)
create(:push_event_payload,
event: event,
@@ -12,10 +14,18 @@ describe 'Projects > Activity > User sees activity' do
commit_to: '6d394385cf567f80a8fd85055db1ab4c5295806f',
ref: 'fix',
commit_count: 1)
- visit activity_project_path(project)
end
it 'shows the last push in the activity page', :js do
+ visit activity_project_path(project)
+
expect(page).to have_content "#{user.name} pushed new branch fix"
end
+
+ it 'allows to filter event with the "event_filter=issue" URL param', :js do
+ visit activity_project_path(project, event_filter: 'issue')
+
+ expect(page).not_to have_content "#{user.name} pushed new branch fix"
+ expect(page).to have_content "#{user.name} opened issue #{issue.to_reference}"
+ end
end
diff --git a/spec/features/projects/artifacts/user_downloads_artifacts_spec.rb b/spec/features/projects/artifacts/user_downloads_artifacts_spec.rb
index 67ed2f18d76..554f0b49052 100644
--- a/spec/features/projects/artifacts/user_downloads_artifacts_spec.rb
+++ b/spec/features/projects/artifacts/user_downloads_artifacts_spec.rb
@@ -20,23 +20,13 @@ describe "User downloads artifacts" do
end
context "via job id" do
- set(:url) { download_project_job_artifacts_path(project, job) }
+ let(:url) { download_project_job_artifacts_path(project, job) }
it_behaves_like "downloading"
end
context "via branch name and job name" do
- set(:url) { latest_succeeded_project_artifacts_path(project, "#{pipeline.ref}/download", job: job.name) }
-
- it_behaves_like "downloading"
- end
-
- context "via clicking the `Download` button" do
- set(:url) { project_job_path(project, job) }
-
- before do
- click_link("Download")
- end
+ let(:url) { latest_succeeded_project_artifacts_path(project, "#{pipeline.ref}/download", job: job.name) }
it_behaves_like "downloading"
end
diff --git a/spec/features/projects/blobs/blob_show_spec.rb b/spec/features/projects/blobs/blob_show_spec.rb
index 2ba4d4918ff..e2f9e7e9cc5 100644
--- a/spec/features/projects/blobs/blob_show_spec.rb
+++ b/spec/features/projects/blobs/blob_show_spec.rb
@@ -533,7 +533,7 @@ describe 'File blob', :js do
expect(page).to have_content('This project is licensed under the MIT License.')
# shows a learn more link
- expect(page).to have_link('Learn more', 'http://choosealicense.com/licenses/mit/')
+ expect(page).to have_link('Learn more', href: 'http://choosealicense.com/licenses/mit/')
end
end
end
@@ -566,10 +566,10 @@ describe 'File blob', :js do
expect(page).to have_content('This project manages its dependencies using RubyGems and defines a gem named activerecord.')
# shows a link to the gem
- expect(page).to have_link('activerecord', 'https://rubygems.org/gems/activerecord')
+ expect(page).to have_link('activerecord', href: 'https://rubygems.org/gems/activerecord')
# shows a learn more link
- expect(page).to have_link('Learn more', 'http://choosealicense.com/licenses/mit/')
+ expect(page).to have_link('Learn more', href: 'https://rubygems.org/')
end
end
end
diff --git a/spec/features/projects/clusters/gcp_spec.rb b/spec/features/projects/clusters/gcp_spec.rb
index 31e3ebf675d..edc763ad0ad 100644
--- a/spec/features/projects/clusters/gcp_spec.rb
+++ b/spec/features/projects/clusters/gcp_spec.rb
@@ -33,6 +33,32 @@ describe 'Gcp Cluster', :js do
context 'when user filled form with valid parameters' do
subject { click_button 'Create Kubernetes cluster' }
+ shared_examples 'valid cluster gcp form' do
+ it 'users sees a form with the GCP token' do
+ expect(page).to have_selector(:css, 'form[data-token="token"]')
+ end
+
+ it 'user sees a cluster details page and creation status' do
+ subject
+
+ expect(page).to have_content('Kubernetes cluster is being created on Google Kubernetes Engine...')
+
+ Clusters::Cluster.last.provider.make_created!
+
+ expect(page).to have_content('Kubernetes cluster was successfully created on Google Kubernetes Engine')
+ end
+
+ it 'user sees a error if something wrong during creation' do
+ subject
+
+ expect(page).to have_content('Kubernetes cluster is being created on Google Kubernetes Engine...')
+
+ Clusters::Cluster.last.provider.make_errored!('Something wrong!')
+
+ expect(page).to have_content('Something wrong!')
+ end
+ end
+
before do
allow_any_instance_of(GoogleApi::CloudPlatform::Client)
.to receive(:projects_zones_clusters_create) do
@@ -56,28 +82,16 @@ describe 'Gcp Cluster', :js do
fill_in 'cluster[provider_gcp_attributes][machine_type]', with: 'n1-standard-2'
end
- it 'users sees a form with the GCP token' do
- expect(page).to have_selector(:css, 'form[data-token="token"]')
- end
-
- it 'user sees a cluster details page and creation status' do
- subject
-
- expect(page).to have_content('Kubernetes cluster is being created on Google Kubernetes Engine...')
-
- Clusters::Cluster.last.provider.make_created!
-
- expect(page).to have_content('Kubernetes cluster was successfully created on Google Kubernetes Engine')
- end
-
- it 'user sees a error if something wrong during creation' do
- subject
+ it_behaves_like 'valid cluster gcp form'
- expect(page).to have_content('Kubernetes cluster is being created on Google Kubernetes Engine...')
+ context 'rbac_clusters feature flag is enabled' do
+ before do
+ stub_feature_flags(rbac_clusters: true)
- Clusters::Cluster.last.provider.make_errored!('Something wrong!')
+ check 'cluster_provider_gcp_attributes_legacy_abac'
+ end
- expect(page).to have_content('Something wrong!')
+ it_behaves_like 'valid cluster gcp form'
end
end
diff --git a/spec/features/projects/clusters/user_spec.rb b/spec/features/projects/clusters/user_spec.rb
index ec968bfcf7d..2b4998ed5ac 100644
--- a/spec/features/projects/clusters/user_spec.rb
+++ b/spec/features/projects/clusters/user_spec.rb
@@ -21,42 +21,43 @@ describe 'User Cluster', :js do
end
context 'when user filled form with valid parameters' do
+ shared_examples 'valid cluster user form' do
+ it 'user sees a cluster details page' do
+ subject
+
+ expect(page).to have_content('Kubernetes cluster integration')
+ expect(page.find_field('cluster[name]').value).to eq('dev-cluster')
+ expect(page.find_field('cluster[platform_kubernetes_attributes][api_url]').value)
+ .to have_content('http://example.com')
+ expect(page.find_field('cluster[platform_kubernetes_attributes][token]').value)
+ .to have_content('my-token')
+ end
+ end
+
before do
fill_in 'cluster_name', with: 'dev-cluster'
fill_in 'cluster_platform_kubernetes_attributes_api_url', with: 'http://example.com'
fill_in 'cluster_platform_kubernetes_attributes_token', with: 'my-token'
- click_button 'Add Kubernetes cluster'
end
- it 'user sees a cluster details page' do
- expect(page).to have_content('Kubernetes cluster integration')
- expect(page.find_field('cluster[name]').value).to eq('dev-cluster')
- expect(page.find_field('cluster[platform_kubernetes_attributes][api_url]').value)
- .to have_content('http://example.com')
- expect(page.find_field('cluster[platform_kubernetes_attributes][token]').value)
- .to have_content('my-token')
- end
- end
+ subject { click_button 'Add Kubernetes cluster' }
- context 'rbac_clusters feature flag is enabled' do
- before do
- stub_feature_flags(rbac_clusters: true)
+ it_behaves_like 'valid cluster user form'
- fill_in 'cluster_name', with: 'dev-cluster'
- fill_in 'cluster_platform_kubernetes_attributes_api_url', with: 'http://example.com'
- fill_in 'cluster_platform_kubernetes_attributes_token', with: 'my-token'
- check 'cluster_platform_kubernetes_attributes_authorization_type'
- click_button 'Add Kubernetes cluster'
- end
+ context 'rbac_clusters feature flag is enabled' do
+ before do
+ stub_feature_flags(rbac_clusters: true)
+
+ check 'cluster_platform_kubernetes_attributes_authorization_type'
+ end
- it 'user sees a cluster details page' do
- expect(page).to have_content('Kubernetes cluster integration')
- expect(page.find_field('cluster[name]').value).to eq('dev-cluster')
- expect(page.find_field('cluster[platform_kubernetes_attributes][api_url]').value)
- .to have_content('http://example.com')
- expect(page.find_field('cluster[platform_kubernetes_attributes][token]').value)
- .to have_content('my-token')
- expect(page.find_field('cluster[platform_kubernetes_attributes][authorization_type]', disabled: true)).to be_checked
+ it_behaves_like 'valid cluster user form'
+
+ it 'user sees a cluster details page with RBAC enabled' do
+ subject
+
+ expect(page.find_field('cluster[platform_kubernetes_attributes][authorization_type]', disabled: true)).to be_checked
+ end
end
end
@@ -85,7 +86,6 @@ describe 'User Cluster', :js do
context 'when user disables the cluster' do
before do
page.find(:css, '.js-cluster-enable-toggle-area .js-project-feature-toggle').click
- fill_in 'cluster_name', with: 'dev-cluster'
page.within('#cluster-integration') { click_button 'Save changes' }
end
diff --git a/spec/features/projects/fork_spec.rb b/spec/features/projects/fork_spec.rb
index cd5fef8238e..7c71b4c52e0 100644
--- a/spec/features/projects/fork_spec.rb
+++ b/spec/features/projects/fork_spec.rb
@@ -53,6 +53,18 @@ describe 'Project fork' do
expect(current_path).to have_content(/#{user.namespace.name}/i)
end
+ it 'shows avatars when Gravatar is disabled' do
+ stub_application_setting(gravatar_enabled: false)
+
+ visit project_path(project)
+
+ click_link 'Fork'
+
+ page.within('.fork-thumbnail-container') do
+ expect(page).to have_css('div.identicon')
+ end
+ end
+
it 'shows the forked project on the list' do
visit project_path(project)
diff --git a/spec/features/projects/import_export/export_file_spec.rb b/spec/features/projects/import_export/export_file_spec.rb
index 8a418356541..a2b96514d64 100644
--- a/spec/features/projects/import_export/export_file_spec.rb
+++ b/spec/features/projects/import_export/export_file_spec.rb
@@ -49,6 +49,8 @@ describe 'Import/Export - project export integration test', :js do
expect(file_permissions(project.export_path)).to eq(0700)
+ expect(project.export_file.path).to include('tar.gz')
+
in_directory_with_expanded_export(project) do |exit_status, tmpdir|
expect(exit_status).to eq(0)
diff --git a/spec/features/projects/jobs_spec.rb b/spec/features/projects/jobs_spec.rb
index 83293c0ca7d..d0bf4975b81 100644
--- a/spec/features/projects/jobs_spec.rb
+++ b/spec/features/projects/jobs_spec.rb
@@ -5,7 +5,7 @@ describe 'Jobs', :clean_gitlab_redis_shared_state do
let(:user) { create(:user) }
let(:user_access_level) { :developer }
let(:project) { create(:project, :repository) }
- let(:pipeline) { create(:ci_pipeline, project: project) }
+ let(:pipeline) { create(:ci_pipeline, project: project, sha: project.commit('HEAD').sha) }
let(:job) { create(:ci_build, :trace_live, pipeline: pipeline) }
let(:job2) { create(:ci_build) }
@@ -20,7 +20,7 @@ describe 'Jobs', :clean_gitlab_redis_shared_state do
end
describe "GET /:project/jobs" do
- let!(:job) { create(:ci_build, pipeline: pipeline) }
+ let!(:job) { create(:ci_build, pipeline: pipeline) }
context "Pending scope" do
before do
@@ -115,22 +115,28 @@ describe 'Jobs', :clean_gitlab_redis_shared_state do
context "Job from project" do
let(:job) { create(:ci_build, :success, :trace_live, pipeline: pipeline) }
- before do
+ it 'shows status name', :js do
visit project_job_path(project, job)
- end
- it 'shows status name', :js do
+ wait_for_requests
+
expect(page).to have_css('.ci-status.ci-success', text: 'passed')
end
- it 'shows commit`s data' do
- expect(page.status_code).to eq(200)
+ it 'shows commit`s data', :js do
+ requests = inspect_requests() do
+ visit project_job_path(project, job)
+ end
+
+ wait_for_requests
+ expect(requests.first.status_code).to eq(200)
expect(page).to have_content pipeline.sha[0..7]
- expect(page).to have_content pipeline.git_commit_message
- expect(page).to have_content pipeline.git_author_name
+ expect(page).to have_content pipeline.commit.title
end
it 'shows active job' do
+ visit project_job_path(project, job)
+
expect(page).to have_selector('.build-job.active')
end
end
@@ -199,7 +205,7 @@ describe 'Jobs', :clean_gitlab_redis_shared_state do
it { expect(page.status_code).to eq(404) }
end
- context "Download artifacts" do
+ context "Download artifacts", :js do
before do
job.update(legacy_artifacts_file: artifacts_file)
visit project_job_path(project, job)
@@ -208,9 +214,22 @@ describe 'Jobs', :clean_gitlab_redis_shared_state do
it 'has button to download artifacts' do
expect(page).to have_content 'Download'
end
+
+ it 'downloads the zip file when user clicks the download button' do
+ requests = inspect_requests() do
+ click_link 'Download'
+ end
+
+ artifact_request = requests.find { |req| req.url.match(%r{artifacts/download}) }
+
+ expect(artifact_request.response_headers["Content-Disposition"]).to eq(%Q{attachment; filename="#{job.artifacts_file.filename}"})
+ expect(artifact_request.response_headers['Content-Transfer-Encoding']).to eq("binary")
+ expect(artifact_request.response_headers['Content-Type']).to eq("image/gif")
+ expect(artifact_request.body).to eq(job.artifacts_file.file.read.b)
+ end
end
- context 'Artifacts expire date' do
+ context 'Artifacts expire date', :js do
before do
job.update(legacy_artifacts_file: artifacts_file,
artifacts_expire_at: expire_at)
@@ -231,12 +250,12 @@ describe 'Jobs', :clean_gitlab_redis_shared_state do
context 'when user has ability to update job' do
it 'keeps artifacts when keep button is clicked' do
- expect(page).to have_content 'The artifacts will be removed'
+ expect(page).to have_content 'The artifacts will be removed in'
click_link 'Keep'
expect(page).to have_no_link 'Keep'
- expect(page).to have_no_content 'The artifacts will be removed'
+ expect(page).to have_no_content 'The artifacts will be removed in'
end
end
@@ -314,6 +333,7 @@ describe 'Jobs', :clean_gitlab_redis_shared_state do
shared_examples 'expected variables behavior' do
it 'shows variable key and value after click', :js do
+ expect(page).to have_content('Token')
expect(page).to have_css('.js-reveal-variables')
expect(page).not_to have_css('.js-build-variable')
expect(page).not_to have_css('.js-build-value')
@@ -542,20 +562,26 @@ describe 'Jobs', :clean_gitlab_redis_shared_state do
end
end
- describe "GET /:project/jobs/:id/download" do
+ describe "GET /:project/jobs/:id/download", :js do
before do
job.update(legacy_artifacts_file: artifacts_file)
visit project_job_path(project, job)
+
click_link 'Download'
end
context "Build from other project" do
before do
job2.update(legacy_artifacts_file: artifacts_file)
- visit download_project_job_artifacts_path(project, job2)
end
- it { expect(page.status_code).to eq(404) }
+ it do
+ requests = inspect_requests() do
+ visit download_project_job_artifacts_path(project, job2)
+ end
+
+ expect(requests.first.status_code).to eq(404)
+ end
end
end
diff --git a/spec/features/projects/members/invite_group_spec.rb b/spec/features/projects/members/invite_group_spec.rb
index 0fb3eb20b5b..fceead0b45e 100644
--- a/spec/features/projects/members/invite_group_spec.rb
+++ b/spec/features/projects/members/invite_group_spec.rb
@@ -40,7 +40,7 @@ describe 'Project > Members > Invite group', :js do
select2 group_to_share_with.id, from: '#link_group_id'
page.find('body').click
- find('.btn-create').click
+ find('.btn-success').click
page.within('.project-members-groups') do
expect(page).to have_content(group_to_share_with.name)
@@ -122,7 +122,7 @@ describe 'Project > Members > Invite group', :js do
fill_in 'expires_at_groups', with: (Time.now + 4.5.days).strftime('%Y-%m-%d')
click_on 'invite-group-tab'
- find('.btn-create').click
+ find('.btn-success').click
end
it 'the group link shows the expiration time with a warning class' do
diff --git a/spec/features/projects/pipelines/pipelines_spec.rb b/spec/features/projects/pipelines/pipelines_spec.rb
index 26a92f14787..41822babbc9 100644
--- a/spec/features/projects/pipelines/pipelines_spec.rb
+++ b/spec/features/projects/pipelines/pipelines_spec.rb
@@ -9,6 +9,7 @@ describe 'Pipelines', :js do
before do
sign_in(user)
project.add_developer(user)
+ project.update!(auto_devops_attributes: { enabled: false })
end
describe 'GET /:project/pipelines' do
@@ -641,6 +642,7 @@ describe 'Pipelines', :js do
context 'when user is not logged in' do
before do
+ project.update!(auto_devops_attributes: { enabled: false })
visit project_pipelines_path(project)
end
diff --git a/spec/features/projects/services/user_activates_mattermost_slash_command_spec.rb b/spec/features/projects/services/user_activates_mattermost_slash_command_spec.rb
index 25b74cc481d..70f3a812ee9 100644
--- a/spec/features/projects/services/user_activates_mattermost_slash_command_spec.rb
+++ b/spec/features/projects/services/user_activates_mattermost_slash_command_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe 'Setup Mattermost slash commands', :js do
+describe 'Set up Mattermost slash commands', :js do
let(:user) { create(:user) }
let(:project) { create(:project) }
let(:service) { project.create_mattermost_slash_commands_service }
diff --git a/spec/features/projects/settings/user_tags_project_spec.rb b/spec/features/projects/settings/user_tags_project_spec.rb
index 57b4b1287fa..9357215ae6f 100644
--- a/spec/features/projects/settings/user_tags_project_spec.rb
+++ b/spec/features/projects/settings/user_tags_project_spec.rb
@@ -9,15 +9,13 @@ describe 'Projects > Settings > User tags a project' do
visit edit_project_path(project)
end
- context 'when a project is archived' do
- it 'unarchives a project' do
- fill_in 'Tags', with: 'tag1, tag2'
+ it 'sets project tags' do
+ fill_in 'Tags', with: 'tag1, tag2'
- page.within '.general-settings' do
- click_button 'Save changes'
- end
-
- expect(find_field('Tags').value).to eq 'tag1, tag2'
+ page.within '.general-settings' do
+ click_button 'Save changes'
end
+
+ expect(find_field('Tags').value).to eq 'tag1, tag2'
end
end
diff --git a/spec/features/projects/show/user_sees_setup_shortcut_buttons_spec.rb b/spec/features/projects/show/user_sees_setup_shortcut_buttons_spec.rb
index b8326edd4fd..6fe21579e8e 100644
--- a/spec/features/projects/show/user_sees_setup_shortcut_buttons_spec.rb
+++ b/spec/features/projects/show/user_sees_setup_shortcut_buttons_spec.rb
@@ -28,8 +28,6 @@ describe 'Projects > Show > User sees setup shortcut buttons' do
end
it '"Auto DevOps enabled" button not linked' do
- project.create_auto_devops!(enabled: true)
-
visit project_path(project)
page.within('.project-stats') do
@@ -65,19 +63,23 @@ describe 'Projects > Show > User sees setup shortcut buttons' do
end
describe 'Auto DevOps button' do
- it '"Enable Auto DevOps" button linked to settings page' do
- page.within('.project-stats') do
- expect(page).to have_link('Enable Auto DevOps', href: project_settings_ci_cd_path(project, anchor: 'autodevops-settings'))
+ context 'when Auto DevOps is enabled' do
+ it '"Auto DevOps enabled" anchor linked to settings page' do
+ visit project_path(project)
+
+ page.within('.project-stats') do
+ expect(page).to have_link('Auto DevOps enabled', href: project_settings_ci_cd_path(project, anchor: 'autodevops-settings'))
+ end
end
end
- it '"Auto DevOps enabled" anchor linked to settings page' do
- project.create_auto_devops!(enabled: true)
-
- visit project_path(project)
+ context 'when Auto DevOps is not enabled' do
+ let(:project) { create(:project, :public, :empty_repo, auto_devops_attributes: { enabled: false }) }
- page.within('.project-stats') do
- expect(page).to have_link('Auto DevOps enabled', href: project_settings_ci_cd_path(project, anchor: 'autodevops-settings'))
+ it '"Enable Auto DevOps" button linked to settings page' do
+ page.within('.project-stats') do
+ expect(page).to have_link('Enable Auto DevOps', href: project_settings_ci_cd_path(project, anchor: 'autodevops-settings'))
+ end
end
end
end
@@ -113,27 +115,31 @@ describe 'Projects > Show > User sees setup shortcut buttons' do
visit project_path(project)
end
- it 'no Auto DevOps button if can not manage pipelines' do
- page.within('.project-stats') do
- expect(page).not_to have_link('Enable Auto DevOps')
- expect(page).not_to have_link('Auto DevOps enabled')
+ context 'when Auto DevOps is enabled' do
+ it '"Auto DevOps enabled" button not linked' do
+ visit project_path(project)
+
+ page.within('.project-stats') do
+ expect(page).to have_text('Auto DevOps enabled')
+ end
end
end
- it '"Auto DevOps enabled" button not linked' do
- project.create_auto_devops!(enabled: true)
-
- visit project_path(project)
+ context 'when Auto DevOps is not enabled' do
+ let(:project) { create(:project, :public, :repository, auto_devops_attributes: { enabled: false }) }
- page.within('.project-stats') do
- expect(page).to have_text('Auto DevOps enabled')
+ it 'no Auto DevOps button if can not manage pipelines' do
+ page.within('.project-stats') do
+ expect(page).not_to have_link('Enable Auto DevOps')
+ expect(page).not_to have_link('Auto DevOps enabled')
+ end
end
- end
- it 'no Kubernetes cluster button if can not manage clusters' do
- page.within('.project-stats') do
- expect(page).not_to have_link('Add Kubernetes cluster')
- expect(page).not_to have_link('Kubernetes configured')
+ it 'no Kubernetes cluster button if can not manage clusters' do
+ page.within('.project-stats') do
+ expect(page).not_to have_link('Add Kubernetes cluster')
+ expect(page).not_to have_link('Kubernetes configured')
+ end
end
end
end
@@ -222,97 +228,105 @@ describe 'Projects > Show > User sees setup shortcut buttons' do
end
describe 'GitLab CI configuration button' do
- it '"Set up CI/CD" button linked to new file populated for a .gitlab-ci.yml' do
- visit project_path(project)
-
- expect(project.repository.gitlab_ci_yml).to be_nil
+ context 'when Auto DevOps is enabled' do
+ it 'no "Set up CI/CD" button if the project has Auto DevOps enabled' do
+ visit project_path(project)
- page.within('.project-stats') do
- expect(page).to have_link('Set up CI/CD', href: presenter.add_ci_yml_path)
+ page.within('.project-stats') do
+ expect(page).not_to have_link('Set up CI/CD')
+ end
end
end
- it 'no "Set up CI/CD" button if the project already has a .gitlab-ci.yml' do
- Files::CreateService.new(
- project,
- project.creator,
- start_branch: 'master',
- branch_name: 'master',
- commit_message: "Add .gitlab-ci.yml",
- file_path: '.gitlab-ci.yml',
- file_content: File.read(Rails.root.join('spec/support/gitlab_stubs/gitlab_ci.yml'))
- ).execute
+ context 'when Auto DevOps is not enabled' do
+ let(:project) { create(:project, :public, :repository, auto_devops_attributes: { enabled: false }) }
- expect(project.repository.gitlab_ci_yml).not_to be_nil
+ it '"Set up CI/CD" button linked to new file populated for a .gitlab-ci.yml' do
+ visit project_path(project)
- visit project_path(project)
+ expect(project.repository.gitlab_ci_yml).to be_nil
- page.within('.project-stats') do
- expect(page).not_to have_link('Set up CI/CD')
+ page.within('.project-stats') do
+ expect(page).to have_link('Set up CI/CD', href: presenter.add_ci_yml_path)
+ end
end
- end
- it 'no "Set up CI/CD" button if the project has Auto DevOps enabled' do
- project.create_auto_devops!(enabled: true)
+ it 'no "Set up CI/CD" button if the project already has a .gitlab-ci.yml' do
+ Files::CreateService.new(
+ project,
+ project.creator,
+ start_branch: 'master',
+ branch_name: 'master',
+ commit_message: "Add .gitlab-ci.yml",
+ file_path: '.gitlab-ci.yml',
+ file_content: File.read(Rails.root.join('spec/support/gitlab_stubs/gitlab_ci.yml'))
+ ).execute
- visit project_path(project)
+ expect(project.repository.gitlab_ci_yml).not_to be_nil
- page.within('.project-stats') do
- expect(page).not_to have_link('Set up CI/CD')
+ visit project_path(project)
+
+ page.within('.project-stats') do
+ expect(page).not_to have_link('Set up CI/CD')
+ end
end
end
end
describe 'Auto DevOps button' do
- it '"Enable Auto DevOps" button linked to settings page' do
- visit project_path(project)
+ context 'when Auto DevOps is enabled' do
+ it '"Auto DevOps enabled" anchor linked to settings page' do
+ visit project_path(project)
- page.within('.project-stats') do
- expect(page).to have_link('Enable Auto DevOps', href: project_settings_ci_cd_path(project, anchor: 'autodevops-settings'))
+ page.within('.project-stats') do
+ expect(page).to have_link('Auto DevOps enabled', href: project_settings_ci_cd_path(project, anchor: 'autodevops-settings'))
+ end
end
end
- it '"Enable Auto DevOps" button linked to settings page' do
- project.create_auto_devops!(enabled: true)
+ context 'when Auto DevOps is not enabled' do
+ let(:project) { create(:project, :public, :repository, auto_devops_attributes: { enabled: false }) }
- visit project_path(project)
+ it '"Enable Auto DevOps" button linked to settings page' do
+ visit project_path(project)
- page.within('.project-stats') do
- expect(page).to have_link('Auto DevOps enabled', href: project_settings_ci_cd_path(project, anchor: 'autodevops-settings'))
+ page.within('.project-stats') do
+ expect(page).to have_link('Enable Auto DevOps', href: project_settings_ci_cd_path(project, anchor: 'autodevops-settings'))
+ end
end
- end
- it 'no Auto DevOps button if Auto DevOps callout is shown' do
- allow_any_instance_of(AutoDevopsHelper).to receive(:show_auto_devops_callout?).and_return(true)
+ it 'no Auto DevOps button if Auto DevOps callout is shown' do
+ allow_any_instance_of(AutoDevopsHelper).to receive(:show_auto_devops_callout?).and_return(true)
- visit project_path(project)
+ visit project_path(project)
- expect(page).to have_selector('.js-autodevops-banner')
+ expect(page).to have_selector('.js-autodevops-banner')
- page.within('.project-stats') do
- expect(page).not_to have_link('Enable Auto DevOps')
- expect(page).not_to have_link('Auto DevOps enabled')
+ page.within('.project-stats') do
+ expect(page).not_to have_link('Enable Auto DevOps')
+ expect(page).not_to have_link('Auto DevOps enabled')
+ end
end
- end
- it 'no "Enable Auto DevOps" button when .gitlab-ci.yml already exists' do
- Files::CreateService.new(
- project,
- project.creator,
- start_branch: 'master',
- branch_name: 'master',
- commit_message: "Add .gitlab-ci.yml",
- file_path: '.gitlab-ci.yml',
- file_content: File.read(Rails.root.join('spec/support/gitlab_stubs/gitlab_ci.yml'))
- ).execute
+ it 'no "Enable Auto DevOps" button when .gitlab-ci.yml already exists' do
+ Files::CreateService.new(
+ project,
+ project.creator,
+ start_branch: 'master',
+ branch_name: 'master',
+ commit_message: "Add .gitlab-ci.yml",
+ file_path: '.gitlab-ci.yml',
+ file_content: File.read(Rails.root.join('spec/support/gitlab_stubs/gitlab_ci.yml'))
+ ).execute
- expect(project.repository.gitlab_ci_yml).not_to be_nil
+ expect(project.repository.gitlab_ci_yml).not_to be_nil
- visit project_path(project)
+ visit project_path(project)
- page.within('.project-stats') do
- expect(page).not_to have_link('Enable Auto DevOps')
- expect(page).not_to have_link('Auto DevOps enabled')
+ page.within('.project-stats') do
+ expect(page).not_to have_link('Enable Auto DevOps')
+ expect(page).not_to have_link('Auto DevOps enabled')
+ end
end
end
end
diff --git a/spec/features/projects/tree/create_directory_spec.rb b/spec/features/projects/tree/create_directory_spec.rb
index 9e58280b868..2cb2a23b7be 100644
--- a/spec/features/projects/tree/create_directory_spec.rb
+++ b/spec/features/projects/tree/create_directory_spec.rb
@@ -43,7 +43,7 @@ describe 'Multi-file editor new directory', :js do
find('.js-ide-commit-mode').click
find('.multi-file-commit-list-item').hover
- first('.multi-file-discard-btn .btn').click
+ click_button 'Stage'
fill_in('commit-message', with: 'commit message ide')
diff --git a/spec/features/projects/tree/create_file_spec.rb b/spec/features/projects/tree/create_file_spec.rb
index a04d3566a7e..9f5524da8e9 100644
--- a/spec/features/projects/tree/create_file_spec.rb
+++ b/spec/features/projects/tree/create_file_spec.rb
@@ -35,7 +35,7 @@ describe 'Multi-file editor new file', :js do
find('.js-ide-commit-mode').click
find('.multi-file-commit-list-item').hover
- first('.multi-file-discard-btn .btn').click
+ click_button 'Stage'
fill_in('commit-message', with: 'commit message ide')
diff --git a/spec/features/runners_spec.rb b/spec/features/runners_spec.rb
index 0c6cf3dc477..cb7a912946c 100644
--- a/spec/features/runners_spec.rb
+++ b/spec/features/runners_spec.rb
@@ -198,7 +198,7 @@ describe 'Runners' do
expect(page).to have_content 'This group does not provide any group Runners yet'
expect(page).to have_content 'Group maintainers can register group runners in the Group CI/CD settings'
- expect(page).not_to have_content 'Ask your group maintainer to setup a group Runner'
+ expect(page).not_to have_content 'Ask your group maintainer to set up a group Runner'
end
end
end
@@ -224,7 +224,7 @@ describe 'Runners' do
expect(page).to have_content 'This group does not provide any group Runners yet.'
expect(page).not_to have_content 'Group maintainers can register group runners in the Group CI/CD settings'
- expect(page).to have_content 'Ask your group maintainer to setup a group Runner.'
+ expect(page).to have_content 'Ask your group maintainer to set up a group Runner.'
end
end
diff --git a/spec/features/snippets/notes_on_personal_snippets_spec.rb b/spec/features/snippets/notes_on_personal_snippets_spec.rb
index 1442e011d52..eeacaf5f72a 100644
--- a/spec/features/snippets/notes_on_personal_snippets_spec.rb
+++ b/spec/features/snippets/notes_on_personal_snippets_spec.rb
@@ -103,7 +103,7 @@ describe 'Comments on personal snippets', :js do
page.within('.current-note-edit-form') do
fill_in 'note[note]', with: 'new content'
- find('.btn-save').click
+ find('.btn-success').click
end
page.within("#notes-list li#note_#{snippet_notes[0].id}") do
diff --git a/spec/features/snippets/user_sees_breadcrumb_links.rb b/spec/features/snippets/user_sees_breadcrumb_links.rb
new file mode 100644
index 00000000000..696f2b93390
--- /dev/null
+++ b/spec/features/snippets/user_sees_breadcrumb_links.rb
@@ -0,0 +1,17 @@
+require 'rails_helper'
+
+describe 'New user snippet breadcrumbs' do
+ let(:user) { create(:user) }
+
+ before do
+ sign_in(user)
+ visit new_snippet_path
+ end
+
+ it 'display a link to user snippets and new user snippet pages' do
+ page.within '.breadcrumbs' do
+ expect(find_link('Snippets')[:href]).to end_with(dashboard_snippets_path)
+ expect(find_link('New')[:href]).to end_with(new_snippet_path)
+ end
+ end
+end
diff --git a/spec/features/u2f_spec.rb b/spec/features/u2f_spec.rb
index f245c1ebbd9..f1192f48b86 100644
--- a/spec/features/u2f_spec.rb
+++ b/spec/features/u2f_spec.rb
@@ -3,14 +3,14 @@ require 'spec_helper'
describe 'Using U2F (Universal 2nd Factor) Devices for Authentication', :js do
def manage_two_factor_authentication
click_on 'Manage two-factor authentication'
- expect(page).to have_content("Setup new U2F device")
+ expect(page).to have_content("Set up new U2F device")
wait_for_requests
end
def register_u2f_device(u2f_device = nil, name: 'My device')
u2f_device ||= FakeU2fDevice.new(page, name)
u2f_device.respond_to_u2f_registration
- click_on 'Setup new U2F device'
+ click_on 'Set up new U2F device'
expect(page).to have_content('Your device was successfully set up')
fill_in "Pick a name", with: name
click_on 'Register U2F device'
@@ -34,7 +34,7 @@ describe 'Using U2F (Universal 2nd Factor) Devices for Authentication', :js do
visit profile_account_path
click_on 'Enable two-factor authentication'
- expect(page).to have_button('Setup new U2F device', disabled: true)
+ expect(page).to have_button('Set up new U2F device', disabled: true)
end
end
@@ -109,7 +109,7 @@ describe 'Using U2F (Universal 2nd Factor) Devices for Authentication', :js do
# Have the "u2f device" respond with bad data
page.execute_script("u2f.register = function(_,_,_,callback) { callback('bad response'); };")
- click_on 'Setup new U2F device'
+ click_on 'Set up new U2F device'
expect(page).to have_content('Your device was successfully set up')
click_on 'Register U2F device'
@@ -124,7 +124,7 @@ describe 'Using U2F (Universal 2nd Factor) Devices for Authentication', :js do
# Failed registration
page.execute_script("u2f.register = function(_,_,_,callback) { callback('bad response'); };")
- click_on 'Setup new U2F device'
+ click_on 'Set up new U2F device'
expect(page).to have_content('Your device was successfully set up')
click_on 'Register U2F device'
expect(page).to have_content("The form contains the following error")
diff --git a/spec/finders/admin/runners_finder_spec.rb b/spec/finders/admin/runners_finder_spec.rb
index 1e9793a5e0a..0b2325cc7ca 100644
--- a/spec/finders/admin/runners_finder_spec.rb
+++ b/spec/finders/admin/runners_finder_spec.rb
@@ -29,6 +29,14 @@ describe Admin::RunnersFinder do
end
end
+ context 'filter by runner type' do
+ it 'calls the corresponding scope on Ci::Runner' do
+ expect(Ci::Runner).to receive(:project_type).and_call_original
+
+ described_class.new(params: { type_type: 'project_type' }).execute
+ end
+ end
+
context 'sort' do
context 'without sort param' do
it 'sorts by created_at' do
diff --git a/spec/finders/group_labels_finder_spec.rb b/spec/finders/group_labels_finder_spec.rb
new file mode 100644
index 00000000000..ef68fc105e4
--- /dev/null
+++ b/spec/finders/group_labels_finder_spec.rb
@@ -0,0 +1,33 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe GroupLabelsFinder, '#execute' do
+ let!(:group) { create(:group) }
+ let!(:label1) { create(:group_label, title: 'Foo', description: 'Lorem ipsum', group: group) }
+ let!(:label2) { create(:group_label, title: 'Bar', description: 'Fusce consequat', group: group) }
+
+ it 'returns all group labels sorted by name if no params' do
+ result = described_class.new(group).execute
+
+ expect(result.to_a).to match_array([label2, label1])
+ end
+
+ it 'returns all group labels sorted by name desc' do
+ result = described_class.new(group, sort: 'name_desc').execute
+
+ expect(result.to_a).to match_array([label2, label1])
+ end
+
+ it 'returns group labels that march search' do
+ result = described_class.new(group, search: 'Foo').execute
+
+ expect(result.to_a).to match_array([label1])
+ end
+
+ it 'returns second page of labels' do
+ result = described_class.new(group, page: '2').execute
+
+ expect(result.to_a).to match_array([])
+ end
+end
diff --git a/spec/fixtures/api/schemas/deployment.json b/spec/fixtures/api/schemas/deployment.json
index 536e6475c23..8c8cdf8bcb2 100644
--- a/spec/fixtures/api/schemas/deployment.json
+++ b/spec/fixtures/api/schemas/deployment.json
@@ -1,45 +1,31 @@
{
- "additionalProperties": false,
- "properties": {
- "created_at": {
- "type": "string"
- },
- "id": {
- "type": "integer"
- },
- "iid": {
- "type": "integer"
- },
- "last?": {
- "type": "boolean"
- },
- "ref": {
- "additionalProperties": false,
- "properties": {
- "name": {
- "type": "string"
- }
- },
- "required": [
- "name"
- ],
- "type": "object"
- },
- "sha": {
- "type": "string"
- },
- "tag": {
- "type": "boolean"
- }
+ "type": "object",
+ "required": [
+ "sha",
+ "created_at",
+ "iid",
+ "tag",
+ "last?",
+ "ref",
+ "id"
+ ],
+ "properties": {
+ "created_at": { "type": "string" },
+ "id": { "type": "integer" },
+ "iid": { "type": "integer" },
+ "last?": { "type": "boolean" },
+ "ref": {
+ "type": "object",
+ "required": [
+ "name"
+ ],
+ "properties": {
+ "name": { "type": "string" }
+ },
+ "additionalProperties": false
},
- "required": [
- "sha",
- "created_at",
- "iid",
- "tag",
- "last?",
- "ref",
- "id"
- ],
- "type": "object"
+ "sha": { "type": "string" },
+ "tag": { "type": "boolean" }
+ },
+ "additionalProperties": false
}
diff --git a/spec/fixtures/api/schemas/entities/commit.json b/spec/fixtures/api/schemas/entities/commit.json
new file mode 100644
index 00000000000..686d29c97d2
--- /dev/null
+++ b/spec/fixtures/api/schemas/entities/commit.json
@@ -0,0 +1,27 @@
+{
+ "type": "object",
+ "allOf": [
+ { "$ref": "../public_api/v4/commit/basic.json" },
+ {
+ "type": "object",
+ "required": [
+ "author_gravatar_url",
+ "commit_url",
+ "commit_path",
+ "author"
+ ],
+ "properties": {
+ "author_gravatar_url": { "type": "string" },
+ "commit_url": { "type": "string" },
+ "commit_path": { "type": "string" },
+ "author": {
+ "oneOf": [
+ { "type": "null" },
+ { "type": "user.json" }
+ ]
+ }
+ },
+ "additionalProperties": false
+ }
+ ]
+}
diff --git a/spec/fixtures/api/schemas/entities/user.json b/spec/fixtures/api/schemas/entities/user.json
index 6482e0eedd2..82d80b75cef 100644
--- a/spec/fixtures/api/schemas/entities/user.json
+++ b/spec/fixtures/api/schemas/entities/user.json
@@ -5,13 +5,19 @@
"state",
"avatar_url",
"web_url",
- "path"
+ "path",
+ "name",
+ "username"
],
"properties": {
"id": { "type": "integer" },
"state": { "type": "string" },
"avatar_url": { "type": "string" },
"web_url": { "type": "string" },
- "path": { "type": "string" }
- }
+ "path": { "type": "string" },
+ "name": { "type": "string" },
+ "username": { "type": "string" },
+ "status_tooltip_html": { "$ref": "../types/nullable_string.json" }
+ },
+ "additionalProperties": false
}
diff --git a/spec/fixtures/api/schemas/environment.json b/spec/fixtures/api/schemas/environment.json
new file mode 100644
index 00000000000..f1d33e3ce7b
--- /dev/null
+++ b/spec/fixtures/api/schemas/environment.json
@@ -0,0 +1,38 @@
+{
+ "type": "object",
+ "required": [
+ "id",
+ "name",
+ "state",
+ "external_url",
+ "environment_type",
+ "has_stop_action",
+ "environment_path",
+ "stop_path",
+ "folder_path",
+ "created_at",
+ "updated_at",
+ "can_stop"
+ ],
+ "properties": {
+ "id": { "type": "integer" },
+ "name": { "type": "string" },
+ "state": { "type": "string" },
+ "external_url": { "$ref": "types/nullable_string.json" },
+ "environment_type": { "$ref": "types/nullable_string.json" },
+ "has_stop_action": { "type": "boolean" },
+ "environment_path": { "type": "string" },
+ "stop_path": { "type": "string" },
+ "folder_path": { "type": "string" },
+ "created_at": { "type": "string", "format": "date-time" },
+ "updated_at": { "type": "string", "format": "date-time" },
+ "can_stop": { "type": "boolean" },
+ "last_deployment": {
+ "oneOf": [
+ { "type": "null" },
+ { "$ref": "deployment.json" }
+ ]
+ }
+ },
+ "additionalProperties": false
+}
diff --git a/spec/fixtures/api/schemas/job/deployment_status.json b/spec/fixtures/api/schemas/job/deployment_status.json
new file mode 100644
index 00000000000..a90b8b35654
--- /dev/null
+++ b/spec/fixtures/api/schemas/job/deployment_status.json
@@ -0,0 +1,27 @@
+{
+ "type": "object",
+ "required": [
+ "status",
+ "icon",
+ "environment"
+ ],
+ "properties": {
+ "status": {
+ "oneOf": [
+ {
+ "type": "string",
+ "enum": [
+ "last",
+ "creating",
+ "failed",
+ "out_of_date"
+ ]
+ },
+ { "type": "null" }
+ ]
+ },
+ "icon": { "type": "string" },
+ "environment": { "$ref": "../environment.json" }
+ },
+ "additionalProperties": false
+}
diff --git a/spec/fixtures/api/schemas/job/job.json b/spec/fixtures/api/schemas/job/job.json
index f5d58b21e3d..734c535ef70 100644
--- a/spec/fixtures/api/schemas/job/job.json
+++ b/spec/fixtures/api/schemas/job/job.json
@@ -25,7 +25,9 @@
"playable": { "type": "boolean" },
"created_at": { "type": "string" },
"updated_at": { "type": "string" },
- "status": { "$ref": "../status/ci_detailed_status.json" }
+ "status": { "$ref": "../status/ci_detailed_status.json" },
+ "callout_message": { "type": "string" },
+ "recoverable": { "type": "boolean" }
},
"additionalProperties": true
}
diff --git a/spec/fixtures/api/schemas/job/job_details.json b/spec/fixtures/api/schemas/job/job_details.json
index b82f7413b50..07e674216fa 100644
--- a/spec/fixtures/api/schemas/job/job_details.json
+++ b/spec/fixtures/api/schemas/job/job_details.json
@@ -3,9 +3,19 @@
{ "$ref": "job.json" }
],
"description": "An extension of job.json with more detailed information",
+ "required": [
+ "artifact",
+ "runner",
+ "runners",
+ "has_trace"
+ ],
"properties": {
"artifact": { "$ref": "artifact.json" },
"terminal_path": { "type": "string" },
- "trigger": { "$ref": "trigger.json" }
+ "trigger": { "$ref": "trigger.json" },
+ "deployment_status": { "$ref": "deployment_status.json" },
+ "runner": { "$ref": "runner.json" },
+ "runners": { "$ref": "runners.json" },
+ "has_trace": { "type": "boolean" }
}
}
diff --git a/spec/fixtures/api/schemas/job/runner.json b/spec/fixtures/api/schemas/job/runner.json
new file mode 100644
index 00000000000..acfeeeeb808
--- /dev/null
+++ b/spec/fixtures/api/schemas/job/runner.json
@@ -0,0 +1,17 @@
+{
+ "oneOf": [
+ { "type": "null" },
+ {
+ "type": "object",
+ "required": [
+ "id",
+ "description"
+ ],
+ "properties": {
+ "id": { "type": "integer" },
+ "description": { "type": "string" },
+ "edit_path": { "type": "string" }
+ }
+ }
+ ]
+}
diff --git a/spec/fixtures/api/schemas/job/runners.json b/spec/fixtures/api/schemas/job/runners.json
new file mode 100644
index 00000000000..bebb0c88652
--- /dev/null
+++ b/spec/fixtures/api/schemas/job/runners.json
@@ -0,0 +1,13 @@
+{
+ "type": "object",
+ "required": [
+ "online",
+ "available"
+ ],
+ "properties": {
+ "online": { "type": "boolean" },
+ "available": { "type": "boolean" },
+ "settings_path": { "type": "string" }
+ },
+ "additionalProperties": false
+}
diff --git a/spec/fixtures/api/schemas/pipeline_stage.json b/spec/fixtures/api/schemas/pipeline_stage.json
index f72988a3d3d..c01a1946185 100644
--- a/spec/fixtures/api/schemas/pipeline_stage.json
+++ b/spec/fixtures/api/schemas/pipeline_stage.json
@@ -16,6 +16,11 @@
"items": { "$ref": "job/job.json" },
"optional": true
},
+ "retried": {
+ "type": "array",
+ "items": { "$ref": "job/job.json" },
+ "optional": true
+ },
"status": { "$ref": "status/ci_detailed_status.json" },
"path": { "type": "string" },
"dropdown_path": { "type": "string" }
diff --git a/spec/fixtures/api/schemas/types/nullable_string.json b/spec/fixtures/api/schemas/types/nullable_string.json
new file mode 100644
index 00000000000..e3b0baef849
--- /dev/null
+++ b/spec/fixtures/api/schemas/types/nullable_string.json
@@ -0,0 +1,6 @@
+{
+ "oneOf": [
+ { "type": "null" },
+ { "type": "string" }
+ ]
+}
diff --git a/spec/helpers/application_helper_spec.rb b/spec/helpers/application_helper_spec.rb
index 14297a1a544..1238cfbd1e7 100644
--- a/spec/helpers/application_helper_spec.rb
+++ b/spec/helpers/application_helper_spec.rb
@@ -3,48 +3,66 @@ require 'spec_helper'
describe ApplicationHelper do
describe 'current_controller?' do
- it 'returns true when controller matches argument' do
+ before do
stub_controller_name('foo')
+ end
- expect(helper.current_controller?(:foo)).to eq true
+ it 'returns true when controller matches argument' do
+ expect(helper.current_controller?(:foo)).to be_truthy
end
it 'returns false when controller does not match argument' do
- stub_controller_name('foo')
-
- expect(helper.current_controller?(:bar)).to eq false
+ expect(helper.current_controller?(:bar)).to be_falsey
end
it 'takes any number of arguments' do
- stub_controller_name('foo')
+ expect(helper.current_controller?(:baz, :bar)).to be_falsey
+ expect(helper.current_controller?(:baz, :bar, :foo)).to be_truthy
+ end
+
+ context 'when namespaced' do
+ before do
+ stub_controller_path('bar/foo')
+ end
+
+ it 'returns true when controller matches argument' do
+ expect(helper.current_controller?(:foo)).to be_truthy
+ end
- expect(helper.current_controller?(:baz, :bar)).to eq false
- expect(helper.current_controller?(:baz, :bar, :foo)).to eq true
+ it 'returns true when controller and namespace matches argument in path notation' do
+ expect(helper.current_controller?('bar/foo')).to be_truthy
+ end
+
+ it 'returns false when namespace doesnt match' do
+ expect(helper.current_controller?('foo/foo')).to be_falsey
+ end
end
def stub_controller_name(value)
allow(helper.controller).to receive(:controller_name).and_return(value)
end
+
+ def stub_controller_path(value)
+ allow(helper.controller).to receive(:controller_path).and_return(value)
+ end
end
describe 'current_action?' do
- it 'returns true when action matches' do
+ before do
stub_action_name('foo')
+ end
- expect(helper.current_action?(:foo)).to eq true
+ it 'returns true when action matches' do
+ expect(helper.current_action?(:foo)).to be_truthy
end
it 'returns false when action does not match' do
- stub_action_name('foo')
-
- expect(helper.current_action?(:bar)).to eq false
+ expect(helper.current_action?(:bar)).to be_falsey
end
it 'takes any number of arguments' do
- stub_action_name('foo')
-
- expect(helper.current_action?(:baz, :bar)).to eq false
- expect(helper.current_action?(:baz, :bar, :foo)).to eq true
+ expect(helper.current_action?(:baz, :bar)).to be_falsey
+ expect(helper.current_action?(:baz, :bar, :foo)).to be_truthy
end
def stub_action_name(value)
@@ -100,8 +118,7 @@ describe ApplicationHelper do
end
it 'accepts a custom html_class' do
- expect(element(html_class: 'custom_class').attr('class'))
- .to eq 'js-timeago custom_class'
+ expect(element(html_class: 'custom_class').attr('class')).to eq 'js-timeago custom_class'
end
it 'accepts a custom tooltip placement' do
@@ -114,6 +131,7 @@ describe ApplicationHelper do
it 'add class for the short format' do
timeago_element = element(short_format: 'short')
+
expect(timeago_element.attr('class')).to eq 'js-short-timeago'
expect(timeago_element.next_element).to eq nil
end
@@ -128,11 +146,9 @@ describe ApplicationHelper do
context 'when alternate support url is specified' do
let(:alternate_url) { 'http://company.example.com/getting-help' }
- before do
+ it 'returns the alternate support url' do
stub_application_setting(help_page_support_url: alternate_url)
- end
- it 'returns the alternate support url' do
expect(helper.support_url).to eq(alternate_url)
end
end
@@ -155,9 +171,12 @@ describe ApplicationHelper do
describe '#autocomplete_data_sources' do
let(:project) { create(:project) }
let(:noteable_type) { Issue }
+
it 'returns paths for autocomplete_sources_controller' do
sources = helper.autocomplete_data_sources(project, noteable_type)
+
expect(sources.keys).to match_array([:members, :issues, :mergeRequests, :labels, :milestones, :commands])
+
sources.keys.each do |key|
expect(sources[key]).not_to be_nil
end
diff --git a/spec/helpers/auto_devops_helper_spec.rb b/spec/helpers/auto_devops_helper_spec.rb
index 1950c2b129b..75c30dbfe48 100644
--- a/spec/helpers/auto_devops_helper_spec.rb
+++ b/spec/helpers/auto_devops_helper_spec.rb
@@ -16,7 +16,15 @@ describe AutoDevopsHelper do
subject { helper.show_auto_devops_callout?(project) }
- context 'when all conditions are met' do
+ context 'when auto devops is implicitly enabled' do
+ it { is_expected.to eq(false) }
+ end
+
+ context 'when auto devops is not implicitly enabled' do
+ before do
+ Gitlab::CurrentSettings.update!(auto_devops_enabled: false)
+ end
+
it { is_expected.to eq(true) }
end
diff --git a/spec/helpers/avatars_helper_spec.rb b/spec/helpers/avatars_helper_spec.rb
index 55ee87163f9..aa0442ab847 100644
--- a/spec/helpers/avatars_helper_spec.rb
+++ b/spec/helpers/avatars_helper_spec.rb
@@ -32,18 +32,6 @@ describe AvatarsHelper do
end
end
- context 'when providing a project path' do
- it_behaves_like 'resource with a default avatar', 'project' do
- let(:resource) { create(:project, name: 'foo') }
- let(:helper_args) { [resource.full_path] }
- end
-
- it_behaves_like 'resource with a custom avatar', 'project' do
- let(:resource) { create(:project, :public, avatar: File.open(uploaded_image_temp_path)) }
- let(:helper_args) { [resource.full_path] }
- end
- end
-
context 'when providing a group' do
it_behaves_like 'resource with a default avatar', 'group' do
let(:resource) { create(:group, name: 'foo') }
@@ -55,18 +43,6 @@ describe AvatarsHelper do
let(:helper_args) { [resource] }
end
end
-
- context 'when providing a group path' do
- it_behaves_like 'resource with a default avatar', 'group' do
- let(:resource) { create(:group, name: 'foo') }
- let(:helper_args) { [resource.full_path] }
- end
-
- it_behaves_like 'resource with a custom avatar', 'group' do
- let(:resource) { create(:group, avatar: File.open(uploaded_image_temp_path)) }
- let(:helper_args) { [resource.full_path] }
- end
- end
end
describe '#avatar_icon_for' do
diff --git a/spec/helpers/commits_helper_spec.rb b/spec/helpers/commits_helper_spec.rb
index 4b6c7c33e5b..9c0e55739d6 100644
--- a/spec/helpers/commits_helper_spec.rb
+++ b/spec/helpers/commits_helper_spec.rb
@@ -37,7 +37,7 @@ describe CommitsHelper do
.not_to include('onmouseover="alert(1)"')
end
- it 'escapes the commiter name' do
+ it 'escapes the committer name' do
user = build_stubbed(:user, name: 'Foo <script>alert("XSS")</script>')
commit = double(committer: user, committer_name: '', committer_email: '')
diff --git a/spec/helpers/tab_helper_spec.rb b/spec/helpers/tab_helper_spec.rb
index b473c0a7416..9abf63d4bd4 100644
--- a/spec/helpers/tab_helper_spec.rb
+++ b/spec/helpers/tab_helper_spec.rb
@@ -9,31 +9,71 @@ describe TabHelper do
allow(self).to receive(:action_name).and_return('foo')
end
- it "captures block output" do
- expect(nav_link { "Testing Blocks" }).to match(/Testing Blocks/)
+ context 'with the content of the li' do
+ it "captures block output" do
+ expect(nav_link { "Testing Blocks" }).to match(/Testing Blocks/)
+ end
end
- it "performs checks on the current controller" do
- expect(nav_link(controller: :foo)).to match(/<li class="active">/)
- expect(nav_link(controller: :bar)).not_to match(/active/)
- expect(nav_link(controller: [:foo, :bar])).to match(/active/)
- end
+ context 'with controller param' do
+ it "performs checks on the current controller" do
+ expect(nav_link(controller: :foo)).to match(/<li class="active">/)
+ expect(nav_link(controller: :bar)).not_to match(/active/)
+ expect(nav_link(controller: [:foo, :bar])).to match(/active/)
+ end
+
+ context 'with action param' do
+ it "performs checks on both controller and action when both are present" do
+ expect(nav_link(controller: :bar, action: :foo)).not_to match(/active/)
+ expect(nav_link(controller: :foo, action: :bar)).not_to match(/active/)
+ expect(nav_link(controller: :foo, action: :foo)).to match(/active/)
+ end
+ end
+
+ context 'with namespace in path notation' do
+ before do
+ allow(controller).to receive(:controller_path).and_return('bar/foo')
+ end
- it "performs checks on the current action" do
- expect(nav_link(action: :foo)).to match(/<li class="active">/)
- expect(nav_link(action: :bar)).not_to match(/active/)
- expect(nav_link(action: [:foo, :bar])).to match(/active/)
+ it 'performs checks on both controller and namespace' do
+ expect(nav_link(controller: 'foo/foo')).not_to match(/active/)
+ expect(nav_link(controller: 'bar/foo')).to match(/active/)
+ end
+
+ context 'with action param' do
+ it "performs checks on both namespace, controller and action when they are all present" do
+ expect(nav_link(controller: 'foo/foo', action: :foo)).not_to match(/active/)
+ expect(nav_link(controller: 'bar/foo', action: :bar)).not_to match(/active/)
+ expect(nav_link(controller: 'bar/foo', action: :foo)).to match(/active/)
+ end
+ end
+ end
end
- it "performs checks on both controller and action when both are present" do
- expect(nav_link(controller: :bar, action: :foo)).not_to match(/active/)
- expect(nav_link(controller: :foo, action: :bar)).not_to match(/active/)
- expect(nav_link(controller: :foo, action: :foo)).to match(/active/)
+ context 'with action param' do
+ it "performs checks on the current action" do
+ expect(nav_link(action: :foo)).to match(/<li class="active">/)
+ expect(nav_link(action: :bar)).not_to match(/active/)
+ expect(nav_link(action: [:foo, :bar])).to match(/active/)
+ end
end
- it "accepts a path shorthand" do
- expect(nav_link(path: 'foo#bar')).not_to match(/active/)
- expect(nav_link(path: 'foo#foo')).to match(/active/)
+ context 'with path param' do
+ it "accepts a path shorthand" do
+ expect(nav_link(path: 'foo#bar')).not_to match(/active/)
+ expect(nav_link(path: 'foo#foo')).to match(/active/)
+ end
+
+ context 'with namespace' do
+ before do
+ allow(controller).to receive(:controller_path).and_return('bar/foo')
+ end
+
+ it 'accepts a path shorthand with namespace' do
+ expect(nav_link(path: 'bar/foo#foo')).to match(/active/)
+ expect(nav_link(path: 'foo/foo#foo')).not_to match(/active/)
+ end
+ end
end
it "passes extra html options to the list element" do
diff --git a/spec/javascripts/.eslintrc.yml b/spec/javascripts/.eslintrc.yml
index 5525c9f5bd0..9b2c84ce9f5 100644
--- a/spec/javascripts/.eslintrc.yml
+++ b/spec/javascripts/.eslintrc.yml
@@ -35,3 +35,9 @@ rules:
- error
- ignore:
- 'fixtures/blob'
+ # Temporarily disabled to facilitate an upgrade to eslint-plugin-jasmine
+ jasmine/new-line-before-expect: off
+ jasmine/new-line-between-declarations: off
+ jasmine/no-promise-without-done-fail: off
+ jasmine/prefer-jasmine-matcher: off
+ jasmine/prefer-toHaveBeenCalledWith: off
diff --git a/spec/javascripts/shortcuts_issuable_spec.js b/spec/javascripts/behaviors/shortcuts/shortcuts_issuable_spec.js
index a4753ab7cde..01b5bc112b2 100644
--- a/spec/javascripts/shortcuts_issuable_spec.js
+++ b/spec/javascripts/behaviors/shortcuts/shortcuts_issuable_spec.js
@@ -1,6 +1,6 @@
import $ from 'jquery';
import initCopyAsGFM from '~/behaviors/markdown/copy_as_gfm';
-import ShortcutsIssuable from '~/shortcuts_issuable';
+import ShortcutsIssuable from '~/behaviors/shortcuts/shortcuts_issuable';
initCopyAsGFM();
diff --git a/spec/javascripts/boards/board_blank_state_spec.js b/spec/javascripts/boards/board_blank_state_spec.js
index 89a4fae4b59..0e4e1697fd0 100644
--- a/spec/javascripts/boards/board_blank_state_spec.js
+++ b/spec/javascripts/boards/board_blank_state_spec.js
@@ -64,7 +64,7 @@ describe('Boards blank state', () => {
});
it('creates pre-defined labels', (done) => {
- vm.$el.querySelector('.btn-create').click();
+ vm.$el.querySelector('.btn-success').click();
setTimeout(() => {
expect(gl.issueBoards.BoardsStore.state.lists.length).toBe(2);
@@ -78,7 +78,7 @@ describe('Boards blank state', () => {
it('resets the store if request fails', (done) => {
fail = true;
- vm.$el.querySelector('.btn-create').click();
+ vm.$el.querySelector('.btn-success').click();
setTimeout(() => {
expect(gl.issueBoards.BoardsStore.welcomeIsHidden()).toBeFalsy();
diff --git a/spec/javascripts/boards/modal_store_spec.js b/spec/javascripts/boards/modal_store_spec.js
index a234c81fadf..3257a3fb8a3 100644
--- a/spec/javascripts/boards/modal_store_spec.js
+++ b/spec/javascripts/boards/modal_store_spec.js
@@ -11,7 +11,7 @@ describe('Modal store', () => {
let issue2;
beforeEach(() => {
- // Setup default state
+ // Set up default state
Store.store.issues = [];
Store.store.selectedIssues = [];
diff --git a/spec/javascripts/close_reopen_report_toggle_spec.js b/spec/javascripts/close_reopen_report_toggle_spec.js
index 925e959c85a..412abe2cbf8 100644
--- a/spec/javascripts/close_reopen_report_toggle_spec.js
+++ b/spec/javascripts/close_reopen_report_toggle_spec.js
@@ -1,3 +1,5 @@
+/* eslint-disable jasmine/no-unsafe-spy */
+
import CloseReopenReportToggle from '~/close_reopen_report_toggle';
import DropLab from '~/droplab/drop_lab';
diff --git a/spec/javascripts/deploy_keys/components/app_spec.js b/spec/javascripts/deploy_keys/components/app_spec.js
index 183d7cf2d41..cd147bb2935 100644
--- a/spec/javascripts/deploy_keys/components/app_spec.js
+++ b/spec/javascripts/deploy_keys/components/app_spec.js
@@ -11,7 +11,7 @@ describe('Deploy keys app component', () => {
let mock;
beforeEach((done) => {
- // setup axios mock before component
+ // set up axios mock before component
mock = new MockAdapter(axios);
mock.onGet(`${TEST_HOST}/dummy/`).replyOnce(200, data);
diff --git a/spec/javascripts/diffs/components/app_spec.js b/spec/javascripts/diffs/components/app_spec.js
index 7be44a26ded..cf7d8df5405 100644
--- a/spec/javascripts/diffs/components/app_spec.js
+++ b/spec/javascripts/diffs/components/app_spec.js
@@ -3,6 +3,7 @@ import { mountComponentWithStore } from 'spec/helpers/vue_mount_component_helper
import { TEST_HOST } from 'spec/test_constants';
import App from '~/diffs/components/app.vue';
import createDiffsStore from '../create_diffs_store';
+import getDiffWithCommit from '../mock_data/diff_with_commit';
describe('diffs/components/app', () => {
const oldMrTabs = window.mrTabs;
@@ -36,12 +37,17 @@ describe('diffs/components/app', () => {
vm.$destroy();
});
+ it('does not show commit info', () => {
+ expect(vm.$el).not.toContainElement('.blob-commit-info');
+ });
+
it('shows comments message, with commit', done => {
- vm.$store.state.diffs.commit = {};
+ vm.$store.state.diffs.commit = getDiffWithCommit().commit;
vm.$nextTick()
.then(() => {
expect(vm.$el).toContainText('Only comments from the following commit are shown below');
+ expect(vm.$el).toContainElement('.blob-commit-info');
})
.then(done)
.catch(done.fail);
diff --git a/spec/javascripts/diffs/components/commit_item_spec.js b/spec/javascripts/diffs/components/commit_item_spec.js
new file mode 100644
index 00000000000..627fb8c490a
--- /dev/null
+++ b/spec/javascripts/diffs/components/commit_item_spec.js
@@ -0,0 +1,128 @@
+import Vue from 'vue';
+import { TEST_HOST } from 'spec/test_constants';
+import mountComponent from 'spec/helpers/vue_mount_component_helper';
+import { trimText } from 'spec/helpers/vue_component_helper';
+import { getTimeago } from '~/lib/utils/datetime_utility';
+import CommitItem from '~/diffs/components/commit_item.vue';
+import getDiffWithCommit from '../mock_data/diff_with_commit';
+
+const TEST_AUTHOR_NAME = 'test';
+const TEST_AUTHOR_EMAIL = 'test+test@gitlab.com';
+const TEST_AUTHOR_GRAVATAR = `${TEST_HOST}/avatar/test?s=36`;
+
+const getTitleElement = vm => vm.$el.querySelector('.commit-row-message.item-title');
+const getDescElement = vm => vm.$el.querySelector('pre.commit-row-description');
+const getDescExpandElement = vm => vm.$el.querySelector('.commit-content .text-expander.js-toggle-button');
+const getShaElement = vm => vm.$el.querySelector('.commit-sha-group');
+const getAvatarElement = vm => vm.$el.querySelector('.user-avatar-link');
+const getCommitterElement = vm => vm.$el.querySelector('.commiter');
+
+describe('diffs/components/commit_widget', () => {
+ const Component = Vue.extend(CommitItem);
+ const timeago = getTimeago();
+ const { commit } = getDiffWithCommit();
+
+ let vm;
+
+ beforeEach(() => {
+ vm = mountComponent(Component, {
+ commit: getDiffWithCommit().commit,
+ });
+ });
+
+ it('renders commit title', () => {
+ const titleElement = getTitleElement(vm);
+
+ expect(titleElement).toHaveAttr('href', commit.commitUrl);
+ expect(titleElement).toHaveText(commit.titleHtml);
+ });
+
+ it('renders commit description', () => {
+ const descElement = getDescElement(vm);
+ const descExpandElement = getDescExpandElement(vm);
+
+ const expected = commit.descriptionHtml.replace(/&#x000A;/g, '');
+
+ expect(trimText(descElement.innerHTML)).toEqual(trimText(expected));
+ expect(descExpandElement).not.toBeNull();
+ });
+
+ it('renders commit sha', () => {
+ const shaElement = getShaElement(vm);
+ const labelElement = shaElement.querySelector('.label');
+ const buttonElement = shaElement.querySelector('button');
+
+ expect(labelElement.textContent).toEqual(commit.shortId);
+ expect(buttonElement).toHaveData('clipboard-text', commit.id);
+ });
+
+ it('renders author avatar', () => {
+ const avatarElement = getAvatarElement(vm);
+ const imgElement = avatarElement.querySelector('img');
+
+ expect(avatarElement).toHaveAttr('href', commit.author.webUrl);
+ expect(imgElement).toHaveClass('s36');
+ expect(imgElement).toHaveAttr('alt', commit.author.name);
+ expect(imgElement).toHaveAttr('src', commit.author.avatarUrl);
+ });
+
+ it('renders committer text', () => {
+ const committerElement = getCommitterElement(vm);
+ const nameElement = committerElement.querySelector('a');
+
+ const expectTimeText = timeago.format(commit.authoredDate);
+ const expectedText = `${commit.author.name} authored ${expectTimeText}`;
+
+ expect(trimText(committerElement.textContent)).toEqual(expectedText);
+ expect(nameElement).toHaveAttr('href', commit.author.webUrl);
+ expect(nameElement).toHaveText(commit.author.name);
+ });
+
+ describe('without commit description', () => {
+ beforeEach(done => {
+ vm.commit.descriptionHtml = '';
+
+ vm.$nextTick()
+ .then(done)
+ .catch(done.fail);
+ });
+
+ it('hides description', () => {
+ const descElement = getDescElement(vm);
+ const descExpandElement = getDescExpandElement(vm);
+
+ expect(descElement).toBeNull();
+ expect(descExpandElement).toBeNull();
+ });
+ });
+
+ describe('with no matching user', () => {
+ beforeEach(done => {
+ vm.commit.author = null;
+ vm.commit.authorEmail = TEST_AUTHOR_EMAIL;
+ vm.commit.authorName = TEST_AUTHOR_NAME;
+ vm.commit.authorGravatarUrl = TEST_AUTHOR_GRAVATAR;
+
+ vm.$nextTick()
+ .then(done)
+ .catch(done.fail);
+ });
+
+ it('renders author avatar', () => {
+ const avatarElement = getAvatarElement(vm);
+ const imgElement = avatarElement.querySelector('img');
+
+ expect(avatarElement).toHaveAttr('href', `mailto:${TEST_AUTHOR_EMAIL}`);
+ expect(imgElement).toHaveAttr('alt', TEST_AUTHOR_NAME);
+ expect(imgElement).toHaveAttr('src', TEST_AUTHOR_GRAVATAR);
+ });
+
+ it('renders committer text', () => {
+ const committerElement = getCommitterElement(vm);
+ const nameElement = committerElement.querySelector('a');
+
+ expect(nameElement).toHaveAttr('href', `mailto:${TEST_AUTHOR_EMAIL}`);
+ expect(nameElement).toHaveText(TEST_AUTHOR_NAME);
+ });
+ });
+});
diff --git a/spec/javascripts/diffs/components/commit_widget_spec.js b/spec/javascripts/diffs/components/commit_widget_spec.js
new file mode 100644
index 00000000000..951eb57255d
--- /dev/null
+++ b/spec/javascripts/diffs/components/commit_widget_spec.js
@@ -0,0 +1,24 @@
+import Vue from 'vue';
+import mountComponent from 'spec/helpers/vue_mount_component_helper';
+import CommitWidget from '~/diffs/components/commit_widget.vue';
+import getDiffWithCommit from '../mock_data/diff_with_commit';
+
+describe('diffs/components/commit_widget', () => {
+ const Component = Vue.extend(CommitWidget);
+ const { commit } = getDiffWithCommit();
+
+ let vm;
+
+ beforeEach(() => {
+ vm = mountComponent(Component, {
+ commit: getDiffWithCommit().commit,
+ });
+ });
+
+ it('renders commit item', () => {
+ const commitElement = vm.$el.querySelector('li.commit');
+
+ expect(commitElement).not.toBeNull();
+ expect(commitElement).toContainText(commit.shortId);
+ });
+});
diff --git a/spec/javascripts/diffs/components/diff_line_note_form_spec.js b/spec/javascripts/diffs/components/diff_line_note_form_spec.js
index 6fe5fdaf7f9..f31fc1f0e2b 100644
--- a/spec/javascripts/diffs/components/diff_line_note_form_spec.js
+++ b/spec/javascripts/diffs/components/diff_line_note_form_spec.js
@@ -69,22 +69,21 @@ describe('DiffLineNoteForm', () => {
describe('saveNoteForm', () => {
it('should call saveNote action with proper params', done => {
- let isPromiseCalled = false;
- const formDataSpy = spyOnDependency(DiffLineNoteForm, 'getNoteFormData').and.returnValue({
- postData: 1,
- });
- const saveNoteSpy = spyOn(component, 'saveNote').and.returnValue(
- new Promise(() => {
- isPromiseCalled = true;
- done();
- }),
+ const saveDiffDiscussionSpy = spyOn(component, 'saveDiffDiscussion').and.returnValue(
+ Promise.resolve(),
);
-
- component.handleSaveNote('note body');
-
- expect(formDataSpy).toHaveBeenCalled();
- expect(saveNoteSpy).toHaveBeenCalled();
- expect(isPromiseCalled).toEqual(true);
+ spyOnProperty(component, 'formData').and.returnValue('formData');
+
+ component
+ .handleSaveNote('note body')
+ .then(() => {
+ expect(saveDiffDiscussionSpy).toHaveBeenCalledWith({
+ note: 'note body',
+ formData: 'formData',
+ });
+ })
+ .then(done)
+ .catch(done.fail);
});
});
});
diff --git a/spec/javascripts/diffs/mock_data/diff_with_commit.js b/spec/javascripts/diffs/mock_data/diff_with_commit.js
new file mode 100644
index 00000000000..98393a20583
--- /dev/null
+++ b/spec/javascripts/diffs/mock_data/diff_with_commit.js
@@ -0,0 +1,12 @@
+import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
+
+const FIXTURE = 'merge_request_diffs/with_commit.json';
+
+preloadFixtures(FIXTURE);
+
+export default function getDiffWithCommit() {
+ return convertObjectPropsToCamelCase(
+ getJSONFixture(FIXTURE),
+ { deep: true },
+ );
+}
diff --git a/spec/javascripts/diffs/store/actions_spec.js b/spec/javascripts/diffs/store/actions_spec.js
index cfb8f862598..05b39bad6ea 100644
--- a/spec/javascripts/diffs/store/actions_spec.js
+++ b/spec/javascripts/diffs/store/actions_spec.js
@@ -5,7 +5,24 @@ import {
INLINE_DIFF_VIEW_TYPE,
PARALLEL_DIFF_VIEW_TYPE,
} from '~/diffs/constants';
-import * as actions from '~/diffs/store/actions';
+import actions, {
+ setBaseConfig,
+ fetchDiffFiles,
+ assignDiscussionsToDiff,
+ removeDiscussionsFromDiff,
+ startRenderDiffsQueue,
+ setInlineDiffViewType,
+ setParallelDiffViewType,
+ showCommentForm,
+ cancelCommentForm,
+ loadMoreLines,
+ scrollToLineIfNeededInline,
+ scrollToLineIfNeededParallel,
+ loadCollapsedDiff,
+ expandAllFiles,
+ toggleFileDiscussions,
+ saveDiffDiscussion,
+} from '~/diffs/store/actions';
import * as types from '~/diffs/store/mutation_types';
import { reduceDiscussionsToLineCodes } from '~/notes/stores/utils';
import axios from '~/lib/utils/axios_utils';
@@ -37,7 +54,7 @@ describe('DiffsStoreActions', () => {
const projectPath = '/root/project';
testAction(
- actions.setBaseConfig,
+ setBaseConfig,
{ endpoint, projectPath },
{ endpoint: '', projectPath: '' },
[{ type: types.SET_BASE_CONFIG, payload: { endpoint, projectPath } }],
@@ -55,7 +72,7 @@ describe('DiffsStoreActions', () => {
mock.onGet(endpoint).reply(200, res);
testAction(
- actions.fetchDiffFiles,
+ fetchDiffFiles,
{},
{ endpoint },
[
@@ -139,7 +156,7 @@ describe('DiffsStoreActions', () => {
const discussions = reduceDiscussionsToLineCodes([singleDiscussion]);
testAction(
- actions.assignDiscussionsToDiff,
+ assignDiscussionsToDiff,
discussions,
state,
[
@@ -157,6 +174,7 @@ describe('DiffsStoreActions', () => {
newPath: 'file1',
oldLine: 5,
oldPath: 'file2',
+ lineCode: 'ABC_1_1',
},
},
},
@@ -207,7 +225,7 @@ describe('DiffsStoreActions', () => {
};
testAction(
- actions.removeDiscussionsFromDiff,
+ removeDiscussionsFromDiff,
singleDiscussion,
state,
[
@@ -228,7 +246,7 @@ describe('DiffsStoreActions', () => {
});
describe('startRenderDiffsQueue', () => {
- it('should set all files to RENDER_FILE', done => {
+ it('should set all files to RENDER_FILE', () => {
const state = {
diffFiles: [
{
@@ -251,24 +269,17 @@ describe('DiffsStoreActions', () => {
});
};
- actions
- .startRenderDiffsQueue({ state, commit: pseudoCommit })
- .then(() => {
- expect(state.diffFiles[0].renderIt).toBeTruthy();
- expect(state.diffFiles[1].renderIt).toBeTruthy();
+ startRenderDiffsQueue({ state, commit: pseudoCommit });
- done();
- })
- .catch(() => {
- done.fail();
- });
+ expect(state.diffFiles[0].renderIt).toBe(true);
+ expect(state.diffFiles[1].renderIt).toBe(true);
});
});
describe('setInlineDiffViewType', () => {
it('should set diff view type to inline and also set the cookie properly', done => {
testAction(
- actions.setInlineDiffViewType,
+ setInlineDiffViewType,
null,
{},
[{ type: types.SET_DIFF_VIEW_TYPE, payload: INLINE_DIFF_VIEW_TYPE }],
@@ -286,7 +297,7 @@ describe('DiffsStoreActions', () => {
describe('setParallelDiffViewType', () => {
it('should set diff view type to parallel and also set the cookie properly', done => {
testAction(
- actions.setParallelDiffViewType,
+ setParallelDiffViewType,
null,
{},
[{ type: types.SET_DIFF_VIEW_TYPE, payload: PARALLEL_DIFF_VIEW_TYPE }],
@@ -306,7 +317,7 @@ describe('DiffsStoreActions', () => {
const payload = { lineCode: 'lineCode' };
testAction(
- actions.showCommentForm,
+ showCommentForm,
payload,
{},
[{ type: types.ADD_COMMENT_FORM_LINE, payload }],
@@ -321,7 +332,7 @@ describe('DiffsStoreActions', () => {
const payload = { lineCode: 'lineCode' };
testAction(
- actions.cancelCommentForm,
+ cancelCommentForm,
payload,
{},
[{ type: types.REMOVE_COMMENT_FORM_LINE, payload }],
@@ -343,7 +354,7 @@ describe('DiffsStoreActions', () => {
mock.onGet(endpoint).reply(200, contextLines);
testAction(
- actions.loadMoreLines,
+ loadMoreLines,
options,
{},
[
@@ -369,7 +380,7 @@ describe('DiffsStoreActions', () => {
mock.onGet(file.loadCollapsedDiffUrl).reply(200, data);
testAction(
- actions.loadCollapsedDiff,
+ loadCollapsedDiff,
file,
{},
[
@@ -390,7 +401,7 @@ describe('DiffsStoreActions', () => {
describe('expandAllFiles', () => {
it('should change the collapsed prop from the diffFiles', done => {
testAction(
- actions.expandAllFiles,
+ expandAllFiles,
null,
{},
[
@@ -414,7 +425,7 @@ describe('DiffsStoreActions', () => {
const dispatch = jasmine.createSpy('dispatch');
- actions.toggleFileDiscussions({ getters, dispatch });
+ toggleFileDiscussions({ getters, dispatch });
expect(dispatch).toHaveBeenCalledWith(
'collapseDiscussion',
@@ -432,7 +443,7 @@ describe('DiffsStoreActions', () => {
const dispatch = jasmine.createSpy();
- actions.toggleFileDiscussions({ getters, dispatch });
+ toggleFileDiscussions({ getters, dispatch });
expect(dispatch).toHaveBeenCalledWith(
'expandDiscussion',
@@ -450,7 +461,7 @@ describe('DiffsStoreActions', () => {
const dispatch = jasmine.createSpy();
- actions.toggleFileDiscussions({ getters, dispatch });
+ toggleFileDiscussions({ getters, dispatch });
expect(dispatch).toHaveBeenCalledWith(
'expandDiscussion',
@@ -459,4 +470,142 @@ describe('DiffsStoreActions', () => {
);
});
});
+
+ describe('scrollToLineIfNeededInline', () => {
+ const lineMock = {
+ lineCode: 'ABC_123',
+ };
+
+ it('should not call handleLocationHash when there is not hash', () => {
+ window.location.hash = '';
+
+ const handleLocationHashSpy = spyOnDependency(actions, 'handleLocationHash').and.stub();
+
+ scrollToLineIfNeededInline({}, lineMock);
+
+ expect(handleLocationHashSpy).not.toHaveBeenCalled();
+ });
+
+ it('should not call handleLocationHash when the hash does not match any line', () => {
+ window.location.hash = 'XYZ_456';
+
+ const handleLocationHashSpy = spyOnDependency(actions, 'handleLocationHash').and.stub();
+
+ scrollToLineIfNeededInline({}, lineMock);
+
+ expect(handleLocationHashSpy).not.toHaveBeenCalled();
+ });
+
+ it('should call handleLocationHash only when the hash matches a line', () => {
+ window.location.hash = 'ABC_123';
+
+ const handleLocationHashSpy = spyOnDependency(actions, 'handleLocationHash').and.stub();
+
+ scrollToLineIfNeededInline(
+ {},
+ {
+ lineCode: 'ABC_456',
+ },
+ );
+ scrollToLineIfNeededInline({}, lineMock);
+ scrollToLineIfNeededInline(
+ {},
+ {
+ lineCode: 'XYZ_456',
+ },
+ );
+
+ expect(handleLocationHashSpy).toHaveBeenCalled();
+ expect(handleLocationHashSpy).toHaveBeenCalledTimes(1);
+ });
+ });
+
+ describe('scrollToLineIfNeededParallel', () => {
+ const lineMock = {
+ left: null,
+ right: {
+ lineCode: 'ABC_123',
+ },
+ };
+
+ it('should not call handleLocationHash when there is not hash', () => {
+ window.location.hash = '';
+
+ const handleLocationHashSpy = spyOnDependency(actions, 'handleLocationHash').and.stub();
+
+ scrollToLineIfNeededParallel({}, lineMock);
+
+ expect(handleLocationHashSpy).not.toHaveBeenCalled();
+ });
+
+ it('should not call handleLocationHash when the hash does not match any line', () => {
+ window.location.hash = 'XYZ_456';
+
+ const handleLocationHashSpy = spyOnDependency(actions, 'handleLocationHash').and.stub();
+
+ scrollToLineIfNeededParallel({}, lineMock);
+
+ expect(handleLocationHashSpy).not.toHaveBeenCalled();
+ });
+
+ it('should call handleLocationHash only when the hash matches a line', () => {
+ window.location.hash = 'ABC_123';
+
+ const handleLocationHashSpy = spyOnDependency(actions, 'handleLocationHash').and.stub();
+
+ scrollToLineIfNeededParallel(
+ {},
+ {
+ left: null,
+ right: {
+ lineCode: 'ABC_456',
+ },
+ },
+ );
+ scrollToLineIfNeededParallel({}, lineMock);
+ scrollToLineIfNeededParallel(
+ {},
+ {
+ left: null,
+ right: {
+ lineCode: 'XYZ_456',
+ },
+ },
+ );
+
+ expect(handleLocationHashSpy).toHaveBeenCalled();
+ expect(handleLocationHashSpy).toHaveBeenCalledTimes(1);
+ });
+ });
+
+ describe('saveDiffDiscussion', () => {
+ beforeEach(() => {
+ spyOnDependency(actions, 'getNoteFormData').and.returnValue('testData');
+ spyOnDependency(actions, 'reduceDiscussionsToLineCodes').and.returnValue('discussions');
+ });
+
+ it('dispatches actions', done => {
+ const dispatch = jasmine.createSpy('dispatch').and.callFake(name => {
+ switch (name) {
+ case 'saveNote':
+ return Promise.resolve({
+ discussion: 'test',
+ });
+ case 'updateDiscussion':
+ return Promise.resolve('discussion');
+ default:
+ return Promise.resolve({});
+ }
+ });
+
+ saveDiffDiscussion({ dispatch }, { note: {}, formData: {} })
+ .then(() => {
+ expect(dispatch.calls.argsFor(0)).toEqual(['saveNote', 'testData', { root: true }]);
+ expect(dispatch.calls.argsFor(1)).toEqual(['updateDiscussion', 'test', { root: true }]);
+ expect(dispatch.calls.argsFor(2)).toEqual(['assignDiscussionsToDiff', 'discussions']);
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+ });
});
diff --git a/spec/javascripts/diffs/store/mutations_spec.js b/spec/javascripts/diffs/store/mutations_spec.js
index 7eeca6712cc..9a5d8dfbd15 100644
--- a/spec/javascripts/diffs/store/mutations_spec.js
+++ b/spec/javascripts/diffs/store/mutations_spec.js
@@ -162,6 +162,7 @@ describe('DiffsStoreMutations', () => {
};
const state = {
+ latestDiff: true,
diffFiles: [
{
fileHash: 'ABC',
@@ -229,6 +230,76 @@ describe('DiffsStoreMutations', () => {
expect(state.diffFiles[0].highlightedDiffLines[0].discussions.length).toEqual(2);
expect(state.diffFiles[0].highlightedDiffLines[0].discussions[1].id).toEqual(2);
});
+
+ it('should add legacy discussions to the given line', () => {
+ const diffPosition = {
+ baseSha: 'ed13df29948c41ba367caa757ab3ec4892509910',
+ headSha: 'b921914f9a834ac47e6fd9420f78db0f83559130',
+ newLine: null,
+ newPath: '500-lines-4.txt',
+ oldLine: 5,
+ oldPath: '500-lines-4.txt',
+ startSha: 'ed13df29948c41ba367caa757ab3ec4892509910',
+ lineCode: 'ABC_1',
+ };
+
+ const state = {
+ latestDiff: true,
+ diffFiles: [
+ {
+ fileHash: 'ABC',
+ parallelDiffLines: [
+ {
+ left: {
+ lineCode: 'ABC_1',
+ discussions: [],
+ },
+ right: {
+ lineCode: 'ABC_1',
+ discussions: [],
+ },
+ },
+ ],
+ highlightedDiffLines: [
+ {
+ lineCode: 'ABC_1',
+ discussions: [],
+ },
+ ],
+ },
+ ],
+ };
+ const discussions = [
+ {
+ id: 1,
+ line_code: 'ABC_1',
+ diff_discussion: true,
+ active: true,
+ },
+ {
+ id: 2,
+ line_code: 'ABC_1',
+ diff_discussion: true,
+ active: true,
+ },
+ ];
+
+ const diffPositionByLineCode = {
+ ABC_1: diffPosition,
+ };
+
+ mutations[types.SET_LINE_DISCUSSIONS_FOR_FILE](state, {
+ fileHash: 'ABC',
+ discussions,
+ diffPositionByLineCode,
+ });
+
+ expect(state.diffFiles[0].parallelDiffLines[0].left.discussions.length).toEqual(2);
+ expect(state.diffFiles[0].parallelDiffLines[0].left.discussions[1].id).toEqual(2);
+
+ expect(state.diffFiles[0].highlightedDiffLines[0].discussions.length).toEqual(2);
+ expect(state.diffFiles[0].highlightedDiffLines[0].discussions[1].id).toEqual(2);
+ });
});
describe('REMOVE_LINE_DISCUSSIONS', () => {
diff --git a/spec/javascripts/diffs/store/utils_spec.js b/spec/javascripts/diffs/store/utils_spec.js
index 4b5cf450c68..897cd1483aa 100644
--- a/spec/javascripts/diffs/store/utils_spec.js
+++ b/spec/javascripts/diffs/store/utils_spec.js
@@ -3,6 +3,7 @@ import {
LINE_POSITION_LEFT,
LINE_POSITION_RIGHT,
TEXT_DIFF_POSITION_TYPE,
+ LEGACY_DIFF_NOTE_TYPE,
DIFF_NOTE_TYPE,
NEW_LINE_TYPE,
OLD_LINE_TYPE,
@@ -135,6 +136,7 @@ describe('DiffsStoreUtils', () => {
note_project_id: '',
target_type: options.noteableType,
target_id: options.noteableData.id,
+ return_discussion: true,
note: {
noteable_type: options.noteableType,
noteable_id: options.noteableData.id,
@@ -151,6 +153,65 @@ describe('DiffsStoreUtils', () => {
data: postData,
});
});
+
+ it('should create legacy note form data', () => {
+ const diffFile = getDiffFileMock();
+ delete diffFile.diffRefs.startSha;
+ delete diffFile.diffRefs.headSha;
+
+ noteableDataMock.targetType = MERGE_REQUEST_NOTEABLE_TYPE;
+
+ const options = {
+ note: 'Hello world!',
+ noteableData: noteableDataMock,
+ noteableType: MERGE_REQUEST_NOTEABLE_TYPE,
+ diffFile,
+ noteTargetLine: {
+ lineCode: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_1_3',
+ metaData: null,
+ newLine: 3,
+ oldLine: 1,
+ },
+ diffViewType: PARALLEL_DIFF_VIEW_TYPE,
+ linePosition: LINE_POSITION_LEFT,
+ };
+
+ const position = JSON.stringify({
+ base_sha: diffFile.diffRefs.baseSha,
+ start_sha: undefined,
+ head_sha: undefined,
+ old_path: diffFile.oldPath,
+ new_path: diffFile.newPath,
+ position_type: TEXT_DIFF_POSITION_TYPE,
+ old_line: options.noteTargetLine.oldLine,
+ new_line: options.noteTargetLine.newLine,
+ });
+
+ const postData = {
+ view: options.diffViewType,
+ line_type: options.linePosition === LINE_POSITION_RIGHT ? NEW_LINE_TYPE : OLD_LINE_TYPE,
+ merge_request_diff_head_sha: undefined,
+ in_reply_to_discussion_id: '',
+ note_project_id: '',
+ target_type: options.noteableType,
+ target_id: options.noteableData.id,
+ return_discussion: true,
+ note: {
+ noteable_type: options.noteableType,
+ noteable_id: options.noteableData.id,
+ commit_id: '',
+ type: LEGACY_DIFF_NOTE_TYPE,
+ line_code: options.noteTargetLine.lineCode,
+ note: options.note,
+ position,
+ },
+ };
+
+ expect(utils.getNoteFormData(options)).toEqual({
+ endpoint: options.noteableData.create_note_path,
+ data: postData,
+ });
+ });
});
describe('addLineReferences', () => {
@@ -291,13 +352,72 @@ describe('DiffsStoreUtils', () => {
it('returns true when the discussion is up to date', () => {
expect(
- utils.isDiscussionApplicableToLine(discussions.upToDateDiscussion1, diffPosition),
+ utils.isDiscussionApplicableToLine({
+ discussion: discussions.upToDateDiscussion1,
+ diffPosition,
+ latestDiff: true,
+ }),
).toBe(true);
});
it('returns false when the discussion is not up to date', () => {
expect(
- utils.isDiscussionApplicableToLine(discussions.outDatedDiscussion1, diffPosition),
+ utils.isDiscussionApplicableToLine({
+ discussion: discussions.outDatedDiscussion1,
+ diffPosition,
+ latestDiff: true,
+ }),
+ ).toBe(false);
+ });
+
+ it('returns true when line codes match and discussion does not contain position and is not active', () => {
+ const discussion = { ...discussions.outDatedDiscussion1, line_code: 'ABC_1', active: false };
+ delete discussion.original_position;
+ delete discussion.position;
+
+ expect(
+ utils.isDiscussionApplicableToLine({
+ discussion,
+ diffPosition: {
+ ...diffPosition,
+ lineCode: 'ABC_1',
+ },
+ latestDiff: true,
+ }),
+ ).toBe(false);
+ });
+
+ it('returns true when line codes match and discussion does not contain position and is active', () => {
+ const discussion = { ...discussions.outDatedDiscussion1, line_code: 'ABC_1', active: true };
+ delete discussion.original_position;
+ delete discussion.position;
+
+ expect(
+ utils.isDiscussionApplicableToLine({
+ discussion,
+ diffPosition: {
+ ...diffPosition,
+ lineCode: 'ABC_1',
+ },
+ latestDiff: true,
+ }),
+ ).toBe(true);
+ });
+
+ it('returns false when not latest diff', () => {
+ const discussion = { ...discussions.outDatedDiscussion1, line_code: 'ABC_1', active: true };
+ delete discussion.original_position;
+ delete discussion.position;
+
+ expect(
+ utils.isDiscussionApplicableToLine({
+ discussion,
+ diffPosition: {
+ ...diffPosition,
+ lineCode: 'ABC_1',
+ },
+ latestDiff: false,
+ }),
).toBe(false);
});
});
diff --git a/spec/javascripts/fixtures/merge_requests_diffs.rb b/spec/javascripts/fixtures/merge_requests_diffs.rb
index ddce00bc0fe..afe34b834b0 100644
--- a/spec/javascripts/fixtures/merge_requests_diffs.rb
+++ b/spec/javascripts/fixtures/merge_requests_diffs.rb
@@ -9,6 +9,7 @@ describe Projects::MergeRequests::DiffsController, '(JavaScript fixtures)', type
let(:project) { create(:project, :repository, namespace: namespace, path: 'merge-requests-project') }
let(:merge_request) { create(:merge_request, :with_diffs, source_project: project, target_project: project, description: '- [ ] Task List Item') }
let(:path) { "files/ruby/popen.rb" }
+ let(:selected_commit) { merge_request.all_commits[0] }
let(:position) do
Gitlab::Diff::Position.new(
old_path: path,
@@ -33,6 +34,14 @@ describe Projects::MergeRequests::DiffsController, '(JavaScript fixtures)', type
remove_repository(project)
end
+ it 'merge_request_diffs/with_commit.json' do |example|
+ # Create a user that matches the selected commit author
+ # This is so that the "author" information will be populated
+ create(:user, email: selected_commit.author_email, name: selected_commit.author_name)
+
+ render_merge_request(example.description, merge_request, commit_id: selected_commit.sha)
+ end
+
it 'merge_request_diffs/inline_changes_tab_with_comments.json' do |example|
create(:diff_note_on_merge_request, project: project, author: admin, position: position, noteable: merge_request)
create(:note_on_merge_request, author: admin, project: project, noteable: merge_request)
@@ -47,13 +56,14 @@ describe Projects::MergeRequests::DiffsController, '(JavaScript fixtures)', type
private
- def render_merge_request(fixture_file_name, merge_request, view: 'inline')
+ def render_merge_request(fixture_file_name, merge_request, view: 'inline', **extra_params)
get :show,
namespace_id: project.namespace.to_param,
project_id: project,
id: merge_request.to_param,
format: :json,
- view: view
+ view: view,
+ **extra_params
expect(response).to be_success
store_frontend_fixture(response, fixture_file_name)
diff --git a/spec/javascripts/ide/components/commit_sidebar/list_item_spec.js b/spec/javascripts/ide/components/commit_sidebar/list_item_spec.js
index b45ae5bbb0f..bf48d7bfdad 100644
--- a/spec/javascripts/ide/components/commit_sidebar/list_item_spec.js
+++ b/spec/javascripts/ide/components/commit_sidebar/list_item_spec.js
@@ -33,10 +33,6 @@ describe('Multi-file editor commit sidebar list item', () => {
expect(vm.$el.querySelector('.multi-file-commit-list-path').textContent).toContain(f.path);
});
- it('renders actionn button', () => {
- expect(vm.$el.querySelector('.multi-file-discard-btn')).not.toBeNull();
- });
-
it('opens a closed file in the editor when clicking the file path', done => {
spyOn(vm, 'openPendingTab').and.callThrough();
spyOn(router, 'push');
diff --git a/spec/javascripts/ide/components/file_row_extra_spec.js b/spec/javascripts/ide/components/file_row_extra_spec.js
new file mode 100644
index 00000000000..60dabe28045
--- /dev/null
+++ b/spec/javascripts/ide/components/file_row_extra_spec.js
@@ -0,0 +1,159 @@
+import Vue from 'vue';
+import { createStore } from '~/ide/stores';
+import { createComponentWithStore } from 'spec/helpers/vue_mount_component_helper';
+import FileRowExtra from '~/ide/components/file_row_extra.vue';
+import { file, resetStore } from '../helpers';
+
+describe('IDE extra file row component', () => {
+ let Component;
+ let vm;
+ let unstagedFilesCount = 0;
+ let stagedFilesCount = 0;
+ let changesCount = 0;
+
+ beforeAll(() => {
+ Component = Vue.extend(FileRowExtra);
+ });
+
+ beforeEach(() => {
+ vm = createComponentWithStore(Component, createStore(), {
+ file: {
+ ...file('test'),
+ },
+ mouseOver: false,
+ });
+
+ spyOnProperty(vm, 'getUnstagedFilesCountForPath').and.returnValue(() => unstagedFilesCount);
+ spyOnProperty(vm, 'getStagedFilesCountForPath').and.returnValue(() => stagedFilesCount);
+ spyOnProperty(vm, 'getChangesInFolder').and.returnValue(() => changesCount);
+
+ vm.$mount();
+ });
+
+ afterEach(() => {
+ vm.$destroy();
+ resetStore(vm.$store);
+
+ stagedFilesCount = 0;
+ unstagedFilesCount = 0;
+ changesCount = 0;
+ });
+
+ describe('folderChangesTooltip', () => {
+ it('returns undefined when changes count is 0', () => {
+ expect(vm.folderChangesTooltip).toBe(undefined);
+ });
+
+ it('returns unstaged changes text', () => {
+ changesCount = 1;
+ unstagedFilesCount = 1;
+
+ expect(vm.folderChangesTooltip).toBe('1 unstaged change');
+ });
+
+ it('returns staged changes text', () => {
+ changesCount = 1;
+ stagedFilesCount = 1;
+
+ expect(vm.folderChangesTooltip).toBe('1 staged change');
+ });
+
+ it('returns staged and unstaged changes text', () => {
+ changesCount = 1;
+ stagedFilesCount = 1;
+ unstagedFilesCount = 1;
+
+ expect(vm.folderChangesTooltip).toBe('1 unstaged and 1 staged changes');
+ });
+ });
+
+ describe('show tree changes count', () => {
+ it('does not show for blobs', () => {
+ vm.file.type = 'blob';
+
+ expect(vm.$el.querySelector('.ide-tree-changes')).toBe(null);
+ });
+
+ it('does not show when changes count is 0', () => {
+ vm.file.type = 'tree';
+
+ expect(vm.$el.querySelector('.ide-tree-changes')).toBe(null);
+ });
+
+ it('does not show when tree is open', done => {
+ vm.file.type = 'tree';
+ vm.file.opened = true;
+ changesCount = 1;
+
+ vm.$nextTick(() => {
+ expect(vm.$el.querySelector('.ide-tree-changes')).toBe(null);
+
+ done();
+ });
+ });
+
+ it('shows for trees with changes', done => {
+ vm.file.type = 'tree';
+ vm.file.opened = false;
+ changesCount = 1;
+
+ vm.$nextTick(() => {
+ expect(vm.$el.querySelector('.ide-tree-changes')).not.toBe(null);
+
+ done();
+ });
+ });
+ });
+
+ describe('changes file icon', () => {
+ it('hides when file is not changed', () => {
+ expect(vm.$el.querySelector('.ide-file-changed-icon')).toBe(null);
+ });
+
+ it('shows when file is changed', done => {
+ vm.file.changed = true;
+
+ vm.$nextTick(() => {
+ expect(vm.$el.querySelector('.ide-file-changed-icon')).not.toBe(null);
+
+ done();
+ });
+ });
+
+ it('shows when file is staged', done => {
+ vm.file.staged = true;
+
+ vm.$nextTick(() => {
+ expect(vm.$el.querySelector('.ide-file-changed-icon')).not.toBe(null);
+
+ done();
+ });
+ });
+
+ it('shows when file is a tempFile', done => {
+ vm.file.tempFile = true;
+
+ vm.$nextTick(() => {
+ expect(vm.$el.querySelector('.ide-file-changed-icon')).not.toBe(null);
+
+ done();
+ });
+ });
+ });
+
+ describe('merge request icon', () => {
+ it('hides when not a merge request change', () => {
+ expect(vm.$el.querySelector('.ic-git-merge')).toBe(null);
+ });
+
+ it('shows when a merge request change', done => {
+ vm.file.mrChange = true;
+
+ vm.$nextTick(() => {
+ expect(vm.$el.querySelector('.ic-git-merge')).not.toBe(null);
+
+ done();
+ });
+ });
+ });
+});
diff --git a/spec/javascripts/ide/components/ide_status_bar_spec.js b/spec/javascripts/ide/components/ide_status_bar_spec.js
index 0e93c5193a1..47d6492a7a6 100644
--- a/spec/javascripts/ide/components/ide_status_bar_spec.js
+++ b/spec/javascripts/ide/components/ide_status_bar_spec.js
@@ -1,6 +1,7 @@
import Vue from 'vue';
import store from '~/ide/stores';
import ideStatusBar from '~/ide/components/ide_status_bar.vue';
+import { rightSidebarViews } from '~/ide/constants';
import { createComponentWithStore } from 'spec/helpers/vue_mount_component_helper';
import { resetStore } from '../helpers';
import { projectData } from '../mock_data';
@@ -64,7 +65,7 @@ describe('ideStatusBar', () => {
describe('pipeline status', () => {
it('opens right sidebar on clicking icon', done => {
- spyOn(vm, 'setRightPane');
+ spyOn(vm, 'openRightPane');
Vue.set(vm.$store.state.pipelines, 'latestPipeline', {
details: {
status: {
@@ -80,7 +81,7 @@ describe('ideStatusBar', () => {
.then(() => {
vm.$el.querySelector('.ide-status-pipeline button').click();
- expect(vm.setRightPane).toHaveBeenCalledWith('pipelines-list');
+ expect(vm.openRightPane).toHaveBeenCalledWith(rightSidebarViews.pipelines);
})
.then(done)
.catch(done.fail);
diff --git a/spec/javascripts/ide/components/panes/right_spec.js b/spec/javascripts/ide/components/panes/right_spec.js
index c75975d2af6..4899f850cf4 100644
--- a/spec/javascripts/ide/components/panes/right_spec.js
+++ b/spec/javascripts/ide/components/panes/right_spec.js
@@ -25,7 +25,8 @@ describe('IDE right pane', () => {
describe('active', () => {
it('renders merge request button as active', done => {
- vm.$store.state.rightPane = rightSidebarViews.mergeRequestInfo;
+ vm.$store.state.rightPane.isOpen = true;
+ vm.$store.state.rightPane.currentView = rightSidebarViews.mergeRequestInfo.name;
vm.$store.state.currentMergeRequestId = '123';
vm.$store.state.currentProjectId = 'gitlab-ce';
vm.$store.state.currentMergeRequestId = 1;
@@ -41,20 +42,21 @@ describe('IDE right pane', () => {
},
};
- vm.$nextTick(() => {
- expect(vm.$el.querySelector('.ide-sidebar-link.active')).not.toBe(null);
- expect(
- vm.$el.querySelector('.ide-sidebar-link.active').getAttribute('data-original-title'),
- ).toBe('Merge Request');
-
- done();
- });
+ vm.$nextTick()
+ .then(() => {
+ expect(vm.$el.querySelector('.ide-sidebar-link.active')).not.toBe(null);
+ expect(
+ vm.$el.querySelector('.ide-sidebar-link.active').getAttribute('data-original-title'),
+ ).toBe('Merge Request');
+ })
+ .then(done)
+ .catch(done.fail);
});
});
describe('click', () => {
beforeEach(() => {
- spyOn(vm, 'setRightPane');
+ spyOn(vm, 'open');
});
it('sets view to merge request', done => {
@@ -63,7 +65,7 @@ describe('IDE right pane', () => {
vm.$nextTick(() => {
vm.$el.querySelector('.ide-sidebar-link').click();
- expect(vm.setRightPane).toHaveBeenCalledWith(rightSidebarViews.mergeRequestInfo);
+ expect(vm.open).toHaveBeenCalledWith(rightSidebarViews.mergeRequestInfo);
done();
});
diff --git a/spec/javascripts/ide/components/repo_commit_section_spec.js b/spec/javascripts/ide/components/repo_commit_section_spec.js
index d09ccd7ac34..6c726c1e154 100644
--- a/spec/javascripts/ide/components/repo_commit_section_spec.js
+++ b/spec/javascripts/ide/components/repo_commit_section_spec.js
@@ -103,65 +103,6 @@ describe('RepoCommitSection', () => {
});
});
- it('adds changed files into staged files', done => {
- vm.$el.querySelector('.multi-file-discard-btn .btn').click();
- vm
- .$nextTick()
- .then(() => vm.$el.querySelector('.multi-file-discard-btn .btn').click())
- .then(vm.$nextTick)
- .then(() => {
- expect(vm.$el.querySelector('.ide-commit-list-container').textContent).toContain(
- 'There are no unstaged changes',
- );
- })
- .then(done)
- .catch(done.fail);
- });
-
- it('stages a single file', done => {
- vm.$el.querySelector('.multi-file-discard-btn .btn').click();
-
- Vue.nextTick(() => {
- expect(
- vm.$el
- .querySelector('.ide-commit-list-container')
- .querySelectorAll('.multi-file-commit-list > li').length,
- ).toBe(1);
-
- done();
- });
- });
-
- it('discards a single file', done => {
- vm.$el.querySelector('.multi-file-commit-list li:first-child .js-modal-primary-action').click();
-
- Vue.nextTick(() => {
- expect(vm.$el.querySelector('.ide-commit-list-container').textContent).not.toContain('file1');
- expect(
- vm.$el
- .querySelector('.ide-commit-list-container')
- .querySelectorAll('.multi-file-commit-list > li').length,
- ).toBe(1);
-
- done();
- });
- });
-
- it('unstages a single file', done => {
- vm.$el
- .querySelectorAll('.multi-file-discard-btn')[2]
- .querySelector('.btn')
- .click();
-
- Vue.nextTick(() => {
- expect(
- vm.$el.querySelectorAll('.ide-commit-list-container')[1].querySelectorAll('li').length,
- ).toBe(1);
-
- done();
- });
- });
-
describe('mounted', () => {
it('opens last opened file', () => {
expect(store.state.openFiles.length).toBe(1);
diff --git a/spec/javascripts/ide/components/repo_editor_spec.js b/spec/javascripts/ide/components/repo_editor_spec.js
index 0e2e246defd..991fb750876 100644
--- a/spec/javascripts/ide/components/repo_editor_spec.js
+++ b/spec/javascripts/ide/components/repo_editor_spec.js
@@ -319,8 +319,8 @@ describe('RepoEditor', () => {
});
});
- it('calls updateDimensions when rightPane is updated', done => {
- vm.$store.state.rightPane = 'testing';
+ it('calls updateDimensions when rightPane is opened', done => {
+ vm.$store.state.rightPane.isOpen = true;
vm.$nextTick(() => {
expect(vm.editor.updateDimensions).toHaveBeenCalled();
diff --git a/spec/javascripts/ide/components/repo_file_spec.js b/spec/javascripts/ide/components/repo_file_spec.js
deleted file mode 100644
index fc639a672e2..00000000000
--- a/spec/javascripts/ide/components/repo_file_spec.js
+++ /dev/null
@@ -1,145 +0,0 @@
-import Vue from 'vue';
-import store from '~/ide/stores';
-import repoFile from '~/ide/components/repo_file.vue';
-import router from '~/ide/ide_router';
-import { createComponentWithStore } from '../../helpers/vue_mount_component_helper';
-import { file } from '../helpers';
-
-describe('RepoFile', () => {
- let vm;
-
- function createComponent(propsData) {
- const RepoFile = Vue.extend(repoFile);
-
- vm = createComponentWithStore(RepoFile, store, propsData);
-
- vm.$mount();
- }
-
- afterEach(() => {
- vm.$destroy();
- });
-
- it('renders link, icon and name', () => {
- createComponent({
- file: file('t4'),
- level: 0,
- });
-
- const name = vm.$el.querySelector('.ide-file-name');
-
- expect(name.href).toMatch('');
- expect(name.textContent.trim()).toEqual(vm.file.name);
- });
-
- it('fires clickFile when the link is clicked', done => {
- spyOn(router, 'push');
- createComponent({
- file: file('t3'),
- level: 0,
- });
-
- vm.$el.querySelector('.file-name').click();
-
- setTimeout(() => {
- expect(router.push).toHaveBeenCalledWith(`/project${vm.file.url}`);
-
- done();
- });
- });
-
- describe('folder', () => {
- it('renders changes count inside folder', () => {
- const f = {
- ...file('folder'),
- path: 'testing',
- type: 'tree',
- branchId: 'master',
- projectId: 'project',
- };
-
- store.state.changedFiles.push({
- ...file('fileName'),
- path: 'testing/fileName',
- });
-
- createComponent({
- file: f,
- level: 0,
- });
-
- const treeChangesEl = vm.$el.querySelector('.ide-tree-changes');
-
- expect(treeChangesEl).not.toBeNull();
- expect(treeChangesEl.textContent).toContain('1');
- });
-
- it('renders action dropdown', done => {
- createComponent({
- file: {
- ...file('t4'),
- type: 'tree',
- branchId: 'master',
- projectId: 'project',
- },
- level: 0,
- });
-
- setTimeout(() => {
- expect(vm.$el.querySelector('.ide-new-btn')).not.toBeNull();
-
- done();
- });
- });
- });
-
- describe('locked file', () => {
- let f;
-
- beforeEach(() => {
- f = file('locked file');
- f.file_lock = {
- user: {
- name: 'testuser',
- updated_at: new Date(),
- },
- };
-
- createComponent({
- file: f,
- level: 0,
- });
- });
-
- it('renders lock icon', () => {
- expect(vm.$el.querySelector('.file-status-icon')).not.toBeNull();
- });
-
- it('renders a tooltip', () => {
- expect(
- vm.$el.querySelector('.ide-file-name span:nth-child(2)').dataset.originalTitle,
- ).toContain('Locked by testuser');
- });
- });
-
- it('calls scrollIntoView if made active', done => {
- createComponent({
- file: {
- ...file(),
- type: 'blob',
- active: false,
- },
- level: 0,
- });
-
- spyOn(vm, 'scrollIntoView');
-
- vm.file.active = true;
-
- vm.$nextTick(() => {
- expect(vm.scrollIntoView).toHaveBeenCalled();
-
- done();
- });
- });
-});
diff --git a/spec/javascripts/ide/components/repo_loading_file_spec.js b/spec/javascripts/ide/components/repo_loading_file_spec.js
deleted file mode 100644
index 7c20b8302f9..00000000000
--- a/spec/javascripts/ide/components/repo_loading_file_spec.js
+++ /dev/null
@@ -1,63 +0,0 @@
-import Vue from 'vue';
-import store from '~/ide/stores';
-import repoLoadingFile from '~/ide/components/repo_loading_file.vue';
-import { resetStore } from '../helpers';
-
-describe('RepoLoadingFile', () => {
- let vm;
-
- function createComponent() {
- const RepoLoadingFile = Vue.extend(repoLoadingFile);
-
- return new RepoLoadingFile({
- store,
- }).$mount();
- }
-
- function assertLines(lines) {
- lines.forEach((line, n) => {
- const index = n + 1;
- expect(line.classList.contains(`skeleton-line-${index}`)).toBeTruthy();
- });
- }
-
- function assertColumns(columns) {
- columns.forEach(column => {
- const container = column.querySelector('.animation-container');
- const lines = [...container.querySelectorAll(':scope > div')];
-
- expect(container).toBeTruthy();
- expect(lines.length).toEqual(3);
- assertLines(lines);
- });
- }
-
- afterEach(() => {
- vm.$destroy();
-
- resetStore(vm.$store);
- });
-
- it('renders 3 columns of animated LoC', () => {
- vm = createComponent();
- const columns = [...vm.$el.querySelectorAll('td')];
-
- expect(columns.length).toEqual(3);
- assertColumns(columns);
- });
-
- it('renders 1 column of animated LoC if isMini', done => {
- vm = createComponent();
- vm.$store.state.leftPanelCollapsed = true;
- vm.$store.state.openFiles.push('test');
-
- vm.$nextTick(() => {
- const columns = [...vm.$el.querySelectorAll('td')];
-
- expect(columns.length).toEqual(1);
- assertColumns(columns);
-
- done();
- });
- });
-});
diff --git a/spec/javascripts/ide/helpers.js b/spec/javascripts/ide/helpers.js
index 3ce9c9fcda1..7e107747346 100644
--- a/spec/javascripts/ide/helpers.js
+++ b/spec/javascripts/ide/helpers.js
@@ -6,6 +6,7 @@ import mergeRequestsState from '~/ide/stores/modules/merge_requests/state';
import pipelinesState from '~/ide/stores/modules/pipelines/state';
import branchesState from '~/ide/stores/modules/branches/state';
import fileTemplatesState from '~/ide/stores/modules/file_templates/state';
+import paneState from '~/ide/stores/modules/pane/state';
export const resetStore = store => {
const newState = {
@@ -15,6 +16,7 @@ export const resetStore = store => {
pipelines: pipelinesState(),
branches: branchesState(),
fileTemplates: fileTemplatesState(),
+ rightPane: paneState(),
};
store.replaceState(newState);
};
diff --git a/spec/javascripts/ide/stores/modules/file_templates/actions_spec.js b/spec/javascripts/ide/stores/modules/file_templates/actions_spec.js
index c29dd9f0d06..734233100ab 100644
--- a/spec/javascripts/ide/stores/modules/file_templates/actions_spec.js
+++ b/spec/javascripts/ide/stores/modules/file_templates/actions_spec.js
@@ -69,11 +69,17 @@ describe('IDE file templates actions', () => {
describe('fetchTemplateTypes', () => {
describe('success', () => {
+ let nextPage;
+
beforeEach(() => {
- mock.onGet(/api\/(.*)\/templates\/licenses/).replyOnce(200, [
- {
- name: 'MIT',
- },
+ mock.onGet(/api\/(.*)\/templates\/licenses/).replyOnce(() => [
+ 200,
+ [
+ {
+ name: 'MIT',
+ },
+ ],
+ { 'X-NEXT-PAGE': nextPage },
]);
});
@@ -116,6 +122,38 @@ describe('IDE file templates actions', () => {
done,
);
});
+
+ it('dispatches actions for next page', done => {
+ nextPage = '2';
+ state.selectedTemplateType = {
+ key: 'licenses',
+ };
+
+ testAction(
+ actions.fetchTemplateTypes,
+ null,
+ state,
+ [],
+ [
+ {
+ type: 'requestTemplateTypes',
+ },
+ {
+ type: 'receiveTemplateTypesSuccess',
+ payload: [
+ {
+ name: 'MIT',
+ },
+ ],
+ },
+ {
+ type: 'fetchTemplateTypes',
+ payload: 2,
+ },
+ ],
+ done,
+ );
+ });
});
describe('error', () => {
diff --git a/spec/javascripts/ide/stores/modules/pane/actions_spec.js b/spec/javascripts/ide/stores/modules/pane/actions_spec.js
new file mode 100644
index 00000000000..f150ded6df5
--- /dev/null
+++ b/spec/javascripts/ide/stores/modules/pane/actions_spec.js
@@ -0,0 +1,87 @@
+import * as actions from '~/ide/stores/modules/pane/actions';
+import * as types from '~/ide/stores/modules/pane/mutation_types';
+import testAction from 'spec/helpers/vuex_action_helper';
+
+describe('IDE pane module actions', () => {
+ const TEST_VIEW = { name: 'test' };
+ const TEST_VIEW_KEEP_ALIVE = { name: 'test-keep-alive', keepAlive: true };
+
+ describe('toggleOpen', () => {
+ it('dispatches open if closed', done => {
+ testAction(
+ actions.toggleOpen,
+ TEST_VIEW,
+ { isOpen: false },
+ [],
+ [{ type: 'open', payload: TEST_VIEW }],
+ done,
+ );
+ });
+
+ it('dispatches close if opened', done => {
+ testAction(
+ actions.toggleOpen,
+ TEST_VIEW,
+ { isOpen: true },
+ [],
+ [{ type: 'close' }],
+ done,
+ );
+ });
+ });
+
+ describe('open', () => {
+ it('commits SET_OPEN', done => {
+ testAction(
+ actions.open,
+ null,
+ {},
+ [{ type: types.SET_OPEN, payload: true }],
+ [],
+ done,
+ );
+ });
+
+ it('commits SET_CURRENT_VIEW if view is given', done => {
+ testAction(
+ actions.open,
+ TEST_VIEW,
+ {},
+ [
+ { type: types.SET_OPEN, payload: true },
+ { type: types.SET_CURRENT_VIEW, payload: TEST_VIEW.name },
+ ],
+ [],
+ done,
+ );
+ });
+
+ it('commits KEEP_ALIVE_VIEW if keepAlive is true', done => {
+ testAction(
+ actions.open,
+ TEST_VIEW_KEEP_ALIVE,
+ {},
+ [
+ { type: types.SET_OPEN, payload: true },
+ { type: types.SET_CURRENT_VIEW, payload: TEST_VIEW_KEEP_ALIVE.name },
+ { type: types.KEEP_ALIVE_VIEW, payload: TEST_VIEW_KEEP_ALIVE.name },
+ ],
+ [],
+ done,
+ );
+ });
+ });
+
+ describe('close', () => {
+ it('commits SET_OPEN', done => {
+ testAction(
+ actions.close,
+ null,
+ {},
+ [{ type: types.SET_OPEN, payload: false }],
+ [],
+ done,
+ );
+ });
+ });
+});
diff --git a/spec/javascripts/ide/stores/modules/pane/getters_spec.js b/spec/javascripts/ide/stores/modules/pane/getters_spec.js
new file mode 100644
index 00000000000..2060863b5d6
--- /dev/null
+++ b/spec/javascripts/ide/stores/modules/pane/getters_spec.js
@@ -0,0 +1,61 @@
+import * as getters from '~/ide/stores/modules/pane/getters';
+import state from '~/ide/stores/modules/pane/state';
+
+describe('IDE pane module getters', () => {
+ const TEST_VIEW = 'test-view';
+ const TEST_KEEP_ALIVE_VIEWS = {
+ [TEST_VIEW]: true,
+ };
+
+ describe('isActiveView', () => {
+ it('returns true if given view matches currentView', () => {
+ const result = getters.isActiveView({ currentView: 'A' })('A');
+
+ expect(result).toBe(true);
+ });
+
+ it('returns false if given view does not match currentView', () => {
+ const result = getters.isActiveView({ currentView: 'A' })('B');
+
+ expect(result).toBe(false);
+ });
+ });
+
+ describe('isAliveView', () => {
+ it('returns true if given view is in keepAliveViews', () => {
+ const result = getters.isAliveView(
+ { keepAliveViews: TEST_KEEP_ALIVE_VIEWS },
+ {},
+ )(TEST_VIEW);
+
+ expect(result).toBe(true);
+ });
+
+ it('returns true if given view is active view and open', () => {
+ const result = getters.isAliveView(
+ { ...state(), isOpen: true },
+ { isActiveView: () => true },
+ )(TEST_VIEW);
+
+ expect(result).toBe(true);
+ });
+
+ it('returns false if given view is active view and closed', () => {
+ const result = getters.isAliveView(
+ state(),
+ { isActiveView: () => true },
+ )(TEST_VIEW);
+
+ expect(result).toBe(false);
+ });
+
+ it('returns false if given view is not activeView', () => {
+ const result = getters.isAliveView(
+ { ...state(), isOpen: true },
+ { isActiveView: () => false },
+ )(TEST_VIEW);
+
+ expect(result).toBe(false);
+ });
+ });
+});
diff --git a/spec/javascripts/ide/stores/modules/pane/mutations_spec.js b/spec/javascripts/ide/stores/modules/pane/mutations_spec.js
new file mode 100644
index 00000000000..b5fcd35912e
--- /dev/null
+++ b/spec/javascripts/ide/stores/modules/pane/mutations_spec.js
@@ -0,0 +1,42 @@
+import state from '~/ide/stores/modules/pane/state';
+import mutations from '~/ide/stores/modules/pane/mutations';
+import * as types from '~/ide/stores/modules/pane/mutation_types';
+
+describe('IDE pane module mutations', () => {
+ const TEST_VIEW = 'test-view';
+ let mockedState;
+
+ beforeEach(() => {
+ mockedState = state();
+ });
+
+ describe('SET_OPEN', () => {
+ it('sets isOpen', () => {
+ mockedState.isOpen = false;
+
+ mutations[types.SET_OPEN](mockedState, true);
+
+ expect(mockedState.isOpen).toBe(true);
+ });
+ });
+
+ describe('SET_CURRENT_VIEW', () => {
+ it('sets currentView', () => {
+ mockedState.currentView = null;
+
+ mutations[types.SET_CURRENT_VIEW](mockedState, TEST_VIEW);
+
+ expect(mockedState.currentView).toEqual(TEST_VIEW);
+ });
+ });
+
+ describe('KEEP_ALIVE_VIEW', () => {
+ it('adds entry to keepAliveViews', () => {
+ mutations[types.KEEP_ALIVE_VIEW](mockedState, TEST_VIEW);
+
+ expect(mockedState.keepAliveViews).toEqual({
+ [TEST_VIEW]: true,
+ });
+ });
+ });
+});
diff --git a/spec/javascripts/ide/stores/modules/pipelines/actions_spec.js b/spec/javascripts/ide/stores/modules/pipelines/actions_spec.js
index 91edb388791..d85354c3681 100644
--- a/spec/javascripts/ide/stores/modules/pipelines/actions_spec.js
+++ b/spec/javascripts/ide/stores/modules/pipelines/actions_spec.js
@@ -315,29 +315,29 @@ describe('IDE pipelines actions', () => {
'job',
mockedState,
[{ type: types.SET_DETAIL_JOB, payload: 'job' }],
- [{ type: 'setRightPane', payload: 'jobs-detail' }],
+ [{ type: 'rightPane/open', payload: rightSidebarViews.jobsDetail }],
done,
);
});
- it('dispatches setRightPane as pipeline when job is null', done => {
+ it('dispatches rightPane/open as pipeline when job is null', done => {
testAction(
setDetailJob,
null,
mockedState,
[{ type: types.SET_DETAIL_JOB, payload: null }],
- [{ type: 'setRightPane', payload: rightSidebarViews.pipelines }],
+ [{ type: 'rightPane/open', payload: rightSidebarViews.pipelines }],
done,
);
});
- it('dispatches setRightPane as job', done => {
+ it('dispatches rightPane/open as job', done => {
testAction(
setDetailJob,
'job',
mockedState,
[{ type: types.SET_DETAIL_JOB, payload: 'job' }],
- [{ type: 'setRightPane', payload: rightSidebarViews.jobsDetail }],
+ [{ type: 'rightPane/open', payload: rightSidebarViews.jobsDetail }],
done,
);
});
diff --git a/spec/javascripts/issue_show/components/edit_actions_spec.js b/spec/javascripts/issue_show/components/edit_actions_spec.js
index d779ab7bb31..004621f488a 100644
--- a/spec/javascripts/issue_show/components/edit_actions_spec.js
+++ b/spec/javascripts/issue_show/components/edit_actions_spec.js
@@ -21,6 +21,7 @@ describe('Edit Actions components', () => {
propsData: {
canDestroy: true,
formState: store.formState,
+ issuableType: 'issue',
},
}).$mount();
@@ -54,7 +55,7 @@ describe('Edit Actions components', () => {
Vue.nextTick(() => {
expect(
- vm.$el.querySelector('.btn-save').getAttribute('disabled'),
+ vm.$el.querySelector('.btn-success').getAttribute('disabled'),
).toBe('disabled');
done();
@@ -72,7 +73,7 @@ describe('Edit Actions components', () => {
describe('updateIssuable', () => {
it('sends update.issauble event when clicking save button', () => {
- vm.$el.querySelector('.btn-save').click();
+ vm.$el.querySelector('.btn-success').click();
expect(
eventHub.$emit,
@@ -80,11 +81,11 @@ describe('Edit Actions components', () => {
});
it('shows loading icon after clicking save button', (done) => {
- vm.$el.querySelector('.btn-save').click();
+ vm.$el.querySelector('.btn-success').click();
Vue.nextTick(() => {
expect(
- vm.$el.querySelector('.btn-save .fa'),
+ vm.$el.querySelector('.btn-success .fa'),
).not.toBeNull();
done();
@@ -92,11 +93,11 @@ describe('Edit Actions components', () => {
});
it('disabled button after clicking save button', (done) => {
- vm.$el.querySelector('.btn-save').click();
+ vm.$el.querySelector('.btn-success').click();
Vue.nextTick(() => {
expect(
- vm.$el.querySelector('.btn-save').getAttribute('disabled'),
+ vm.$el.querySelector('.btn-success').getAttribute('disabled'),
).toBe('disabled');
done();
diff --git a/spec/javascripts/issue_show/components/form_spec.js b/spec/javascripts/issue_show/components/form_spec.js
index 50ce019c32a..eaac1e3536d 100644
--- a/spec/javascripts/issue_show/components/form_spec.js
+++ b/spec/javascripts/issue_show/components/form_spec.js
@@ -15,6 +15,7 @@ describe('Inline edit form component', () => {
description: 'a',
lockedWarningVisible: false,
},
+ issuableType: 'issue',
markdownPreviewPath: '/',
markdownDocsPath: '/',
projectPath: '/',
diff --git a/spec/javascripts/jobs/components/artifacts_block_spec.js b/spec/javascripts/jobs/components/artifacts_block_spec.js
index a06d287b3fa..2fa7ff653fe 100644
--- a/spec/javascripts/jobs/components/artifacts_block_spec.js
+++ b/spec/javascripts/jobs/components/artifacts_block_spec.js
@@ -11,6 +11,19 @@ describe('Artifacts block', () => {
const timeago = getTimeago();
const formatedDate = timeago.format(expireAt);
+ const expiredArtifact = {
+ expire_at: expireAt,
+ expired: true,
+ };
+
+ const nonExpiredArtifact = {
+ download_path: '/gitlab-org/gitlab-ce/-/jobs/98314558/artifacts/download',
+ browse_path: '/gitlab-org/gitlab-ce/-/jobs/98314558/artifacts/browse',
+ keep_path: '/gitlab-org/gitlab-ce/-/jobs/98314558/artifacts/keep',
+ expire_at: expireAt,
+ expired: false,
+ };
+
afterEach(() => {
vm.$destroy();
});
@@ -18,100 +31,87 @@ describe('Artifacts block', () => {
describe('with expired artifacts', () => {
it('renders expired artifact date and info', () => {
vm = mountComponent(Component, {
- haveArtifactsExpired: true,
- willArtifactsExpire: false,
- expireAt,
+ artifact: expiredArtifact,
});
expect(vm.$el.querySelector('.js-artifacts-removed')).not.toBeNull();
expect(vm.$el.querySelector('.js-artifacts-will-be-removed')).toBeNull();
expect(vm.$el.textContent).toContain(formatedDate);
+ expect(vm.$el.querySelector('.js-artifacts-removed').textContent.trim()).toEqual(
+ 'The artifacts were removed',
+ );
});
});
describe('with artifacts that will expire', () => {
it('renders will expire artifact date and info', () => {
vm = mountComponent(Component, {
- haveArtifactsExpired: false,
- willArtifactsExpire: true,
- expireAt,
+ artifact: nonExpiredArtifact,
});
expect(vm.$el.querySelector('.js-artifacts-removed')).toBeNull();
expect(vm.$el.querySelector('.js-artifacts-will-be-removed')).not.toBeNull();
expect(vm.$el.textContent).toContain(formatedDate);
+ expect(vm.$el.querySelector('.js-artifacts-will-be-removed').textContent.trim()).toEqual(
+ 'The artifacts will be removed in',
+ );
});
});
- describe('when the user can keep the artifacts', () => {
+ describe('with keep path', () => {
it('renders the keep button', () => {
vm = mountComponent(Component, {
- haveArtifactsExpired: true,
- willArtifactsExpire: false,
- expireAt,
- keepArtifactsPath: '/keep',
+ artifact: nonExpiredArtifact,
});
expect(vm.$el.querySelector('.js-keep-artifacts')).not.toBeNull();
});
});
- describe('when the user can not keep the artifacts', () => {
+ describe('without keep path', () => {
it('does not render the keep button', () => {
vm = mountComponent(Component, {
- haveArtifactsExpired: true,
- willArtifactsExpire: false,
- expireAt,
+ artifact: expiredArtifact,
});
expect(vm.$el.querySelector('.js-keep-artifacts')).toBeNull();
});
});
- describe('when the user can download the artifacts', () => {
+ describe('with download path', () => {
it('renders the download button', () => {
vm = mountComponent(Component, {
- haveArtifactsExpired: true,
- willArtifactsExpire: false,
- expireAt,
- downloadArtifactsPath: '/download',
+ artifact: nonExpiredArtifact,
});
expect(vm.$el.querySelector('.js-download-artifacts')).not.toBeNull();
});
});
- describe('when the user can not download the artifacts', () => {
+ describe('without download path', () => {
it('does not render the keep button', () => {
vm = mountComponent(Component, {
- haveArtifactsExpired: true,
- willArtifactsExpire: false,
- expireAt,
+ artifact: expiredArtifact,
});
expect(vm.$el.querySelector('.js-download-artifacts')).toBeNull();
});
});
- describe('when the user can browse the artifacts', () => {
+ describe('with browse path', () => {
it('does not render the browse button', () => {
vm = mountComponent(Component, {
- haveArtifactsExpired: true,
- willArtifactsExpire: false,
- expireAt,
- browseArtifactsPath: '/browse',
+ artifact: nonExpiredArtifact,
});
expect(vm.$el.querySelector('.js-browse-artifacts')).not.toBeNull();
});
});
- describe('when the user can not browse the artifacts', () => {
+ describe('without browse path', () => {
it('does not render the browse button', () => {
vm = mountComponent(Component, {
- haveArtifactsExpired: true,
- willArtifactsExpire: false,
- expireAt,
+ artifact: expiredArtifact,
});
expect(vm.$el.querySelector('.js-browse-artifacts')).toBeNull();
diff --git a/spec/javascripts/jobs/components/commit_block_spec.js b/spec/javascripts/jobs/components/commit_block_spec.js
index e21fa9c2874..61ee993f46a 100644
--- a/spec/javascripts/jobs/components/commit_block_spec.js
+++ b/spec/javascripts/jobs/components/commit_block_spec.js
@@ -7,11 +7,16 @@ describe('Commit block', () => {
let vm;
const props = {
- pipelineShortSha: '1f0fb84f',
- pipelineShaPath: 'commit/1f0fb84fb6770d74d97eee58118fd3909cd4f48c',
- mergeRequestReference: '!21244',
- mergeRequestPath: 'merge_requests/21244',
- gitCommitTitlte: 'Regenerate pot files',
+ commit: {
+ short_id: '1f0fb84f',
+ commit_path: 'commit/1f0fb84fb6770d74d97eee58118fd3909cd4f48c',
+ title: 'Update README.md',
+ },
+ mergeRequest: {
+ iid: '!21244',
+ path: 'merge_requests/21244',
+ },
+ isLastBlock: true,
};
afterEach(() => {
@@ -26,12 +31,18 @@ describe('Commit block', () => {
});
it('renders pipeline short sha link', () => {
- expect(vm.$el.querySelector('.js-commit-sha').getAttribute('href')).toEqual(props.pipelineShaPath);
- expect(vm.$el.querySelector('.js-commit-sha').textContent.trim()).toEqual(props.pipelineShortSha);
+ expect(vm.$el.querySelector('.js-commit-sha').getAttribute('href')).toEqual(
+ props.commit.commit_path,
+ );
+ expect(vm.$el.querySelector('.js-commit-sha').textContent.trim()).toEqual(
+ props.commit.short_id,
+ );
});
it('renders clipboard button', () => {
- expect(vm.$el.querySelector('button').getAttribute('data-clipboard-text')).toEqual(props.pipelineShortSha);
+ expect(vm.$el.querySelector('button').getAttribute('data-clipboard-text')).toEqual(
+ props.commit.short_id,
+ );
});
});
@@ -41,17 +52,19 @@ describe('Commit block', () => {
...props,
});
- expect(vm.$el.querySelector('.js-link-commit').getAttribute('href')).toEqual(props.mergeRequestPath);
- expect(vm.$el.querySelector('.js-link-commit').textContent.trim()).toEqual(props.mergeRequestReference);
-
+ expect(vm.$el.querySelector('.js-link-commit').getAttribute('href')).toEqual(
+ props.mergeRequest.path,
+ );
+ expect(vm.$el.querySelector('.js-link-commit').textContent.trim()).toEqual(
+ props.mergeRequest.iid,
+ );
});
});
describe('without merge request', () => {
it('does not render merge request', () => {
const copyProps = Object.assign({}, props);
- delete copyProps.mergeRequestPath;
- delete copyProps.mergeRequestReference;
+ delete copyProps.mergeRequest;
vm = mountComponent(Component, {
...copyProps,
@@ -67,7 +80,7 @@ describe('Commit block', () => {
...props,
});
- expect(vm.$el.textContent).toContain(props.gitCommitTitlte);
+ expect(vm.$el.textContent).toContain(props.commit.title);
});
});
});
diff --git a/spec/javascripts/jobs/components/empty_state_spec.js b/spec/javascripts/jobs/components/empty_state_spec.js
index dcc2b3d8a20..872cc1e3864 100644
--- a/spec/javascripts/jobs/components/empty_state_spec.js
+++ b/spec/javascripts/jobs/components/empty_state_spec.js
@@ -66,7 +66,7 @@ describe('Empty State', () => {
...props,
content,
action: {
- link: 'runner',
+ path: 'runner',
title: 'Check runner',
method: 'post',
},
diff --git a/spec/javascripts/jobs/components/erased_block_spec.js b/spec/javascripts/jobs/components/erased_block_spec.js
index a4ae0c7c81e..8e0433d3fb7 100644
--- a/spec/javascripts/jobs/components/erased_block_spec.js
+++ b/spec/javascripts/jobs/components/erased_block_spec.js
@@ -18,9 +18,10 @@ describe('Erased block', () => {
describe('with job erased by user', () => {
beforeEach(() => {
vm = mountComponent(Component, {
- erasedByUser: true,
- username: 'root',
- linkToUser: 'gitlab.com/root',
+ user: {
+ username: 'root',
+ web_url: 'gitlab.com/root',
+ },
erasedAt,
});
});
@@ -40,7 +41,6 @@ describe('Erased block', () => {
describe('with erased job', () => {
beforeEach(() => {
vm = mountComponent(Component, {
- erasedByUser: false,
erasedAt,
});
});
diff --git a/spec/javascripts/jobs/components/job_details_mediator_spec.js b/spec/javascripts/jobs/components/job_details_mediator_spec.js
deleted file mode 100644
index 3e2fb7bfbbb..00000000000
--- a/spec/javascripts/jobs/components/job_details_mediator_spec.js
+++ /dev/null
@@ -1,39 +0,0 @@
-import MockAdapter from 'axios-mock-adapter';
-import axios from '~/lib/utils/axios_utils';
-import JobMediator from '~/jobs/job_details_mediator';
-import job from '../mock_data';
-
-describe('JobMediator', () => {
- let mediator;
- let mock;
-
- beforeEach(() => {
- mediator = new JobMediator({ endpoint: 'jobs/40291672.json' });
- mock = new MockAdapter(axios);
- });
-
- afterEach(() => {
- mock.restore();
- });
-
- it('should set defaults', () => {
- expect(mediator.store).toBeDefined();
- expect(mediator.service).toBeDefined();
- expect(mediator.options).toEqual({ endpoint: 'jobs/40291672.json' });
- expect(mediator.state.isLoading).toEqual(false);
- });
-
- describe('request and store data', () => {
- beforeEach(() => {
- mock.onGet().reply(200, job, {});
- });
-
- it('should store received data', (done) => {
- mediator.fetchJob();
- setTimeout(() => {
- expect(mediator.store.state.job).toEqual(job);
- done();
- }, 0);
- });
- });
-});
diff --git a/spec/javascripts/jobs/components/job_log_controllers_spec.js b/spec/javascripts/jobs/components/job_log_controllers_spec.js
index 416dfab8a48..099aca602c4 100644
--- a/spec/javascripts/jobs/components/job_log_controllers_spec.js
+++ b/spec/javascripts/jobs/components/job_log_controllers_spec.js
@@ -10,50 +10,51 @@ describe('Job log controllers', () => {
vm.$destroy();
});
- describe('Truncate information', () => {
+ const props = {
+ rawPath: '/raw',
+ erasePath: '/erase',
+ size: 511952,
+ isScrollTopDisabled: false,
+ isScrollBottomDisabled: false,
+ isScrollingDown: true,
+ isTraceSizeVisible: true,
+ };
- beforeEach(() => {
- vm = mountComponent(Component, {
- rawTracePath: '/raw',
- canEraseJob: true,
- size: 511952,
- canScrollToTop: true,
- canScrollToBottom: true,
+ describe('Truncate information', () => {
+ describe('with isTraceSizeVisible', () => {
+ beforeEach(() => {
+ vm = mountComponent(Component, props);
+ });
+ it('renders size information', () => {
+ expect(vm.$el.querySelector('.js-truncated-info').textContent).toContain('499.95 KiB');
});
- });
-
- it('renders size information', () => {
- expect(vm.$el.querySelector('.js-truncated-info').textContent).toContain('499.95 KiB');
- });
- it('renders link to raw trace', () => {
- expect(vm.$el.querySelector('.js-raw-link').getAttribute('href')).toEqual('/raw');
+ it('renders link to raw trace', () => {
+ expect(vm.$el.querySelector('.js-raw-link').getAttribute('href')).toEqual('/raw');
+ });
});
-
});
describe('links section', () => {
describe('with raw trace path', () => {
it('renders raw trace link', () => {
- vm = mountComponent(Component, {
- rawTracePath: '/raw',
- canEraseJob: true,
- size: 511952,
- canScrollToTop: true,
- canScrollToBottom: true,
- });
+ vm = mountComponent(Component, props);
- expect(vm.$el.querySelector('.js-raw-link-controller').getAttribute('href')).toEqual('/raw');
+ expect(vm.$el.querySelector('.js-raw-link-controller').getAttribute('href')).toEqual(
+ '/raw',
+ );
});
});
describe('without raw trace path', () => {
it('does not render raw trace link', () => {
vm = mountComponent(Component, {
- canEraseJob: true,
+ erasePath: '/erase',
size: 511952,
- canScrollToTop: true,
- canScrollToBottom: true,
+ isScrollTopDisabled: true,
+ isScrollBottomDisabled: true,
+ isScrollingDown: false,
+ isTraceSizeVisible: true,
});
expect(vm.$el.querySelector('.js-raw-link-controller')).toBeNull();
@@ -62,52 +63,23 @@ describe('Job log controllers', () => {
describe('when is erasable', () => {
beforeEach(() => {
- vm = mountComponent(Component, {
- rawTracePath: '/raw',
- canEraseJob: true,
- size: 511952,
- canScrollToTop: true,
- canScrollToBottom: true,
- });
+ vm = mountComponent(Component, props);
});
- it('renders erase job button', () => {
+ it('renders erase job link', () => {
expect(vm.$el.querySelector('.js-erase-link')).not.toBeNull();
});
-
- describe('on click', () => {
- describe('when user confirms action', () => {
- it('emits eraseJob event', () => {
- spyOn(window, 'confirm').and.returnValue(true);
- spyOn(vm, '$emit');
-
- vm.$el.querySelector('.js-erase-link').click();
-
- expect(vm.$emit).toHaveBeenCalledWith('eraseJob');
- });
- });
-
- describe('when user does not confirm action', () => {
- it('does not emit eraseJob event', () => {
- spyOn(window, 'confirm').and.returnValue(false);
- spyOn(vm, '$emit');
-
- vm.$el.querySelector('.js-erase-link').click();
-
- expect(vm.$emit).not.toHaveBeenCalledWith('eraseJob');
- });
- });
- });
});
describe('when it is not erasable', () => {
it('does not render erase button', () => {
vm = mountComponent(Component, {
- rawTracePath: '/raw',
- canEraseJob: false,
+ rawPath: '/raw',
size: 511952,
- canScrollToTop: true,
- canScrollToBottom: true,
+ isScrollTopDisabled: true,
+ isScrollBottomDisabled: true,
+ isScrollingDown: false,
+ isTraceSizeVisible: true,
});
expect(vm.$el.querySelector('.js-erase-link')).toBeNull();
@@ -119,13 +91,7 @@ describe('Job log controllers', () => {
describe('scroll top button', () => {
describe('when user can scroll top', () => {
beforeEach(() => {
- vm = mountComponent(Component, {
- rawTracePath: '/raw',
- canEraseJob: true,
- size: 511952,
- canScrollToTop: true,
- canScrollToBottom: true,
- });
+ vm = mountComponent(Component, props);
});
it('renders enabled scroll top button', () => {
@@ -143,16 +109,20 @@ describe('Job log controllers', () => {
describe('when user can not scroll top', () => {
beforeEach(() => {
vm = mountComponent(Component, {
- rawTracePath: '/raw',
- canEraseJob: true,
+ rawPath: '/raw',
+ erasePath: '/erase',
size: 511952,
- canScrollToTop: false,
- canScrollToBottom: true,
+ isScrollTopDisabled: true,
+ isScrollBottomDisabled: false,
+ isScrollingDown: false,
+ isTraceSizeVisible: true,
});
});
it('renders disabled scroll top button', () => {
- expect(vm.$el.querySelector('.js-scroll-top').getAttribute('disabled')).toEqual('disabled');
+ expect(vm.$el.querySelector('.js-scroll-top').getAttribute('disabled')).toEqual(
+ 'disabled',
+ );
});
it('does not emit scrollJobLogTop event on click', () => {
@@ -167,13 +137,7 @@ describe('Job log controllers', () => {
describe('scroll bottom button', () => {
describe('when user can scroll bottom', () => {
beforeEach(() => {
- vm = mountComponent(Component, {
- rawTracePath: '/raw',
- canEraseJob: true,
- size: 511952,
- canScrollToTop: true,
- canScrollToBottom: true,
- });
+ vm = mountComponent(Component, props);
});
it('renders enabled scroll bottom button', () => {
@@ -191,17 +155,20 @@ describe('Job log controllers', () => {
describe('when user can not scroll bottom', () => {
beforeEach(() => {
vm = mountComponent(Component, {
- rawTracePath: '/raw',
- canEraseJob: true,
+ rawPath: '/raw',
+ erasePath: '/erase',
size: 511952,
- canScrollToTop: true,
- canScrollToBottom: false,
+ isScrollTopDisabled: false,
+ isScrollBottomDisabled: true,
+ isScrollingDown: false,
+ isTraceSizeVisible: true,
});
});
it('renders disabled scroll bottom button', () => {
- expect(vm.$el.querySelector('.js-scroll-bottom').getAttribute('disabled')).toEqual('disabled');
-
+ expect(vm.$el.querySelector('.js-scroll-bottom').getAttribute('disabled')).toEqual(
+ 'disabled',
+ );
});
it('does not emit scrollJobLogBottom event on click', () => {
@@ -211,7 +178,29 @@ describe('Job log controllers', () => {
expect(vm.$emit).not.toHaveBeenCalledWith('scrollJobLogBottom');
});
});
+
+ describe('while isScrollingDown is true', () => {
+ it('renders animate class for the scroll down button', () => {
+ vm = mountComponent(Component, props);
+
+ expect(vm.$el.querySelector('.js-scroll-bottom').className).toContain('animate');
+ });
+ });
+
+ describe('while isScrollingDown is false', () => {
+ it('does not render animate class for the scroll down button', () => {
+ vm = mountComponent(Component, {
+ rawPath: '/raw',
+ erasePath: '/erase',
+ size: 511952,
+ isScrollTopDisabled: true,
+ isScrollBottomDisabled: false,
+ isScrollingDown: false,
+ isTraceSizeVisible: true,
+ });
+ expect(vm.$el.querySelector('.js-scroll-bottom').className).not.toContain('animate');
+ });
+ });
});
});
});
-
diff --git a/spec/javascripts/jobs/components/job_log_spec.js b/spec/javascripts/jobs/components/job_log_spec.js
index 6a5b375a26c..1011512360d 100644
--- a/spec/javascripts/jobs/components/job_log_spec.js
+++ b/spec/javascripts/jobs/components/job_log_spec.js
@@ -15,7 +15,7 @@ describe('Job Log', () => {
it('renders provided trace', () => {
vm = mountComponent(Component, {
trace,
- isReceivingBuildTrace: true,
+ isComplete: true,
});
expect(vm.$el.querySelector('code').textContent).toContain('Running with gitlab-runner 11.1.0 (081978aa)');
@@ -25,7 +25,7 @@ describe('Job Log', () => {
it('renders animation', () => {
vm = mountComponent(Component, {
trace,
- isReceivingBuildTrace: true,
+ isComplete: true,
});
expect(vm.$el.querySelector('.js-log-animation')).not.toBeNull();
@@ -36,7 +36,7 @@ describe('Job Log', () => {
it('does not render animation', () => {
vm = mountComponent(Component, {
trace,
- isReceivingBuildTrace: false,
+ isComplete: false,
});
expect(vm.$el.querySelector('.js-log-animation')).toBeNull();
diff --git a/spec/javascripts/jobs/components/job_store_spec.js b/spec/javascripts/jobs/components/job_store_spec.js
deleted file mode 100644
index 0dad5111b32..00000000000
--- a/spec/javascripts/jobs/components/job_store_spec.js
+++ /dev/null
@@ -1,26 +0,0 @@
-import JobStore from '~/jobs/stores/job_store';
-import job from '../mock_data';
-
-describe('Job Store', () => {
- let store;
-
- beforeEach(() => {
- store = new JobStore();
- });
-
- it('should set defaults', () => {
- expect(store.state.job).toEqual({});
- });
-
- describe('storeJob', () => {
- it('should store empty object if none is provided', () => {
- store.storeJob();
- expect(store.state.job).toEqual({});
- });
-
- it('should store provided argument', () => {
- store.storeJob(job);
- expect(store.state.job).toEqual(job);
- });
- });
-});
diff --git a/spec/javascripts/jobs/components/trigger_value_spec.js b/spec/javascripts/jobs/components/trigger_block_spec.js
index 3d41a3cfac1..e1b9898393e 100644
--- a/spec/javascripts/jobs/components/trigger_value_spec.js
+++ b/spec/javascripts/jobs/components/trigger_block_spec.js
@@ -13,7 +13,9 @@ describe('Trigger block', () => {
describe('with short token', () => {
it('renders short token', () => {
vm = mountComponent(Component, {
- shortToken: '0a666b2',
+ trigger: {
+ short_token: '0a666b2',
+ },
});
expect(vm.$el.querySelector('.js-short-token').textContent).toContain('0a666b2');
@@ -22,7 +24,7 @@ describe('Trigger block', () => {
describe('without short token', () => {
it('does not render short token', () => {
- vm = mountComponent(Component, {});
+ vm = mountComponent(Component, { trigger: {} });
expect(vm.$el.querySelector('.js-short-token')).toBeNull();
});
@@ -32,9 +34,12 @@ describe('Trigger block', () => {
describe('reveal variables', () => {
it('reveals variables on click', done => {
vm = mountComponent(Component, {
- variables: {
- key: 'value',
- variable: 'foo',
+ trigger: {
+ short_token: 'bd7e',
+ variables: [
+ { key: 'UPLOAD_TO_GCS', value: 'false', public: false },
+ { key: 'UPLOAD_TO_S3', value: 'true', public: false },
+ ],
},
});
@@ -44,10 +49,10 @@ describe('Trigger block', () => {
.$nextTick()
.then(() => {
expect(vm.$el.querySelector('.js-build-variables')).not.toBeNull();
- expect(vm.$el.querySelector('.js-build-variables').textContent).toContain('key');
- expect(vm.$el.querySelector('.js-build-variables').textContent).toContain('value');
- expect(vm.$el.querySelector('.js-build-variables').textContent).toContain('variable');
- expect(vm.$el.querySelector('.js-build-variables').textContent).toContain('foo');
+ expect(vm.$el.querySelector('.js-build-variables').textContent).toContain('UPLOAD_TO_GCS');
+ expect(vm.$el.querySelector('.js-build-variables').textContent).toContain('false');
+ expect(vm.$el.querySelector('.js-build-variables').textContent).toContain('UPLOAD_TO_S3');
+ expect(vm.$el.querySelector('.js-build-variables').textContent).toContain('true');
})
.then(done)
.catch(done.fail);
@@ -57,7 +62,7 @@ describe('Trigger block', () => {
describe('without variables', () => {
it('does not render variables', () => {
- vm = mountComponent(Component);
+ vm = mountComponent(Component, { trigger: {} });
expect(vm.$el.querySelector('.js-reveal-variables')).toBeNull();
expect(vm.$el.querySelector('.js-build-variables')).toBeNull();
diff --git a/spec/javascripts/jobs/store/mutations_spec.js b/spec/javascripts/jobs/store/mutations_spec.js
index 6900b2e5602..9ba543d32a8 100644
--- a/spec/javascripts/jobs/store/mutations_spec.js
+++ b/spec/javascripts/jobs/store/mutations_spec.js
@@ -12,6 +12,13 @@ describe('Jobs Store Mutations', () => {
stateCopy = state();
});
+ describe('SET_JOB_ENDPOINT', () => {
+ it('should set jobEndpoint', () => {
+ mutations[types.SET_JOB_ENDPOINT](stateCopy, 'job/21312321.json');
+ expect(stateCopy.jobEndpoint).toEqual('job/21312321.json');
+ });
+ });
+
describe('REQUEST_STATUS_FAVICON', () => {
it('should set fetchingStatusFavicon to true', () => {
mutations[types.REQUEST_STATUS_FAVICON](stateCopy);
diff --git a/spec/javascripts/shortcuts_dashboard_navigation_spec.js b/spec/javascripts/lib/utils/navigation_utility_spec.js
index 7cb201e01d8..be620e4a27c 100644
--- a/spec/javascripts/shortcuts_dashboard_navigation_spec.js
+++ b/spec/javascripts/lib/utils/navigation_utility_spec.js
@@ -1,4 +1,4 @@
-import findAndFollowLink from '~/shortcuts_dashboard_navigation';
+import findAndFollowLink from '~/lib/utils/navigation_utility';
describe('findAndFollowLink', () => {
it('visits a link when the selector exists', () => {
diff --git a/spec/javascripts/lib/utils/poll_spec.js b/spec/javascripts/lib/utils/poll_spec.js
index 523f4997bc0..b28a052902e 100644
--- a/spec/javascripts/lib/utils/poll_spec.js
+++ b/spec/javascripts/lib/utils/poll_spec.js
@@ -1,3 +1,5 @@
+/* eslint-disable jasmine/no-unsafe-spy */
+
import Poll from '~/lib/utils/poll';
import { successCodes } from '~/lib/utils/http_status';
diff --git a/spec/javascripts/monitoring/dashboard_spec.js b/spec/javascripts/monitoring/dashboard_spec.js
index 997163c7602..f0d53b2d8d7 100644
--- a/spec/javascripts/monitoring/dashboard_spec.js
+++ b/spec/javascripts/monitoring/dashboard_spec.js
@@ -25,7 +25,10 @@ describe('Dashboard', () => {
};
beforeEach(() => {
- setFixtures('<div class="prometheus-graphs"></div>');
+ setFixtures(`
+ <div class="prometheus-graphs"></div>
+ <div class="nav-sidebar"></div>
+ `);
DashboardComponent = Vue.extend(Dashboard);
});
@@ -127,4 +130,41 @@ describe('Dashboard', () => {
});
});
});
+
+ describe('when the window resizes', () => {
+ let mock;
+ beforeEach(() => {
+ mock = new MockAdapter(axios);
+ mock.onGet(mockApiEndpoint).reply(200, metricsGroupsAPIResponse);
+ jasmine.clock().install();
+ });
+
+ afterEach(() => {
+ mock.restore();
+ jasmine.clock().uninstall();
+ });
+
+ it('rerenders the dashboard when the sidebar is resized', done => {
+ const component = new DashboardComponent({
+ el: document.querySelector('.prometheus-graphs'),
+ propsData: { ...propsData, hasMetrics: true, showPanels: false },
+ });
+
+ expect(component.forceRedraw).toEqual(0);
+
+ const navSidebarEl = document.querySelector('.nav-sidebar');
+ navSidebarEl.classList.add('nav-sidebar-collapsed');
+
+ Vue.nextTick()
+ .then(() => {
+ jasmine.clock().tick(1000);
+ return Vue.nextTick();
+ })
+ .then(() => {
+ expect(component.forceRedraw).toEqual(component.elWidth);
+ done();
+ })
+ .catch(done.fail);
+ });
+ });
});
diff --git a/spec/javascripts/monitoring/graph_spec.js b/spec/javascripts/monitoring/graph_spec.js
index 990619b4109..99180e4d303 100644
--- a/spec/javascripts/monitoring/graph_spec.js
+++ b/spec/javascripts/monitoring/graph_spec.js
@@ -1,7 +1,6 @@
import Vue from 'vue';
import Graph from '~/monitoring/components/graph.vue';
import MonitoringMixins from '~/monitoring/mixins/monitoring_mixins';
-import eventHub from '~/monitoring/event_hub';
import {
deploymentData,
convertDatesMultipleSeries,
@@ -69,23 +68,6 @@ describe('Graph', () => {
});
});
- it('sends an event to the eventhub when it has finished resizing', done => {
- const component = createComponent({
- graphData: convertedMetrics[1],
- updateAspectRatio: false,
- deploymentData,
- tagsPath,
- projectPath,
- });
- spyOn(eventHub, '$emit');
-
- component.updateAspectRatio = true;
- Vue.nextTick(() => {
- expect(eventHub.$emit).toHaveBeenCalled();
- done();
- });
- });
-
it('has a title for the y-axis and the chart legend that comes from the backend', () => {
const component = createComponent({
graphData: convertedMetrics[1],
diff --git a/spec/javascripts/notes/stores/actions_spec.js b/spec/javascripts/notes/stores/actions_spec.js
index b66e8e1ceb3..f4643fd55ed 100644
--- a/spec/javascripts/notes/stores/actions_spec.js
+++ b/spec/javascripts/notes/stores/actions_spec.js
@@ -3,6 +3,7 @@ import _ from 'underscore';
import { headersInterceptor } from 'spec/helpers/vue_resource_helper';
import * as actions from '~/notes/stores/actions';
import createStore from '~/notes/stores';
+import mrWidgetEventHub from '~/vue_merge_request_widget/event_hub';
import testAction from '../../helpers/vuex_action_helper';
import { resetStore } from '../helpers';
import {
@@ -317,4 +318,195 @@ describe('Actions Notes Store', () => {
);
});
});
+
+ describe('deleteNote', () => {
+ const interceptor = (request, next) => {
+ next(
+ request.respondWith(JSON.stringify({}), {
+ status: 200,
+ }),
+ );
+ };
+
+ beforeEach(() => {
+ Vue.http.interceptors.push(interceptor);
+ });
+
+ afterEach(() => {
+ Vue.http.interceptors = _.without(Vue.http.interceptors, interceptor);
+ });
+
+ it('commits DELETE_NOTE and dispatches updateMergeRequestWidget', done => {
+ const note = { path: `${gl.TEST_HOST}`, id: 1 };
+
+ testAction(
+ actions.deleteNote,
+ note,
+ store.state,
+ [
+ {
+ type: 'DELETE_NOTE',
+ payload: note,
+ },
+ ],
+ [
+ {
+ type: 'updateMergeRequestWidget',
+ },
+ ],
+ done,
+ );
+ });
+ });
+
+ describe('createNewNote', () => {
+ describe('success', () => {
+ const res = {
+ id: 1,
+ valid: true,
+ };
+ const interceptor = (request, next) => {
+ next(
+ request.respondWith(JSON.stringify(res), {
+ status: 200,
+ }),
+ );
+ };
+
+ beforeEach(() => {
+ Vue.http.interceptors.push(interceptor);
+ });
+
+ afterEach(() => {
+ Vue.http.interceptors = _.without(Vue.http.interceptors, interceptor);
+ });
+
+ it('commits ADD_NEW_NOTE and dispatches updateMergeRequestWidget', done => {
+ testAction(
+ actions.createNewNote,
+ { endpoint: `${gl.TEST_HOST}`, data: {} },
+ store.state,
+ [
+ {
+ type: 'ADD_NEW_NOTE',
+ payload: res,
+ },
+ ],
+ [
+ {
+ type: 'updateMergeRequestWidget',
+ },
+ ],
+ done,
+ );
+ });
+ });
+
+ describe('error', () => {
+ const res = {
+ errors: ['error'],
+ };
+ const interceptor = (request, next) => {
+ next(
+ request.respondWith(JSON.stringify(res), {
+ status: 200,
+ }),
+ );
+ };
+
+ beforeEach(() => {
+ Vue.http.interceptors.push(interceptor);
+ });
+
+ afterEach(() => {
+ Vue.http.interceptors = _.without(Vue.http.interceptors, interceptor);
+ });
+
+ it('does not commit ADD_NEW_NOTE or dispatch updateMergeRequestWidget', done => {
+ testAction(
+ actions.createNewNote,
+ { endpoint: `${gl.TEST_HOST}`, data: {} },
+ store.state,
+ [],
+ [],
+ done,
+ );
+ });
+ });
+ });
+
+ describe('toggleResolveNote', () => {
+ const res = {
+ resolved: true,
+ };
+ const interceptor = (request, next) => {
+ next(
+ request.respondWith(JSON.stringify(res), {
+ status: 200,
+ }),
+ );
+ };
+
+ beforeEach(() => {
+ Vue.http.interceptors.push(interceptor);
+ });
+
+ afterEach(() => {
+ Vue.http.interceptors = _.without(Vue.http.interceptors, interceptor);
+ });
+
+ describe('as note', () => {
+ it('commits UPDATE_NOTE and dispatches updateMergeRequestWidget', done => {
+ testAction(
+ actions.toggleResolveNote,
+ { endpoint: `${gl.TEST_HOST}`, isResolved: true, discussion: false },
+ store.state,
+ [
+ {
+ type: 'UPDATE_NOTE',
+ payload: res,
+ },
+ ],
+ [
+ {
+ type: 'updateMergeRequestWidget',
+ },
+ ],
+ done,
+ );
+ });
+ });
+
+ describe('as discussion', () => {
+ it('commits UPDATE_DISCUSSION and dispatches updateMergeRequestWidget', done => {
+ testAction(
+ actions.toggleResolveNote,
+ { endpoint: `${gl.TEST_HOST}`, isResolved: true, discussion: true },
+ store.state,
+ [
+ {
+ type: 'UPDATE_DISCUSSION',
+ payload: res,
+ },
+ ],
+ [
+ {
+ type: 'updateMergeRequestWidget',
+ },
+ ],
+ done,
+ );
+ });
+ });
+ });
+
+ describe('updateMergeRequestWidget', () => {
+ it('calls mrWidget checkStatus', () => {
+ spyOn(mrWidgetEventHub, '$emit');
+
+ actions.updateMergeRequestWidget();
+
+ expect(mrWidgetEventHub.$emit).toHaveBeenCalledWith('mr.discussion.updated');
+ });
+ });
});
diff --git a/spec/javascripts/notes/stores/mutation_spec.js b/spec/javascripts/notes/stores/mutation_spec.js
index 6b7f61468d5..1ecfe914859 100644
--- a/spec/javascripts/notes/stores/mutation_spec.js
+++ b/spec/javascripts/notes/stores/mutation_spec.js
@@ -156,6 +156,41 @@ describe('Notes Store mutations', () => {
expect(state.discussions[2].notes[0].note).toBe(legacyNote.notes[1].note);
expect(state.discussions.length).toEqual(3);
});
+
+ it('adds truncated_diff_lines if discussion is a diffFile', () => {
+ const state = {
+ discussions: [],
+ };
+
+ mutations.SET_INITIAL_DISCUSSIONS(state, [
+ {
+ ...note,
+ diff_file: {
+ file_hash: 'a',
+ },
+ truncated_diff_lines: ['a'],
+ },
+ ]);
+
+ expect(state.discussions[0].truncated_diff_lines).toEqual(['a']);
+ });
+
+ it('adds empty truncated_diff_lines when not in discussion', () => {
+ const state = {
+ discussions: [],
+ };
+
+ mutations.SET_INITIAL_DISCUSSIONS(state, [
+ {
+ ...note,
+ diff_file: {
+ file_hash: 'a',
+ },
+ },
+ ]);
+
+ expect(state.discussions[0].truncated_diff_lines).toEqual([]);
+ });
});
describe('SET_LAST_FETCHED_AT', () => {
diff --git a/spec/javascripts/right_sidebar_spec.js b/spec/javascripts/right_sidebar_spec.js
index 6d49536a712..c7190ea9960 100644
--- a/spec/javascripts/right_sidebar_spec.js
+++ b/spec/javascripts/right_sidebar_spec.js
@@ -1,4 +1,4 @@
-/* eslint-disable no-var, one-var, one-var-declaration-per-line, no-return-assign, vars-on-top, max-len */
+/* eslint-disable no-var, one-var, one-var-declaration-per-line, no-return-assign, vars-on-top, jasmine/no-unsafe-spy, max-len */
import $ from 'jquery';
import MockAdapter from 'axios-mock-adapter';
diff --git a/spec/javascripts/search_autocomplete_spec.js b/spec/javascripts/search_autocomplete_spec.js
index 86c001678c5..646d843162c 100644
--- a/spec/javascripts/search_autocomplete_spec.js
+++ b/spec/javascripts/search_autocomplete_spec.js
@@ -2,7 +2,7 @@
import $ from 'jquery';
import '~/gl_dropdown';
-import SearchAutocomplete from '~/search_autocomplete';
+import initSearchAutocomplete from '~/search_autocomplete';
import '~/lib/utils/common_utils';
describe('Search autocomplete dropdown', () => {
@@ -132,7 +132,7 @@ describe('Search autocomplete dropdown', () => {
window.gon.current_user_id = userId;
window.gon.current_username = userName;
- return (widget = new SearchAutocomplete());
+ return (widget = initSearchAutocomplete());
});
afterEach(function() {
diff --git a/spec/javascripts/shortcuts_spec.js b/spec/javascripts/shortcuts_spec.js
index 94cded7ee37..3ca6ecaa938 100644
--- a/spec/javascripts/shortcuts_spec.js
+++ b/spec/javascripts/shortcuts_spec.js
@@ -1,5 +1,5 @@
import $ from 'jquery';
-import Shortcuts from '~/shortcuts';
+import Shortcuts from '~/behaviors/shortcuts/shortcuts';
describe('Shortcuts', () => {
const fixtureName = 'snippets/show.html.raw';
diff --git a/spec/javascripts/sidebar/sidebar_subscriptions_spec.js b/spec/javascripts/sidebar/sidebar_subscriptions_spec.js
index 9e437084224..af2fde0a5be 100644
--- a/spec/javascripts/sidebar/sidebar_subscriptions_spec.js
+++ b/spec/javascripts/sidebar/sidebar_subscriptions_spec.js
@@ -12,7 +12,7 @@ describe('Sidebar Subscriptions', function () {
beforeEach(() => {
SidebarSubscriptions = Vue.extend(sidebarSubscriptions);
- // Setup the stores, services, etc
+ // Set up the stores, services, etc
// eslint-disable-next-line no-new
new SidebarMediator(Mock.mediator);
});
diff --git a/spec/javascripts/u2f/register_spec.js b/spec/javascripts/u2f/register_spec.js
index d9383314891..b774627651f 100644
--- a/spec/javascripts/u2f/register_spec.js
+++ b/spec/javascripts/u2f/register_spec.js
@@ -16,7 +16,7 @@ describe('U2FRegister', function () {
it('allows registering a U2F device', () => {
const setupButton = this.container.find('#js-setup-u2f-device');
- expect(setupButton.text()).toBe('Setup new U2F device');
+ expect(setupButton.text()).toBe('Set up new U2F device');
setupButton.trigger('click');
const inProgressMessage = this.container.children('p');
expect(inProgressMessage.text()).toContain('Trying to communicate with your device');
diff --git a/spec/javascripts/vue_mr_widget/mr_widget_options_spec.js b/spec/javascripts/vue_mr_widget/mr_widget_options_spec.js
index 6342ea00436..6ac7138743b 100644
--- a/spec/javascripts/vue_mr_widget/mr_widget_options_spec.js
+++ b/spec/javascripts/vue_mr_widget/mr_widget_options_spec.js
@@ -27,6 +27,10 @@ describe('mrWidgetOptions', () => {
});
});
+ afterEach(() => {
+ vm.$destroy();
+ });
+
describe('data', () => {
it('should instantiate Store and Service', () => {
expect(vm.mr).toBeDefined();
diff --git a/spec/javascripts/vue_shared/components/file_row_spec.js b/spec/javascripts/vue_shared/components/file_row_spec.js
new file mode 100644
index 00000000000..9914c0b70f3
--- /dev/null
+++ b/spec/javascripts/vue_shared/components/file_row_spec.js
@@ -0,0 +1,74 @@
+import Vue from 'vue';
+import FileRow from '~/vue_shared/components/file_row.vue';
+import { file } from 'spec/ide/helpers';
+import mountComponent from '../../helpers/vue_mount_component_helper';
+
+describe('RepoFile', () => {
+ let vm;
+
+ function createComponent(propsData) {
+ const FileRowComponent = Vue.extend(FileRow);
+
+ vm = mountComponent(FileRowComponent, propsData);
+ }
+
+ afterEach(() => {
+ vm.$destroy();
+ });
+
+ it('renders name', () => {
+ createComponent({
+ file: file('t4'),
+ level: 0,
+ });
+
+ const name = vm.$el.querySelector('.file-row-name');
+
+ expect(name.textContent.trim()).toEqual(vm.file.name);
+ });
+
+ it('emits toggleTreeOpen on click', () => {
+ createComponent({
+ file: {
+ ...file('t3'),
+ type: 'tree',
+ },
+ level: 0,
+ });
+ spyOn(vm, '$emit').and.stub();
+
+ vm.$el.querySelector('.file-row').click();
+
+ expect(vm.$emit).toHaveBeenCalledWith('toggleTreeOpen', vm.file.path);
+ });
+
+ it('calls scrollIntoView if made active', done => {
+ createComponent({
+ file: {
+ ...file(),
+ type: 'blob',
+ active: false,
+ },
+ level: 0,
+ });
+
+ spyOn(vm, 'scrollIntoView').and.stub();
+
+ vm.file.active = true;
+
+ vm.$nextTick(() => {
+ expect(vm.scrollIntoView).toHaveBeenCalled();
+
+ done();
+ });
+ });
+
+ it('indents row based on level', () => {
+ createComponent({
+ file: file('t4'),
+ level: 2,
+ });
+
+ expect(vm.$el.querySelector('.file-row-name').style.marginLeft).toBe('32px');
+ });
+});
diff --git a/spec/javascripts/vue_shared/components/skeleton_loading_container_spec.js b/spec/javascripts/vue_shared/components/skeleton_loading_container_spec.js
deleted file mode 100644
index 34487885cf0..00000000000
--- a/spec/javascripts/vue_shared/components/skeleton_loading_container_spec.js
+++ /dev/null
@@ -1,49 +0,0 @@
-import Vue from 'vue';
-import skeletonLoadingContainer from '~/vue_shared/components/skeleton_loading_container.vue';
-import mountComponent from 'spec/helpers/vue_mount_component_helper';
-
-describe('Skeleton loading container', () => {
- let vm;
-
- beforeEach(() => {
- const component = Vue.extend(skeletonLoadingContainer);
- vm = mountComponent(component);
- });
-
- afterEach(() => {
- vm.$destroy();
- });
-
- it('renders 3 skeleton lines by default', () => {
- expect(vm.$el.querySelector('.skeleton-line-3')).not.toBeNull();
- });
-
- it('renders in full mode by default', () => {
- expect(vm.$el.classList.contains('animation-container-small')).toBeFalsy();
- });
-
- describe('small', () => {
- beforeEach((done) => {
- vm.small = true;
-
- Vue.nextTick(done);
- });
-
- it('renders in small mode', () => {
- expect(vm.$el.classList.contains('animation-container-small')).toBeTruthy();
- });
- });
-
- describe('lines', () => {
- beforeEach((done) => {
- vm.lines = 5;
-
- Vue.nextTick(done);
- });
-
- it('renders 5 lines', () => {
- expect(vm.$el.querySelector('.skeleton-line-5')).not.toBeNull();
- expect(vm.$el.querySelector('.skeleton-line-6')).toBeNull();
- });
- });
-});
diff --git a/spec/javascripts/vue_shared/components/table_pagination_spec.js b/spec/javascripts/vue_shared/components/table_pagination_spec.js
index c36b607a34e..d193667210b 100644
--- a/spec/javascripts/vue_shared/components/table_pagination_spec.js
+++ b/spec/javascripts/vue_shared/components/table_pagination_spec.js
@@ -5,13 +5,13 @@ describe('Pagination component', () => {
let component;
let PaginationComponent;
let spy;
- let mountComponet;
+ let mountComponent;
beforeEach(() => {
spy = jasmine.createSpy('spy');
PaginationComponent = Vue.extend(paginationComp);
- mountComponet = function (props) {
+ mountComponent = function (props) {
return new PaginationComponent({
propsData: props,
}).$mount();
@@ -20,7 +20,7 @@ describe('Pagination component', () => {
describe('render', () => {
it('should not render anything', () => {
- component = mountComponet({
+ component = mountComponent({
pageInfo: {
nextPage: 1,
page: 1,
@@ -37,7 +37,7 @@ describe('Pagination component', () => {
describe('prev button', () => {
it('should be disabled and non clickable', () => {
- component = mountComponet({
+ component = mountComponent({
pageInfo: {
nextPage: 2,
page: 1,
@@ -59,7 +59,7 @@ describe('Pagination component', () => {
});
it('should be enabled and clickable', () => {
- component = mountComponet({
+ component = mountComponent({
pageInfo: {
nextPage: 3,
page: 2,
@@ -78,7 +78,7 @@ describe('Pagination component', () => {
describe('first button', () => {
it('should call the change callback with the first page', () => {
- component = mountComponet({
+ component = mountComponent({
pageInfo: {
nextPage: 3,
page: 2,
@@ -102,7 +102,7 @@ describe('Pagination component', () => {
describe('last button', () => {
it('should call the change callback with the last page', () => {
- component = mountComponet({
+ component = mountComponent({
pageInfo: {
nextPage: 3,
page: 2,
@@ -126,7 +126,7 @@ describe('Pagination component', () => {
describe('next button', () => {
it('should be disabled and non clickable', () => {
- component = mountComponet({
+ component = mountComponent({
pageInfo: {
nextPage: 5,
page: 5,
@@ -148,7 +148,7 @@ describe('Pagination component', () => {
});
it('should be enabled and clickable', () => {
- component = mountComponet({
+ component = mountComponent({
pageInfo: {
nextPage: 4,
page: 3,
@@ -168,7 +168,7 @@ describe('Pagination component', () => {
describe('numbered buttons', () => {
it('should render 5 pages', () => {
- component = mountComponet({
+ component = mountComponent({
pageInfo: {
nextPage: 4,
page: 3,
@@ -185,7 +185,7 @@ describe('Pagination component', () => {
});
it('should render the spread operator', () => {
- component = mountComponet({
+ component = mountComponent({
pageInfo: {
nextPage: 4,
page: 3,
diff --git a/spec/lib/banzai/filter/external_issue_reference_filter_spec.rb b/spec/lib/banzai/filter/external_issue_reference_filter_spec.rb
index d9018a7e4fe..0d0554a2259 100644
--- a/spec/lib/banzai/filter/external_issue_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/external_issue_reference_filter_spec.rb
@@ -79,13 +79,9 @@ describe Banzai::Filter::ExternalIssueReferenceFilter do
expect(link).to eq helper.url_for_issue(issue_id, project, only_path: true)
end
- context 'with RequestStore enabled' do
+ context 'with RequestStore enabled', :request_store do
let(:reference_filter) { HTML::Pipeline.new([described_class]) }
- before do
- allow(RequestStore).to receive(:active?).and_return(true)
- end
-
it 'queries the collection on the first call' do
expect_any_instance_of(Project).to receive(:default_issues_tracker?).once.and_call_original
expect_any_instance_of(Project).to receive(:external_issue_reference_pattern).once.and_call_original
diff --git a/spec/lib/banzai/filter/relative_link_filter_spec.rb b/spec/lib/banzai/filter/relative_link_filter_spec.rb
index ba8dc68ceda..ed1ebe9ebf6 100644
--- a/spec/lib/banzai/filter/relative_link_filter_spec.rb
+++ b/spec/lib/banzai/filter/relative_link_filter_spec.rb
@@ -83,6 +83,11 @@ describe Banzai::Filter::RelativeLinkFilter do
expect { filter(act) }.not_to raise_error
end
+ it 'does not raise an exception with a space in the path' do
+ act = link("/uploads/d18213acd3732630991986120e167e3d/Landscape_8.jpg \nBut here's some more unexpected text :smile:)")
+ expect { filter(act) }.not_to raise_error
+ end
+
it 'ignores ref if commit is passed' do
doc = filter(link('non/existent.file'), commit: project.commit('empty-branch') )
expect(doc.at_css('a')['href'])
diff --git a/spec/lib/banzai/reference_parser/base_parser_spec.rb b/spec/lib/banzai/reference_parser/base_parser_spec.rb
index 4e6e8eca38a..c6e9fc414a1 100644
--- a/spec/lib/banzai/reference_parser/base_parser_spec.rb
+++ b/spec/lib/banzai/reference_parser/base_parser_spec.rb
@@ -263,11 +263,10 @@ describe Banzai::ReferenceParser::BaseParser do
end
end
- context 'with RequestStore enabled' do
+ context 'with RequestStore enabled', :request_store do
before do
cache = Hash.new { |hash, key| hash[key] = {} }
- allow(RequestStore).to receive(:active?).and_return(true)
allow(subject).to receive(:collection_cache).and_return(cache)
end
diff --git a/spec/lib/event_filter_spec.rb b/spec/lib/event_filter_spec.rb
index 87ae6b6cf01..30016da6828 100644
--- a/spec/lib/event_filter_spec.rb
+++ b/spec/lib/event_filter_spec.rb
@@ -1,58 +1,119 @@
require 'spec_helper'
describe EventFilter do
+ describe 'FILTERS' do
+ it 'returns a definite list of filters' do
+ expect(described_class::FILTERS).to eq(%w[all push merged issue comments team])
+ end
+ end
+
+ describe '#filter' do
+ it 'returns "all" if given filter is nil' do
+ expect(described_class.new(nil).filter).to eq(described_class::ALL)
+ end
+
+ it 'returns "all" if given filter is ""' do
+ expect(described_class.new('').filter).to eq(described_class::ALL)
+ end
+
+ it 'returns "all" if given filter is "foo"' do
+ expect(described_class.new('foo').filter).to eq('all')
+ end
+ end
+
describe '#apply_filter' do
- let(:source_user) { create(:user) }
- let!(:public_project) { create(:project, :public) }
+ set(:public_project) { create(:project, :public) }
+
+ set(:push_event) { create(:push_event, project: public_project) }
+ set(:merged_event) { create(:event, :merged, project: public_project, target: public_project) }
+ set(:created_event) { create(:event, :created, project: public_project, target: public_project) }
+ set(:updated_event) { create(:event, :updated, project: public_project, target: public_project) }
+ set(:closed_event) { create(:event, :closed, project: public_project, target: public_project) }
+ set(:reopened_event) { create(:event, :reopened, project: public_project, target: public_project) }
+ set(:comments_event) { create(:event, :commented, project: public_project, target: public_project) }
+ set(:joined_event) { create(:event, :joined, project: public_project, target: public_project) }
+ set(:left_event) { create(:event, :left, project: public_project, target: public_project) }
- let!(:push_event) { create(:push_event, project: public_project, author: source_user) }
- let!(:merged_event) { create(:event, :merged, project: public_project, target: public_project, author: source_user) }
- let!(:created_event) { create(:event, :created, project: public_project, target: public_project, author: source_user) }
- let!(:updated_event) { create(:event, :updated, project: public_project, target: public_project, author: source_user) }
- let!(:closed_event) { create(:event, :closed, project: public_project, target: public_project, author: source_user) }
- let!(:reopened_event) { create(:event, :reopened, project: public_project, target: public_project, author: source_user) }
- let!(:comments_event) { create(:event, :commented, project: public_project, target: public_project, author: source_user) }
- let!(:joined_event) { create(:event, :joined, project: public_project, target: public_project, author: source_user) }
- let!(:left_event) { create(:event, :left, project: public_project, target: public_project, author: source_user) }
+ let(:filtered_events) { described_class.new(filter).apply_filter(Event.all) }
- it 'applies push filter' do
- events = described_class.new(described_class.push).apply_filter(Event.all)
- expect(events).to contain_exactly(push_event)
+ context 'with the "push" filter' do
+ let(:filter) { described_class::PUSH }
+
+ it 'filters push events only' do
+ expect(filtered_events).to contain_exactly(push_event)
+ end
end
- it 'applies merged filter' do
- events = described_class.new(described_class.merged).apply_filter(Event.all)
- expect(events).to contain_exactly(merged_event)
+ context 'with the "merged" filter' do
+ let(:filter) { described_class::MERGED }
+
+ it 'filters merged events only' do
+ expect(filtered_events).to contain_exactly(merged_event)
+ end
end
- it 'applies issue filter' do
- events = described_class.new(described_class.issue).apply_filter(Event.all)
- expect(events).to contain_exactly(created_event, updated_event, closed_event, reopened_event)
+ context 'with the "issue" filter' do
+ let(:filter) { described_class::ISSUE }
+
+ it 'filters issue events only' do
+ expect(filtered_events).to contain_exactly(created_event, updated_event, closed_event, reopened_event)
+ end
end
- it 'applies comments filter' do
- events = described_class.new(described_class.comments).apply_filter(Event.all)
- expect(events).to contain_exactly(comments_event)
+ context 'with the "comments" filter' do
+ let(:filter) { described_class::COMMENTS }
+
+ it 'filters comment events only' do
+ expect(filtered_events).to contain_exactly(comments_event)
+ end
end
- it 'applies team filter' do
- events = described_class.new(described_class.team).apply_filter(Event.all)
- expect(events).to contain_exactly(joined_event, left_event)
+ context 'with the "team" filter' do
+ let(:filter) { described_class::TEAM }
+
+ it 'filters team events only' do
+ expect(filtered_events).to contain_exactly(joined_event, left_event)
+ end
end
- it 'applies all filter' do
- events = described_class.new(described_class.all).apply_filter(Event.all)
- expect(events).to contain_exactly(push_event, merged_event, created_event, updated_event, closed_event, reopened_event, comments_event, joined_event, left_event)
+ context 'with the "all" filter' do
+ let(:filter) { described_class::ALL }
+
+ it 'returns all events' do
+ expect(filtered_events).to eq(Event.all)
+ end
+ end
+
+ context 'with an unknown filter' do
+ let(:filter) { 'foo' }
+
+ it 'returns all events' do
+ expect(filtered_events).to eq(Event.all)
+ end
+ end
+
+ context 'with a nil filter' do
+ let(:filter) { nil }
+
+ it 'returns all events' do
+ expect(filtered_events).to eq(Event.all)
+ end
+ end
+ end
+
+ describe '#active?' do
+ let(:event_filter) { described_class.new(described_class::TEAM) }
+
+ it 'returns false if filter does not include the given key' do
+ expect(event_filter.active?('foo')).to eq(false)
end
- it 'applies no filter' do
- events = described_class.new(nil).apply_filter(Event.all)
- expect(events).to contain_exactly(push_event, merged_event, created_event, updated_event, closed_event, reopened_event, comments_event, joined_event, left_event)
+ it 'returns false if the given key is nil' do
+ expect(event_filter.active?(nil)).to eq(false)
end
- it 'applies unknown filter' do
- events = described_class.new('').apply_filter(Event.all)
- expect(events).to contain_exactly(push_event, merged_event, created_event, updated_event, closed_event, reopened_event, comments_event, joined_event, left_event)
+ it 'returns true if filter does not include the given key' do
+ expect(event_filter.active?(described_class::TEAM)).to eq(true)
end
end
end
diff --git a/spec/lib/feature_spec.rb b/spec/lib/feature_spec.rb
index 48c0ba8a653..9d56c62ae57 100644
--- a/spec/lib/feature_spec.rb
+++ b/spec/lib/feature_spec.rb
@@ -91,7 +91,11 @@ describe Feature do
end
describe '.flipper' do
- shared_examples 'a memoized Flipper instance' do
+ before do
+ described_class.instance_variable_set(:@flipper, nil)
+ end
+
+ context 'when request store is inactive' do
it 'memoizes the Flipper instance' do
expect(Flipper).to receive(:new).once.and_call_original
@@ -101,16 +105,14 @@ describe Feature do
end
end
- context 'when request store is inactive' do
- before do
+ context 'when request store is active', :request_store do
+ it 'memoizes the Flipper instance' do
+ expect(Flipper).to receive(:new).once.and_call_original
+
+ described_class.flipper
described_class.instance_variable_set(:@flipper, nil)
+ described_class.flipper
end
-
- it_behaves_like 'a memoized Flipper instance'
- end
-
- context 'when request store is inactive', :request_store do
- it_behaves_like 'a memoized Flipper instance'
end
end
diff --git a/spec/lib/gitlab/auth/ldap/access_spec.rb b/spec/lib/gitlab/auth/ldap/access_spec.rb
index 7800c543cdb..662f899180b 100644
--- a/spec/lib/gitlab/auth/ldap/access_spec.rb
+++ b/spec/lib/gitlab/auth/ldap/access_spec.rb
@@ -48,7 +48,7 @@ describe Gitlab::Auth::LDAP::Access do
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})"
+ "blocking GitLab user \"#{user.name}\" (#{user.email})"
)
access.allowed?
@@ -79,7 +79,7 @@ describe Gitlab::Auth::LDAP::Access do
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})"
+ "blocking GitLab user \"#{user.name}\" (#{user.email})"
)
access.allowed?
@@ -123,7 +123,7 @@ describe Gitlab::Auth::LDAP::Access do
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})"
+ "unblocking GitLab user \"#{user.name}\" (#{user.email})"
)
access.allowed?
@@ -161,7 +161,7 @@ describe Gitlab::Auth::LDAP::Access do
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})"
+ "blocking GitLab user \"#{user.name}\" (#{user.email})"
)
access.allowed?
@@ -183,7 +183,7 @@ describe Gitlab::Auth::LDAP::Access do
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})"
+ "unblocking GitLab user \"#{user.name}\" (#{user.email})"
)
access.allowed?
diff --git a/spec/lib/gitlab/background_migration/populate_external_pipeline_source_spec.rb b/spec/lib/gitlab/background_migration/populate_external_pipeline_source_spec.rb
new file mode 100644
index 00000000000..c7b272cd6ca
--- /dev/null
+++ b/spec/lib/gitlab/background_migration/populate_external_pipeline_source_spec.rb
@@ -0,0 +1,62 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Gitlab::BackgroundMigration::PopulateExternalPipelineSource, :migration, schema: 20180916011959 do
+ let(:migration) { described_class.new }
+
+ let!(:internal_pipeline) { create(:ci_pipeline, source: :web) }
+ let(:pipelines) { [internal_pipeline, unknown_pipeline].map(&:id) }
+
+ let!(:unknown_pipeline) do
+ build(:ci_pipeline, source: :unknown)
+ .tap { |pipeline| pipeline.save(validate: false) }
+ end
+
+ subject { migration.perform(pipelines.min, pipelines.max) }
+
+ shared_examples 'no changes' do
+ it 'does not change the pipeline source' do
+ expect { subject }.not_to change { unknown_pipeline.reload.source }
+ end
+ end
+
+ context 'when unknown pipeline is external' do
+ before do
+ create(:generic_commit_status, pipeline: unknown_pipeline)
+ end
+
+ it 'populates the pipeline source' do
+ subject
+
+ expect(unknown_pipeline.reload.source).to eq('external')
+ end
+
+ it 'can be repeated without effect' do
+ subject
+
+ expect { subject }.not_to change { unknown_pipeline.reload.source }
+ end
+ end
+
+ context 'when unknown pipeline has just a build' do
+ before do
+ create(:ci_build, pipeline: unknown_pipeline)
+ end
+
+ it_behaves_like 'no changes'
+ end
+
+ context 'when unknown pipeline has no statuses' do
+ it_behaves_like 'no changes'
+ end
+
+ context 'when unknown pipeline has a build and a status' do
+ before do
+ create(:generic_commit_status, pipeline: unknown_pipeline)
+ create(:ci_build, pipeline: unknown_pipeline)
+ end
+
+ it_behaves_like 'no changes'
+ end
+end
diff --git a/spec/lib/gitlab/ci/config/entry/reports_spec.rb b/spec/lib/gitlab/ci/config/entry/reports_spec.rb
index b3a3a6bee1d..e5fc36b5d7a 100644
--- a/spec/lib/gitlab/ci/config/entry/reports_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/reports_spec.rb
@@ -3,27 +3,53 @@ require 'spec_helper'
describe Gitlab::Ci::Config::Entry::Reports do
let(:entry) { described_class.new(config) }
+ describe 'validates ALLOWED_KEYS' do
+ let(:artifact_file_types) { Ci::JobArtifact.file_types }
+
+ described_class::ALLOWED_KEYS.each do |keyword, _|
+ it "expects #{keyword} to be an artifact file_type" do
+ expect(artifact_file_types).to include(keyword)
+ end
+ end
+ end
+
describe 'validation' do
context 'when entry config value is correct' do
- let(:config) { { junit: %w[junit.xml] } }
+ using RSpec::Parameterized::TableSyntax
- describe '#value' do
- it 'returns artifacs configuration' do
- expect(entry.value).to eq config
+ shared_examples 'a valid entry' do |keyword, file|
+ describe '#value' do
+ it 'returns artifacs configuration' do
+ expect(entry.value).to eq({ "#{keyword}": [file] } )
+ end
end
- end
- describe '#valid?' do
- it 'is valid' do
- expect(entry).to be_valid
+ describe '#valid?' do
+ it 'is valid' do
+ expect(entry).to be_valid
+ end
end
end
- context 'when value is not array' do
- let(:config) { { junit: 'junit.xml' } }
+ where(:keyword, :file) do
+ :junit | 'junit.xml'
+ :sast | 'gl-sast-report.json'
+ :dependency_scanning | 'gl-dependency-scanning-report.json'
+ :container_scanning | 'gl-container-scanning-report.json'
+ :dast | 'gl-dast-report.json'
+ end
+
+ with_them do
+ context 'when value is an array' do
+ let(:config) { { "#{keyword}": [file] } }
- it 'converts to array' do
- expect(entry.value).to eq({ junit: ['junit.xml'] } )
+ it_behaves_like 'a valid entry', params[:keyword], params[:file]
+ end
+
+ context 'when value is not array' do
+ let(:config) { { "#{keyword}": file } }
+
+ it_behaves_like 'a valid entry', params[:keyword], params[:file]
end
end
end
@@ -31,11 +57,13 @@ describe Gitlab::Ci::Config::Entry::Reports do
context 'when entry value is not correct' do
describe '#errors' do
context 'when value of attribute is invalid' do
- let(:config) { { junit: 10 } }
+ where(key: described_class::ALLOWED_KEYS) do
+ let(:config) { { "#{key}": 10 } }
- it 'reports error' do
- expect(entry.errors)
- .to include 'reports junit should be an array of strings or a string'
+ it 'reports error' do
+ expect(entry.errors)
+ .to include "reports #{key} should be an array of strings or a string"
+ end
end
end
diff --git a/spec/lib/gitlab/ci/external/file/local_spec.rb b/spec/lib/gitlab/ci/external/file/local_spec.rb
index 3f32d81a827..73bb4ccf468 100644
--- a/spec/lib/gitlab/ci/external/file/local_spec.rb
+++ b/spec/lib/gitlab/ci/external/file/local_spec.rb
@@ -8,7 +8,7 @@ describe Gitlab::Ci::External::File::Local do
describe '#valid?' do
context 'when is a valid local path' do
- let(:location) { '/vendor/gitlab-ci-yml/existent-file.yml' }
+ let(:location) { '/lib/gitlab/ci/templates/existent-file.yml' }
before do
allow_any_instance_of(described_class).to receive(:fetch_local_content).and_return("image: 'ruby2:2'")
@@ -20,7 +20,7 @@ describe Gitlab::Ci::External::File::Local do
end
context 'when is not a valid local path' do
- let(:location) { '/vendor/gitlab-ci-yml/non-existent-file.yml' }
+ let(:location) { '/lib/gitlab/ci/templates/non-existent-file.yml' }
it 'should return false' do
expect(local_file.valid?).to be_falsy
@@ -48,7 +48,7 @@ describe Gitlab::Ci::External::File::Local do
- bundle install --jobs $(nproc) "${FLAGS[@]}"
HEREDOC
end
- let(:location) { '/vendor/gitlab-ci-yml/existent-file.yml' }
+ let(:location) { '/lib/gitlab/ci/templates/existent-file.yml' }
before do
allow_any_instance_of(described_class).to receive(:fetch_local_content).and_return(local_file_content)
@@ -60,7 +60,7 @@ describe Gitlab::Ci::External::File::Local do
end
context 'with an invalid file' do
- let(:location) { '/vendor/gitlab-ci-yml/non-existent-file.yml' }
+ let(:location) { '/lib/gitlab/ci/templates/non-existent-file.yml' }
it 'should be nil' do
expect(local_file.content).to be_nil
@@ -69,7 +69,7 @@ describe Gitlab::Ci::External::File::Local do
end
describe '#error_message' do
- let(:location) { '/vendor/gitlab-ci-yml/non-existent-file.yml' }
+ let(:location) { '/lib/gitlab/ci/templates/non-existent-file.yml' }
it 'should return an error message' do
expect(local_file.error_message).to eq("Local file '#{location}' is not valid.")
diff --git a/spec/lib/gitlab/ci/external/mapper_spec.rb b/spec/lib/gitlab/ci/external/mapper_spec.rb
index 6270d27a36d..d925d6af73d 100644
--- a/spec/lib/gitlab/ci/external/mapper_spec.rb
+++ b/spec/lib/gitlab/ci/external/mapper_spec.rb
@@ -17,7 +17,7 @@ describe Gitlab::Ci::External::Mapper do
context 'when the string is a local file' do
let(:values) do
{
- include: '/vendor/gitlab-ci-yml/non-existent-file.yml',
+ include: '/lib/gitlab/ci/templates/non-existent-file.yml',
image: 'ruby:2.2'
}
end
@@ -61,7 +61,7 @@ describe Gitlab::Ci::External::Mapper do
include:
[
remote_url,
- '/vendor/gitlab-ci-yml/template.yml'
+ '/lib/gitlab/ci/templates/template.yml'
],
image: 'ruby:2.2'
}
diff --git a/spec/lib/gitlab/ci/external/processor_spec.rb b/spec/lib/gitlab/ci/external/processor_spec.rb
index 688c2b3c8aa..3c7394f53d2 100644
--- a/spec/lib/gitlab/ci/external/processor_spec.rb
+++ b/spec/lib/gitlab/ci/external/processor_spec.rb
@@ -16,12 +16,12 @@ describe Gitlab::Ci::External::Processor do
end
context 'when an invalid local file is defined' do
- let(:values) { { include: '/vendor/gitlab-ci-yml/non-existent-file.yml', image: 'ruby:2.2' } }
+ let(:values) { { include: '/lib/gitlab/ci/templates/non-existent-file.yml', image: 'ruby:2.2' } }
it 'should raise an error' do
expect { processor.perform }.to raise_error(
described_class::FileError,
- "Local file '/vendor/gitlab-ci-yml/non-existent-file.yml' is not valid."
+ "Local file '/lib/gitlab/ci/templates/non-existent-file.yml' is not valid."
)
end
end
@@ -79,7 +79,7 @@ describe Gitlab::Ci::External::Processor do
end
context 'with a valid local external file is defined' do
- let(:values) { { include: '/vendor/gitlab-ci-yml/template.yml', image: 'ruby:2.2' } }
+ let(:values) { { include: '/lib/gitlab/ci/templates/template.yml', image: 'ruby:2.2' } }
let(:local_file_content) do
<<-HEREDOC
before_script:
@@ -145,7 +145,7 @@ describe Gitlab::Ci::External::Processor do
end
context 'when external files are defined but not valid' do
- let(:values) { { include: '/vendor/gitlab-ci-yml/template.yml', image: 'ruby:2.2' } }
+ let(:values) { { include: '/lib/gitlab/ci/templates/template.yml', image: 'ruby:2.2' } }
let(:local_file_content) { 'invalid content file ////' }
diff --git a/spec/lib/gitlab/ci/parsers/junit_spec.rb b/spec/lib/gitlab/ci/parsers/test/junit_spec.rb
index 47497f06229..a49402c7398 100644
--- a/spec/lib/gitlab/ci/parsers/junit_spec.rb
+++ b/spec/lib/gitlab/ci/parsers/test/junit_spec.rb
@@ -1,6 +1,6 @@
require 'fast_spec_helper'
-describe Gitlab::Ci::Parsers::Junit do
+describe Gitlab::Ci::Parsers::Test::Junit do
describe '#parse!' do
subject { described_class.new.parse!(junit, test_suite) }
diff --git a/spec/lib/gitlab/ci/parsers_spec.rb b/spec/lib/gitlab/ci/parsers/test_spec.rb
index 2fa83c4abae..0b85b432677 100644
--- a/spec/lib/gitlab/ci/parsers_spec.rb
+++ b/spec/lib/gitlab/ci/parsers/test_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::Ci::Parsers do
+describe Gitlab::Ci::Parsers::Test do
describe '.fabricate!' do
subject { described_class.fabricate!(file_type) }
@@ -16,7 +16,7 @@ describe Gitlab::Ci::Parsers do
let(:file_type) { 'undefined' }
it 'raises an error' do
- expect { subject }.to raise_error(NameError)
+ expect { subject }.to raise_error(Gitlab::Ci::Parsers::Test::ParserNotFoundError)
end
end
end
diff --git a/spec/lib/gitlab/ci/templates/templates_spec.rb b/spec/lib/gitlab/ci/templates/templates_spec.rb
new file mode 100644
index 00000000000..0dd74399a47
--- /dev/null
+++ b/spec/lib/gitlab/ci/templates/templates_spec.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe "CI YML Templates" do
+ Gitlab::Template::GitlabCiYmlTemplate.all.each do |template|
+ it "#{template.name} should be valid" do
+ expect { Gitlab::Ci::YamlProcessor.new(template.content) }.not_to raise_error
+ end
+ end
+end
diff --git a/spec/lib/gitlab/ci/yaml_processor_spec.rb b/spec/lib/gitlab/ci/yaml_processor_spec.rb
index fcbdf71a4e9..a2d429fa859 100644
--- a/spec/lib/gitlab/ci/yaml_processor_spec.rb
+++ b/spec/lib/gitlab/ci/yaml_processor_spec.rb
@@ -1371,18 +1371,6 @@ module Gitlab
end
end
- describe "Validate configuration templates" do
- templates = Dir.glob("#{Rails.root.join('vendor/gitlab-ci-yml')}/**/*.gitlab-ci.yml")
-
- templates.each do |file|
- it "does not return errors for #{file}" do
- file = File.read(file)
-
- expect { Gitlab::Ci::YamlProcessor.new(file) }.not_to raise_error
- end
- end
- end
-
describe "#validation_message" do
subject { Gitlab::Ci::YamlProcessor.validation_message(content) }
diff --git a/spec/lib/gitlab/database/subquery_spec.rb b/spec/lib/gitlab/database/subquery_spec.rb
new file mode 100644
index 00000000000..70380e02f16
--- /dev/null
+++ b/spec/lib/gitlab/database/subquery_spec.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Database::Subquery do
+ describe '.self_join' do
+ set(:project) { create(:project) }
+
+ it 'allows you to delete_all rows with WHERE and LIMIT' do
+ events = create_list(:event, 8, project: project)
+
+ expect do
+ described_class.self_join(Event.where('id < ?', events[5]).recent.limit(2)).delete_all
+ end.to change { Event.count }.by(-2)
+ end
+ end
+end
diff --git a/spec/lib/gitlab/diff/file_collection/commit_spec.rb b/spec/lib/gitlab/diff/file_collection/commit_spec.rb
new file mode 100644
index 00000000000..6d1b66deb6a
--- /dev/null
+++ b/spec/lib/gitlab/diff/file_collection/commit_spec.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Gitlab::Diff::FileCollection::Commit do
+ let(:project) { create(:project, :repository) }
+
+ it_behaves_like 'diff statistics' do
+ let(:collection_default_args) do
+ { diff_options: {} }
+ end
+ let(:diffable) { project.commit }
+ let(:stub_path) { 'bar/branch-test.txt' }
+ end
+end
diff --git a/spec/lib/gitlab/diff/file_collection/compare_spec.rb b/spec/lib/gitlab/diff/file_collection/compare_spec.rb
new file mode 100644
index 00000000000..f330f299ac1
--- /dev/null
+++ b/spec/lib/gitlab/diff/file_collection/compare_spec.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Gitlab::Diff::FileCollection::Compare do
+ include RepoHelpers
+
+ let(:project) { create(:project, :repository) }
+ let(:commit) { project.commit }
+ let(:start_commit) { sample_image_commit }
+ let(:head_commit) { sample_commit }
+ let(:raw_compare) do
+ Gitlab::Git::Compare.new(project.repository.raw_repository,
+ start_commit.id,
+ head_commit.id)
+ end
+
+ it_behaves_like 'diff statistics' do
+ let(:collection_default_args) do
+ {
+ project: diffable.project,
+ diff_options: {},
+ diff_refs: diffable.diff_refs
+ }
+ end
+ let(:diffable) { Compare.new(raw_compare, project) }
+ let(:stub_path) { '.gitignore' }
+ end
+end
diff --git a/spec/lib/gitlab/diff/file_collection/merge_request_diff_spec.rb b/spec/lib/gitlab/diff/file_collection/merge_request_diff_spec.rb
index 79287021981..4578da70bfc 100644
--- a/spec/lib/gitlab/diff/file_collection/merge_request_diff_spec.rb
+++ b/spec/lib/gitlab/diff/file_collection/merge_request_diff_spec.rb
@@ -29,6 +29,14 @@ describe Gitlab::Diff::FileCollection::MergeRequestDiff do
expect(mr_diff.cache_key).not_to eq(key)
end
+ it_behaves_like 'diff statistics' do
+ let(:collection_default_args) do
+ { diff_options: {} }
+ end
+ let(:diffable) { merge_request.merge_request_diff }
+ let(:stub_path) { '.gitignore' }
+ end
+
shared_examples 'initializes a DiffCollection' do
it 'returns a valid instance of a DiffCollection' do
expect(diff_files).to be_a(Gitlab::Git::DiffCollection)
diff --git a/spec/lib/gitlab/diff/file_spec.rb b/spec/lib/gitlab/diff/file_spec.rb
index ebeb05d6e02..2f51642b58e 100644
--- a/spec/lib/gitlab/diff/file_spec.rb
+++ b/spec/lib/gitlab/diff/file_spec.rb
@@ -186,6 +186,70 @@ describe Gitlab::Diff::File do
end
end
+ context 'diff file stats' do
+ let(:diff_file) do
+ described_class.new(diff,
+ diff_refs: commit.diff_refs,
+ repository: project.repository,
+ stats: stats)
+ end
+
+ let(:raw_diff) do
+ <<~EOS
+ --- a/files/ruby/popen.rb
+ +++ b/files/ruby/popen.rb
+ @@ -6,12 +6,18 @@ module Popen
+
+ def popen(cmd, path=nil)
+ unless cmd.is_a?(Array)
+ - raise "System commands must be given as an array of strings"
+ + raise RuntimeError, "System commands must be given as an array of strings"
+ + # foobar
+ end
+ EOS
+ end
+
+ describe '#added_lines' do
+ context 'when stats argument given' do
+ let(:stats) { double(Gitaly::DiffStats, additions: 10, deletions: 15) }
+
+ it 'returns added lines from stats' do
+ expect(diff_file.added_lines).to eq(stats.additions)
+ end
+ end
+
+ context 'when stats argument not given' do
+ let(:stats) { nil }
+
+ it 'returns added lines by parsing raw diff' do
+ allow(diff_file).to receive(:raw_diff) { raw_diff }
+
+ expect(diff_file.added_lines).to eq(2)
+ end
+ end
+ end
+
+ describe '#removed_lines' do
+ context 'when stats argument given' do
+ let(:stats) { double(Gitaly::DiffStats, additions: 10, deletions: 15) }
+
+ it 'returns removed lines from stats' do
+ expect(diff_file.removed_lines).to eq(stats.deletions)
+ end
+ end
+
+ context 'when stats argument not given' do
+ let(:stats) { nil }
+
+ it 'returns removed lines by parsing raw diff' do
+ allow(diff_file).to receive(:raw_diff) { raw_diff }
+
+ expect(diff_file.removed_lines).to eq(1)
+ end
+ end
+ end
+ end
+
describe '#simple_viewer' do
context 'when the file is not diffable' do
before do
diff --git a/spec/lib/gitlab/git/diff_stats_collection_spec.rb b/spec/lib/gitlab/git/diff_stats_collection_spec.rb
new file mode 100644
index 00000000000..89927cbb3a6
--- /dev/null
+++ b/spec/lib/gitlab/git/diff_stats_collection_spec.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+require "spec_helper"
+
+describe Gitlab::Git::DiffStatsCollection do
+ let(:stats_a) do
+ double(Gitaly::DiffStats, additions: 10, deletions: 15, path: 'foo')
+ end
+
+ let(:stats_b) do
+ double(Gitaly::DiffStats, additions: 5, deletions: 1, path: 'bar')
+ end
+
+ let(:diff_stats) { [stats_a, stats_b] }
+ let(:collection) { described_class.new(diff_stats) }
+
+ describe '.find_by_path' do
+ it 'returns stats by path when found' do
+ expect(collection.find_by_path('foo')).to eq(stats_a)
+ end
+
+ it 'returns nil when stats is not found by path' do
+ expect(collection.find_by_path('no-file')).to be_nil
+ end
+ end
+end
diff --git a/spec/lib/gitlab/git/hook_env_spec.rb b/spec/lib/gitlab/git/hook_env_spec.rb
index e6aa5ad8c90..5e49ea6da7a 100644
--- a/spec/lib/gitlab/git/hook_env_spec.rb
+++ b/spec/lib/gitlab/git/hook_env_spec.rb
@@ -4,11 +4,7 @@ describe Gitlab::Git::HookEnv do
let(:gl_repository) { 'project-123' }
describe ".set" do
- context 'with RequestStore.store disabled' do
- before do
- allow(RequestStore).to receive(:active?).and_return(false)
- end
-
+ context 'with RequestStore disabled' do
it 'does not store anything' do
described_class.set(gl_repository, GIT_OBJECT_DIRECTORY_RELATIVE: 'foo')
@@ -16,11 +12,7 @@ describe Gitlab::Git::HookEnv do
end
end
- context 'with RequestStore.store enabled' do
- before do
- allow(RequestStore).to receive(:active?).and_return(true)
- end
-
+ context 'with RequestStore enabled', :request_store do
it 'whitelist some `GIT_*` variables and stores them using RequestStore' do
described_class.set(
gl_repository,
@@ -41,9 +33,8 @@ describe Gitlab::Git::HookEnv do
end
describe ".all" do
- context 'with RequestStore.store enabled' do
+ context 'with RequestStore enabled', :request_store do
before do
- allow(RequestStore).to receive(:active?).and_return(true)
described_class.set(
gl_repository,
GIT_OBJECT_DIRECTORY_RELATIVE: 'foo',
@@ -60,7 +51,7 @@ describe Gitlab::Git::HookEnv do
end
describe ".to_env_hash" do
- context 'with RequestStore.store enabled' do
+ context 'with RequestStore enabled', :request_store do
using RSpec::Parameterized::TableSyntax
let(:key) { 'GIT_OBJECT_DIRECTORY_RELATIVE' }
@@ -76,7 +67,6 @@ describe Gitlab::Git::HookEnv do
with_them do
before do
- allow(RequestStore).to receive(:active?).and_return(true)
described_class.set(gl_repository, key.to_sym => input)
end
@@ -92,7 +82,7 @@ describe Gitlab::Git::HookEnv do
end
describe 'thread-safety' do
- context 'with RequestStore.store enabled' do
+ context 'with RequestStore enabled', :request_store do
before do
allow(RequestStore).to receive(:active?).and_return(true)
described_class.set(gl_repository, GIT_OBJECT_DIRECTORY_RELATIVE: 'foo')
diff --git a/spec/lib/gitlab/git/repository_spec.rb b/spec/lib/gitlab/git/repository_spec.rb
index ce4caf0c27d..d02536a2fb4 100644
--- a/spec/lib/gitlab/git/repository_spec.rb
+++ b/spec/lib/gitlab/git/repository_spec.rb
@@ -1112,6 +1112,40 @@ describe Gitlab::Git::Repository, :seed_helper do
end
end
+ describe '#diff_stats' do
+ let(:left_commit_id) { 'feature' }
+ let(:right_commit_id) { 'master' }
+
+ it 'returns a DiffStatsCollection' do
+ collection = repository.diff_stats(left_commit_id, right_commit_id)
+
+ expect(collection).to be_a(Gitlab::Git::DiffStatsCollection)
+ expect(collection).to be_a(Enumerable)
+ end
+
+ it 'yields Gitaly::DiffStats objects' do
+ collection = repository.diff_stats(left_commit_id, right_commit_id)
+
+ expect(collection.to_a).to all(be_a(Gitaly::DiffStats))
+ end
+
+ it 'returns no Gitaly::DiffStats when SHAs are invalid' do
+ collection = repository.diff_stats('foo', 'bar')
+
+ expect(collection).to be_a(Gitlab::Git::DiffStatsCollection)
+ expect(collection).to be_a(Enumerable)
+ expect(collection.to_a).to be_empty
+ end
+
+ it 'returns no Gitaly::DiffStats when there is a nil SHA' do
+ collection = repository.diff_stats(nil, 'master')
+
+ expect(collection).to be_a(Gitlab::Git::DiffStatsCollection)
+ expect(collection).to be_a(Enumerable)
+ expect(collection.to_a).to be_empty
+ end
+ end
+
describe "#ls_files" do
let(:master_file_paths) { repository.ls_files("master") }
let(:utf8_file_paths) { repository.ls_files("ls-files-utf8") }
diff --git a/spec/lib/gitlab/gitaly_client/commit_service_spec.rb b/spec/lib/gitlab/gitaly_client/commit_service_spec.rb
index bcdf12a00a0..d7bd757149d 100644
--- a/spec/lib/gitlab/gitaly_client/commit_service_spec.rb
+++ b/spec/lib/gitlab/gitaly_client/commit_service_spec.rb
@@ -118,6 +118,22 @@ describe Gitlab::GitalyClient::CommitService do
end
end
+ describe '#diff_stats' do
+ let(:left_commit_id) { 'master' }
+ let(:right_commit_id) { 'cfe32cf61b73a0d5e9f13e774abde7ff789b1660' }
+
+ it 'sends an RPC request' do
+ request = Gitaly::DiffStatsRequest.new(repository: repository_message,
+ left_commit_id: left_commit_id,
+ right_commit_id: right_commit_id)
+
+ expect_any_instance_of(Gitaly::DiffService::Stub).to receive(:diff_stats)
+ .with(request, kind_of(Hash)).and_return([])
+
+ described_class.new(repository).diff_stats(left_commit_id, right_commit_id)
+ end
+ end
+
describe '#tree_entries' do
let(:path) { '/' }
diff --git a/spec/lib/gitlab/import_export/project.json b/spec/lib/gitlab/import_export/project.json
index eefd00e7383..3f2281f213f 100644
--- a/spec/lib/gitlab/import_export/project.json
+++ b/spec/lib/gitlab/import_export/project.json
@@ -6143,7 +6143,7 @@
"id": 36,
"project_id": 5,
"ref": "master",
- "sha": "be93687618e4b132087f430a4d8fc3a609c9b77c",
+ "sha": "sha-notes",
"before_sha": null,
"push_data": null,
"created_at": "2016-03-22T15:20:35.755Z",
@@ -6154,6 +6154,7 @@
"status": "failed",
"started_at": null,
"finished_at": null,
+ "user_id": 9999,
"duration": null,
"notes": [
{
@@ -6353,6 +6354,7 @@
},
{
"id": 38,
+ "iid": 1,
"project_id": 5,
"ref": "master",
"sha": "5f923865dde3436854e9ceb9cdb7815618d4e849",
diff --git a/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb b/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb
index 3ff6be595a8..7ebfc61f5e7 100644
--- a/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb
+++ b/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb
@@ -59,7 +59,11 @@ describe Gitlab::ImportExport::ProjectTreeRestorer do
end
it 'creates a valid pipeline note' do
- expect(Ci::Pipeline.first.notes).not_to be_empty
+ expect(Ci::Pipeline.find_by_sha('sha-notes').notes).not_to be_empty
+ end
+
+ it 'pipeline has the correct user ID' do
+ expect(Ci::Pipeline.find_by_sha('sha-notes').user_id).to eq(@user.id)
end
it 'restores pipelines with missing ref' do
diff --git a/spec/lib/gitlab/kubernetes/kube_client_spec.rb b/spec/lib/gitlab/kubernetes/kube_client_spec.rb
index 9146729d139..53c5a4e7c94 100644
--- a/spec/lib/gitlab/kubernetes/kube_client_spec.rb
+++ b/spec/lib/gitlab/kubernetes/kube_client_spec.rb
@@ -116,12 +116,14 @@ describe Gitlab::Kubernetes::KubeClient do
:get_config_map,
:get_pod,
:get_namespace,
+ :get_secret,
:get_service,
:get_service_account,
:delete_pod,
:create_config_map,
:create_namespace,
:create_pod,
+ :create_secret,
:create_service_account,
:update_config_map,
:update_service_account
diff --git a/spec/lib/gitlab/kubernetes/service_account_token_spec.rb b/spec/lib/gitlab/kubernetes/service_account_token_spec.rb
new file mode 100644
index 00000000000..0773d3d9aec
--- /dev/null
+++ b/spec/lib/gitlab/kubernetes/service_account_token_spec.rb
@@ -0,0 +1,35 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Gitlab::Kubernetes::ServiceAccountToken do
+ let(:name) { 'token-name' }
+ let(:service_account_name) { 'a_service_account' }
+ let(:namespace_name) { 'a_namespace' }
+ let(:service_account_token) { described_class.new(name, service_account_name, namespace_name) }
+
+ it { expect(service_account_token.name).to eq(name) }
+ it { expect(service_account_token.service_account_name).to eq(service_account_name) }
+ it { expect(service_account_token.namespace_name).to eq(namespace_name) }
+
+ describe '#generate' do
+ let(:resource) do
+ ::Kubeclient::Resource.new(
+ metadata: {
+ name: name,
+ namespace: namespace_name,
+ annotations: {
+ 'kubernetes.io/service-account.name': service_account_name
+ }
+ },
+ type: 'kubernetes.io/service-account-token'
+ )
+ end
+
+ subject { service_account_token.generate }
+
+ it 'should build a Kubeclient Resource' do
+ is_expected.to eq(resource)
+ end
+ end
+end
diff --git a/spec/lib/gitlab/middleware/read_only_spec.rb b/spec/lib/gitlab/middleware/read_only_spec.rb
index 8fbeaa065fa..ac3bc6b2dfe 100644
--- a/spec/lib/gitlab/middleware/read_only_spec.rb
+++ b/spec/lib/gitlab/middleware/read_only_spec.rb
@@ -34,7 +34,7 @@ describe Gitlab::Middleware::ReadOnly do
end
end
- context 'normal requests to a read-only Gitlab instance' do
+ context 'normal requests to a read-only GitLab instance' do
let(:fake_app) { lambda { |env| [200, { 'Content-Type' => 'text/plain' }, ['OK']] } }
before do
diff --git a/spec/lib/gitlab/null_request_store_spec.rb b/spec/lib/gitlab/null_request_store_spec.rb
new file mode 100644
index 00000000000..c023dac53ad
--- /dev/null
+++ b/spec/lib/gitlab/null_request_store_spec.rb
@@ -0,0 +1,75 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Gitlab::NullRequestStore do
+ let(:null_store) { described_class.new }
+
+ describe '#store' do
+ it 'returns an empty hash' do
+ expect(null_store.store).to eq({})
+ end
+ end
+
+ describe '#active?' do
+ it 'returns falsey' do
+ expect(null_store.active?).to be_falsey
+ end
+ end
+
+ describe '#read' do
+ it 'returns nil' do
+ expect(null_store.read('foo')).to be nil
+ end
+ end
+
+ describe '#[]' do
+ it 'returns nil' do
+ expect(null_store['foo']).to be nil
+ end
+ end
+
+ describe '#write' do
+ it 'returns the same value' do
+ expect(null_store.write('key', 'value')).to eq('value')
+ end
+ end
+
+ describe '#[]=' do
+ it 'returns the same value' do
+ expect(null_store['key'] = 'value').to eq('value')
+ end
+ end
+
+ describe '#exist?' do
+ it 'returns falsey' do
+ expect(null_store.exist?('foo')).to be_falsey
+ end
+ end
+
+ describe '#fetch' do
+ it 'returns the block result' do
+ expect(null_store.fetch('key') { 'block result' }).to eq('block result')
+ end
+ end
+
+ describe '#delete' do
+ context 'when a block is given' do
+ it 'yields the key to the block' do
+ expect do |b|
+ null_store.delete('foo', &b)
+ end.to yield_with_args('foo')
+ end
+
+ it 'returns the block result' do
+ expect(null_store.delete('foo') { |key| 'block result' }).to eq('block result')
+ end
+ end
+
+ context 'when a block is not given' do
+ it 'returns nil' do
+ expect(null_store.delete('foo')).to be nil
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/repository_cache_adapter_spec.rb b/spec/lib/gitlab/repository_cache_adapter_spec.rb
index 5bd4d6c6a48..0295138fc3a 100644
--- a/spec/lib/gitlab/repository_cache_adapter_spec.rb
+++ b/spec/lib/gitlab/repository_cache_adapter_spec.rb
@@ -65,6 +65,144 @@ describe Gitlab::RepositoryCacheAdapter do
end
end
+ describe '#cache_method_output_asymmetrically', :use_clean_rails_memory_store_caching, :request_store do
+ let(:request_store_cache) { repository.send(:request_store_cache) }
+
+ context 'with a non-existing repository' do
+ let(:project) { create(:project) } # No repository
+ let(:object) { double }
+
+ subject do
+ repository.cache_method_output_asymmetrically(:cats) do
+ object.cats_call_stub
+ end
+ end
+
+ it 'returns the output of the original method' do
+ expect(object).to receive(:cats_call_stub).and_return('output')
+
+ expect(subject).to eq('output')
+ end
+ end
+
+ context 'with a method throwing a non-existing-repository error' do
+ subject do
+ repository.cache_method_output_asymmetrically(:cats) do
+ raise Gitlab::Git::Repository::NoRepository
+ end
+ end
+
+ it 'returns nil' do
+ expect(subject).to eq(nil)
+ end
+
+ it 'does not cache the data' do
+ subject
+
+ expect(repository.instance_variable_defined?(:@cats)).to eq(false)
+ expect(cache.exist?(:cats)).to eq(false)
+ end
+ end
+
+ context 'with an existing repository' do
+ let(:object) { double }
+
+ context 'when it returns truthy' do
+ before do
+ expect(object).to receive(:cats).once.and_return('truthy output')
+ end
+
+ it 'caches the output in RequestStore' do
+ expect do
+ repository.cache_method_output_asymmetrically(:cats) { object.cats }
+ end.to change { request_store_cache.read(:cats) }.from(nil).to('truthy output')
+ end
+
+ it 'caches the output in RepositoryCache' do
+ expect do
+ repository.cache_method_output_asymmetrically(:cats) { object.cats }
+ end.to change { cache.read(:cats) }.from(nil).to('truthy output')
+ end
+ end
+
+ context 'when it returns false' do
+ before do
+ expect(object).to receive(:cats).once.and_return(false)
+ end
+
+ it 'caches the output in RequestStore' do
+ expect do
+ repository.cache_method_output_asymmetrically(:cats) { object.cats }
+ end.to change { request_store_cache.read(:cats) }.from(nil).to(false)
+ end
+
+ it 'does NOT cache the output in RepositoryCache' do
+ expect do
+ repository.cache_method_output_asymmetrically(:cats) { object.cats }
+ end.not_to change { cache.read(:cats) }.from(nil)
+ end
+ end
+ end
+ end
+
+ describe '#memoize_method_output' do
+ let(:fallback) { 10 }
+
+ context 'with a non-existing repository' do
+ let(:project) { create(:project) } # No repository
+
+ subject do
+ repository.memoize_method_output(:cats, fallback: fallback) do
+ repository.cats_call_stub
+ end
+ end
+
+ it 'returns the fallback value' do
+ expect(subject).to eq(fallback)
+ end
+
+ it 'avoids calling the original method' do
+ expect(repository).not_to receive(:cats_call_stub)
+
+ subject
+ end
+
+ it 'does not set the instance variable' do
+ subject
+
+ expect(repository.instance_variable_defined?(:@cats)).to eq(false)
+ end
+ end
+
+ context 'with a method throwing a non-existing-repository error' do
+ subject do
+ repository.memoize_method_output(:cats, fallback: fallback) do
+ raise Gitlab::Git::Repository::NoRepository
+ end
+ end
+
+ it 'returns the fallback value' do
+ expect(subject).to eq(fallback)
+ end
+
+ it 'does not set the instance variable' do
+ subject
+
+ expect(repository.instance_variable_defined?(:@cats)).to eq(false)
+ end
+ end
+
+ context 'with an existing repository' do
+ it 'sets the instance variable' do
+ repository.memoize_method_output(:cats, fallback: fallback) do
+ 'block output'
+ end
+
+ expect(repository.instance_variable_get(:@cats)).to eq('block output')
+ end
+ end
+ end
+
describe '#expire_method_caches' do
it 'expires the caches of the given methods' do
expect(cache).to receive(:expire).with(:rendered_readme)
diff --git a/spec/lib/gitlab/repository_cache_spec.rb b/spec/lib/gitlab/repository_cache_spec.rb
index fc259cf1208..741ee12633f 100644
--- a/spec/lib/gitlab/repository_cache_spec.rb
+++ b/spec/lib/gitlab/repository_cache_spec.rb
@@ -47,4 +47,89 @@ describe Gitlab::RepositoryCache do
expect(backend).to have_received(:fetch).with("baz:#{namespace}", &p)
end
end
+
+ describe '#fetch_without_caching_false', :use_clean_rails_memory_store_caching do
+ let(:key) { :foo }
+ let(:backend) { Rails.cache }
+
+ it 'requires a block' do
+ expect do
+ cache.fetch_without_caching_false(key)
+ end.to raise_error(LocalJumpError)
+ end
+
+ context 'when the key does not exist in the cache' do
+ context 'when the result of the block is truthy' do
+ it 'returns the result of the block' do
+ result = cache.fetch_without_caching_false(key) { true }
+
+ expect(result).to be true
+ end
+
+ it 'caches the value' do
+ expect(backend).to receive(:write).with("#{key}:#{namespace}", true)
+
+ cache.fetch_without_caching_false(key) { true }
+ end
+ end
+
+ context 'when the result of the block is falsey' do
+ let(:p) { -> { false } }
+
+ it 'returns the result of the block' do
+ result = cache.fetch_without_caching_false(key, &p)
+
+ expect(result).to be false
+ end
+
+ it 'does not cache the value' do
+ expect(backend).not_to receive(:write).with("#{key}:#{namespace}", true)
+
+ cache.fetch_without_caching_false(key, &p)
+ end
+ end
+ end
+
+ context 'when the cached value is truthy' do
+ before do
+ backend.write("#{key}:#{namespace}", true)
+ end
+
+ it 'returns the cached value' do
+ result = cache.fetch_without_caching_false(key) { 'block result' }
+
+ expect(result).to be true
+ end
+
+ it 'does not execute the block' do
+ expect do |b|
+ cache.fetch_without_caching_false(key, &b)
+ end.not_to yield_control
+ end
+
+ it 'does not write to the cache' do
+ expect(backend).not_to receive(:write)
+
+ cache.fetch_without_caching_false(key) { 'block result' }
+ end
+ end
+
+ context 'when the cached value is falsey' do
+ before do
+ backend.write("#{key}:#{namespace}", false)
+ end
+
+ it 'returns the result of the block' do
+ result = cache.fetch_without_caching_false(key) { 'block result' }
+
+ expect(result).to eq 'block result'
+ end
+
+ it 'writes the truthy value to the cache' do
+ expect(backend).to receive(:write).with("#{key}:#{namespace}", 'block result')
+
+ cache.fetch_without_caching_false(key) { 'block result' }
+ end
+ end
+ end
end
diff --git a/spec/lib/gitlab/safe_request_store_spec.rb b/spec/lib/gitlab/safe_request_store_spec.rb
new file mode 100644
index 00000000000..c797171dbe2
--- /dev/null
+++ b/spec/lib/gitlab/safe_request_store_spec.rb
@@ -0,0 +1,245 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Gitlab::SafeRequestStore do
+ describe '.store' do
+ context 'when RequestStore is active', :request_store do
+ it 'uses RequestStore' do
+ expect(described_class.store).to eq(RequestStore)
+ end
+ end
+
+ context 'when RequestStore is NOT active' do
+ it 'does not use RequestStore' do
+ expect(described_class.store).to be_a(Gitlab::NullRequestStore)
+ end
+ end
+ end
+
+ describe '.begin!' do
+ context 'when RequestStore is active', :request_store do
+ it 'uses RequestStore' do
+ expect(RequestStore).to receive(:begin!)
+
+ described_class.begin!
+ end
+ end
+
+ context 'when RequestStore is NOT active' do
+ it 'uses RequestStore' do
+ expect(RequestStore).to receive(:begin!)
+
+ described_class.begin!
+ end
+ end
+ end
+
+ describe '.clear!' do
+ context 'when RequestStore is active', :request_store do
+ it 'uses RequestStore' do
+ expect(RequestStore).to receive(:clear!).twice.and_call_original
+
+ described_class.clear!
+ end
+ end
+
+ context 'when RequestStore is NOT active' do
+ it 'uses RequestStore' do
+ expect(RequestStore).to receive(:clear!).and_call_original
+
+ described_class.clear!
+ end
+ end
+ end
+
+ describe '.end!' do
+ context 'when RequestStore is active', :request_store do
+ it 'uses RequestStore' do
+ expect(RequestStore).to receive(:end!).twice.and_call_original
+
+ described_class.end!
+ end
+ end
+
+ context 'when RequestStore is NOT active' do
+ it 'uses RequestStore' do
+ expect(RequestStore).to receive(:end!).and_call_original
+
+ described_class.end!
+ end
+ end
+ end
+
+ describe '.write' do
+ context 'when RequestStore is active', :request_store do
+ it 'uses RequestStore' do
+ expect do
+ described_class.write('foo', true)
+ end.to change { described_class.read('foo') }.from(nil).to(true)
+ end
+ end
+
+ context 'when RequestStore is NOT active' do
+ it 'does not use RequestStore' do
+ expect do
+ described_class.write('foo', true)
+ end.not_to change { described_class.read('foo') }.from(nil)
+ end
+ end
+ end
+
+ describe '.[]=' do
+ context 'when RequestStore is active', :request_store do
+ it 'uses RequestStore' do
+ expect do
+ described_class['foo'] = true
+ end.to change { described_class.read('foo') }.from(nil).to(true)
+ end
+ end
+
+ context 'when RequestStore is NOT active' do
+ it 'does not use RequestStore' do
+ expect do
+ described_class['foo'] = true
+ end.not_to change { described_class.read('foo') }.from(nil)
+ end
+ end
+ end
+
+ describe '.read' do
+ context 'when RequestStore is active', :request_store do
+ it 'uses RequestStore' do
+ expect do
+ RequestStore.write('foo', true)
+ end.to change { described_class.read('foo') }.from(nil).to(true)
+ end
+ end
+
+ context 'when RequestStore is NOT active' do
+ it 'does not use RequestStore' do
+ expect do
+ RequestStore.write('foo', true)
+ end.not_to change { described_class.read('foo') }.from(nil)
+
+ RequestStore.clear! # Clean up
+ end
+ end
+ end
+
+ describe '.[]' do
+ context 'when RequestStore is active', :request_store do
+ it 'uses RequestStore' do
+ expect do
+ RequestStore.write('foo', true)
+ end.to change { described_class['foo'] }.from(nil).to(true)
+ end
+ end
+
+ context 'when RequestStore is NOT active' do
+ it 'does not use RequestStore' do
+ expect do
+ RequestStore.write('foo', true)
+ end.not_to change { described_class['foo'] }.from(nil)
+
+ RequestStore.clear! # Clean up
+ end
+ end
+ end
+
+ describe '.exist?' do
+ context 'when RequestStore is active', :request_store do
+ it 'uses RequestStore' do
+ expect do
+ RequestStore.write('foo', 'not nil')
+ end.to change { described_class.exist?('foo') }.from(false).to(true)
+ end
+ end
+
+ context 'when RequestStore is NOT active' do
+ it 'does not use RequestStore' do
+ expect do
+ RequestStore.write('foo', 'not nil')
+ end.not_to change { described_class.exist?('foo') }.from(false)
+
+ RequestStore.clear! # Clean up
+ end
+ end
+ end
+
+ describe '.fetch' do
+ context 'when RequestStore is active', :request_store do
+ it 'uses RequestStore' do
+ expect do
+ described_class.fetch('foo') { 'block result' }
+ end.to change { described_class.read('foo') }.from(nil).to('block result')
+ end
+ end
+
+ context 'when RequestStore is NOT active' do
+ it 'does not use RequestStore' do
+ RequestStore.clear! # Ensure clean
+
+ expect do
+ described_class.fetch('foo') { 'block result' }
+ end.not_to change { described_class.read('foo') }.from(nil)
+
+ RequestStore.clear! # Clean up
+ end
+ end
+ end
+
+ describe '.delete' do
+ context 'when RequestStore is active', :request_store do
+ it 'uses RequestStore' do
+ described_class.write('foo', true)
+
+ expect do
+ described_class.delete('foo')
+ end.to change { described_class.read('foo') }.from(true).to(nil)
+ end
+
+ context 'when given a block and the key exists' do
+ it 'does not execute the block' do
+ described_class.write('foo', true)
+
+ expect do |b|
+ described_class.delete('foo', &b)
+ end.not_to yield_control
+ end
+ end
+
+ context 'when given a block and the key does not exist' do
+ it 'yields the key and returns the block result' do
+ result = described_class.delete('foo') { |key| "#{key} block result" }
+
+ expect(result).to eq('foo block result')
+ end
+ end
+ end
+
+ context 'when RequestStore is NOT active' do
+ before do
+ RequestStore.write('foo', true)
+ end
+
+ after do
+ RequestStore.clear! # Clean up
+ end
+
+ it 'does not use RequestStore' do
+ expect do
+ described_class.delete('foo')
+ end.not_to change { RequestStore.read('foo') }.from(true)
+ end
+
+ context 'when given a block' do
+ it 'yields the key and returns the block result' do
+ result = described_class.delete('foo') { |key| "#{key} block result" }
+
+ expect(result).to eq('foo block result')
+ end
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/sidekiq_throttler_spec.rb b/spec/lib/gitlab/sidekiq_throttler_spec.rb
deleted file mode 100644
index 2dbb7bb7c34..00000000000
--- a/spec/lib/gitlab/sidekiq_throttler_spec.rb
+++ /dev/null
@@ -1,44 +0,0 @@
-require 'spec_helper'
-
-describe Gitlab::SidekiqThrottler do
- describe '#execute!' do
- context 'when job throttling is enabled' do
- before do
- Sidekiq.options[:concurrency] = 35
-
- stub_application_setting(
- sidekiq_throttling_enabled: true,
- sidekiq_throttling_factor: 0.1,
- sidekiq_throttling_queues: %w[build project_cache]
- )
- end
-
- it 'requires sidekiq-limit_fetch' do
- expect(described_class).to receive(:require).with('sidekiq-limit_fetch').and_call_original
-
- described_class.execute!
- end
-
- it 'sets limits on the selected queues' do
- described_class.execute!
-
- expect(Sidekiq::Queue['build'].limit).to eq 4
- expect(Sidekiq::Queue['project_cache'].limit).to eq 4
- end
-
- it 'does not set limits on other queues' do
- described_class.execute!
-
- expect(Sidekiq::Queue['merge'].limit).to be_nil
- end
- end
-
- context 'when job throttling is disabled' do
- it 'does not require sidekiq-limit_fetch' do
- expect(described_class).not_to receive(:require).with('sidekiq-limit_fetch')
-
- described_class.execute!
- end
- end
- end
-end
diff --git a/spec/lib/gitlab/template/gitlab_ci_yml_template_spec.rb b/spec/lib/gitlab/template/gitlab_ci_yml_template_spec.rb
index e2fa76522bc..fe46c67a920 100644
--- a/spec/lib/gitlab/template/gitlab_ci_yml_template_spec.rb
+++ b/spec/lib/gitlab/template/gitlab_ci_yml_template_spec.rb
@@ -40,7 +40,7 @@ describe Gitlab::Template::GitlabCiYmlTemplate do
describe '#content' do
it 'loads the full file' do
- gitignore = subject.new(Rails.root.join('vendor/gitlab-ci-yml/Ruby.gitlab-ci.yml'))
+ gitignore = subject.new(Rails.root.join('lib/gitlab/ci/templates/Ruby.gitlab-ci.yml'))
expect(gitignore.name).to eq 'Ruby'
expect(gitignore.content).to start_with('#')
diff --git a/spec/lib/google_api/cloud_platform/client_spec.rb b/spec/lib/google_api/cloud_platform/client_spec.rb
index 27cb3198e5b..e2134dc279c 100644
--- a/spec/lib/google_api/cloud_platform/client_spec.rb
+++ b/spec/lib/google_api/cloud_platform/client_spec.rb
@@ -66,25 +66,30 @@ describe GoogleApi::CloudPlatform::Client do
describe '#projects_zones_clusters_create' do
subject do
client.projects_zones_clusters_create(
- spy, spy, cluster_name, cluster_size, machine_type: machine_type)
+ project_id, zone, cluster_name, cluster_size, machine_type: machine_type, legacy_abac: legacy_abac)
end
+ let(:project_id) { 'project-123' }
+ let(:zone) { 'us-central1-a' }
let(:cluster_name) { 'test-cluster' }
let(:cluster_size) { 1 }
let(:machine_type) { 'n1-standard-2' }
+ let(:legacy_abac) { true }
+ let(:create_cluster_request_body) { double('Google::Apis::ContainerV1::CreateClusterRequest') }
let(:operation) { double }
before do
allow_any_instance_of(Google::Apis::ContainerV1::ContainerService)
- .to receive(:create_cluster).with(any_args, options: user_agent_options)
+ .to receive(:create_cluster).with(any_args)
.and_return(operation)
end
- it { is_expected.to eq(operation) }
-
it 'sets corresponded parameters' do
- expect_any_instance_of(Google::Apis::ContainerV1::CreateClusterRequest)
- .to receive(:initialize).with(
+ expect_any_instance_of(Google::Apis::ContainerV1::ContainerService)
+ .to receive(:create_cluster).with(project_id, zone, create_cluster_request_body, options: user_agent_options)
+
+ expect(Google::Apis::ContainerV1::CreateClusterRequest)
+ .to receive(:new).with(
{
"cluster": {
"name": cluster_name,
@@ -96,9 +101,35 @@ describe GoogleApi::CloudPlatform::Client do
"enabled": true
}
}
- } )
+ } ).and_return(create_cluster_request_body)
+
+ expect(subject).to eq operation
+ end
+
+ context 'create without legacy_abac' do
+ let(:legacy_abac) { false }
+
+ it 'sets corresponded parameters' do
+ expect_any_instance_of(Google::Apis::ContainerV1::ContainerService)
+ .to receive(:create_cluster).with(project_id, zone, create_cluster_request_body, options: user_agent_options)
+
+ expect(Google::Apis::ContainerV1::CreateClusterRequest)
+ .to receive(:new).with(
+ {
+ "cluster": {
+ "name": cluster_name,
+ "initial_node_count": cluster_size,
+ "node_config": {
+ "machine_type": machine_type
+ },
+ "legacy_abac": {
+ "enabled": false
+ }
+ }
+ } ).and_return(create_cluster_request_body)
- subject
+ expect(subject).to eq operation
+ end
end
end
diff --git a/spec/lib/mattermost/session_spec.rb b/spec/lib/mattermost/session_spec.rb
index b7687d48c68..f18f97a9c6a 100644
--- a/spec/lib/mattermost/session_spec.rb
+++ b/spec/lib/mattermost/session_spec.rb
@@ -82,7 +82,7 @@ describe Mattermost::Session, type: :request do
.to_return(headers: { Authorization: 'token thisworksnow' }, status: 200)
end
- it 'can setup a session' do
+ it 'can set up a session' do
subject.with_session do |session|
end
@@ -106,7 +106,7 @@ describe Mattermost::Session, type: :request do
expect_to_obtain_exclusive_lease(lease_key, 'uuid')
expect_to_cancel_exclusive_lease(lease_key, 'uuid')
- # Cannot setup a session, but we should still cancel the lease
+ # Cannot set up a session, but we should still cancel the lease
expect { subject.with_session }.to raise_error(Mattermost::NoSessionError)
end
diff --git a/spec/lib/quality/helm_client_spec.rb b/spec/lib/quality/helm_client_spec.rb
new file mode 100644
index 00000000000..553cd8719de
--- /dev/null
+++ b/spec/lib/quality/helm_client_spec.rb
@@ -0,0 +1,62 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Quality::HelmClient do
+ let(:namespace) { 'review-apps-ee' }
+ let(:release_name) { 'my-release' }
+ let(:raw_helm_list_result) do
+ <<~OUTPUT
+ NAME REVISION UPDATED STATUS CHART NAMESPACE
+ review-improve-re-2dsd9d 1 Tue Jul 31 15:53:17 2018 FAILED gitlab-0.3.4 #{namespace}
+ review-11-1-stabl-3r2fso 1 Mon Jul 30 22:44:14 2018 FAILED gitlab-0.3.3 #{namespace}
+ review-49375-css-fk664j 1 Thu Jul 19 11:01:30 2018 FAILED gitlab-0.2.4 #{namespace}
+ OUTPUT
+ end
+
+ subject { described_class.new(namespace: namespace) }
+
+ describe '#releases' do
+ it 'calls helm list with default arguments' do
+ expect(Gitlab::Popen).to receive(:popen_with_detail)
+ .with([%(helm list --namespace "#{namespace}")])
+ .and_return(Gitlab::Popen::Result.new([], ''))
+
+ subject.releases
+ end
+
+ it 'calls helm list with given arguments' do
+ expect(Gitlab::Popen).to receive(:popen_with_detail)
+ .with([%(helm list --namespace "#{namespace}" --deployed)])
+ .and_return(Gitlab::Popen::Result.new([], ''))
+
+ subject.releases(args: ['--deployed'])
+ end
+
+ it 'returns a list of Release objects' do
+ expect(Gitlab::Popen).to receive(:popen_with_detail)
+ .with([%(helm list --namespace "#{namespace}" --deployed)])
+ .and_return(Gitlab::Popen::Result.new([], raw_helm_list_result))
+
+ releases = subject.releases(args: ['--deployed'])
+
+ expect(releases.size).to eq(3)
+ expect(releases[0].name).to eq('review-improve-re-2dsd9d')
+ expect(releases[0].revision).to eq(1)
+ expect(releases[0].last_update).to eq(Time.parse('Tue Jul 31 15:53:17 2018'))
+ expect(releases[0].status).to eq('FAILED')
+ expect(releases[0].chart).to eq('gitlab-0.3.4')
+ expect(releases[0].namespace).to eq(namespace)
+ end
+ end
+
+ describe '#delete' do
+ it 'calls helm delete with default arguments' do
+ expect(Gitlab::Popen).to receive(:popen_with_detail)
+ .with(["helm delete --purge #{release_name}"])
+ .and_return(Gitlab::Popen::Result.new([], '', '', 0))
+
+ expect(subject.delete(release_name: release_name).status).to eq(0)
+ end
+ end
+end
diff --git a/spec/lib/quality/kubernetes_client_spec.rb b/spec/lib/quality/kubernetes_client_spec.rb
new file mode 100644
index 00000000000..3c0c0d0977a
--- /dev/null
+++ b/spec/lib/quality/kubernetes_client_spec.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Quality::KubernetesClient do
+ subject { described_class.new(namespace: 'review-apps-ee') }
+
+ describe '#cleanup' do
+ it 'calls kubectl with the correct arguments' do
+ # popen_with_detail will receive an array with a bunch of arguments; we're
+ # only concerned with it having the correct namespace and release name
+ expect(Gitlab::Popen).to receive(:popen_with_detail) do |args|
+ expect(args)
+ .to satisfy_one { |arg| arg.start_with?('-n "review-apps-ee" get') }
+ expect(args)
+ .to satisfy_one { |arg| arg == 'grep "my-release"' }
+ expect(args)
+ .to satisfy_one { |arg| arg.end_with?('-n "review-apps-ee" delete') }
+ end
+
+ # We're not verifying the output here, just silencing it
+ expect { subject.cleanup(release_name: 'my-release') }.to output.to_stdout
+ end
+ end
+end
diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb
index 42b627b6823..e82d93d5935 100644
--- a/spec/models/ci/build_spec.rb
+++ b/spec/models/ci/build_spec.rb
@@ -176,9 +176,7 @@ describe Ci::Build do
it 'does not execute a query for selecting job artifact one by one' do
recorded = ActiveRecord::QueryRecorder.new do
subject.each do |build|
- Ci::JobArtifact::TEST_REPORT_FILE_TYPES.each do |file_type|
- build.public_send("job_artifacts_#{file_type}").file.exists?
- end
+ build.job_artifacts.map { |a| a.file.exists? }
end
end
@@ -550,44 +548,22 @@ describe Ci::Build do
end
end
- describe '#has_test_reports?' do
- subject { build.has_test_reports? }
+ describe '#has_job_artifacts?' do
+ subject { build.has_job_artifacts? }
- context 'when build has a test report' do
- let(:build) { create(:ci_build, :test_reports) }
+ context 'when build has a job artifact' do
+ let(:build) { create(:ci_build, :artifacts) }
it { is_expected.to be_truthy }
end
- context 'when build does not have test reports' do
- let(:build) { create(:ci_build, :artifacts) }
+ context 'when build does not have job artifacts' do
+ let(:build) { create(:ci_build, :legacy_artifacts) }
it { is_expected.to be_falsy }
end
end
- describe '#erase_test_reports!' do
- subject { build.erase_test_reports! }
-
- context 'when build has a test report' do
- let!(:build) { create(:ci_build, :test_reports) }
-
- it 'removes a test report' do
- subject
-
- expect(build.has_test_reports?).to be_falsy
- end
- end
-
- context 'when build does not have test reports' do
- let!(:build) { create(:ci_build, :artifacts) }
-
- it 'does not erase anything' do
- expect { subject }.not_to change { Ci::JobArtifact.count }
- end
- end
- end
-
describe '#has_old_trace?' do
subject { build.has_old_trace? }
@@ -850,8 +826,8 @@ describe Ci::Build do
expect(build.artifacts_metadata.exists?).to be_falsy
end
- it 'removes test reports' do
- expect(build.job_artifacts.test_reports.count).to eq(0)
+ it 'removes all job_artifacts' do
+ expect(build.job_artifacts.count).to eq(0)
end
it 'erases build trace in trace file' do
@@ -1022,6 +998,32 @@ describe Ci::Build do
end
end
+ describe '#erase_erasable_artifacts!' do
+ let!(:build) { create(:ci_build, :success) }
+
+ subject { build.erase_erasable_artifacts! }
+
+ before do
+ Ci::JobArtifact.file_types.keys.each do |file_type|
+ create(:ci_job_artifact, job: build, file_type: file_type, file_format: Ci::JobArtifact::TYPE_AND_FORMAT_PAIRS[file_type.to_sym])
+ end
+ end
+
+ it "erases erasable artifacts" do
+ subject
+
+ expect(build.job_artifacts.erasable).to be_empty
+ end
+
+ it "keeps non erasable artifacts" do
+ subject
+
+ Ci::JobArtifact::NON_ERASABLE_FILE_TYPES.each do |file_type|
+ expect(build.send("job_artifacts_#{file_type}")).not_to be_nil
+ end
+ end
+ end
+
describe '#first_pending' do
let!(:first) { create(:ci_build, pipeline: pipeline, status: 'pending', created_at: Date.yesterday) }
let!(:second) { create(:ci_build, pipeline: pipeline, status: 'pending') }
@@ -2844,16 +2846,10 @@ describe Ci::Build do
end
it 'raises an error' do
- expect { subject }.to raise_error(Gitlab::Ci::Parsers::Junit::JunitParserError)
+ expect { subject }.to raise_error(Gitlab::Ci::Parsers::Test::Junit::JunitParserError)
end
end
end
-
- context 'when build does not have test reports' do
- it 'raises an error' do
- expect { subject }.to raise_error(NoMethodError)
- end
- end
end
describe '#artifacts_metadata_entry' do
@@ -2981,4 +2977,46 @@ describe Ci::Build do
end
end
end
+
+ describe '#deployment_status' do
+ context 'when build is a last deployment' do
+ let(:build) { create(:ci_build, :success, environment: 'production') }
+ let(:environment) { create(:environment, name: 'production', project: build.project) }
+ let!(:deployment) { create(:deployment, environment: environment, project: environment.project, deployable: build) }
+
+ it { expect(build.deployment_status).to eq(:last) }
+ end
+
+ context 'when there is a newer build with deployment' do
+ let(:build) { create(:ci_build, :success, environment: 'production') }
+ let(:environment) { create(:environment, name: 'production', project: build.project) }
+ let!(:deployment) { create(:deployment, environment: environment, project: environment.project, deployable: build) }
+ let!(:last_deployment) { create(:deployment, environment: environment, project: environment.project) }
+
+ it { expect(build.deployment_status).to eq(:out_of_date) }
+ end
+
+ context 'when build with deployment has failed' do
+ let(:build) { create(:ci_build, :failed, environment: 'production') }
+ let(:environment) { create(:environment, name: 'production', project: build.project) }
+ let!(:deployment) { create(:deployment, environment: environment, project: environment.project, deployable: build) }
+
+ it { expect(build.deployment_status).to eq(:failed) }
+ end
+
+ context 'when build with deployment is running' do
+ let(:build) { create(:ci_build, environment: 'production') }
+ let(:environment) { create(:environment, name: 'production', project: build.project) }
+ let!(:deployment) { create(:deployment, environment: environment, project: environment.project, deployable: build) }
+
+ it { expect(build.deployment_status).to eq(:creating) }
+ end
+
+ context 'when build is successful but deployment is not ready yet' do
+ let(:build) { create(:ci_build, :success, environment: 'production') }
+ let(:environment) { create(:environment, name: 'production', project: build.project) }
+
+ it { expect(build.deployment_status).to eq(:creating) }
+ end
+ end
end
diff --git a/spec/models/ci/job_artifact_spec.rb b/spec/models/ci/job_artifact_spec.rb
index 1bf338f4c70..2f449d617be 100644
--- a/spec/models/ci/job_artifact_spec.rb
+++ b/spec/models/ci/job_artifact_spec.rb
@@ -31,6 +31,22 @@ describe Ci::JobArtifact do
end
end
+ describe '.erasable' do
+ subject { described_class.erasable }
+
+ context 'when there is am erasable artifact' do
+ let!(:artifact) { create(:ci_job_artifact, :junit) }
+
+ it { is_expected.to eq([artifact]) }
+ end
+
+ context 'when there are no erasable artifacts' do
+ let!(:artifact) { create(:ci_job_artifact, :trace) }
+
+ it { is_expected.to be_empty }
+ end
+ end
+
describe 'callbacks' do
subject { create(:ci_job_artifact, :archive) }
@@ -106,34 +122,46 @@ describe Ci::JobArtifact do
describe 'validates file format' do
subject { artifact }
- context 'when archive type with zip format' do
- let(:artifact) { build(:ci_job_artifact, :archive, file_format: :zip) }
+ described_class::TYPE_AND_FORMAT_PAIRS.except(:trace).each do |file_type, file_format|
+ context "when #{file_type} type with #{file_format} format" do
+ let(:artifact) { build(:ci_job_artifact, file_type: file_type, file_format: file_format) }
- it { is_expected.to be_valid }
- end
+ it { is_expected.to be_valid }
+ end
- context 'when archive type with gzip format' do
- let(:artifact) { build(:ci_job_artifact, :archive, file_format: :gzip) }
+ context "when #{file_type} type without format specification" do
+ let(:artifact) { build(:ci_job_artifact, file_type: file_type, file_format: nil) }
- it { is_expected.not_to be_valid }
- end
+ it { is_expected.not_to be_valid }
+ end
- context 'when archive type without format specification' do
- let(:artifact) { build(:ci_job_artifact, :archive, file_format: nil) }
+ context "when #{file_type} type with other formats" do
+ described_class.file_formats.except(file_format).values.each do |other_format|
+ let(:artifact) { build(:ci_job_artifact, file_type: file_type, file_format: other_format) }
- it { is_expected.not_to be_valid }
+ it { is_expected.not_to be_valid }
+ end
+ end
end
+ end
- context 'when junit type with zip format' do
- let(:artifact) { build(:ci_job_artifact, :junit, file_format: :zip) }
+ describe 'validates DEFAULT_FILE_NAMES' do
+ subject { described_class::DEFAULT_FILE_NAMES }
- it { is_expected.not_to be_valid }
+ described_class.file_types.each do |file_type, _|
+ it "expects #{file_type} to be included" do
+ is_expected.to include(file_type.to_sym)
+ end
end
+ end
- context 'when junit type with gzip format' do
- let(:artifact) { build(:ci_job_artifact, :junit, file_format: :gzip) }
+ describe 'validates TYPE_AND_FORMAT_PAIRS' do
+ subject { described_class::TYPE_AND_FORMAT_PAIRS }
- it { is_expected.to be_valid }
+ described_class.file_types.each do |file_type, _|
+ it "expects #{file_type} to be included" do
+ expect(described_class.file_formats).to include(subject[file_type.to_sym])
+ end
end
end
diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb
index 2216705c032..4755702c0e9 100644
--- a/spec/models/ci/pipeline_spec.rb
+++ b/spec/models/ci/pipeline_spec.rb
@@ -1151,7 +1151,11 @@ describe Ci::Pipeline, :mailer do
end
describe '#set_config_source' do
- context 'when pipelines does not contain needed data' do
+ context 'when pipelines does not contain needed data and auto devops is disabled' do
+ before do
+ stub_application_setting(auto_devops_enabled: false)
+ end
+
it 'defines source to be unknown' do
pipeline.set_config_source
@@ -1196,7 +1200,6 @@ describe Ci::Pipeline, :mailer do
context 'auto devops enabled' do
before do
- stub_application_setting(auto_devops_enabled: true)
allow(project).to receive(:ci_config_path) { 'custom' }
end
diff --git a/spec/models/clusters/applications/jupyter_spec.rb b/spec/models/clusters/applications/jupyter_spec.rb
index 591a01d78a9..9c4396731eb 100644
--- a/spec/models/clusters/applications/jupyter_spec.rb
+++ b/spec/models/clusters/applications/jupyter_spec.rb
@@ -108,8 +108,15 @@ describe Clusters::Applications::Jupyter do
expect(values).to include('rbac')
expect(values).to include('proxy')
expect(values).to include('auth')
+ expect(values).to include('singleuser')
expect(values).to match(/clientId: '?#{application.oauth_application.uid}/)
expect(values).to match(/callbackUrl: '?#{application.callback_url}/)
end
+
+ context 'when cluster belongs to a project' do
+ it 'sets GitLab project id' do
+ expect(values).to match(/GITLAB_CLUSTER_ID: '?#{application.cluster.id}/)
+ end
+ end
end
end
diff --git a/spec/models/clusters/providers/gcp_spec.rb b/spec/models/clusters/providers/gcp_spec.rb
index b38b5e6bcad..d134608b538 100644
--- a/spec/models/clusters/providers/gcp_spec.rb
+++ b/spec/models/clusters/providers/gcp_spec.rb
@@ -74,6 +74,24 @@ describe Clusters::Providers::Gcp do
end
end
+ describe '#legacy_abac?' do
+ let(:gcp) { build(:cluster_provider_gcp) }
+
+ subject { gcp }
+
+ it 'should default to true' do
+ is_expected.to be_legacy_abac
+ end
+
+ context 'legacy_abac is set to false' do
+ let(:gcp) { build(:cluster_provider_gcp, legacy_abac: false) }
+
+ it 'is false' do
+ is_expected.not_to be_legacy_abac
+ end
+ end
+ end
+
describe '#state_machine' do
context 'when any => [:created]' do
let(:gcp) { build(:cluster_provider_gcp, :creating) }
diff --git a/spec/models/commit_spec.rb b/spec/models/commit_spec.rb
index d5f88e930d4..ed41ff7a0fa 100644
--- a/spec/models/commit_spec.rb
+++ b/spec/models/commit_spec.rb
@@ -65,7 +65,7 @@ describe Commit do
key = "Commit:author:#{commit.author_email.downcase}"
- expect(RequestStore.store[key]).to eq(user)
+ expect(Gitlab::SafeRequestStore[key]).to eq(user)
expect(commit.author).to eq(user)
end
@@ -270,11 +270,11 @@ eos
let(:issue) { create :issue, project: project }
let(:other_project) { create(:project, :public) }
let(:other_issue) { create :issue, project: other_project }
- let(:commiter) { create :user }
+ let(:committer) { create :user }
before do
- project.add_developer(commiter)
- other_project.add_developer(commiter)
+ project.add_developer(committer)
+ other_project.add_developer(committer)
end
it 'detects issues that this commit is marked as closing' do
@@ -282,7 +282,7 @@ eos
allow(commit).to receive_messages(
safe_message: "Fixes ##{issue.iid} and #{ext_ref}",
- committer_email: commiter.email
+ committer_email: committer.email
)
expect(commit.closes_issues).to include(issue)
diff --git a/spec/models/concerns/from_union_spec.rb b/spec/models/concerns/from_union_spec.rb
new file mode 100644
index 00000000000..ee427a667c6
--- /dev/null
+++ b/spec/models/concerns/from_union_spec.rb
@@ -0,0 +1,40 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe FromUnion do
+ describe '.from_union' do
+ let(:model) do
+ Class.new(ActiveRecord::Base) do
+ self.table_name = 'users'
+
+ include FromUnion
+ end
+ end
+
+ it 'selects from the results of the UNION' do
+ query = model.from_union([model.where(id: 1), model.where(id: 2)])
+
+ expect(query.to_sql).to match(/FROM \(SELECT.+UNION.+SELECT.+\) users/m)
+ end
+
+ it 'supports the use of a custom alias for the sub query' do
+ query = model.from_union(
+ [model.where(id: 1), model.where(id: 2)],
+ alias_as: 'kittens'
+ )
+
+ expect(query.to_sql).to match(/FROM \(SELECT.+UNION.+SELECT.+\) kittens/m)
+ end
+
+ it 'supports keeping duplicate rows' do
+ query = model.from_union(
+ [model.where(id: 1), model.where(id: 2)],
+ remove_duplicates: false
+ )
+
+ expect(query.to_sql)
+ .to match(/FROM \(SELECT.+UNION ALL.+SELECT.+\) users/m)
+ end
+ end
+end
diff --git a/spec/models/event_collection_spec.rb b/spec/models/event_collection_spec.rb
index e0a87c18cc7..6078f429bdc 100644
--- a/spec/models/event_collection_spec.rb
+++ b/spec/models/event_collection_spec.rb
@@ -41,7 +41,7 @@ describe EventCollection do
end
it 'allows filtering of events using an EventFilter' do
- filter = EventFilter.new(EventFilter.issue)
+ filter = EventFilter.new(EventFilter::ISSUE)
events = described_class.new(projects, filter: filter).to_a
expect(events.length).to eq(1)
diff --git a/spec/models/instance_configuration_spec.rb b/spec/models/instance_configuration_spec.rb
index 8548fff5c76..34db94920f3 100644
--- a/spec/models/instance_configuration_spec.rb
+++ b/spec/models/instance_configuration_spec.rb
@@ -52,7 +52,7 @@ RSpec.describe InstanceConfiguration do
expect(gitlab_pages).to eq(Settings.pages.symbolize_keys)
end
- it 'returns the Gitlab\'s pages host ip address' do
+ it 'returns the GitLab\'s pages host ip address' do
expect(gitlab_pages.keys).to include(:ip_address)
end
diff --git a/spec/models/issue_spec.rb b/spec/models/issue_spec.rb
index c21d85fb2a4..19bc2713ef5 100644
--- a/spec/models/issue_spec.rb
+++ b/spec/models/issue_spec.rb
@@ -84,15 +84,32 @@ describe Issue do
end
end
- describe '#closed_at' do
- it 'sets closed_at to Time.now when issue is closed' do
- issue = create(:issue, state: 'opened')
+ describe '#close' do
+ subject(:issue) { create(:issue, state: 'opened') }
- expect(issue.closed_at).to be_nil
+ it 'sets closed_at to Time.now when an issue is closed' do
+ expect { issue.close }.to change { issue.closed_at }.from(nil)
+ end
- issue.close
+ it 'changes the state to closed' do
+ expect { issue.close }.to change { issue.state }.from('opened').to('closed')
+ end
+ end
+
+ describe '#reopen' do
+ let(:user) { create(:user) }
+ let(:issue) { create(:issue, state: 'closed', closed_at: Time.now, closed_by: user) }
+
+ it 'sets closed_at to nil when an issue is reopend' do
+ expect { issue.reopen }.to change { issue.closed_at }.to(nil)
+ end
+
+ it 'sets closed_by to nil when an issue is reopend' do
+ expect { issue.reopen }.to change { issue.closed_by }.from(user).to(nil)
+ end
- expect(issue.closed_at).to be_present
+ it 'changes the state to opened' do
+ expect { issue.reopen }.to change { issue.state }.from('closed').to('opened')
end
end
diff --git a/spec/models/milestone_spec.rb b/spec/models/milestone_spec.rb
index 55b984faecf..27d4e622710 100644
--- a/spec/models/milestone_spec.rb
+++ b/spec/models/milestone_spec.rb
@@ -95,6 +95,24 @@ describe Milestone do
end
end
+ describe '.order_by_name_asc' do
+ it 'sorts by name ascending' do
+ milestone1 = create(:milestone, title: 'Foo')
+ milestone2 = create(:milestone, title: 'Bar')
+
+ expect(described_class.order_by_name_asc).to eq([milestone2, milestone1])
+ end
+ end
+
+ describe '.reorder_by_due_date_asc' do
+ it 'reorders the input relation' do
+ milestone1 = create(:milestone, due_date: Date.new(2018, 9, 30))
+ milestone2 = create(:milestone, due_date: Date.new(2018, 10, 20))
+
+ expect(described_class.reorder_by_due_date_asc).to eq([milestone1, milestone2])
+ end
+ end
+
describe "#percent_complete" do
it "does not count open issues" do
milestone.issues << issue
diff --git a/spec/models/project_feature_spec.rb b/spec/models/project_feature_spec.rb
index 10617edec0f..cd7f77024da 100644
--- a/spec/models/project_feature_spec.rb
+++ b/spec/models/project_feature_spec.rb
@@ -119,46 +119,4 @@ describe ProjectFeature do
end
end
end
-
- context 'Site Statistics' do
- set(:project_with_wiki) { create(:project, :wiki_enabled) }
- set(:project_without_wiki) { create(:project, :wiki_disabled) }
-
- context 'when creating a project' do
- it 'tracks wiki availability when wikis are enabled by default' do
- expect { create(:project) }.to change { SiteStatistic.fetch.wikis_count }.by(1)
- end
-
- it 'does not track wiki availability when wikis are disabled by default' do
- expect { create(:project, :wiki_disabled) }.not_to change { SiteStatistic.fetch.wikis_count }
- end
- end
-
- context 'when updating a project_feature' do
- it 'untracks wiki availability when disabling wiki access' do
- expect { project_with_wiki.project_feature.update_attribute(:wiki_access_level, ProjectFeature::DISABLED) }
- .to change { SiteStatistic.fetch.wikis_count }.by(-1)
- end
-
- it 'tracks again wiki availability when re-enabling wiki access as public' do
- expect { project_without_wiki.project_feature.update_attribute(:wiki_access_level, ProjectFeature::ENABLED) }
- .to change { SiteStatistic.fetch.wikis_count }.by(1)
- end
-
- it 'tracks again wiki availability when re-enabling wiki access as private' do
- expect { project_without_wiki.project_feature.update_attribute(:wiki_access_level, ProjectFeature::PRIVATE) }
- .to change { SiteStatistic.fetch.wikis_count }.by(1)
- end
- end
-
- context 'when removing a project' do
- it 'untracks wiki availability when removing a project with previous wiki access' do
- expect { project_with_wiki.destroy }.to change { SiteStatistic.fetch.wikis_count }.by(-1)
- end
-
- it 'does not untrack wiki availability when removing a project without wiki access' do
- expect { project_without_wiki.destroy }.not_to change { SiteStatistic.fetch.wikis_count }
- end
- end
- end
end
diff --git a/spec/models/project_services/chat_message/merge_message_spec.rb b/spec/models/project_services/chat_message/merge_message_spec.rb
index 184a07ae0f9..7997b5bb6b9 100644
--- a/spec/models/project_services/chat_message/merge_message_spec.rb
+++ b/spec/models/project_services/chat_message/merge_message_spec.rb
@@ -27,13 +27,30 @@ describe ChatMessage::MergeMessage do
}
end
+ # Integration point in EE
+ context 'when state is overridden' do
+ it 'respects the overridden state' do
+ allow(subject).to receive(:state_or_action_text) { 'devoured' }
+
+ aggregate_failures do
+ expect(subject.summary).not_to include('opened')
+ expect(subject.summary).to include('devoured')
+
+ activity_title = subject.activity[:title]
+
+ expect(activity_title).not_to include('opened')
+ expect(activity_title).to include('devoured')
+ end
+ end
+ end
+
context 'without markdown' do
let(:color) { '#345' }
context 'open' do
it 'returns a message regarding opening of merge requests' do
expect(subject.pretext).to eq(
- 'Test User (test.user) opened <http://somewhere.com/merge_requests/100|!100 *Merge Request title*> in <http://somewhere.com|project_name>: *Merge Request title*')
+ 'Test User (test.user) opened <http://somewhere.com/merge_requests/100|!100 *Merge Request title*> in <http://somewhere.com|project_name>')
expect(subject.attachments).to be_empty
end
end
@@ -44,7 +61,7 @@ describe ChatMessage::MergeMessage do
end
it 'returns a message regarding closing of merge requests' do
expect(subject.pretext).to eq(
- 'Test User (test.user) closed <http://somewhere.com/merge_requests/100|!100 *Merge Request title*> in <http://somewhere.com|project_name>: *Merge Request title*')
+ 'Test User (test.user) closed <http://somewhere.com/merge_requests/100|!100 *Merge Request title*> in <http://somewhere.com|project_name>')
expect(subject.attachments).to be_empty
end
end
@@ -58,7 +75,7 @@ describe ChatMessage::MergeMessage do
context 'open' do
it 'returns a message regarding opening of merge requests' do
expect(subject.pretext).to eq(
- 'Test User (test.user) opened [!100 *Merge Request title*](http://somewhere.com/merge_requests/100) in [project_name](http://somewhere.com): *Merge Request title*')
+ 'Test User (test.user) opened [!100 *Merge Request title*](http://somewhere.com/merge_requests/100) in [project_name](http://somewhere.com)')
expect(subject.attachments).to be_empty
expect(subject.activity).to eq({
title: 'Merge Request opened by Test User (test.user)',
@@ -76,7 +93,7 @@ describe ChatMessage::MergeMessage do
it 'returns a message regarding closing of merge requests' do
expect(subject.pretext).to eq(
- 'Test User (test.user) closed [!100 *Merge Request title*](http://somewhere.com/merge_requests/100) in [project_name](http://somewhere.com): *Merge Request title*')
+ 'Test User (test.user) closed [!100 *Merge Request title*](http://somewhere.com/merge_requests/100) in [project_name](http://somewhere.com)')
expect(subject.attachments).to be_empty
expect(subject.activity).to eq({
title: 'Merge Request closed by Test User (test.user)',
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index dfe2de71a76..afc9ea1917e 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -1072,6 +1072,18 @@ describe Project do
it { expect(project.builds_enabled?).to be_truthy }
end
+ describe '.sort_by_attribute' do
+ it 'reorders the input relation by start count desc' do
+ project1 = create(:project, star_count: 2)
+ project2 = create(:project, star_count: 1)
+ project3 = create(:project)
+
+ projects = described_class.sort_by_attribute(:stars_desc)
+
+ expect(projects).to eq([project1, project2, project3])
+ end
+ end
+
describe '.with_shared_runners' do
subject { described_class.with_shared_runners }
@@ -3229,17 +3241,17 @@ describe Project do
expect(repository).to receive(:gitlab_ci_yml) { nil }
end
- it "CI is not available" do
- expect(project).not_to have_ci
+ it "CI is available" do
+ expect(project).to have_ci
end
- context 'when auto devops is enabled' do
+ context 'when auto devops is disabled' do
before do
- stub_application_setting(auto_devops_enabled: true)
+ stub_application_setting(auto_devops_enabled: false)
end
- it "CI is available" do
- expect(project).to have_ci
+ it "CI is not available" do
+ expect(project).not_to have_ci
end
end
end
@@ -3983,40 +3995,6 @@ describe Project do
end
end
- describe '#update_root_ref' do
- let(:project) { create(:project, :repository) }
-
- it 'updates the default branch when HEAD has changed' do
- stub_find_remote_root_ref(project, ref: 'feature')
-
- expect { project.update_root_ref('origin') }
- .to change { project.default_branch }
- .from('master')
- .to('feature')
- end
-
- it 'does not update the default branch when HEAD does not change' do
- stub_find_remote_root_ref(project, ref: 'master')
-
- expect { project.update_root_ref('origin') }
- .not_to change { project.default_branch }
- end
-
- it 'does not update the default branch when HEAD does not exist' do
- stub_find_remote_root_ref(project, ref: 'foo')
-
- expect { project.update_root_ref('origin') }
- .not_to change { project.default_branch }
- end
-
- def stub_find_remote_root_ref(project, ref:)
- allow(project.repository)
- .to receive(:find_remote_root_ref)
- .with('origin')
- .and_return(ref)
- end
- end
-
def rugged_config
Gitlab::GitalyClient::StorageSettings.allow_disk_access do
project.repository.rugged.config
diff --git a/spec/models/project_wiki_spec.rb b/spec/models/project_wiki_spec.rb
index 528f5b610d7..f38fc191943 100644
--- a/spec/models/project_wiki_spec.rb
+++ b/spec/models/project_wiki_spec.rb
@@ -2,12 +2,13 @@
require "spec_helper"
describe ProjectWiki do
- let(:project) { create(:project, :wiki_repo) }
+ let(:user) { create(:user, :commit_email) }
+ let(:project) { create(:project, :wiki_repo, namespace: user.namespace) }
let(:repository) { project.repository }
- let(:user) { project.owner }
let(:gitlab_shell) { Gitlab::Shell.new }
let(:project_wiki) { described_class.new(project, user) }
let(:raw_repository) { Gitlab::Git::Repository.new(project.repository_storage, subject.disk_path + '.git', 'foo') }
+ let(:commit) { project_wiki.repository.head_commit }
subject { project_wiki }
@@ -276,6 +277,14 @@ describe ProjectWiki do
expect(subject.pages.first.page.version.message).to eq("commit message")
end
+ it 'sets the correct commit email' do
+ subject.create_page('test page', 'content')
+
+ expect(user.commit_email).not_to eq(user.email)
+ expect(commit.author_email).to eq(user.commit_email)
+ expect(commit.committer_email).to eq(user.commit_email)
+ end
+
it 'updates project activity' do
subject.create_page('Test Page', 'This is content')
@@ -320,6 +329,12 @@ describe ProjectWiki do
expect(@page.version.message).to eq("updated page")
end
+ it 'sets the correct commit email' do
+ expect(user.commit_email).not_to eq(user.email)
+ expect(commit.author_email).to eq(user.commit_email)
+ expect(commit.committer_email).to eq(user.commit_email)
+ end
+
it 'updates project activity' do
subject.update_page(
@gitlab_git_wiki_page,
@@ -347,6 +362,14 @@ describe ProjectWiki do
expect(subject.pages.count).to eq(0)
end
+ it 'sets the correct commit email' do
+ subject.delete_page(@page)
+
+ expect(user.commit_email).not_to eq(user.email)
+ expect(commit.author_email).to eq(user.commit_email)
+ expect(commit.committer_email).to eq(user.commit_email)
+ end
+
it 'updates project activity' do
subject.delete_page(@page)
@@ -420,7 +443,7 @@ describe ProjectWiki do
end
def commit_details
- Gitlab::Git::Wiki::CommitDetails.new(user.id, user.username, user.name, user.email, "test commit")
+ Gitlab::Git::Wiki::CommitDetails.new(user.id, user.username, user.name, user.commit_email, "test commit")
end
def create_page(name, content)
diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb
index dffac05152b..784d17e271e 100644
--- a/spec/models/repository_spec.rb
+++ b/spec/models/repository_spec.rb
@@ -188,6 +188,57 @@ describe Repository do
end
end
+ describe '#list_last_commits_for_tree' do
+ let(:path_to_commit) do
+ {
+ "encoding" => "913c66a37b4a45b9769037c55c2d238bd0942d2e",
+ "files" => "570e7b2abdd848b95f2f578043fc23bd6f6fd24d",
+ ".gitignore" => "c1acaa58bbcbc3eafe538cb8274ba387047b69f8",
+ ".gitmodules" => "6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9",
+ "CHANGELOG" => "913c66a37b4a45b9769037c55c2d238bd0942d2e",
+ "CONTRIBUTING.md" => "6d394385cf567f80a8fd85055db1ab4c5295806f",
+ "Gemfile.zip" => "ae73cb07c9eeaf35924a10f713b364d32b2dd34f",
+ "LICENSE" => "1a0b36b3cdad1d2ee32457c102a8c0b7056fa863",
+ "MAINTENANCE.md" => "913c66a37b4a45b9769037c55c2d238bd0942d2e",
+ "PROCESS.md" => "913c66a37b4a45b9769037c55c2d238bd0942d2e",
+ "README.md" => "1a0b36b3cdad1d2ee32457c102a8c0b7056fa863",
+ "VERSION" => "913c66a37b4a45b9769037c55c2d238bd0942d2e",
+ "gitlab-shell" => "6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9",
+ "six" => "cfe32cf61b73a0d5e9f13e774abde7ff789b1660"
+ }
+ end
+
+ subject { repository.list_last_commits_for_tree(sample_commit.id, '.').id }
+
+ it 'returns the last commits for every entry in the current path' do
+ result = repository.list_last_commits_for_tree(sample_commit.id, '.')
+
+ result.each do |key, value|
+ result[key] = value.id
+ end
+
+ expect(result).to include(path_to_commit)
+ end
+
+ it 'returns the last commits for every entry in the current path starting from the offset' do
+ result = repository.list_last_commits_for_tree(sample_commit.id, '.', offset: path_to_commit.size - 1)
+
+ expect(result.size).to eq(1)
+ end
+
+ it 'returns a limited number of last commits for every entry in the current path starting from the offset' do
+ result = repository.list_last_commits_for_tree(sample_commit.id, '.', limit: 1)
+
+ expect(result.size).to eq(1)
+ end
+
+ it 'returns an empty hash when offset is out of bounds' do
+ result = repository.list_last_commits_for_tree(sample_commit.id, '.', offset: path_to_commit.size)
+
+ expect(result.size).to eq(0)
+ end
+ end
+
describe '#last_commit_for_path' do
shared_examples 'getting last commit for path' do
subject { repository.last_commit_for_path(sample_commit.id, '.gitignore').id }
@@ -1044,6 +1095,47 @@ describe Repository do
expect_to_raise_storage_error { broken_repository.exists? }
end
end
+
+ context 'asymmetric caching', :use_clean_rails_memory_store_caching, :request_store do
+ let(:cache) { repository.send(:cache) }
+ let(:request_store_cache) { repository.send(:request_store_cache) }
+
+ context 'when it returns true' do
+ before do
+ expect(repository.raw_repository).to receive(:exists?).once.and_return(true)
+ end
+
+ it 'caches the output in RequestStore' do
+ expect do
+ repository.exists?
+ end.to change { request_store_cache.read(:exists?) }.from(nil).to(true)
+ end
+
+ it 'caches the output in RepositoryCache' do
+ expect do
+ repository.exists?
+ end.to change { cache.read(:exists?) }.from(nil).to(true)
+ end
+ end
+
+ context 'when it returns false' do
+ before do
+ expect(repository.raw_repository).to receive(:exists?).once.and_return(false)
+ end
+
+ it 'caches the output in RequestStore' do
+ expect do
+ repository.exists?
+ end.to change { request_store_cache.read(:exists?) }.from(nil).to(false)
+ end
+
+ it 'does NOT cache the output in RepositoryCache' do
+ expect do
+ repository.exists?
+ end.not_to change { cache.read(:exists?) }.from(nil)
+ end
+ end
+ end
end
describe '#has_visible_content?' do
@@ -1716,12 +1808,19 @@ describe Repository do
describe '#expire_exists_cache' do
let(:cache) { repository.send(:cache) }
+ let(:request_store_cache) { repository.send(:request_store_cache) }
it 'expires the cache' do
expect(cache).to receive(:expire).with(:exists?)
repository.expire_exists_cache
end
+
+ it 'expires the request store cache', :request_store do
+ expect(request_store_cache).to receive(:expire).with(:exists?)
+
+ repository.expire_exists_cache
+ end
end
describe '#xcode_project?' do
@@ -1892,7 +1991,7 @@ describe Repository do
match[1].to_sym if match
end.compact
- expect(methods).to match_array(Repository::CACHED_METHODS + Repository::MEMOIZED_CACHED_METHODS)
+ expect(Repository::CACHED_METHODS + Repository::MEMOIZED_CACHED_METHODS).to include(*methods)
end
end
diff --git a/spec/models/site_statistic_spec.rb b/spec/models/site_statistic_spec.rb
index 9b056fbf332..0e739900065 100644
--- a/spec/models/site_statistic_spec.rb
+++ b/spec/models/site_statistic_spec.rb
@@ -25,7 +25,6 @@ describe SiteStatistic do
it 'increases the attribute counter' do
expect { described_class.track('repositories_count') }.to change { statistics.reload.repositories_count }.by(1)
- expect { described_class.track('wikis_count') }.to change { statistics.reload.wikis_count }.by(1)
end
it 'doesnt increase the attribute counter when an exception happens during transaction' do
@@ -56,7 +55,6 @@ describe SiteStatistic do
it 'decreases the attribute counter' do
expect { described_class.untrack('repositories_count') }.to change { statistics.reload.repositories_count }.by(-1)
- expect { described_class.untrack('wikis_count') }.to change { statistics.reload.wikis_count }.by(-1)
end
it 'doesnt decrease the attribute counter when an exception happens during transaction' do
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index 27aec49e348..99d17f563d9 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -2543,6 +2543,34 @@ describe User do
end
end
+ describe '#assigned_open_merge_requests_count' do
+ it 'returns number of open merge requests from non-archived projects' do
+ user = create(:user)
+ project = create(:project, :public)
+ archived_project = create(:project, :public, :archived)
+
+ create(:merge_request, source_project: project, author: user, assignee: user)
+ create(:merge_request, :closed, source_project: project, author: user, assignee: user)
+ create(:merge_request, source_project: archived_project, author: user, assignee: user)
+
+ expect(user.assigned_open_merge_requests_count(force: true)).to eq 1
+ end
+ end
+
+ describe '#assigned_open_issues_count' do
+ it 'returns number of open issues from non-archived projects' do
+ user = create(:user)
+ project = create(:project, :public)
+ archived_project = create(:project, :public, :archived)
+
+ create(:issue, project: project, author: user, assignees: [user])
+ create(:issue, :closed, project: project, author: user, assignees: [user])
+ create(:issue, project: archived_project, author: user, assignees: [user])
+
+ expect(user.assigned_open_issues_count(force: true)).to eq 1
+ end
+ end
+
describe '#personal_projects_count' do
it 'returns the number of personal projects using a single query' do
user = build(:user)
diff --git a/spec/presenters/ci/build_runner_presenter_spec.rb b/spec/presenters/ci/build_runner_presenter_spec.rb
index e7019b990dd..a42d1f3d399 100644
--- a/spec/presenters/ci/build_runner_presenter_spec.rb
+++ b/spec/presenters/ci/build_runner_presenter_spec.rb
@@ -3,7 +3,6 @@ require 'spec_helper'
describe Ci::BuildRunnerPresenter do
let(:presenter) { described_class.new(build) }
let(:archive) { { paths: ['sample.txt'] } }
- let(:junit) { { junit: ['junit.xml'] } }
let(:archive_expectation) do
{
@@ -14,16 +13,6 @@ describe Ci::BuildRunnerPresenter do
}
end
- let(:junit_expectation) do
- {
- name: 'junit.xml',
- artifact_type: :junit,
- artifact_format: :gzip,
- paths: ['junit.xml'],
- when: 'always'
- }
- end
-
describe '#artifacts' do
context "when option contains archive-type artifacts" do
let(:build) { create(:ci_build, options: { artifacts: archive } ) }
@@ -49,20 +38,44 @@ describe Ci::BuildRunnerPresenter do
end
end
- context "when option has 'junit' keyword" do
- let(:build) { create(:ci_build, options: { artifacts: { reports: junit } } ) }
+ context "with reports" do
+ Ci::JobArtifact::DEFAULT_FILE_NAMES.each do |file_type, filename|
+ let(:report) { { "#{file_type}": [filename] } }
+ let(:build) { create(:ci_build, options: { artifacts: { reports: report } } ) }
+
+ let(:report_expectation) do
+ {
+ name: filename,
+ artifact_type: :"#{file_type}",
+ artifact_format: :gzip,
+ paths: [filename],
+ when: 'always'
+ }
+ end
- it 'presents correct hash' do
- expect(presenter.artifacts.first).to include(junit_expectation)
+ it 'presents correct hash' do
+ expect(presenter.artifacts.first).to include(report_expectation)
+ end
end
end
context "when option has both archive and reports specification" do
- let(:build) { create(:ci_build, options: { script: 'echo', artifacts: { **archive, reports: junit } } ) }
+ let(:report) { { junit: ['junit.xml'] } }
+ let(:build) { create(:ci_build, options: { script: 'echo', artifacts: { **archive, reports: report } } ) }
+
+ let(:report_expectation) do
+ {
+ name: 'junit.xml',
+ artifact_type: :junit,
+ artifact_format: :gzip,
+ paths: ['junit.xml'],
+ when: 'always'
+ }
+ end
it 'presents correct hash' do
expect(presenter.artifacts.first).to include(archive_expectation)
- expect(presenter.artifacts.second).to include(junit_expectation)
+ expect(presenter.artifacts.second).to include(report_expectation)
end
context "when archive specifies 'expire_in' keyword" do
@@ -70,7 +83,7 @@ describe Ci::BuildRunnerPresenter do
it 'inherits expire_in from archive' do
expect(presenter.artifacts.first).to include({ **archive_expectation, expire_in: '3 mins 4 sec' })
- expect(presenter.artifacts.second).to include({ **junit_expectation, expire_in: '3 mins 4 sec' })
+ expect(presenter.artifacts.second).to include({ **report_expectation, expire_in: '3 mins 4 sec' })
end
end
end
diff --git a/spec/presenters/project_presenter_spec.rb b/spec/presenters/project_presenter_spec.rb
index d9fb27e101e..96193784072 100644
--- a/spec/presenters/project_presenter_spec.rb
+++ b/spec/presenters/project_presenter_spec.rb
@@ -412,7 +412,7 @@ describe ProjectPresenter do
end
describe '#koding_anchor_data' do
- it 'returns link to setup Koding if user can push and no koding YML exists' do
+ it 'returns link to set up Koding if user can push and no koding YML exists' do
project.add_developer(user)
allow(project.repository).to receive(:koding_yml).and_return(nil)
allow(Gitlab::CurrentSettings).to receive(:koding_enabled?).and_return(true)
diff --git a/spec/requests/api/commits_spec.rb b/spec/requests/api/commits_spec.rb
index d5b31610dad..f3fb88474a4 100644
--- a/spec/requests/api/commits_spec.rb
+++ b/spec/requests/api/commits_spec.rb
@@ -238,7 +238,7 @@ describe API::Commits do
describe 'create' do
let(:message) { 'Created file' }
- let!(:invalid_c_params) do
+ let(:invalid_c_params) do
{
branch: 'master',
commit_message: message,
@@ -251,7 +251,7 @@ describe API::Commits do
]
}
end
- let!(:valid_c_params) do
+ let(:valid_c_params) do
{
branch: 'master',
commit_message: message,
@@ -264,7 +264,7 @@ describe API::Commits do
]
}
end
- let!(:valid_utf8_c_params) do
+ let(:valid_utf8_c_params) do
{
branch: 'master',
commit_message: message,
@@ -315,7 +315,7 @@ describe API::Commits do
describe 'delete' do
let(:message) { 'Deleted file' }
- let!(:invalid_d_params) do
+ let(:invalid_d_params) do
{
branch: 'markdown',
commit_message: message,
@@ -327,7 +327,7 @@ describe API::Commits do
]
}
end
- let!(:valid_d_params) do
+ let(:valid_d_params) do
{
branch: 'markdown',
commit_message: message,
@@ -356,7 +356,7 @@ describe API::Commits do
describe 'move' do
let(:message) { 'Moved file' }
- let!(:invalid_m_params) do
+ let(:invalid_m_params) do
{
branch: 'feature',
commit_message: message,
@@ -370,7 +370,7 @@ describe API::Commits do
]
}
end
- let!(:valid_m_params) do
+ let(:valid_m_params) do
{
branch: 'feature',
commit_message: message,
@@ -401,7 +401,7 @@ describe API::Commits do
describe 'update' do
let(:message) { 'Updated file' }
- let!(:invalid_u_params) do
+ let(:invalid_u_params) do
{
branch: 'master',
commit_message: message,
@@ -414,7 +414,7 @@ describe API::Commits do
]
}
end
- let!(:valid_u_params) do
+ let(:valid_u_params) do
{
branch: 'master',
commit_message: message,
@@ -442,9 +442,57 @@ describe API::Commits do
end
end
+ describe 'chmod' do
+ let(:message) { 'Chmod +x file' }
+ let(:file_path) { 'files/ruby/popen.rb' }
+ let(:execute_filemode) { true }
+ let(:params) do
+ {
+ branch: 'master',
+ commit_message: message,
+ actions: [
+ {
+ action: 'chmod',
+ file_path: file_path,
+ execute_filemode: execute_filemode
+ }
+ ]
+ }
+ end
+
+ it 'responds with success' do
+ post api(url, user), params
+
+ expect(response).to have_gitlab_http_status(201)
+ expect(json_response['title']).to eq(message)
+ end
+
+ context 'when execute_filemode is false' do
+ let(:execute_filemode) { false }
+
+ it 'responds with success' do
+ post api(url, user), params
+
+ expect(response).to have_gitlab_http_status(201)
+ expect(json_response['title']).to eq(message)
+ end
+ end
+
+ context "when the file doesn't exists" do
+ let(:file_path) { 'foo/bar.baz' }
+
+ it "responds with 400" do
+ post api(url, user), params
+
+ expect(response).to have_gitlab_http_status(400)
+ expect(json_response['message']).to eq("A file with this name doesn't exist")
+ end
+ end
+ end
+
describe 'multiple operations' do
let(:message) { 'Multiple actions' }
- let!(:invalid_mo_params) do
+ let(:invalid_mo_params) do
{
branch: 'master',
commit_message: message,
@@ -468,11 +516,16 @@ describe API::Commits do
action: 'update',
file_path: 'foo/bar.baz',
content: 'puts 8'
+ },
+ {
+ action: 'chmod',
+ file_path: 'files/ruby/popen.rb',
+ execute_filemode: true
}
]
}
end
- let!(:valid_mo_params) do
+ let(:valid_mo_params) do
{
branch: 'master',
commit_message: message,
@@ -496,6 +549,11 @@ describe API::Commits do
action: 'update',
file_path: 'files/ruby/popen.rb',
content: 'puts 8'
+ },
+ {
+ action: 'chmod',
+ file_path: 'files/ruby/popen.rb',
+ execute_filemode: true
}
]
}
diff --git a/spec/requests/api/jobs_spec.rb b/spec/requests/api/jobs_spec.rb
index 6adbbb40489..8770365c893 100644
--- a/spec/requests/api/jobs_spec.rb
+++ b/spec/requests/api/jobs_spec.rb
@@ -721,7 +721,7 @@ describe API::Jobs do
expect(job.trace.exist?).to be_falsy
expect(job.artifacts_file.exists?).to be_falsy
expect(job.artifacts_metadata.exists?).to be_falsy
- expect(job.has_test_reports?).to be_falsy
+ expect(job.has_job_artifacts?).to be_falsy
end
it 'updates job' do
diff --git a/spec/requests/api/pipelines_spec.rb b/spec/requests/api/pipelines_spec.rb
index 342a97b6a69..f0e1992bccd 100644
--- a/spec/requests/api/pipelines_spec.rb
+++ b/spec/requests/api/pipelines_spec.rb
@@ -370,12 +370,18 @@ describe API::Pipelines do
end
context 'without gitlab-ci.yml' do
- it 'fails to create pipeline' do
- post api("/projects/#{project.id}/pipeline", user), ref: project.default_branch
+ context 'without auto devops enabled' do
+ before do
+ project.update!(auto_devops_attributes: { enabled: false })
+ end
- expect(response).to have_gitlab_http_status(400)
- expect(json_response['message']['base'].first).to eq 'Missing .gitlab-ci.yml file'
- expect(json_response).not_to be_an Array
+ it 'fails to create pipeline' do
+ post api("/projects/#{project.id}/pipeline", user), ref: project.default_branch
+
+ expect(response).to have_gitlab_http_status(400)
+ expect(json_response['message']['base'].first).to eq 'Missing .gitlab-ci.yml file'
+ expect(json_response).not_to be_an Array
+ end
end
end
end
diff --git a/spec/requests/api/runners_spec.rb b/spec/requests/api/runners_spec.rb
index 3ebdb54f71f..49a79d2ccf9 100644
--- a/spec/requests/api/runners_spec.rb
+++ b/spec/requests/api/runners_spec.rb
@@ -25,36 +25,71 @@ describe API::Runners do
describe 'GET /runners' do
context 'authorized user' do
- it 'returns user available runners' do
+ it 'returns response status and headers' do
get api('/runners', user)
- shared = json_response.any? { |r| r['is_shared'] }
- descriptions = json_response.map { |runner| runner['description'] }
expect(response).to have_gitlab_http_status(200)
expect(response).to include_pagination_headers
- expect(json_response).to be_an Array
- expect(json_response[0]).to have_key('ip_address')
- expect(descriptions).to contain_exactly(
- 'Project runner', 'Two projects runner', 'Group runner'
- )
- expect(shared).to be_falsey
+ end
+
+ it 'returns user available runners' do
+ get api('/runners', user)
+
+ expect(json_response).to match_array [
+ a_hash_including('description' => 'Project runner'),
+ a_hash_including('description' => 'Two projects runner'),
+ a_hash_including('description' => 'Group runner')
+ ]
end
it 'filters runners by scope' do
- get api('/runners?scope=active', user)
+ create(:ci_runner, :project, :inactive, description: 'Inactive project runner', projects: [project])
+
+ get api('/runners?scope=paused', user)
- shared = json_response.any? { |r| r['is_shared'] }
expect(response).to have_gitlab_http_status(200)
expect(response).to include_pagination_headers
- expect(json_response).to be_an Array
- expect(json_response[0]).to have_key('ip_address')
- expect(shared).to be_falsey
+
+ expect(json_response).to match_array [
+ a_hash_including('description' => 'Inactive project runner')
+ ]
end
it 'avoids filtering if scope is invalid' do
get api('/runners?scope=unknown', user)
expect(response).to have_gitlab_http_status(400)
end
+
+ it 'filters runners by type' do
+ get api('/runners?type=project_type', user)
+
+ expect(json_response).to match_array [
+ a_hash_including('description' => 'Project runner'),
+ a_hash_including('description' => 'Two projects runner')
+ ]
+ end
+
+ it 'does not filter by invalid type' do
+ get api('/runners?type=bogus', user)
+
+ expect(response).to have_gitlab_http_status(400)
+ end
+
+ it 'filters runners by status' do
+ create(:ci_runner, :project, :inactive, description: 'Inactive project runner', projects: [project])
+
+ get api('/runners?status=paused', user)
+
+ expect(json_response).to match_array [
+ a_hash_including('description' => 'Inactive project runner')
+ ]
+ end
+
+ it 'does not filter by invalid status' do
+ get api('/runners?status=bogus', user)
+
+ expect(response).to have_gitlab_http_status(400)
+ end
end
context 'unauthorized user' do
@@ -69,51 +104,91 @@ describe API::Runners do
describe 'GET /runners/all' do
context 'authorized user' do
context 'with admin privileges' do
+ it 'returns response status and headers' do
+ get api('/runners/all', admin)
+
+ expect(response).to have_gitlab_http_status(200)
+ expect(response).to include_pagination_headers
+ end
+
it 'returns all runners' do
get api('/runners/all', admin)
- shared = json_response.any? { |r| r['is_shared'] }
+ expect(json_response).to match_array [
+ a_hash_including('description' => 'Project runner'),
+ a_hash_including('description' => 'Two projects runner'),
+ a_hash_including('description' => 'Group runner'),
+ a_hash_including('description' => 'Shared runner')
+ ]
+ end
+
+ it 'filters runners by scope' do
+ get api('/runners/all?scope=shared', admin)
+
+ shared = json_response.all? { |r| r['is_shared'] }
expect(response).to have_gitlab_http_status(200)
expect(response).to include_pagination_headers
expect(json_response).to be_an Array
expect(json_response[0]).to have_key('ip_address')
expect(shared).to be_truthy
end
- end
- context 'without admin privileges' do
- it 'does not return runners list' do
- get api('/runners/all', user)
+ it 'filters runners by scope' do
+ get api('/runners/all?scope=specific', admin)
- expect(response).to have_gitlab_http_status(403)
+ expect(response).to have_gitlab_http_status(200)
+ expect(response).to include_pagination_headers
+
+ expect(json_response).to match_array [
+ a_hash_including('description' => 'Project runner'),
+ a_hash_including('description' => 'Two projects runner'),
+ a_hash_including('description' => 'Group runner')
+ ]
end
- end
- it 'filters runners by scope' do
- get api('/runners/all?scope=shared', admin)
+ it 'avoids filtering if scope is invalid' do
+ get api('/runners/all?scope=unknown', admin)
+ expect(response).to have_gitlab_http_status(400)
+ end
- shared = json_response.all? { |r| r['is_shared'] }
- expect(response).to have_gitlab_http_status(200)
- expect(response).to include_pagination_headers
- expect(json_response).to be_an Array
- expect(json_response[0]).to have_key('ip_address')
- expect(shared).to be_truthy
- end
+ it 'filters runners by type' do
+ get api('/runners/all?type=project_type', admin)
- it 'filters runners by scope' do
- get api('/runners/all?scope=specific', admin)
+ expect(json_response).to match_array [
+ a_hash_including('description' => 'Project runner'),
+ a_hash_including('description' => 'Two projects runner')
+ ]
+ end
- shared = json_response.any? { |r| r['is_shared'] }
- expect(response).to have_gitlab_http_status(200)
- expect(response).to include_pagination_headers
- expect(json_response).to be_an Array
- expect(json_response[0]).to have_key('ip_address')
- expect(shared).to be_falsey
+ it 'does not filter by invalid type' do
+ get api('/runners/all?type=bogus', admin)
+
+ expect(response).to have_gitlab_http_status(400)
+ end
+
+ it 'filters runners by status' do
+ create(:ci_runner, :project, :inactive, description: 'Inactive project runner', projects: [project])
+
+ get api('/runners/all?status=paused', admin)
+
+ expect(json_response).to match_array [
+ a_hash_including('description' => 'Inactive project runner')
+ ]
+ end
+
+ it 'does not filter by invalid status' do
+ get api('/runners/all?status=bogus', admin)
+
+ expect(response).to have_gitlab_http_status(400)
+ end
end
- it 'avoids filtering if scope is invalid' do
- get api('/runners?scope=unknown', admin)
- expect(response).to have_gitlab_http_status(400)
+ context 'without admin privileges' do
+ it 'does not return runners list' do
+ get api('/runners/all', user)
+
+ expect(response).to have_gitlab_http_status(403)
+ end
end
end
@@ -577,15 +652,69 @@ describe API::Runners do
describe 'GET /projects/:id/runners' do
context 'authorized user with maintainer privileges' do
- it "returns project's runners" do
+ it 'returns response status and headers' do
+ get api('/runners/all', admin)
+
+ expect(response).to have_gitlab_http_status(200)
+ expect(response).to include_pagination_headers
+ end
+
+ it 'returns all runners' do
get api("/projects/#{project.id}/runners", user)
- shared = json_response.any? { |r| r['is_shared'] }
+ expect(json_response).to match_array [
+ a_hash_including('description' => 'Project runner'),
+ a_hash_including('description' => 'Two projects runner'),
+ a_hash_including('description' => 'Shared runner')
+ ]
+ end
+
+ it 'filters runners by scope' do
+ get api("/projects/#{project.id}/runners?scope=specific", user)
+
expect(response).to have_gitlab_http_status(200)
expect(response).to include_pagination_headers
- expect(json_response).to be_an Array
- expect(json_response[0]).to have_key('ip_address')
- expect(shared).to be_truthy
+
+ expect(json_response).to match_array [
+ a_hash_including('description' => 'Project runner'),
+ a_hash_including('description' => 'Two projects runner')
+ ]
+ end
+
+ it 'avoids filtering if scope is invalid' do
+ get api("/projects/#{project.id}/runners?scope=unknown", user)
+ expect(response).to have_gitlab_http_status(400)
+ end
+
+ it 'filters runners by type' do
+ get api("/projects/#{project.id}/runners?type=project_type", user)
+
+ expect(json_response).to match_array [
+ a_hash_including('description' => 'Project runner'),
+ a_hash_including('description' => 'Two projects runner')
+ ]
+ end
+
+ it 'does not filter by invalid type' do
+ get api("/projects/#{project.id}/runners?type=bogus", user)
+
+ expect(response).to have_gitlab_http_status(400)
+ end
+
+ it 'filters runners by status' do
+ create(:ci_runner, :project, :inactive, description: 'Inactive project runner', projects: [project])
+
+ get api("/projects/#{project.id}/runners?status=paused", user)
+
+ expect(json_response).to match_array [
+ a_hash_including('description' => 'Inactive project runner')
+ ]
+ end
+
+ it 'does not filter by invalid status' do
+ get api("/projects/#{project.id}/runners?status=bogus", user)
+
+ expect(response).to have_gitlab_http_status(400)
end
end
diff --git a/spec/requests/openid_connect_spec.rb b/spec/requests/openid_connect_spec.rb
index b14d4b8fb6e..b1cf7a531f4 100644
--- a/spec/requests/openid_connect_spec.rb
+++ b/spec/requests/openid_connect_spec.rb
@@ -121,7 +121,7 @@ describe 'OpenID Connect requests' do
expect(@payload).to match(a_hash_including(id_token_claims))
end
- it 'includes the Gitlab root URL' do
+ it 'includes the GitLab root URL' do
expect(@payload['iss']).to eq Gitlab.config.gitlab.url
end
diff --git a/spec/rubocop/cop/avoid_route_redirect_leading_slash_spec.rb b/spec/rubocop/cop/avoid_route_redirect_leading_slash_spec.rb
new file mode 100644
index 00000000000..c9eb61ccc72
--- /dev/null
+++ b/spec/rubocop/cop/avoid_route_redirect_leading_slash_spec.rb
@@ -0,0 +1,32 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require 'rubocop'
+require_relative '../../../rubocop/cop/avoid_route_redirect_leading_slash'
+
+describe RuboCop::Cop::AvoidRouteRedirectLeadingSlash do
+ include CopHelper
+
+ subject(:cop) { described_class.new }
+
+ before do
+ allow(cop).to receive(:in_routes?).and_return(true)
+ end
+
+ it 'registers an offense when redirect has a leading slash' do
+ expect_offense(<<~PATTERN.strip_indent)
+ root to: redirect("/-/route")
+ ^^^^^^^^^^^^^^^^^^^^ Do not use a leading "/" in route redirects
+ PATTERN
+ end
+
+ it 'does not register an offense when redirect does not have a leading slash' do
+ expect_no_offenses(<<~PATTERN.strip_indent)
+ root to: redirect("-/route")
+ PATTERN
+ end
+
+ it 'autocorrect `/-/route` to `-/route`' do
+ expect(autocorrect_source('redirect("/-/route")')).to eq('redirect("-/route")')
+ end
+end
diff --git a/spec/rubocop/cop/gitlab/union_spec.rb b/spec/rubocop/cop/gitlab/union_spec.rb
new file mode 100644
index 00000000000..5b06f30b25f
--- /dev/null
+++ b/spec/rubocop/cop/gitlab/union_spec.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require 'rubocop'
+require 'rubocop/rspec/support'
+require_relative '../../../../rubocop/cop/gitlab/union'
+
+describe RuboCop::Cop::Gitlab::Union do
+ include CopHelper
+
+ subject(:cop) { described_class.new }
+
+ it 'flags the use of Gitlab::SQL::Union.new' do
+ expect_offense(<<~SOURCE)
+ Gitlab::SQL::Union.new([foo])
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use the `FromUnion` concern, instead of using `Gitlab::SQL::Union` directly
+ SOURCE
+ end
+
+ it 'does not flag the use of Gitlab::SQL::Union in a spec' do
+ allow(cop).to receive(:in_spec?).and_return(true)
+
+ expect_no_offenses('Gitlab::SQL::Union.new([foo])')
+ end
+end
diff --git a/spec/serializers/commit_entity_spec.rb b/spec/serializers/commit_entity_spec.rb
index 04247c78549..35215e06f5f 100644
--- a/spec/serializers/commit_entity_spec.rb
+++ b/spec/serializers/commit_entity_spec.rb
@@ -51,4 +51,37 @@ describe CommitEntity do
it 'exposes gravatar url that belongs to author' do
expect(subject.fetch(:author_gravatar_url)).to match /gravatar/
end
+
+ context 'when type is not set' do
+ it 'does not expose extra properties' do
+ expect(subject).not_to include(:description_html)
+ expect(subject).not_to include(:title_html)
+ end
+ end
+
+ context 'when type is "full"' do
+ let(:entity) do
+ described_class.new(commit, request: request, type: :full)
+ end
+
+ it 'exposes extra properties' do
+ expect(subject).to include(:description_html)
+ expect(subject).to include(:title_html)
+ expect(subject.fetch(:description_html)).not_to be_nil
+ expect(subject.fetch(:title_html)).not_to be_nil
+ end
+ end
+
+ context 'when commit_url_params is set' do
+ let(:entity) do
+ params = { merge_request_iid: 3 }
+
+ described_class.new(commit, request: request, commit_url_params: params)
+ end
+
+ it 'adds commit_url_params to url and path' do
+ expect(subject[:commit_path]).to include "?merge_request_iid=3"
+ expect(subject[:commit_url]).to include "?merge_request_iid=3"
+ end
+ end
end
diff --git a/spec/services/auth/container_registry_authentication_service_spec.rb b/spec/services/auth/container_registry_authentication_service_spec.rb
index c7f88e45c84..f2e9799452a 100644
--- a/spec/services/auth/container_registry_authentication_service_spec.rb
+++ b/spec/services/auth/container_registry_authentication_service_spec.rb
@@ -145,7 +145,7 @@ describe Auth::ContainerRegistryAuthenticationService do
{ scopes: ["registry:catalog:*"] }
end
- context 'disallow browsing for users without Gitlab admin rights' do
+ context 'disallow browsing for users without GitLab admin rights' do
it_behaves_like 'an inaccessible'
it_behaves_like 'not a container repository factory'
end
diff --git a/spec/services/boards/issues/list_service_spec.rb b/spec/services/boards/issues/list_service_spec.rb
index 27a7bf0e605..010679b5360 100644
--- a/spec/services/boards/issues/list_service_spec.rb
+++ b/spec/services/boards/issues/list_service_spec.rb
@@ -24,7 +24,7 @@ describe Boards::Issues::ListService do
let!(:opened_issue1) { create(:labeled_issue, project: project, milestone: m1, title: 'Issue 1', labels: [bug]) }
let!(:opened_issue2) { create(:labeled_issue, project: project, milestone: m2, title: 'Issue 2', labels: [p2]) }
- let!(:reopened_issue1) { create(:issue, :opened, project: project, title: 'Issue 3' ) }
+ let!(:reopened_issue1) { create(:issue, :opened, project: project, title: 'Reopened Issue 1' ) }
let!(:list1_issue1) { create(:labeled_issue, project: project, milestone: m1, labels: [p2, development]) }
let!(:list1_issue2) { create(:labeled_issue, project: project, milestone: m2, labels: [development]) }
@@ -44,12 +44,19 @@ describe Boards::Issues::ListService do
end
it_behaves_like 'issues list service'
+
+ context 'when project is archived' do
+ let(:project) { create(:project, :archived) }
+
+ it_behaves_like 'issues list service'
+ end
end
context 'when parent is a group' do
let(:user) { create(:user) }
let(:project) { create(:project, :empty_repo, namespace: group) }
let(:project1) { create(:project, :empty_repo, namespace: group) }
+ let(:project_archived) { create(:project, :empty_repo, :archived, namespace: group) }
let(:m1) { create(:milestone, group: group) }
let(:m2) { create(:milestone, group: group) }
@@ -77,7 +84,8 @@ describe Boards::Issues::ListService do
let!(:opened_issue1) { create(:labeled_issue, project: project, milestone: m1, title: 'Issue 1', labels: [bug]) }
let!(:opened_issue2) { create(:labeled_issue, project: project, milestone: m2, title: 'Issue 2', labels: [p2, p2_project]) }
- let!(:reopened_issue1) { create(:issue, state: 'opened', project: project, title: 'Issue 3', closed_at: Time.now ) }
+ let!(:opened_issue3) { create(:labeled_issue, project: project_archived, milestone: m1, title: 'Issue 3', labels: [bug]) }
+ let!(:reopened_issue1) { create(:issue, state: 'opened', project: project, title: 'Reopened Issue 1', closed_at: Time.now ) }
let!(:list1_issue1) { create(:labeled_issue, project: project, milestone: m1, labels: [p2, p2_project, development]) }
let!(:list1_issue2) { create(:labeled_issue, project: project, milestone: m2, labels: [development]) }
diff --git a/spec/services/ci/fetch_kubernetes_token_service_spec.rb b/spec/services/ci/fetch_kubernetes_token_service_spec.rb
deleted file mode 100644
index 1d05c9671a9..00000000000
--- a/spec/services/ci/fetch_kubernetes_token_service_spec.rb
+++ /dev/null
@@ -1,64 +0,0 @@
-require 'spec_helper'
-
-describe Ci::FetchKubernetesTokenService do
- describe '#execute' do
- subject { described_class.new(api_url, ca_pem, username, password).execute }
-
- let(:api_url) { 'http://111.111.111.111' }
- let(:ca_pem) { '' }
- let(:username) { 'admin' }
- let(:password) { 'xxx' }
-
- context 'when params correct' do
- let(:token) { 'xxx.token.xxx' }
-
- let(:secrets_json) do
- [
- {
- 'metadata': {
- name: metadata_name
- },
- 'data': {
- 'token': Base64.encode64(token)
- }
- }
- ]
- end
-
- before do
- allow_any_instance_of(Kubeclient::Client)
- .to receive(:get_secrets).and_return(secrets_json)
- end
-
- context 'when default-token exists' do
- let(:metadata_name) { 'default-token-123' }
-
- it { is_expected.to eq(token) }
- end
-
- context 'when default-token does not exist' do
- let(:metadata_name) { 'another-token-123' }
-
- it { is_expected.to be_nil }
- end
- end
-
- context 'when api_url is nil' do
- let(:api_url) { nil }
-
- it { expect { subject }.to raise_error("Incomplete settings") }
- end
-
- context 'when username is nil' do
- let(:username) { nil }
-
- it { expect { subject }.to raise_error("Incomplete settings") }
- end
-
- context 'when password is nil' do
- let(:password) { nil }
-
- it { expect { subject }.to raise_error("Incomplete settings") }
- end
- end
-end
diff --git a/spec/services/ci/retry_build_service_spec.rb b/spec/services/ci/retry_build_service_spec.rb
index 18d52082399..951c0b16a68 100644
--- a/spec/services/ci/retry_build_service_spec.rb
+++ b/spec/services/ci/retry_build_service_spec.rb
@@ -24,7 +24,9 @@ describe Ci::RetryBuildService do
artifacts_file artifacts_metadata artifacts_size created_at
updated_at started_at finished_at queued_at erased_by
erased_at auto_canceled_by job_artifacts job_artifacts_archive
- job_artifacts_metadata job_artifacts_trace job_artifacts_junit].freeze
+ job_artifacts_metadata job_artifacts_trace job_artifacts_junit
+ job_artifacts_sast job_artifacts_dependency_scanning
+ job_artifacts_container_scanning job_artifacts_dast].freeze
IGNORE_ACCESSORS =
%i[type lock_version target_url base_tags trace_sections
@@ -38,9 +40,8 @@ describe Ci::RetryBuildService do
let(:another_pipeline) { create(:ci_empty_pipeline, project: project) }
let(:build) do
- create(:ci_build, :failed, :artifacts, :test_reports, :expired, :erased,
- :queued, :coverage, :tags, :allowed_to_fail, :on_tag,
- :triggered, :trace_artifact, :teardown_environment,
+ create(:ci_build, :failed, :expired, :erased, :queued, :coverage, :tags,
+ :allowed_to_fail, :on_tag, :triggered, :teardown_environment,
description: 'my-job', stage: 'test', stage_id: stage.id,
pipeline: pipeline, auto_canceled_by: another_pipeline)
end
@@ -50,6 +51,15 @@ describe Ci::RetryBuildService do
# can reset one of the fields when assigning another. We plan to deprecate
# and remove legacy `stage` column in the future.
build.update(stage: 'test', stage_id: stage.id)
+
+ # Make sure we have one instance for every possible job_artifact_X
+ # associations to check they are correctly rejected on build duplication.
+ Ci::JobArtifact::TYPE_AND_FORMAT_PAIRS.each do |file_type, file_format|
+ create(:ci_job_artifact, file_format,
+ file_type: file_type, job: build, expire_at: build.artifacts_expire_at)
+ end
+
+ build.reload
end
describe 'clone accessors' do
diff --git a/spec/services/clusters/gcp/finalize_creation_service_spec.rb b/spec/services/clusters/gcp/finalize_creation_service_spec.rb
index 0cf91307589..0f484222228 100644
--- a/spec/services/clusters/gcp/finalize_creation_service_spec.rb
+++ b/spec/services/clusters/gcp/finalize_creation_service_spec.rb
@@ -12,9 +12,11 @@ describe Clusters::Gcp::FinalizeCreationService do
let(:zone) { provider.zone }
let(:cluster_name) { cluster.name }
+ subject { described_class.new.execute(provider) }
+
shared_examples 'success' do
it 'configures provider and kubernetes' do
- described_class.new.execute(provider)
+ subject
expect(provider).to be_created
end
@@ -22,7 +24,7 @@ describe Clusters::Gcp::FinalizeCreationService do
shared_examples 'error' do
it 'sets an error to provider object' do
- described_class.new.execute(provider)
+ subject
expect(provider.reload).to be_errored
end
@@ -33,6 +35,7 @@ describe Clusters::Gcp::FinalizeCreationService do
let(:api_url) { 'https://' + endpoint }
let(:username) { 'sample-username' }
let(:password) { 'sample-password' }
+ let(:secret_name) { 'gitlab-token' }
before do
stub_cloud_platform_get_zone_cluster(
@@ -43,60 +46,102 @@ describe Clusters::Gcp::FinalizeCreationService do
password: password
}
)
-
- stub_kubeclient_discover(api_url)
end
- context 'when suceeded to fetch kuberenetes token' do
- let(:token) { 'sample-token' }
-
+ context 'service account and token created' do
before do
- stub_kubeclient_get_secrets(
- api_url,
- {
- token: Base64.encode64(token)
- } )
+ stub_kubeclient_discover(api_url)
+ stub_kubeclient_create_service_account(api_url)
+ stub_kubeclient_create_secret(api_url)
end
- it_behaves_like 'success'
+ shared_context 'kubernetes token successfully fetched' do
+ let(:token) { 'sample-token' }
+
+ before do
+ stub_kubeclient_get_secret(
+ api_url,
+ {
+ metadata_name: secret_name,
+ token: Base64.encode64(token)
+ } )
+ end
+ end
+
+ context 'provider legacy_abac is enabled' do
+ include_context 'kubernetes token successfully fetched'
+
+ it_behaves_like 'success'
- it 'has corresponded data' do
- described_class.new.execute(provider)
- cluster.reload
- provider.reload
- platform.reload
+ it 'properly configures database models' do
+ subject
- expect(provider.endpoint).to eq(endpoint)
- expect(platform.api_url).to eq(api_url)
- expect(platform.ca_cert).to eq(Base64.decode64(load_sample_cert))
- expect(platform.username).to eq(username)
- expect(platform.password).to eq(password)
- expect(platform.token).to eq(token)
+ cluster.reload
+
+ expect(provider.endpoint).to eq(endpoint)
+ expect(platform.api_url).to eq(api_url)
+ expect(platform.ca_cert).to eq(Base64.decode64(load_sample_cert))
+ expect(platform.username).to eq(username)
+ expect(platform.password).to eq(password)
+ expect(platform).to be_abac
+ expect(platform.authorization_type).to eq('abac')
+ expect(platform.token).to eq(token)
+ end
end
- end
- context 'when default-token is not found' do
- before do
- stub_kubeclient_get_secrets(api_url, metadata_name: 'aaaa')
+ context 'provider legacy_abac is disabled' do
+ before do
+ provider.legacy_abac = false
+ end
+
+ include_context 'kubernetes token successfully fetched'
+
+ context 'cluster role binding created' do
+ before do
+ stub_kubeclient_create_cluster_role_binding(api_url)
+ end
+
+ it_behaves_like 'success'
+
+ it 'properly configures database models' do
+ subject
+
+ cluster.reload
+
+ expect(provider.endpoint).to eq(endpoint)
+ expect(platform.api_url).to eq(api_url)
+ expect(platform.ca_cert).to eq(Base64.decode64(load_sample_cert))
+ expect(platform.username).to eq(username)
+ expect(platform.password).to eq(password)
+ expect(platform).to be_rbac
+ expect(platform.token).to eq(token)
+ end
+ end
end
- it_behaves_like 'error'
- end
+ context 'when token is empty' do
+ before do
+ stub_kubeclient_get_secret(api_url, token: '', metadata_name: secret_name)
+ end
- context 'when token is empty' do
- before do
- stub_kubeclient_get_secrets(api_url, token: '')
+ it_behaves_like 'error'
end
- it_behaves_like 'error'
- end
+ context 'when failed to fetch kubernetes token' do
+ before do
+ stub_kubeclient_get_secret_error(api_url, secret_name)
+ end
- context 'when failed to fetch kuberenetes token' do
- before do
- stub_kubeclient_get_secrets_error(api_url)
+ it_behaves_like 'error'
end
- it_behaves_like 'error'
+ context 'when service account fails to create' do
+ before do
+ stub_kubeclient_create_service_account_error(api_url)
+ end
+
+ it_behaves_like 'error'
+ end
end
end
diff --git a/spec/services/clusters/gcp/kubernetes/create_service_account_service_spec.rb b/spec/services/clusters/gcp/kubernetes/create_service_account_service_spec.rb
new file mode 100644
index 00000000000..065d021db5e
--- /dev/null
+++ b/spec/services/clusters/gcp/kubernetes/create_service_account_service_spec.rb
@@ -0,0 +1,96 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Clusters::Gcp::Kubernetes::CreateServiceAccountService do
+ include KubernetesHelpers
+
+ let(:service) { described_class.new(kubeclient, rbac: rbac) }
+
+ describe '#execute' do
+ let(:rbac) { false }
+ let(:api_url) { 'http://111.111.111.111' }
+ let(:username) { 'admin' }
+ let(:password) { 'xxx' }
+
+ let(:kubeclient) do
+ Gitlab::Kubernetes::KubeClient.new(
+ api_url,
+ ['api', 'apis/rbac.authorization.k8s.io'],
+ auth_options: { username: username, password: password }
+ )
+ end
+
+ subject { service.execute }
+
+ context 'when params are correct' do
+ before do
+ stub_kubeclient_discover(api_url)
+ stub_kubeclient_create_service_account(api_url)
+ stub_kubeclient_create_secret(api_url)
+ end
+
+ shared_examples 'creates service account and token' do
+ it 'creates a kubernetes service account' do
+ subject
+
+ expect(WebMock).to have_requested(:post, api_url + '/api/v1/namespaces/default/serviceaccounts').with(
+ body: hash_including(
+ kind: 'ServiceAccount',
+ metadata: { name: 'gitlab', namespace: 'default' }
+ )
+ )
+ end
+
+ it 'creates a kubernetes secret of type ServiceAccountToken' do
+ subject
+
+ expect(WebMock).to have_requested(:post, api_url + '/api/v1/namespaces/default/secrets').with(
+ body: hash_including(
+ kind: 'Secret',
+ metadata: {
+ name: 'gitlab-token',
+ namespace: 'default',
+ annotations: {
+ 'kubernetes.io/service-account.name': 'gitlab'
+ }
+ },
+ type: 'kubernetes.io/service-account-token'
+ )
+ )
+ end
+ end
+
+ context 'abac enabled cluster' do
+ it_behaves_like 'creates service account and token'
+ end
+
+ context 'rbac enabled cluster' do
+ let(:rbac) { true }
+
+ before do
+ stub_kubeclient_create_cluster_role_binding(api_url)
+ end
+
+ it_behaves_like 'creates service account and token'
+
+ it 'creates a kubernetes cluster role binding' do
+ subject
+
+ expect(WebMock).to have_requested(:post, api_url + '/apis/rbac.authorization.k8s.io/v1/clusterrolebindings').with(
+ body: hash_including(
+ kind: 'ClusterRoleBinding',
+ metadata: { name: 'gitlab-admin' },
+ roleRef: {
+ apiGroup: 'rbac.authorization.k8s.io',
+ kind: 'ClusterRole',
+ name: 'cluster-admin'
+ },
+ subjects: [{ kind: 'ServiceAccount', namespace: 'default', name: 'gitlab' }]
+ )
+ )
+ end
+ end
+ end
+ end
+end
diff --git a/spec/services/clusters/gcp/kubernetes/fetch_kubernetes_token_service_spec.rb b/spec/services/clusters/gcp/kubernetes/fetch_kubernetes_token_service_spec.rb
new file mode 100644
index 00000000000..c543de21d5b
--- /dev/null
+++ b/spec/services/clusters/gcp/kubernetes/fetch_kubernetes_token_service_spec.rb
@@ -0,0 +1,60 @@
+# frozen_string_literal: true
+
+require 'fast_spec_helper'
+
+describe Clusters::Gcp::Kubernetes::FetchKubernetesTokenService do
+ describe '#execute' do
+ let(:api_url) { 'http://111.111.111.111' }
+ let(:username) { 'admin' }
+ let(:password) { 'xxx' }
+
+ let(:kubeclient) do
+ Gitlab::Kubernetes::KubeClient.new(
+ api_url,
+ ['api', 'apis/rbac.authorization.k8s.io'],
+ auth_options: { username: username, password: password }
+ )
+ end
+
+ subject { described_class.new(kubeclient).execute }
+
+ context 'when params correct' do
+ let(:decoded_token) { 'xxx.token.xxx' }
+ let(:token) { Base64.encode64(decoded_token) }
+
+ let(:secret_json) do
+ {
+ 'metadata': {
+ name: 'gitlab-token'
+ },
+ 'data': {
+ 'token': token
+ }
+ }
+ end
+
+ before do
+ allow_any_instance_of(Kubeclient::Client)
+ .to receive(:get_secret).and_return(secret_json)
+ end
+
+ context 'when gitlab-token exists' do
+ let(:metadata_name) { 'gitlab-token' }
+
+ it { is_expected.to eq(decoded_token) }
+ end
+
+ context 'when gitlab-token does not exist' do
+ let(:secret_json) { {} }
+
+ it { is_expected.to be_nil }
+ end
+
+ context 'when token is nil' do
+ let(:token) { nil }
+
+ it { is_expected.to be_nil }
+ end
+ end
+ end
+end
diff --git a/spec/services/files/create_service_spec.rb b/spec/services/files/create_service_spec.rb
index 30d94e4318d..751b7160276 100644
--- a/spec/services/files/create_service_spec.rb
+++ b/spec/services/files/create_service_spec.rb
@@ -3,7 +3,7 @@ require "spec_helper"
describe Files::CreateService do
let(:project) { create(:project, :repository) }
let(:repository) { project.repository }
- let(:user) { create(:user) }
+ let(:user) { create(:user, :commit_email) }
let(:file_content) { 'Test file content' }
let(:branch_name) { project.default_branch }
let(:start_branch) { branch_name }
@@ -20,6 +20,8 @@ describe Files::CreateService do
}
end
+ let(:commit) { repository.head_commit }
+
subject { described_class.new(project, user, commit_params) }
before do
@@ -75,4 +77,16 @@ describe Files::CreateService do
end
end
end
+
+ context 'commit attribute' do
+ let(:file_path) { 'test-commit-attributes.txt' }
+
+ it 'uses the commit email' do
+ subject.execute
+
+ expect(user.commit_email).not_to eq(user.email)
+ expect(commit.author_email).to eq(user.commit_email)
+ expect(commit.committer_email).to eq(user.commit_email)
+ end
+ end
end
diff --git a/spec/services/files/delete_service_spec.rb b/spec/services/files/delete_service_spec.rb
index 73566afe8c8..309802ce733 100644
--- a/spec/services/files/delete_service_spec.rb
+++ b/spec/services/files/delete_service_spec.rb
@@ -4,10 +4,11 @@ describe Files::DeleteService do
subject { described_class.new(project, user, commit_params) }
let(:project) { create(:project, :repository) }
- let(:user) { create(:user) }
+ let(:user) { create(:user, :commit_email) }
let(:file_path) { 'files/ruby/popen.rb' }
let(:branch_name) { project.default_branch }
let(:last_commit_sha) { nil }
+ let(:commit) { project.repository.head_commit }
let(:commit_params) do
{
@@ -34,6 +35,14 @@ describe Files::DeleteService do
expect(blob).to be_nil
end
+
+ it 'uses the commit email' do
+ subject.execute
+
+ expect(user.commit_email).not_to eq(user.email)
+ expect(commit.author_email).to eq(user.commit_email)
+ expect(commit.committer_email).to eq(user.commit_email)
+ end
end
before do
diff --git a/spec/services/files/multi_service_spec.rb b/spec/services/files/multi_service_spec.rb
index 3bdedaf3770..5f3c8e82715 100644
--- a/spec/services/files/multi_service_spec.rb
+++ b/spec/services/files/multi_service_spec.rb
@@ -11,6 +11,7 @@ describe Files::MultiService do
let(:new_file_path) { 'files/ruby/popen.rb' }
let(:file_content) { 'New content' }
let(:action) { 'update' }
+ let(:commit_message) { 'Update File' }
let!(:original_commit_id) do
Gitlab::Git::Commit.last_for_path(project.repository, branch_name, original_file_path).sha
@@ -30,7 +31,7 @@ describe Files::MultiService do
let(:commit_params) do
{
- commit_message: "Update File",
+ commit_message: commit_message,
branch_name: branch_name,
start_branch: branch_name,
actions: actions
@@ -84,6 +85,39 @@ describe Files::MultiService do
end
end
+ describe 'changing execute_filemode of a file' do
+ let(:commit_message) { 'Chmod +x file' }
+ let(:file_path) { original_file_path }
+ let(:default_action) do
+ {
+ action: 'chmod',
+ file_path: file_path,
+ execute_filemode: true
+ }
+ end
+
+ it 'accepts the commit' do
+ results = subject.execute
+
+ expect(results[:status]).to eq(:success)
+ end
+
+ it 'updates the execute_filemode of the file' do
+ expect { subject.execute }.to change { repository.blob_at_branch(branch_name, file_path).mode }.from('100644').to('100755')
+ end
+
+ context "when the file doesn't exists" do
+ let(:file_path) { 'files/wrong_path.rb' }
+
+ it 'rejects the commit' do
+ results = subject.execute
+
+ expect(results[:status]).to eq(:error)
+ expect(results[:message]).to eq("A file with this name doesn't exist")
+ end
+ end
+ end
+
context 'when moving a file' do
let(:action) { 'move' }
let(:new_file_path) { 'files/ruby/new_popen.rb' }
diff --git a/spec/services/files/update_service_spec.rb b/spec/services/files/update_service_spec.rb
index e01fe487ffa..23db35c2418 100644
--- a/spec/services/files/update_service_spec.rb
+++ b/spec/services/files/update_service_spec.rb
@@ -4,11 +4,12 @@ describe Files::UpdateService do
subject { described_class.new(project, user, commit_params) }
let(:project) { create(:project, :repository) }
- let(:user) { create(:user) }
+ let(:user) { create(:user, :commit_email) }
let(:file_path) { 'files/ruby/popen.rb' }
let(:new_contents) { 'New Content' }
let(:branch_name) { project.default_branch }
let(:last_commit_sha) { nil }
+ let(:commit) { project.repository.commit }
let(:commit_params) do
{
@@ -54,6 +55,14 @@ describe Files::UpdateService do
expect(results.data).to eq(new_contents)
end
+
+ it 'uses the commit email' do
+ subject.execute
+
+ expect(user.commit_email).not_to eq(user.email)
+ expect(commit.author_email).to eq(user.commit_email)
+ expect(commit.committer_email).to eq(user.commit_email)
+ end
end
context "when the last_commit_sha is not supplied" do
diff --git a/spec/services/git_push_service_spec.rb b/spec/services/git_push_service_spec.rb
index d4528256640..45ef26aebbd 100644
--- a/spec/services/git_push_service_spec.rb
+++ b/spec/services/git_push_service_spec.rb
@@ -246,13 +246,15 @@ describe GitPushService, services: true do
describe 'system hooks' do
let!(:push_data) { push_data_from_service(project, user, oldrev, newrev, ref) }
- let(:system_hooks_service) { SystemHooksService.new }
+ let!(:system_hooks_service) { SystemHooksService.new }
it "sends a system hook after pushing a branch" do
- expect(SystemHooksService).to receive(:new).and_return(system_hooks_service)
- expect(system_hooks_service).to receive(:execute_hooks).with(push_data, :push_hooks)
+ allow(SystemHooksService).to receive(:new).and_return(system_hooks_service)
+ allow(system_hooks_service).to receive(:execute_hooks)
execute_service(project, user, oldrev, newrev, ref)
+
+ expect(system_hooks_service).to have_received(:execute_hooks).with(push_data, :push_hooks)
end
end
end
diff --git a/spec/services/groups/destroy_service_spec.rb b/spec/services/groups/destroy_service_spec.rb
index 97a88b5d697..d80d0f5a8a8 100644
--- a/spec/services/groups/destroy_service_spec.rb
+++ b/spec/services/groups/destroy_service_spec.rb
@@ -35,14 +35,6 @@ 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/groups/transfer_service_spec.rb b/spec/services/groups/transfer_service_spec.rb
index 999677cfaaa..d71ccfb4334 100644
--- a/spec/services/groups/transfer_service_spec.rb
+++ b/spec/services/groups/transfer_service_spec.rb
@@ -22,7 +22,7 @@ describe Groups::TransferService, :postgresql do
end
end
- context "when there's an exception on Gitlab shell directories" do
+ context "when there's an exception on GitLab shell directories" do
let(:new_parent_group) { create(:group, :public) }
before do
diff --git a/spec/services/merge_requests/rebase_service_spec.rb b/spec/services/merge_requests/rebase_service_spec.rb
index 2703da7ae44..427a2d63a88 100644
--- a/spec/services/merge_requests/rebase_service_spec.rb
+++ b/spec/services/merge_requests/rebase_service_spec.rb
@@ -87,7 +87,7 @@ describe MergeRequests::RebaseService do
expect(merge_request.reload.rebase_commit_sha).to eq(head_sha)
end
- it 'logs correct author and commiter' do
+ it 'logs correct author and committer' do
head_commit = merge_request.source_project.repository.commit(merge_request.source_branch)
expect(head_commit.author_email).to eq('dmitriy.zaporozhets@gmail.com')
diff --git a/spec/services/notes/build_service_spec.rb b/spec/services/notes/build_service_spec.rb
index 6e1c1fe6c02..ff85c261cd4 100644
--- a/spec/services/notes/build_service_spec.rb
+++ b/spec/services/notes/build_service_spec.rb
@@ -4,6 +4,8 @@ describe Notes::BuildService do
let(:note) { create(:discussion_note_on_issue) }
let(:project) { note.project }
let(:author) { note.author }
+ let(:merge_request) { create(:merge_request, source_project: project) }
+ let(:mr_note) { create(:discussion_note_on_merge_request, noteable: merge_request, project: project, author: author) }
describe '#execute' do
context 'when in_reply_to_discussion_id is specified' do
@@ -12,6 +14,19 @@ describe Notes::BuildService do
new_note = described_class.new(project, author, note: 'Test', in_reply_to_discussion_id: note.discussion_id).execute
expect(new_note).to be_valid
expect(new_note.in_reply_to?(note)).to be_truthy
+ expect(new_note.resolved?).to be_falsey
+ end
+
+ context 'when discussion is resolved' do
+ before do
+ mr_note.resolve!(author)
+ end
+
+ it 'resolves the note' do
+ new_note = described_class.new(project, author, note: 'Test', in_reply_to_discussion_id: mr_note.discussion_id).execute
+ expect(new_note).to be_valid
+ expect(new_note.resolved?).to be_truthy
+ end
end
end
diff --git a/spec/services/projects/container_repository/destroy_service_spec.rb b/spec/services/projects/container_repository/destroy_service_spec.rb
index 307ccc88865..affcc66d2bb 100644
--- a/spec/services/projects/container_repository/destroy_service_spec.rb
+++ b/spec/services/projects/container_repository/destroy_service_spec.rb
@@ -33,6 +33,7 @@ describe Projects::ContainerRepository::DestroyService do
end
it 'deletes the repository' do
+ expect(repository).to receive(:delete_tags!).and_call_original
expect { described_class.new(project, user).execute(repository) }.to change { ContainerRepository.all.count }.by(-1)
end
end
diff --git a/spec/services/projects/destroy_service_spec.rb b/spec/services/projects/destroy_service_spec.rb
index e428808ab68..beff499f2be 100644
--- a/spec/services/projects/destroy_service_spec.rb
+++ b/spec/services/projects/destroy_service_spec.rb
@@ -204,7 +204,7 @@ describe Projects::DestroyService do
context 'when image repository deletion fails' do
it 'raises an exception' do
expect_any_instance_of(ContainerRepository)
- .to receive(:delete_tags!).and_return(false)
+ .to receive(:delete_tags!).and_raise(RuntimeError)
expect(destroy_project(project, user)).to be false
end
diff --git a/spec/services/projects/update_remote_mirror_service_spec.rb b/spec/services/projects/update_remote_mirror_service_spec.rb
index 56a36432462..cd903bfe8a5 100644
--- a/spec/services/projects/update_remote_mirror_service_spec.rb
+++ b/spec/services/projects/update_remote_mirror_service_spec.rb
@@ -17,7 +17,6 @@ describe Projects::UpdateRemoteMirrorService do
it "ensures the remote exists" do
stub_fetch_remote(project, remote_name: remote_name)
- stub_find_remote_root_ref(project, remote_name: remote_name)
expect(remote_mirror).to receive(:ensure_remote!)
@@ -25,8 +24,6 @@ describe Projects::UpdateRemoteMirrorService do
end
it "fetches the remote repository" do
- stub_find_remote_root_ref(project, remote_name: remote_name)
-
expect(project.repository)
.to receive(:fetch_remote)
.with(remote_mirror.remote_name, no_tags: true)
@@ -34,26 +31,8 @@ describe Projects::UpdateRemoteMirrorService do
service.execute(remote_mirror)
end
- it "updates the default branch when HEAD has changed" do
- stub_fetch_remote(project, remote_name: remote_name)
- stub_find_remote_root_ref(project, remote_name: remote_name, ref: "existing-branch")
-
- expect { service.execute(remote_mirror) }
- .to change { project.default_branch }
- .from("master")
- .to("existing-branch")
- end
-
- it "does not update the default branch when HEAD does not change" do
- stub_fetch_remote(project, remote_name: remote_name)
- stub_find_remote_root_ref(project, remote_name: remote_name, ref: "master")
-
- expect { service.execute(remote_mirror) }.not_to change { project.default_branch }
- end
-
it "returns success when updated succeeds" do
stub_fetch_remote(project, remote_name: remote_name)
- stub_find_remote_root_ref(project, remote_name: remote_name)
result = service.execute(remote_mirror)
@@ -63,7 +42,6 @@ describe Projects::UpdateRemoteMirrorService do
context 'when syncing all branches' do
it "push all the branches the first time" do
stub_fetch_remote(project, remote_name: remote_name)
- stub_find_remote_root_ref(project, remote_name: remote_name)
expect(remote_mirror).to receive(:update_repository).with({})
@@ -74,7 +52,6 @@ describe Projects::UpdateRemoteMirrorService do
context 'when only syncing protected branches' do
it "sync updated protected branches" do
stub_fetch_remote(project, remote_name: remote_name)
- stub_find_remote_root_ref(project, remote_name: remote_name)
protected_branch = create_protected_branch(project)
remote_mirror.only_protected_branches = true
@@ -92,13 +69,6 @@ describe Projects::UpdateRemoteMirrorService do
end
end
- def stub_find_remote_root_ref(project, ref: 'master', remote_name:)
- allow(project.repository)
- .to receive(:find_remote_root_ref)
- .with(remote_name)
- .and_return(ref)
- end
-
def stub_fetch_remote(project, remote_name:)
allow(project.repository)
.to receive(:fetch_remote)
diff --git a/spec/services/quick_actions/interpret_service_spec.rb b/spec/services/quick_actions/interpret_service_spec.rb
index 06cad9c00d2..ac0ca1f33a5 100644
--- a/spec/services/quick_actions/interpret_service_spec.rb
+++ b/spec/services/quick_actions/interpret_service_spec.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
require 'spec_helper'
describe QuickActions::InterpretService do
@@ -863,6 +865,13 @@ describe QuickActions::InterpretService do
let(:source_issuable) { create(:labeled_issue, project: project, labels: [inreview_label, todo_label]) }
let(:content) { "/copy_metadata #{source_issuable.to_reference}" }
+ let(:issuable) { build(:issue, project: project) }
+ end
+
+ it_behaves_like 'copy_metadata command' do
+ let(:source_issuable) { create(:labeled_issue, project: project, labels: [inreview_label, todo_label]) }
+
+ let(:content) { "/copy_metadata #{source_issuable.to_reference}" }
let(:issuable) { issue }
end
diff --git a/spec/support/helpers/kubernetes_helpers.rb b/spec/support/helpers/kubernetes_helpers.rb
index 994a2aaef90..c077ca9f15b 100644
--- a/spec/support/helpers/kubernetes_helpers.rb
+++ b/spec/support/helpers/kubernetes_helpers.rb
@@ -33,31 +33,49 @@ module KubernetesHelpers
WebMock.stub_request(:get, deployments_url).to_return(response || kube_deployments_response)
end
- def stub_kubeclient_get_secrets(api_url, **options)
- WebMock.stub_request(:get, api_url + '/api/v1/secrets')
- .to_return(kube_response(kube_v1_secrets_body(options)))
+ def stub_kubeclient_get_secret(api_url, namespace: 'default', **options)
+ options[:metadata_name] ||= "default-token-1"
+
+ WebMock.stub_request(:get, api_url + "/api/v1/namespaces/#{namespace}/secrets/#{options[:metadata_name]}")
+ .to_return(kube_response(kube_v1_secret_body(options)))
end
- def stub_kubeclient_get_secrets_error(api_url)
- WebMock.stub_request(:get, api_url + '/api/v1/secrets')
+ def stub_kubeclient_get_secret_error(api_url, name, namespace: 'default')
+ WebMock.stub_request(:get, api_url + "/api/v1/namespaces/#{namespace}/secrets/#{name}")
.to_return(status: [404, "Internal Server Error"])
end
- def kube_v1_secrets_body(**options)
+ def stub_kubeclient_create_service_account(api_url, namespace: 'default')
+ WebMock.stub_request(:post, api_url + "/api/v1/namespaces/#{namespace}/serviceaccounts")
+ .to_return(kube_response({}))
+ end
+
+ def stub_kubeclient_create_service_account_error(api_url, namespace: 'default')
+ WebMock.stub_request(:post, api_url + "/api/v1/namespaces/#{namespace}/serviceaccounts")
+ .to_return(status: [500, "Internal Server Error"])
+ end
+
+ def stub_kubeclient_create_secret(api_url, namespace: 'default')
+ WebMock.stub_request(:post, api_url + "/api/v1/namespaces/#{namespace}/secrets")
+ .to_return(kube_response({}))
+ end
+
+ def stub_kubeclient_create_cluster_role_binding(api_url)
+ WebMock.stub_request(:post, api_url + '/apis/rbac.authorization.k8s.io/v1/clusterrolebindings')
+ .to_return(kube_response({}))
+ end
+
+ def kube_v1_secret_body(**options)
{
"kind" => "SecretList",
"apiVersion": "v1",
- "items" => [
- {
- "metadata": {
- "name": options[:metadata_name] || "default-token-1",
- "namespace": "kube-system"
- },
- "data": {
- "token": options[:token] || Base64.encode64('token-sample-123')
- }
- }
- ]
+ "metadata": {
+ "name": options[:metadata_name] || "default-token-1",
+ "namespace": "kube-system"
+ },
+ "data": {
+ "token": options[:token] || Base64.encode64('token-sample-123')
+ }
}
end
@@ -68,6 +86,7 @@ module KubernetesHelpers
{ "name" => "pods", "namespaced" => true, "kind" => "Pod" },
{ "name" => "deployments", "namespaced" => true, "kind" => "Deployment" },
{ "name" => "secrets", "namespaced" => true, "kind" => "Secret" },
+ { "name" => "serviceaccounts", "namespaced" => true, "kind" => "ServiceAccount" },
{ "name" => "services", "namespaced" => true, "kind" => "Service" }
]
}
@@ -80,6 +99,7 @@ module KubernetesHelpers
{ "name" => "pods", "namespaced" => true, "kind" => "Pod" },
{ "name" => "deployments", "namespaced" => true, "kind" => "Deployment" },
{ "name" => "secrets", "namespaced" => true, "kind" => "Secret" },
+ { "name" => "serviceaccounts", "namespaced" => true, "kind" => "ServiceAccount" },
{ "name" => "services", "namespaced" => true, "kind" => "Service" }
]
}
diff --git a/spec/support/helpers/markdown_feature.rb b/spec/support/helpers/markdown_feature.rb
index 346f5b1cc4d..96401379cf0 100644
--- a/spec/support/helpers/markdown_feature.rb
+++ b/spec/support/helpers/markdown_feature.rb
@@ -10,6 +10,12 @@
class MarkdownFeature
include FactoryBot::Syntax::Methods
+ attr_reader :fixture_path
+
+ def initialize(fixture_path = Rails.root.join('spec/fixtures/markdown.md.erb'))
+ @fixture_path = fixture_path
+ end
+
def user
@user ||= create(:user)
end
@@ -122,7 +128,7 @@ class MarkdownFeature
end
def raw_markdown
- markdown = File.read(Rails.root.join('spec/fixtures/markdown.md.erb'))
+ markdown = File.read(fixture_path)
ERB.new(markdown).result(binding)
end
end
diff --git a/spec/support/helpers/migrations_helpers.rb b/spec/support/helpers/migrations_helpers.rb
index 0bc235701eb..0c35764ed9a 100644
--- a/spec/support/helpers/migrations_helpers.rb
+++ b/spec/support/helpers/migrations_helpers.rb
@@ -3,6 +3,10 @@ module MigrationsHelpers
Class.new(ActiveRecord::Base) do
self.table_name = name
self.inheritance_column = :_type_disabled
+
+ def self.name
+ table_name.singularize.camelcase
+ end
end
end
diff --git a/spec/support/helpers/test_env.rb b/spec/support/helpers/test_env.rb
index 8e8ec574edb..97875669d0e 100644
--- a/spec/support/helpers/test_env.rb
+++ b/spec/support/helpers/test_env.rb
@@ -85,7 +85,7 @@ module TestEnv
clean_test_path
- # Setup GitLab shell for test instance
+ # Set up GitLab shell for test instance
setup_gitlab_shell
setup_gitaly
@@ -367,7 +367,7 @@ module TestEnv
FileUtils.rm_rf(install_dir)
exit 1
ensure
- puts " #{component} setup in #{Time.now - start} seconds...\n"
+ puts " #{component} set up in #{Time.now - start} seconds...\n"
end
def ensure_component_dir_name_is_correct!(component, path)
diff --git a/spec/support/services/clusters/create_service_shared.rb b/spec/support/services/clusters/create_service_shared.rb
index 43a2fd05498..22f712f3fcf 100644
--- a/spec/support/services/clusters/create_service_shared.rb
+++ b/spec/support/services/clusters/create_service_shared.rb
@@ -7,7 +7,8 @@ shared_context 'valid cluster create params' do
gcp_project_id: 'gcp-project',
zone: 'us-central1-a',
num_nodes: 1,
- machine_type: 'machine_type-a'
+ machine_type: 'machine_type-a',
+ legacy_abac: 'true'
}
}
end
@@ -29,6 +30,10 @@ shared_context 'invalid cluster create params' do
end
shared_examples 'create cluster service success' do
+ before do
+ stub_feature_flags(rbac_clusters: false)
+ end
+
it 'creates a cluster object and performs a worker' do
expect(ClusterProvisionWorker).to receive(:perform_async)
@@ -44,6 +49,7 @@ shared_examples 'create cluster service success' do
expect(subject.provider.num_nodes).to eq(1)
expect(subject.provider.machine_type).to eq('machine_type-a')
expect(subject.provider.access_token).to eq(access_token)
+ expect(subject.provider).to be_legacy_abac
expect(subject.platform).to be_nil
end
end
diff --git a/spec/support/shared_examples/diff_file_collections.rb b/spec/support/shared_examples/diff_file_collections.rb
new file mode 100644
index 00000000000..55ce160add0
--- /dev/null
+++ b/spec/support/shared_examples/diff_file_collections.rb
@@ -0,0 +1,47 @@
+# frozen_string_literal: true
+
+shared_examples 'diff statistics' do |test_include_stats_flag: true|
+ def stub_stats_find_by_path(path, stats_mock)
+ expect_next_instance_of(Gitlab::Git::DiffStatsCollection) do |collection|
+ allow(collection).to receive(:find_by_path).and_call_original
+ expect(collection).to receive(:find_by_path).with(path).and_return(stats_mock)
+ end
+ end
+
+ context 'when should request diff stats' do
+ it 'Repository#diff_stats is called' do
+ subject = described_class.new(diffable, collection_default_args)
+
+ expect(diffable.project.repository)
+ .to receive(:diff_stats)
+ .with(diffable.diff_refs.base_sha, diffable.diff_refs.head_sha)
+ .and_call_original
+
+ subject.diff_files
+ end
+
+ it 'Gitlab::Diff::File is initialized with diff stats' do
+ subject = described_class.new(diffable, collection_default_args)
+
+ stats_mock = double(Gitaly::DiffStats, path: '.gitignore', additions: 758, deletions: 120)
+ stub_stats_find_by_path(stub_path, stats_mock)
+
+ diff_file = subject.diff_files.find { |file| file.new_path == stub_path }
+
+ expect(diff_file.added_lines).to eq(stats_mock.additions)
+ expect(diff_file.removed_lines).to eq(stats_mock.deletions)
+ end
+ end
+
+ context 'when should not request diff stats' do
+ it 'Repository#diff_stats is not called' do
+ collection_default_args[:diff_options][:include_stats] = false
+
+ subject = described_class.new(diffable, collection_default_args)
+
+ expect(diffable.project.repository).not_to receive(:diff_stats)
+
+ subject.diff_files
+ end
+ end
+end
diff --git a/spec/tasks/gitlab/db_rake_spec.rb b/spec/tasks/gitlab/db_rake_spec.rb
index b81aea23306..5818892d56a 100644
--- a/spec/tasks/gitlab/db_rake_spec.rb
+++ b/spec/tasks/gitlab/db_rake_spec.rb
@@ -61,6 +61,39 @@ describe 'gitlab:db namespace rake task' do
expect(Rake::Task['db:migrate']).not_to receive(:invoke)
expect { run_rake_task('gitlab:db:configure') }.to raise_error(RuntimeError, 'error')
end
+
+ context 'SKIP_POST_DEPLOYMENT_MIGRATIONS environment variable set' do
+ let(:rails_paths) { { 'db' => ['db'], 'db/migrate' => ['db/migrate'] } }
+
+ before do
+ allow(ENV).to receive(:[]).and_call_original
+ allow(ENV).to receive(:[]).with('SKIP_POST_DEPLOYMENT_MIGRATIONS').and_return true
+
+ # Our environment has already been loaded, so we need to pretend like post_migrations were not
+ allow(Rails.application.config).to receive(:paths).and_return(rails_paths)
+ allow(ActiveRecord::Migrator).to receive(:migrations_paths).and_return(rails_paths['db/migrate'].dup)
+ end
+
+ it 'adds post deployment migrations before schema load if the schema is not already loaded' do
+ allow(ActiveRecord::Base.connection).to receive(:tables).and_return([])
+ expect(Gitlab::Database).to receive(:add_post_migrate_path_to_rails).and_call_original
+ expect(Rake::Task['db:schema:load']).to receive(:invoke)
+ expect(Rake::Task['db:seed_fu']).to receive(:invoke)
+ expect(Rake::Task['db:migrate']).not_to receive(:invoke)
+ expect { run_rake_task('gitlab:db:configure') }.not_to raise_error
+ expect(rails_paths['db/migrate'].include?(File.join(Rails.root, 'db', 'post_migrate'))).to be(true)
+ end
+
+ it 'ignores post deployment migrations when schema has already been loaded' do
+ allow(ActiveRecord::Base.connection).to receive(:tables).and_return(%w[table1 table2])
+ expect(Rake::Task['db:migrate']).to receive(:invoke)
+ expect(Gitlab::Database).not_to receive(:add_post_migrate_path_to_rails)
+ expect(Rake::Task['db:schema:load']).not_to receive(:invoke)
+ expect(Rake::Task['db:seed_fu']).not_to receive(:invoke)
+ expect { run_rake_task('gitlab:db:configure') }.not_to raise_error
+ expect(rails_paths['db/migrate'].include?(File.join(Rails.root, 'db', 'post_migrate'))).to be(false)
+ end
+ end
end
def run_rake_task(task_name)
diff --git a/spec/tasks/gitlab/site_statistics_rake_spec.rb b/spec/tasks/gitlab/site_statistics_rake_spec.rb
index 20f0df65e63..c43ce25a540 100644
--- a/spec/tasks/gitlab/site_statistics_rake_spec.rb
+++ b/spec/tasks/gitlab/site_statistics_rake_spec.rb
@@ -6,7 +6,7 @@ describe 'rake gitlab:refresh_site_statistics' do
Rake.application.rake_require 'tasks/gitlab/site_statistics'
create(:project)
- SiteStatistic.fetch.update(repositories_count: 0, wikis_count: 0)
+ SiteStatistic.fetch.update(repositories_count: 0)
end
let(:task) { 'gitlab:refresh_site_statistics' }
@@ -15,10 +15,9 @@ describe 'rake gitlab:refresh_site_statistics' do
run_rake_task(task)
expect(SiteStatistic.fetch.repositories_count).to eq(1)
- expect(SiteStatistic.fetch.wikis_count).to eq(1)
end
it 'displays message listing counters' do
- expect { run_rake_task(task) }.to output(/Updating Site Statistics counters:.* Repositories\.\.\. OK!.* Wikis\.\.\. OK!/m).to_stdout
+ expect { run_rake_task(task) }.to output(/Updating Site Statistics counters:.* Repositories\.\.\. OK!/m).to_stdout
end
end
diff --git a/spec/validators/url_validator_spec.rb b/spec/validators/url_validator_spec.rb
index 93fe013d11c..ab6100509a6 100644
--- a/spec/validators/url_validator_spec.rb
+++ b/spec/validators/url_validator_spec.rb
@@ -24,6 +24,21 @@ describe UrlValidator do
expect(badge.errors.empty?).to be true
end
+
+ it 'strips urls' do
+ badge.link_url = "\n\r\n\nhttps://127.0.0.1\r\n\r\n\n\n\n"
+
+ # It's unusual for a validator to modify its arguments. Some extensions,
+ # such as attr_encrypted, freeze the string to signal that modifications
+ # will not be persisted, so freeze this string to ensure the scheme is
+ # compatible with them.
+ badge.link_url.freeze
+
+ subject
+
+ expect(badge.errors).to be_empty
+ expect(badge.link_url).to eq('https://127.0.0.1')
+ end
end
context 'when allow_localhost is set to false' do
diff --git a/spec/views/help/index.html.haml_spec.rb b/spec/views/help/index.html.haml_spec.rb
index 836d452304c..c8c9c4e773d 100644
--- a/spec/views/help/index.html.haml_spec.rb
+++ b/spec/views/help/index.html.haml_spec.rb
@@ -21,7 +21,7 @@ describe 'help/index' do
render
expect(rendered).to match '8.0.2'
- expect(rendered).to have_link('abcdefg', 'https://gitlab.com/gitlab-org/gitlab-ce/commits/abcdefg')
+ expect(rendered).to have_link('8.0.2', href: 'https://gitlab.com/gitlab-org/gitlab-ce/tags/v8.0.2')
end
end
@@ -29,7 +29,7 @@ describe 'help/index' do
it 'is visible to guests' do
render
- expect(rendered).to have_link(nil, help_instance_configuration_url)
+ expect(rendered).to have_link(nil, href: help_instance_configuration_url)
end
end
diff --git a/spec/views/projects/jobs/show.html.haml_spec.rb b/spec/views/projects/jobs/show.html.haml_spec.rb
index c93152b88e3..496646dc623 100644
--- a/spec/views/projects/jobs/show.html.haml_spec.rb
+++ b/spec/views/projects/jobs/show.html.haml_spec.rb
@@ -188,40 +188,4 @@ describe 'projects/jobs/show' do
expect(rendered).not_to have_link('New issue')
end
end
-
- context 'when incomplete trigger_request is used' do
- before do
- build.trigger_request = FactoryBot.build(:ci_trigger_request, trigger: nil)
- end
-
- it 'test should not render token block' do
- render
-
- expect(rendered).not_to have_content('Token')
- end
- end
-
- context 'when complete trigger_request is used' do
- before do
- build.trigger_request = FactoryBot.build(:ci_trigger_request)
- end
-
- it 'should render token' do
- render
-
- expect(rendered).to have_content('Token')
- expect(rendered).to have_content(build.trigger_request.trigger.short_token)
- end
- end
-
- describe 'commit title in sidebar' do
- let(:commit_title) { project.commit.title }
-
- it 'shows commit title and not show commit message' do
- render
-
- expect(rendered).to have_css('p.build-light-text.append-bottom-0',
- text: /\A\n#{Regexp.escape(commit_title)}\n\Z/)
- end
- end
end
diff --git a/vendor/gitlab-ci-yml/.gitlab-ci.yml b/vendor/gitlab-ci-yml/.gitlab-ci.yml
deleted file mode 100644
index e2a55163682..00000000000
--- a/vendor/gitlab-ci-yml/.gitlab-ci.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-image: ruby:2.4-alpine
-
-test:
- script: ./verify_templates.rb
diff --git a/vendor/gitlab-ci-yml/CONTRIBUTING.md b/vendor/gitlab-ci-yml/CONTRIBUTING.md
deleted file mode 100644
index d33a1f06f26..00000000000
--- a/vendor/gitlab-ci-yml/CONTRIBUTING.md
+++ /dev/null
@@ -1,46 +0,0 @@
-## Developer Certificate of Origin + License
-
-By contributing to GitLab B.V., You accept and agree to the following terms and
-conditions for Your present and future Contributions submitted to GitLab B.V.
-Except for the license granted herein to GitLab B.V. and recipients of software
-distributed by GitLab B.V., You reserve all right, title, and interest in and to
-Your Contributions. All Contributions are subject to the following DCO + License
-terms.
-
-[DCO + License](https://gitlab.com/gitlab-org/dco/blob/master/README.md)
-
-_This notice should stay as the first item in the CONTRIBUTING.md file._
-
-## Code of conduct
-
-As contributors and maintainers of this project, we pledge to respect all people
-who contribute through reporting issues, posting feature requests, updating
-documentation, submitting pull requests or patches, and other activities.
-
-We are committed to making participation in this project a harassment-free
-experience for everyone, regardless of level of experience, gender, gender
-identity and expression, sexual orientation, disability, personal appearance,
-body size, race, ethnicity, age, or religion.
-
-Examples of unacceptable behavior by participants include the use of sexual
-language or imagery, derogatory comments or personal attacks, trolling, public
-or private harassment, insults, or other unprofessional conduct.
-
-Project maintainers have the right and responsibility to remove, edit, or reject
-comments, commits, code, wiki edits, issues, and other contributions that are
-not aligned to this Code of Conduct. Project maintainers who do not follow the
-Code of Conduct may be removed from the project team.
-
-This code of conduct applies both within project spaces and in public spaces
-when an individual is representing the project or its community.
-
-Instances of abusive, harassing, or otherwise unacceptable behavior can be
-reported by emailing contact@gitlab.com.
-
-This Code of Conduct is adapted from the [Contributor Covenant][contributor-covenant], version 1.1.0,
-available at [http://contributor-covenant.org/version/1/1/0/](http://contributor-covenant.org/version/1/1/0/).
-
-[contributor-covenant]: http://contributor-covenant.org
-[individual-agreement]: https://docs.gitlab.com/ee/legal/individual_contributor_license_agreement.html
-[corporate-agreement]: https://docs.gitlab.com/ee/legal/corporate_contributor_license_agreement.html
-
diff --git a/vendor/gitlab-ci-yml/LICENSE b/vendor/gitlab-ci-yml/LICENSE
deleted file mode 100644
index 27a215686e7..00000000000
--- a/vendor/gitlab-ci-yml/LICENSE
+++ /dev/null
@@ -1,25 +0,0 @@
-Copyright (c) 2011-2017 GitLab B.V.
-
-With regard to the GitLab Software:
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
-
-For all third party components incorporated into the GitLab Software, those
-components are licensed under the original license provided by the owner of the
-applicable component.
diff --git a/vendor/licenses.csv b/vendor/licenses.csv
index 85b7d16db54..b36aabb9b3d 100644
--- a/vendor/licenses.csv
+++ b/vendor/licenses.csv
@@ -336,7 +336,6 @@ doorkeeper,4.3.2,MIT
doorkeeper-openid_connect,1.5.0,MIT
dot-prop,4.2.0,MIT
dropzone,4.2.0,MIT
-dropzonejs-rails,0.7.2,MIT
duplexer,0.1.1,MIT
duplexer3,0.1.4,New BSD
duplexify,3.5.3,MIT
diff --git a/yarn.lock b/yarn.lock
index fe4702f3a78..33849642705 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2,89 +2,171 @@
# yarn lockfile v1
-"@babel/code-frame@7.0.0-beta.44":
- version "7.0.0-beta.44"
- resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.0.0-beta.44.tgz#2a02643368de80916162be70865c97774f3adbd9"
+"@babel/code-frame@7.0.0-beta.51":
+ version "7.0.0-beta.51"
+ resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.0.0-beta.51.tgz#bd71d9b192af978df915829d39d4094456439a0c"
dependencies:
- "@babel/highlight" "7.0.0-beta.44"
+ "@babel/highlight" "7.0.0-beta.51"
-"@babel/generator@7.0.0-beta.44":
- version "7.0.0-beta.44"
- resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.0.0-beta.44.tgz#c7e67b9b5284afcf69b309b50d7d37f3e5033d42"
+"@babel/code-frame@^7.0.0":
+ version "7.0.0"
+ resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.0.0.tgz#06e2ab19bdb535385559aabb5ba59729482800f8"
+ dependencies:
+ "@babel/highlight" "^7.0.0"
+
+"@babel/generator@7.0.0-beta.51":
+ version "7.0.0-beta.51"
+ resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.0.0-beta.51.tgz#6c7575ffde761d07485e04baedc0392c6d9e30f6"
dependencies:
- "@babel/types" "7.0.0-beta.44"
+ "@babel/types" "7.0.0-beta.51"
jsesc "^2.5.1"
- lodash "^4.2.0"
+ lodash "^4.17.5"
source-map "^0.5.0"
trim-right "^1.0.1"
-"@babel/helper-function-name@7.0.0-beta.44":
- version "7.0.0-beta.44"
- resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.0.0-beta.44.tgz#e18552aaae2231100a6e485e03854bc3532d44dd"
+"@babel/generator@^7.0.0":
+ version "7.0.0"
+ resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.0.0.tgz#1efd58bffa951dc846449e58ce3a1d7f02d393aa"
+ dependencies:
+ "@babel/types" "^7.0.0"
+ jsesc "^2.5.1"
+ lodash "^4.17.10"
+ source-map "^0.5.0"
+ trim-right "^1.0.1"
+
+"@babel/helper-function-name@7.0.0-beta.51":
+ version "7.0.0-beta.51"
+ resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.0.0-beta.51.tgz#21b4874a227cf99ecafcc30a90302da5a2640561"
+ dependencies:
+ "@babel/helper-get-function-arity" "7.0.0-beta.51"
+ "@babel/template" "7.0.0-beta.51"
+ "@babel/types" "7.0.0-beta.51"
+
+"@babel/helper-function-name@^7.1.0":
+ version "7.1.0"
+ resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz#a0ceb01685f73355d4360c1247f582bfafc8ff53"
+ dependencies:
+ "@babel/helper-get-function-arity" "^7.0.0"
+ "@babel/template" "^7.1.0"
+ "@babel/types" "^7.0.0"
+
+"@babel/helper-get-function-arity@7.0.0-beta.51":
+ version "7.0.0-beta.51"
+ resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0-beta.51.tgz#3281b2d045af95c172ce91b20825d85ea4676411"
+ dependencies:
+ "@babel/types" "7.0.0-beta.51"
+
+"@babel/helper-get-function-arity@^7.0.0":
+ version "7.0.0"
+ resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz#83572d4320e2a4657263734113c42868b64e49c3"
dependencies:
- "@babel/helper-get-function-arity" "7.0.0-beta.44"
- "@babel/template" "7.0.0-beta.44"
- "@babel/types" "7.0.0-beta.44"
+ "@babel/types" "^7.0.0"
-"@babel/helper-get-function-arity@7.0.0-beta.44":
- version "7.0.0-beta.44"
- resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0-beta.44.tgz#d03ca6dd2b9f7b0b1e6b32c56c72836140db3a15"
+"@babel/helper-split-export-declaration@7.0.0-beta.51":
+ version "7.0.0-beta.51"
+ resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.0.0-beta.51.tgz#8a6c3f66c4d265352fc077484f9f6e80a51ab978"
dependencies:
- "@babel/types" "7.0.0-beta.44"
+ "@babel/types" "7.0.0-beta.51"
-"@babel/helper-split-export-declaration@7.0.0-beta.44":
- version "7.0.0-beta.44"
- resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.0.0-beta.44.tgz#c0b351735e0fbcb3822c8ad8db4e583b05ebd9dc"
+"@babel/helper-split-export-declaration@^7.0.0":
+ version "7.0.0"
+ resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.0.0.tgz#3aae285c0311c2ab095d997b8c9a94cad547d813"
dependencies:
- "@babel/types" "7.0.0-beta.44"
+ "@babel/types" "^7.0.0"
-"@babel/highlight@7.0.0-beta.44":
- version "7.0.0-beta.44"
- resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.0.0-beta.44.tgz#18c94ce543916a80553edcdcf681890b200747d5"
+"@babel/highlight@7.0.0-beta.51":
+ version "7.0.0-beta.51"
+ resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.0.0-beta.51.tgz#e8844ae25a1595ccfd42b89623b4376ca06d225d"
dependencies:
chalk "^2.0.0"
esutils "^2.0.2"
js-tokens "^3.0.0"
-"@babel/template@7.0.0-beta.44":
- version "7.0.0-beta.44"
- resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.0.0-beta.44.tgz#f8832f4fdcee5d59bf515e595fc5106c529b394f"
- dependencies:
- "@babel/code-frame" "7.0.0-beta.44"
- "@babel/types" "7.0.0-beta.44"
- babylon "7.0.0-beta.44"
- lodash "^4.2.0"
-
-"@babel/traverse@7.0.0-beta.44":
- version "7.0.0-beta.44"
- resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.0.0-beta.44.tgz#a970a2c45477ad18017e2e465a0606feee0d2966"
- dependencies:
- "@babel/code-frame" "7.0.0-beta.44"
- "@babel/generator" "7.0.0-beta.44"
- "@babel/helper-function-name" "7.0.0-beta.44"
- "@babel/helper-split-export-declaration" "7.0.0-beta.44"
- "@babel/types" "7.0.0-beta.44"
- babylon "7.0.0-beta.44"
+"@babel/highlight@^7.0.0":
+ version "7.0.0"
+ resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.0.0.tgz#f710c38c8d458e6dd9a201afb637fcb781ce99e4"
+ dependencies:
+ chalk "^2.0.0"
+ esutils "^2.0.2"
+ js-tokens "^4.0.0"
+
+"@babel/parser@7.0.0-beta.51":
+ version "7.0.0-beta.51"
+ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.0.0-beta.51.tgz#27cec2df409df60af58270ed8f6aa55409ea86f6"
+
+"@babel/parser@^7.0.0", "@babel/parser@^7.1.0":
+ version "7.1.0"
+ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.1.0.tgz#a7cd42cb3c12aec52e24375189a47b39759b783e"
+
+"@babel/template@7.0.0-beta.51":
+ version "7.0.0-beta.51"
+ resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.0.0-beta.51.tgz#9602a40aebcf357ae9677e2532ef5fc810f5fbff"
+ dependencies:
+ "@babel/code-frame" "7.0.0-beta.51"
+ "@babel/parser" "7.0.0-beta.51"
+ "@babel/types" "7.0.0-beta.51"
+ lodash "^4.17.5"
+
+"@babel/template@^7.1.0":
+ version "7.1.0"
+ resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.1.0.tgz#58cc9572e1bfe24fe1537fdf99d839d53e517e22"
+ dependencies:
+ "@babel/code-frame" "^7.0.0"
+ "@babel/parser" "^7.1.0"
+ "@babel/types" "^7.0.0"
+
+"@babel/traverse@7.0.0-beta.51":
+ version "7.0.0-beta.51"
+ resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.0.0-beta.51.tgz#981daf2cec347a6231d3aa1d9e1803b03aaaa4a8"
+ dependencies:
+ "@babel/code-frame" "7.0.0-beta.51"
+ "@babel/generator" "7.0.0-beta.51"
+ "@babel/helper-function-name" "7.0.0-beta.51"
+ "@babel/helper-split-export-declaration" "7.0.0-beta.51"
+ "@babel/parser" "7.0.0-beta.51"
+ "@babel/types" "7.0.0-beta.51"
debug "^3.1.0"
globals "^11.1.0"
invariant "^2.2.0"
- lodash "^4.2.0"
+ lodash "^4.17.5"
+
+"@babel/traverse@^7.0.0":
+ version "7.1.0"
+ resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.1.0.tgz#503ec6669387efd182c3888c4eec07bcc45d91b2"
+ dependencies:
+ "@babel/code-frame" "^7.0.0"
+ "@babel/generator" "^7.0.0"
+ "@babel/helper-function-name" "^7.1.0"
+ "@babel/helper-split-export-declaration" "^7.0.0"
+ "@babel/parser" "^7.1.0"
+ "@babel/types" "^7.0.0"
+ debug "^3.1.0"
+ globals "^11.1.0"
+ lodash "^4.17.10"
-"@babel/types@7.0.0-beta.44":
- version "7.0.0-beta.44"
- resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.0.0-beta.44.tgz#6b1b164591f77dec0a0342aca995f2d046b3a757"
+"@babel/types@7.0.0-beta.51":
+ version "7.0.0-beta.51"
+ resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.0.0-beta.51.tgz#d802b7b543b5836c778aa691797abf00f3d97ea9"
dependencies:
esutils "^2.0.2"
- lodash "^4.2.0"
+ lodash "^4.17.5"
+ to-fast-properties "^2.0.0"
+
+"@babel/types@^7.0.0":
+ version "7.0.0"
+ resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.0.0.tgz#6e191793d3c854d19c6749989e3bc55f0e962118"
+ dependencies:
+ esutils "^2.0.2"
+ lodash "^4.17.10"
to-fast-properties "^2.0.0"
"@gitlab-org/gitlab-svgs@^1.23.0", "@gitlab-org/gitlab-svgs@^1.29.0":
version "1.29.0"
resolved "https://registry.yarnpkg.com/@gitlab-org/gitlab-svgs/-/gitlab-svgs-1.29.0.tgz#03b65b513f9099bbda6ecf94d673a2952f8c6c70"
-"@gitlab-org/gitlab-ui@^1.5.0":
- version "1.5.0"
- resolved "https://registry.yarnpkg.com/@gitlab-org/gitlab-ui/-/gitlab-ui-1.5.0.tgz#320ba164ba8812ff64f94b1cae79a7b749f5bc03"
+"@gitlab-org/gitlab-ui@^1.7.1":
+ version "1.7.1"
+ resolved "https://registry.yarnpkg.com/@gitlab-org/gitlab-ui/-/gitlab-ui-1.7.1.tgz#e9cce86cb7e34311405e705c1de674276b453f17"
dependencies:
"@gitlab-org/gitlab-svgs" "^1.23.0"
bootstrap-vue "^2.0.0-rc.11"
@@ -122,9 +204,9 @@
version "5.0.0"
resolved "https://registry.yarnpkg.com/@types/parse5/-/parse5-5.0.0.tgz#9ae2106efc443d7c1e26570aa8247828c9c80f11"
-"@vue/component-compiler-utils@^1.2.1":
- version "1.2.1"
- resolved "https://registry.yarnpkg.com/@vue/component-compiler-utils/-/component-compiler-utils-1.2.1.tgz#3d543baa75cfe5dab96e29415b78366450156ef6"
+"@vue/component-compiler-utils@^2.0.0":
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/@vue/component-compiler-utils/-/component-compiler-utils-2.2.0.tgz#bbbb7ed38a9a8a7c93abe7ef2e54a90a04b631b4"
dependencies:
consolidate "^0.15.1"
hash-sum "^1.0.2"
@@ -132,155 +214,156 @@
merge-source-map "^1.1.0"
postcss "^6.0.20"
postcss-selector-parser "^3.1.1"
- prettier "^1.11.1"
+ prettier "1.13.7"
source-map "^0.5.6"
vue-template-es2015-compiler "^1.6.0"
-"@webassemblyjs/ast@1.5.13":
- version "1.5.13"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.5.13.tgz#81155a570bd5803a30ec31436bc2c9c0ede38f25"
+"@webassemblyjs/ast@1.7.6":
+ version "1.7.6"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.7.6.tgz#3ef8c45b3e5e943a153a05281317474fef63e21e"
dependencies:
- "@webassemblyjs/helper-module-context" "1.5.13"
- "@webassemblyjs/helper-wasm-bytecode" "1.5.13"
- "@webassemblyjs/wast-parser" "1.5.13"
- debug "^3.1.0"
+ "@webassemblyjs/helper-module-context" "1.7.6"
+ "@webassemblyjs/helper-wasm-bytecode" "1.7.6"
+ "@webassemblyjs/wast-parser" "1.7.6"
mamacro "^0.0.3"
-"@webassemblyjs/floating-point-hex-parser@1.5.13":
- version "1.5.13"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.5.13.tgz#29ce0baa97411f70e8cce68ce9c0f9d819a4e298"
+"@webassemblyjs/floating-point-hex-parser@1.7.6":
+ version "1.7.6"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.7.6.tgz#7cb37d51a05c3fe09b464ae7e711d1ab3837801f"
-"@webassemblyjs/helper-api-error@1.5.13":
- version "1.5.13"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.5.13.tgz#e49b051d67ee19a56e29b9aa8bd949b5b4442a59"
+"@webassemblyjs/helper-api-error@1.7.6":
+ version "1.7.6"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.7.6.tgz#99b7e30e66f550a2638299a109dda84a622070ef"
-"@webassemblyjs/helper-buffer@1.5.13":
- version "1.5.13"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.5.13.tgz#873bb0a1b46449231137c1262ddfd05695195a1e"
- dependencies:
- debug "^3.1.0"
+"@webassemblyjs/helper-buffer@1.7.6":
+ version "1.7.6"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.7.6.tgz#ba0648be12bbe560c25c997e175c2018df39ca3e"
-"@webassemblyjs/helper-code-frame@1.5.13":
- version "1.5.13"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.5.13.tgz#1bd2181b6a0be14e004f0fe9f5a660d265362b58"
+"@webassemblyjs/helper-code-frame@1.7.6":
+ version "1.7.6"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.7.6.tgz#5a94d21b0057b69a7403fca0c253c3aaca95b1a5"
dependencies:
- "@webassemblyjs/wast-printer" "1.5.13"
+ "@webassemblyjs/wast-printer" "1.7.6"
-"@webassemblyjs/helper-fsm@1.5.13":
- version "1.5.13"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-fsm/-/helper-fsm-1.5.13.tgz#cdf3d9d33005d543a5c5e5adaabf679ffa8db924"
+"@webassemblyjs/helper-fsm@1.7.6":
+ version "1.7.6"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-fsm/-/helper-fsm-1.7.6.tgz#ae1741c6f6121213c7a0b587fb964fac492d3e49"
-"@webassemblyjs/helper-module-context@1.5.13":
- version "1.5.13"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-module-context/-/helper-module-context-1.5.13.tgz#dc29ddfb51ed657655286f94a5d72d8a489147c5"
+"@webassemblyjs/helper-module-context@1.7.6":
+ version "1.7.6"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-module-context/-/helper-module-context-1.7.6.tgz#116d19a51a6cebc8900ad53ca34ff8269c668c23"
dependencies:
- debug "^3.1.0"
mamacro "^0.0.3"
-"@webassemblyjs/helper-wasm-bytecode@1.5.13":
- version "1.5.13"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.5.13.tgz#03245817f0a762382e61733146f5773def15a747"
-
-"@webassemblyjs/helper-wasm-section@1.5.13":
- version "1.5.13"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.5.13.tgz#efc76f44a10d3073b584b43c38a179df173d5c7d"
- dependencies:
- "@webassemblyjs/ast" "1.5.13"
- "@webassemblyjs/helper-buffer" "1.5.13"
- "@webassemblyjs/helper-wasm-bytecode" "1.5.13"
- "@webassemblyjs/wasm-gen" "1.5.13"
- debug "^3.1.0"
-
-"@webassemblyjs/ieee754@1.5.13":
- version "1.5.13"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.5.13.tgz#573e97c8c12e4eebb316ca5fde0203ddd90b0364"
- dependencies:
- ieee754 "^1.1.11"
-
-"@webassemblyjs/leb128@1.5.13":
- version "1.5.13"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.5.13.tgz#ab52ebab9cec283c1c1897ac1da833a04a3f4cee"
- dependencies:
- long "4.0.0"
-
-"@webassemblyjs/utf8@1.5.13":
- version "1.5.13"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.5.13.tgz#6b53d2cd861cf94fa99c1f12779dde692fbc2469"
-
-"@webassemblyjs/wasm-edit@1.5.13":
- version "1.5.13"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.5.13.tgz#c9cef5664c245cf11b3b3a73110c9155831724a8"
- dependencies:
- "@webassemblyjs/ast" "1.5.13"
- "@webassemblyjs/helper-buffer" "1.5.13"
- "@webassemblyjs/helper-wasm-bytecode" "1.5.13"
- "@webassemblyjs/helper-wasm-section" "1.5.13"
- "@webassemblyjs/wasm-gen" "1.5.13"
- "@webassemblyjs/wasm-opt" "1.5.13"
- "@webassemblyjs/wasm-parser" "1.5.13"
- "@webassemblyjs/wast-printer" "1.5.13"
- debug "^3.1.0"
-
-"@webassemblyjs/wasm-gen@1.5.13":
- version "1.5.13"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.5.13.tgz#8e6ea113c4b432fa66540189e79b16d7a140700e"
- dependencies:
- "@webassemblyjs/ast" "1.5.13"
- "@webassemblyjs/helper-wasm-bytecode" "1.5.13"
- "@webassemblyjs/ieee754" "1.5.13"
- "@webassemblyjs/leb128" "1.5.13"
- "@webassemblyjs/utf8" "1.5.13"
+"@webassemblyjs/helper-wasm-bytecode@1.7.6":
+ version "1.7.6"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.7.6.tgz#98e515eaee611aa6834eb5f6a7f8f5b29fefb6f1"
+
+"@webassemblyjs/helper-wasm-section@1.7.6":
+ version "1.7.6"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.7.6.tgz#783835867bdd686df7a95377ab64f51a275e8333"
+ dependencies:
+ "@webassemblyjs/ast" "1.7.6"
+ "@webassemblyjs/helper-buffer" "1.7.6"
+ "@webassemblyjs/helper-wasm-bytecode" "1.7.6"
+ "@webassemblyjs/wasm-gen" "1.7.6"
+
+"@webassemblyjs/ieee754@1.7.6":
+ version "1.7.6"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.7.6.tgz#c34fc058f2f831fae0632a8bb9803cf2d3462eb1"
+ dependencies:
+ "@xtuc/ieee754" "^1.2.0"
+
+"@webassemblyjs/leb128@1.7.6":
+ version "1.7.6"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.7.6.tgz#197f75376a29f6ed6ace15898a310d871d92f03b"
+ dependencies:
+ "@xtuc/long" "4.2.1"
+
+"@webassemblyjs/utf8@1.7.6":
+ version "1.7.6"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.7.6.tgz#eb62c66f906af2be70de0302e29055d25188797d"
+
+"@webassemblyjs/wasm-edit@1.7.6":
+ version "1.7.6"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.7.6.tgz#fa41929160cd7d676d4c28ecef420eed5b3733c5"
+ dependencies:
+ "@webassemblyjs/ast" "1.7.6"
+ "@webassemblyjs/helper-buffer" "1.7.6"
+ "@webassemblyjs/helper-wasm-bytecode" "1.7.6"
+ "@webassemblyjs/helper-wasm-section" "1.7.6"
+ "@webassemblyjs/wasm-gen" "1.7.6"
+ "@webassemblyjs/wasm-opt" "1.7.6"
+ "@webassemblyjs/wasm-parser" "1.7.6"
+ "@webassemblyjs/wast-printer" "1.7.6"
+
+"@webassemblyjs/wasm-gen@1.7.6":
+ version "1.7.6"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.7.6.tgz#695ac38861ab3d72bf763c8c75e5f087ffabc322"
+ dependencies:
+ "@webassemblyjs/ast" "1.7.6"
+ "@webassemblyjs/helper-wasm-bytecode" "1.7.6"
+ "@webassemblyjs/ieee754" "1.7.6"
+ "@webassemblyjs/leb128" "1.7.6"
+ "@webassemblyjs/utf8" "1.7.6"
+
+"@webassemblyjs/wasm-opt@1.7.6":
+ version "1.7.6"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.7.6.tgz#fbafa78e27e1a75ab759a4b658ff3d50b4636c21"
+ dependencies:
+ "@webassemblyjs/ast" "1.7.6"
+ "@webassemblyjs/helper-buffer" "1.7.6"
+ "@webassemblyjs/wasm-gen" "1.7.6"
+ "@webassemblyjs/wasm-parser" "1.7.6"
+
+"@webassemblyjs/wasm-parser@1.7.6":
+ version "1.7.6"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.7.6.tgz#84eafeeff405ad6f4c4b5777d6a28ae54eed51fe"
+ dependencies:
+ "@webassemblyjs/ast" "1.7.6"
+ "@webassemblyjs/helper-api-error" "1.7.6"
+ "@webassemblyjs/helper-wasm-bytecode" "1.7.6"
+ "@webassemblyjs/ieee754" "1.7.6"
+ "@webassemblyjs/leb128" "1.7.6"
+ "@webassemblyjs/utf8" "1.7.6"
+
+"@webassemblyjs/wast-parser@1.7.6":
+ version "1.7.6"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-parser/-/wast-parser-1.7.6.tgz#ca4d20b1516e017c91981773bd7e819d6bd9c6a7"
+ dependencies:
+ "@webassemblyjs/ast" "1.7.6"
+ "@webassemblyjs/floating-point-hex-parser" "1.7.6"
+ "@webassemblyjs/helper-api-error" "1.7.6"
+ "@webassemblyjs/helper-code-frame" "1.7.6"
+ "@webassemblyjs/helper-fsm" "1.7.6"
+ "@xtuc/long" "4.2.1"
+ mamacro "^0.0.3"
-"@webassemblyjs/wasm-opt@1.5.13":
- version "1.5.13"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.5.13.tgz#147aad7717a7ee4211c36b21a5f4c30dddf33138"
+"@webassemblyjs/wast-printer@1.7.6":
+ version "1.7.6"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.7.6.tgz#a6002c526ac5fa230fe2c6d2f1bdbf4aead43a5e"
dependencies:
- "@webassemblyjs/ast" "1.5.13"
- "@webassemblyjs/helper-buffer" "1.5.13"
- "@webassemblyjs/wasm-gen" "1.5.13"
- "@webassemblyjs/wasm-parser" "1.5.13"
- debug "^3.1.0"
+ "@webassemblyjs/ast" "1.7.6"
+ "@webassemblyjs/wast-parser" "1.7.6"
+ "@xtuc/long" "4.2.1"
-"@webassemblyjs/wasm-parser@1.5.13":
- version "1.5.13"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.5.13.tgz#6f46516c5bb23904fbdf58009233c2dd8a54c72f"
- dependencies:
- "@webassemblyjs/ast" "1.5.13"
- "@webassemblyjs/helper-api-error" "1.5.13"
- "@webassemblyjs/helper-wasm-bytecode" "1.5.13"
- "@webassemblyjs/ieee754" "1.5.13"
- "@webassemblyjs/leb128" "1.5.13"
- "@webassemblyjs/utf8" "1.5.13"
-
-"@webassemblyjs/wast-parser@1.5.13":
- version "1.5.13"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-parser/-/wast-parser-1.5.13.tgz#5727a705d397ae6a3ae99d7f5460acf2ec646eea"
- dependencies:
- "@webassemblyjs/ast" "1.5.13"
- "@webassemblyjs/floating-point-hex-parser" "1.5.13"
- "@webassemblyjs/helper-api-error" "1.5.13"
- "@webassemblyjs/helper-code-frame" "1.5.13"
- "@webassemblyjs/helper-fsm" "1.5.13"
- long "^3.2.0"
- mamacro "^0.0.3"
+"@xtuc/ieee754@^1.2.0":
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790"
-"@webassemblyjs/wast-printer@1.5.13":
- version "1.5.13"
- resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.5.13.tgz#bb34d528c14b4f579e7ec11e793ec50ad7cd7c95"
- dependencies:
- "@webassemblyjs/ast" "1.5.13"
- "@webassemblyjs/wast-parser" "1.5.13"
- long "^3.2.0"
+"@xtuc/long@4.2.1":
+ version "4.2.1"
+ resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.1.tgz#5c85d662f76fa1d34575766c5dcd6615abcd30d8"
abbrev@1, abbrev@1.0.x:
version "1.0.9"
resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.0.9.tgz#91b4792588a7738c25f35dd6f63752a2f8776135"
-accepts@~1.3.3, accepts@~1.3.4:
- version "1.3.4"
- resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.4.tgz#86246758c7dd6d21a6474ff084a4740ec05eb21f"
+accepts@~1.3.3, accepts@~1.3.4, accepts@~1.3.5:
+ version "1.3.5"
+ resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.5.tgz#eb777df6011723a3b14e8a72c0805c8e86746bd2"
dependencies:
- mime-types "~2.1.16"
+ mime-types "~2.1.18"
negotiator "0.6.1"
acorn-dynamic-import@^3.0.0:
@@ -289,56 +372,36 @@ acorn-dynamic-import@^3.0.0:
dependencies:
acorn "^5.0.0"
-acorn-jsx@^3.0.0:
- version "3.0.1"
- resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-3.0.1.tgz#afdf9488fb1ecefc8348f6fb22f464e32a58b36b"
+acorn-jsx@^4.1.1:
+ version "4.1.1"
+ resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-4.1.1.tgz#e8e41e48ea2fe0c896740610ab6a4ffd8add225e"
dependencies:
- acorn "^3.0.4"
+ acorn "^5.0.3"
-acorn@^3.0.4:
- version "3.3.0"
- resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a"
-
-acorn@^5.0.0, acorn@^5.3.0, acorn@^5.5.0, acorn@^5.6.2:
- version "5.7.1"
- resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.1.tgz#f095829297706a7c9776958c0afc8930a9b9d9d8"
+acorn@^5.0.0, acorn@^5.0.3, acorn@^5.6.0, acorn@^5.6.2, acorn@^5.7.3:
+ version "5.7.3"
+ resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.3.tgz#67aa231bf8812974b85235a96771eb6bd07ea279"
after@0.8.2:
version "0.8.2"
resolved "https://registry.yarnpkg.com/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f"
-ajv-keywords@^2.1.0:
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-2.1.1.tgz#617997fc5f60576894c435f940d819e135b80762"
-
-ajv-keywords@^3.1.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.1.0.tgz#ac2b27939c543e95d2c06e7f7f5c27be4aa543be"
+ajv-errors@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/ajv-errors/-/ajv-errors-1.0.0.tgz#ecf021fa108fd17dfb5e6b383f2dd233e31ffc59"
-ajv@^5.2.3, ajv@^5.3.0:
- version "5.5.2"
- resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965"
- dependencies:
- co "^4.6.0"
- fast-deep-equal "^1.0.0"
- fast-json-stable-stringify "^2.0.0"
- json-schema-traverse "^0.3.0"
+ajv-keywords@^3.0.0, ajv-keywords@^3.1.0:
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.2.0.tgz#e86b819c602cf8821ad637413698f1dec021847a"
-ajv@^6.1.0:
- version "6.1.1"
- resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.1.1.tgz#978d597fbc2b7d0e5a5c3ddeb149a682f2abfa0e"
+ajv@^6.0.1, ajv@^6.1.0, ajv@^6.5.3:
+ version "6.5.3"
+ resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.5.3.tgz#71a569d189ecf4f4f321224fecb166f071dd90f9"
dependencies:
- fast-deep-equal "^1.0.0"
+ fast-deep-equal "^2.0.1"
fast-json-stable-stringify "^2.0.0"
- json-schema-traverse "^0.3.0"
-
-align-text@^0.1.1, align-text@^0.1.3:
- version "0.1.4"
- resolved "https://registry.yarnpkg.com/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117"
- dependencies:
- kind-of "^3.0.2"
- longest "^1.0.1"
- repeat-string "^1.5.2"
+ json-schema-traverse "^0.4.1"
+ uri-js "^4.2.2"
amdefine@>=0.0.4:
version "1.0.1"
@@ -350,6 +413,10 @@ ansi-align@^2.0.0:
dependencies:
string-width "^2.0.0"
+ansi-colors@^3.0.0:
+ version "3.0.5"
+ resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.0.5.tgz#cb9dc64993b64fd6945485f797fc3853137d9a7b"
+
ansi-escapes@^1.1.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e"
@@ -405,8 +472,8 @@ are-we-there-yet@~1.1.2:
readable-stream "^2.0.6"
argparse@^1.0.7:
- version "1.0.9"
- resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.9.tgz#73d83bc263f86e97f8cc4f6bae1b0e90a7d22c86"
+ version "1.0.10"
+ resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911"
dependencies:
sprintf-js "~1.0.2"
@@ -438,13 +505,6 @@ array-flatten@^2.1.0:
version "2.1.1"
resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-2.1.1.tgz#426bb9da84090c1838d812c8150af20a8331e296"
-array-includes@^3.0.3:
- version "3.0.3"
- resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.0.3.tgz#184b48f62d92d7452bb31b323165c7f8bd02266d"
- dependencies:
- define-properties "^1.1.2"
- es-abstract "^1.7.0"
-
array-slice@^0.2.3:
version "0.2.3"
resolved "https://registry.yarnpkg.com/array-slice/-/array-slice-0.2.3.tgz#dd3cfb80ed7973a75117cdac69b0b99ec86186f5"
@@ -501,11 +561,11 @@ async-limiter@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8"
-async@1.x, async@^1.4.0, async@^1.5.2:
+async@1.x, async@^1.5.2:
version "1.5.2"
resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a"
-async@^2.0.0, async@^2.1.4:
+async@^2.0.0, async@^2.1.4, async@^2.5.0:
version "2.6.1"
resolved "https://registry.yarnpkg.com/async/-/async-2.6.1.tgz#b245a23ca71930044ec53fa46aa00a3e87c6a610"
dependencies:
@@ -532,7 +592,7 @@ axios@^0.17.1:
follow-redirects "^1.2.5"
is-buffer "^1.1.5"
-babel-code-frame@^6.22.0, babel-code-frame@^6.26.0:
+babel-code-frame@^6.26.0:
version "6.26.0"
resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b"
dependencies:
@@ -564,20 +624,20 @@ babel-core@^6.26.0, babel-core@^6.26.3:
slash "^1.0.0"
source-map "^0.5.7"
-babel-eslint@^8.2.3:
- version "8.2.3"
- resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-8.2.3.tgz#1a2e6681cc9bc4473c32899e59915e19cd6733cf"
+babel-eslint@^9.0.0:
+ version "9.0.0"
+ resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-9.0.0.tgz#7d9445f81ed9f60aff38115f838970df9f2b6220"
dependencies:
- "@babel/code-frame" "7.0.0-beta.44"
- "@babel/traverse" "7.0.0-beta.44"
- "@babel/types" "7.0.0-beta.44"
- babylon "7.0.0-beta.44"
- eslint-scope "~3.7.1"
+ "@babel/code-frame" "^7.0.0"
+ "@babel/parser" "^7.0.0"
+ "@babel/traverse" "^7.0.0"
+ "@babel/types" "^7.0.0"
+ eslint-scope "3.7.1"
eslint-visitor-keys "^1.0.0"
babel-generator@^6.18.0, babel-generator@^6.26.0:
- version "6.26.0"
- resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.26.0.tgz#ac1ae20070b79f6e3ca1d3269613053774f20dc5"
+ version "6.26.1"
+ resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.26.1.tgz#1844408d3b8f0d35a404ea7ac180f087a601bd90"
dependencies:
babel-messages "^6.23.0"
babel-runtime "^6.26.0"
@@ -585,7 +645,7 @@ babel-generator@^6.18.0, babel-generator@^6.26.0:
detect-indent "^4.0.0"
jsesc "^1.3.0"
lodash "^4.17.4"
- source-map "^0.5.6"
+ source-map "^0.5.7"
trim-right "^1.0.1"
babel-helper-bindify-decorators@^6.24.1:
@@ -726,18 +786,17 @@ babel-plugin-check-es2015-constants@^6.22.0:
dependencies:
babel-runtime "^6.22.0"
-babel-plugin-istanbul@^4.1.6:
- version "4.1.6"
- resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-4.1.6.tgz#36c59b2192efce81c5b378321b74175add1c9a45"
+babel-plugin-istanbul@^5.0.1:
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-5.0.1.tgz#2ce7bf211f0d9480ff7fd294bd05e2fa555e31ea"
dependencies:
- babel-plugin-syntax-object-rest-spread "^6.13.0"
- find-up "^2.1.0"
- istanbul-lib-instrument "^1.10.1"
- test-exclude "^4.2.1"
+ find-up "^3.0.0"
+ istanbul-lib-instrument "^2.2.0"
+ test-exclude "^5.0.0"
-babel-plugin-rewire@^1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/babel-plugin-rewire/-/babel-plugin-rewire-1.1.0.tgz#a6b966d9d8c06c03d95dcda2eec4e2521519549b"
+babel-plugin-rewire@^1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-rewire/-/babel-plugin-rewire-1.2.0.tgz#822562d72ed2c84e47c0f95ee232c920853e9d89"
babel-plugin-syntax-async-functions@^6.8.0:
version "6.13.0"
@@ -763,7 +822,7 @@ babel-plugin-syntax-exponentiation-operator@^6.8.0:
version "6.13.0"
resolved "https://registry.yarnpkg.com/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz#9ee7e8337290da95288201a6a57f4170317830de"
-babel-plugin-syntax-object-rest-spread@^6.13.0, babel-plugin-syntax-object-rest-spread@^6.8.0:
+babel-plugin-syntax-object-rest-spread@^6.8.0:
version "6.13.0"
resolved "https://registry.yarnpkg.com/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz#fd6536f2bce13836ffa3a5458c4903a597bb3bf5"
@@ -1098,7 +1157,7 @@ babel-register@^6.26.0:
mkdirp "^0.5.1"
source-map-support "^0.4.15"
-babel-runtime@^6.0.0, babel-runtime@^6.18.0, babel-runtime@^6.22.0, babel-runtime@^6.26.0:
+babel-runtime@^6.18.0, babel-runtime@^6.22.0, babel-runtime@^6.26.0:
version "6.26.0"
resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe"
dependencies:
@@ -1138,10 +1197,6 @@ babel-types@^6.18.0, babel-types@^6.19.0, babel-types@^6.24.1, babel-types@^6.26
lodash "^4.17.4"
to-fast-properties "^1.0.3"
-babylon@7.0.0-beta.44:
- version "7.0.0-beta.44"
- resolved "https://registry.yarnpkg.com/babylon/-/babylon-7.0.0-beta.44.tgz#89159e15e6e30c5096e22d738d8c0af8a0e8ca1d"
-
babylon@^6.18.0:
version "6.18.0"
resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3"
@@ -1188,17 +1243,18 @@ better-assert@~1.0.0:
dependencies:
callsite "1.0.0"
-bfj-node4@^5.2.0:
- version "5.2.1"
- resolved "https://registry.yarnpkg.com/bfj-node4/-/bfj-node4-5.2.1.tgz#3a6aa2730cf6911ba2afb836c2f88f015d718f3f"
+bfj@^6.1.1:
+ version "6.1.1"
+ resolved "https://registry.yarnpkg.com/bfj/-/bfj-6.1.1.tgz#05a3b7784fbd72cfa3c22e56002ef99336516c48"
dependencies:
bluebird "^3.5.1"
check-types "^7.3.0"
+ hoopy "^0.1.2"
tryer "^1.0.0"
big.js@^3.1.3:
- version "3.1.3"
- resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.1.3.tgz#4cada2193652eb3ca9ec8e55c9015669c9806978"
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.2.0.tgz#a5fc298b81b9e0dca2e458824784b65c52ba588e"
binary-extensions@^1.0.0:
version "1.11.0"
@@ -1268,14 +1324,10 @@ bootstrap-vue@^2.0.0-rc.11:
popper.js "^1.12.9"
vue-functional-data-merge "^2.0.5"
-bootstrap@4.1.1:
+bootstrap@4.1.1, bootstrap@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-4.1.1.tgz#3aec85000fa619085da8d2e4983dfd67cf2114cb"
-bootstrap@^4.1.1:
- version "4.1.3"
- resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-4.1.3.tgz#0eb371af2c8448e8c210411d0cb824a6409a12be"
-
boxen@^1.2.1:
version "1.3.0"
resolved "https://registry.yarnpkg.com/boxen/-/boxen-1.3.0.tgz#55c6c39a8ba58d9c61ad22cd877532deb665a20b"
@@ -1410,7 +1462,7 @@ bytes@3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048"
-cacache@^10.0.1, cacache@^10.0.4:
+cacache@^10.0.4:
version "10.0.4"
resolved "https://registry.yarnpkg.com/cacache/-/cacache-10.0.4.tgz#6452367999eff9d4188aefd9a14e9d7c6a263460"
dependencies:
@@ -1428,6 +1480,25 @@ cacache@^10.0.1, cacache@^10.0.4:
unique-filename "^1.1.0"
y18n "^4.0.0"
+cacache@^11.2.0:
+ version "11.2.0"
+ resolved "https://registry.yarnpkg.com/cacache/-/cacache-11.2.0.tgz#617bdc0b02844af56310e411c0878941d5739965"
+ dependencies:
+ bluebird "^3.5.1"
+ chownr "^1.0.1"
+ figgy-pudding "^3.1.0"
+ glob "^7.1.2"
+ graceful-fs "^4.1.11"
+ lru-cache "^4.1.3"
+ mississippi "^3.0.0"
+ mkdirp "^0.5.1"
+ move-concurrently "^1.0.1"
+ promise-inflight "^1.0.1"
+ rimraf "^2.6.2"
+ ssri "^6.0.0"
+ unique-filename "^1.1.0"
+ y18n "^4.0.0"
+
cache-base@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2"
@@ -1477,21 +1548,6 @@ callsites@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/callsites/-/callsites-0.2.0.tgz#afab96262910a7f33c19a5775825c69f34e350ca"
-camelcase-keys@^2.0.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-2.1.0.tgz#308beeaffdf28119051efa1d932213c91b8f92e7"
- dependencies:
- camelcase "^2.0.0"
- map-obj "^1.0.0"
-
-camelcase@^1.0.2:
- version "1.2.1"
- resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39"
-
-camelcase@^2.0.0:
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f"
-
camelcase@^4.0.0, camelcase@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd"
@@ -1500,13 +1556,6 @@ capture-stack-trace@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/capture-stack-trace/-/capture-stack-trace-1.0.0.tgz#4a6fa07399c26bba47f0b2496b4d0fb408c5550d"
-center-align@^0.1.1:
- version "0.1.3"
- resolved "https://registry.yarnpkg.com/center-align/-/center-align-0.1.3.tgz#aa0d32629b6ee972200411cbd4461c907bc2b7ad"
- dependencies:
- align-text "^0.1.3"
- lazy-cache "^1.0.3"
-
chalk@1.1.3, chalk@^1.0.0, chalk@^1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98"
@@ -1517,7 +1566,7 @@ chalk@1.1.3, chalk@^1.0.0, chalk@^1.1.3:
strip-ansi "^3.0.0"
supports-color "^2.0.0"
-chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.0, chalk@^2.4.1:
+chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.4.1:
version "2.4.1"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.1.tgz#18c49ab16a037b6eb0152cc83e3471338215b66e"
dependencies:
@@ -1624,14 +1673,6 @@ clipboard@^1.5.5, clipboard@^1.7.1:
select "^1.1.2"
tiny-emitter "^2.0.0"
-cliui@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/cliui/-/cliui-2.1.0.tgz#4b475760ff80264c762c3a1719032e91c7fea0d1"
- dependencies:
- center-align "^0.1.1"
- right-align "^0.1.1"
- wordwrap "0.0.2"
-
cliui@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/cliui/-/cliui-4.0.0.tgz#743d4650e05f36d1ed2575b59638d87322bfbbcc"
@@ -1646,10 +1687,6 @@ clone-response@1.0.2:
dependencies:
mimic-response "^1.0.0"
-co@^4.6.0:
- version "4.6.0"
- resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184"
-
code-point-at@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77"
@@ -1678,14 +1715,14 @@ collection-visit@^1.0.0:
object-visit "^1.0.0"
color-convert@^1.9.0:
- version "1.9.1"
- resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.1.tgz#c1261107aeb2f294ebffec9ed9ecad529a6097ed"
+ version "1.9.3"
+ resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
dependencies:
- color-name "^1.1.1"
+ color-name "1.1.3"
-color-name@^1.1.1:
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.2.tgz#5c8ab72b64bd2215d617ae9559ebb148475cf98d"
+color-name@1.1.3:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
colors@^1.1.0:
version "1.1.2"
@@ -1697,14 +1734,18 @@ combine-lists@^1.0.0:
dependencies:
lodash "^4.5.0"
-commander@2, commander@^2.13.0, commander@^2.15.1:
- version "2.15.1"
- resolved "https://registry.yarnpkg.com/commander/-/commander-2.15.1.tgz#df46e867d0fc2aec66a34662b406a9ccafff5b0f"
+commander@2, commander@^2.18.0:
+ version "2.18.0"
+ resolved "https://registry.yarnpkg.com/commander/-/commander-2.18.0.tgz#2bf063ddee7c7891176981a2cc798e5754bc6970"
commander@~2.13.0:
version "2.13.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.13.0.tgz#6964bca67685df7c1f1430c584f07d7597885b9c"
+commander@~2.17.1:
+ version "2.17.1"
+ resolved "https://registry.yarnpkg.com/commander/-/commander-2.17.1.tgz#bd77ab7de6de94205ceacc72f1716d29f20a77bf"
+
commondir@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b"
@@ -1727,13 +1768,14 @@ compressible@~2.0.10:
dependencies:
mime-db ">= 1.29.0 < 2"
-compression-webpack-plugin@^1.1.11:
- version "1.1.11"
- resolved "https://registry.yarnpkg.com/compression-webpack-plugin/-/compression-webpack-plugin-1.1.11.tgz#8384c7a6ead1d2e2efb190bdfcdcf35878ed8266"
+compression-webpack-plugin@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/compression-webpack-plugin/-/compression-webpack-plugin-2.0.0.tgz#46476350c1eb27f783dccc79ac2f709baa2cffbc"
dependencies:
- cacache "^10.0.1"
- find-cache-dir "^1.0.0"
+ cacache "^11.2.0"
+ find-cache-dir "^2.0.0"
neo-async "^2.5.0"
+ schema-utils "^1.0.0"
serialize-javascript "^1.4.0"
webpack-sources "^1.0.1"
@@ -1753,7 +1795,7 @@ concat-map@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
-concat-stream@^1.5.0, concat-stream@^1.6.0:
+concat-stream@^1.5.0:
version "1.6.2"
resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34"
dependencies:
@@ -1846,8 +1888,8 @@ copy-descriptor@^0.1.0:
resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d"
core-js@^2.2.0, core-js@^2.4.0, core-js@^2.4.1, core-js@^2.5.0:
- version "2.5.3"
- resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.3.tgz#8acc38345824f16d8365b7c9b4259168e8ed603e"
+ version "2.5.7"
+ resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.7.tgz#f972608ff0cead68b841a16a932d0b183791814e"
core-js@~2.3.0:
version "2.3.0"
@@ -1896,7 +1938,7 @@ cropper@^2.3.0:
dependencies:
jquery ">= 1.9.1"
-cross-spawn@^5.0.1, cross-spawn@^5.1.0:
+cross-spawn@^5.0.1:
version "5.1.0"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449"
dependencies:
@@ -1904,7 +1946,7 @@ cross-spawn@^5.0.1, cross-spawn@^5.1.0:
shebang-command "^1.2.0"
which "^1.2.9"
-cross-spawn@^6.0.5:
+cross-spawn@^6.0.0, cross-spawn@^6.0.5:
version "6.0.5"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4"
dependencies:
@@ -2243,15 +2285,23 @@ debug@2.6.9, debug@^2.1.2, debug@^2.2.0, debug@^2.3.3, debug@^2.6.6, debug@^2.6.
dependencies:
ms "2.0.0"
-debug@^3.0.1, debug@^3.1.0, debug@~3.1.0:
+debug@^3.1.0:
+ version "3.2.5"
+ resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.5.tgz#c2418fbfd7a29f4d4f70ff4cea604d4b64c46407"
+ dependencies:
+ ms "^2.1.1"
+
+debug@~3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261"
dependencies:
ms "2.0.0"
-decamelize@^1.0.0, decamelize@^1.1.1, decamelize@^1.1.2:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
+decamelize@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-2.0.0.tgz#656d7bbc8094c4c788ea53c5840908c9c7d063c7"
+ dependencies:
+ xregexp "4.0.0"
deckar01-task_list@^2.0.0:
version "2.0.0"
@@ -2279,6 +2329,13 @@ deep-is@~0.1.3:
version "0.1.3"
resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34"
+default-gateway@^2.6.0:
+ version "2.7.2"
+ resolved "https://registry.yarnpkg.com/default-gateway/-/default-gateway-2.7.2.tgz#b7ef339e5e024b045467af403d50348db4642d0f"
+ dependencies:
+ execa "^0.10.0"
+ ip-regex "^2.1.0"
+
default-require-extensions@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/default-require-extensions/-/default-require-extensions-1.0.0.tgz#f37ea15d3e13ffd9b437d33e1a75b5fb97874cb8"
@@ -2286,11 +2343,10 @@ default-require-extensions@^1.0.0:
strip-bom "^2.0.0"
define-properties@^1.1.2:
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.2.tgz#83a73f2fea569898fb737193c8f873caf6d45c94"
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1"
dependencies:
- foreach "^2.0.5"
- object-keys "^1.0.8"
+ object-keys "^1.0.12"
define-property@^0.2.5:
version "0.2.5"
@@ -2346,6 +2402,10 @@ depd@1.1.1, depd@~1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.1.tgz#5783b4e1c459f06fa5ca27f991f3d06e7a310359"
+depd@~1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9"
+
des.js@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.0.tgz#c074d2e2aa6a8a9a07dbd61f9a15c2cd83ec8ecc"
@@ -2411,7 +2471,7 @@ doctrine@1.5.0:
esutils "^2.0.2"
isarray "^1.0.0"
-doctrine@^2.0.2:
+doctrine@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d"
dependencies:
@@ -2497,9 +2557,9 @@ ee-first@1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
-ejs@^2.5.7:
- version "2.5.9"
- resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.5.9.tgz#7ba254582a560d267437109a68354112475b0ce5"
+ejs@^2.6.1:
+ version "2.6.1"
+ resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.6.1.tgz#498ec0d495655abc6f23cd61868d926464071aa0"
elliptic@^6.0.0:
version "6.4.0"
@@ -2521,7 +2581,7 @@ emojis-list@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389"
-encodeurl@~1.0.1:
+encodeurl@~1.0.1, encodeurl@~1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59"
@@ -2604,15 +2664,15 @@ errno@^0.1.3, errno@^0.1.4:
dependencies:
prr "~1.0.1"
-error-ex@^1.2.0:
- version "1.3.0"
- resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.0.tgz#e67b43f3e82c96ea3a584ffee0b9fc3325d802d9"
+error-ex@^1.2.0, error-ex@^1.3.1:
+ version "1.3.2"
+ resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf"
dependencies:
is-arrayish "^0.2.1"
-es-abstract@^1.7.0:
- version "1.10.0"
- resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.10.0.tgz#1ecb36c197842a00d8ee4c2dfd8646bb97d60864"
+es-abstract@^1.6.1:
+ version "1.12.0"
+ resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.12.0.tgz#9dbbdd27c6856f0001421ca18782d786bf8a6165"
dependencies:
es-to-primitive "^1.1.1"
function-bind "^1.1.1"
@@ -2651,11 +2711,13 @@ escodegen@1.8.x:
optionalDependencies:
source-map "~0.2.0"
-eslint-config-airbnb-base@^12.1.0:
- version "12.1.0"
- resolved "https://registry.yarnpkg.com/eslint-config-airbnb-base/-/eslint-config-airbnb-base-12.1.0.tgz#386441e54a12ccd957b0a92564a4bafebd747944"
+eslint-config-airbnb-base@^13.1.0:
+ version "13.1.0"
+ resolved "https://registry.yarnpkg.com/eslint-config-airbnb-base/-/eslint-config-airbnb-base-13.1.0.tgz#b5a1b480b80dfad16433d6c4ad84e6605052c05c"
dependencies:
eslint-restricted-globals "^0.1.1"
+ object.assign "^4.1.0"
+ object.entries "^1.0.4"
eslint-import-resolver-node@^0.3.1:
version "0.3.2"
@@ -2664,9 +2726,9 @@ eslint-import-resolver-node@^0.3.1:
debug "^2.6.9"
resolve "^1.5.0"
-eslint-import-resolver-webpack@^0.10.0:
- version "0.10.0"
- resolved "https://registry.yarnpkg.com/eslint-import-resolver-webpack/-/eslint-import-resolver-webpack-0.10.0.tgz#b6f2468dc3e8b4ea076e5d75bece8da932789b07"
+eslint-import-resolver-webpack@^0.10.1:
+ version "0.10.1"
+ resolved "https://registry.yarnpkg.com/eslint-import-resolver-webpack/-/eslint-import-resolver-webpack-0.10.1.tgz#4cbceed2c0c43e488a74775c30861e58e00fb290"
dependencies:
array-find "^1.0.0"
debug "^2.6.8"
@@ -2686,24 +2748,24 @@ eslint-module-utils@^2.2.0:
debug "^2.6.8"
pkg-dir "^1.0.0"
-eslint-plugin-filenames@^1.2.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/eslint-plugin-filenames/-/eslint-plugin-filenames-1.2.0.tgz#aee9c1c90189c95d2e49902c160eceefecd99f53"
+eslint-plugin-filenames@^1.3.2:
+ version "1.3.2"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-filenames/-/eslint-plugin-filenames-1.3.2.tgz#7094f00d7aefdd6999e3ac19f72cea058e590cf7"
dependencies:
lodash.camelcase "4.3.0"
lodash.kebabcase "4.1.1"
lodash.snakecase "4.1.1"
lodash.upperfirst "4.3.1"
-eslint-plugin-html@4.0.3:
- version "4.0.3"
- resolved "https://registry.yarnpkg.com/eslint-plugin-html/-/eslint-plugin-html-4.0.3.tgz#97d52dcf9e22724505d02719fbd02754013c8a17"
+eslint-plugin-html@4.0.5:
+ version "4.0.5"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-html/-/eslint-plugin-html-4.0.5.tgz#e8ec7e16485124460f3bff312016feb0a54d9659"
dependencies:
htmlparser2 "^3.8.2"
-eslint-plugin-import@^2.12.0:
- version "2.12.0"
- resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.12.0.tgz#dad31781292d6664b25317fd049d2e2b2f02205d"
+eslint-plugin-import@^2.14.0:
+ version "2.14.0"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.14.0.tgz#6b17626d2e3e6ad52cfce8807a845d15e22111a8"
dependencies:
contains-path "^0.1.0"
debug "^2.6.8"
@@ -2716,93 +2778,105 @@ eslint-plugin-import@^2.12.0:
read-pkg-up "^2.0.0"
resolve "^1.6.0"
-eslint-plugin-jasmine@^2.1.0:
- version "2.2.0"
- resolved "https://registry.yarnpkg.com/eslint-plugin-jasmine/-/eslint-plugin-jasmine-2.2.0.tgz#7135879383c39a667c721d302b9f20f0389543de"
+eslint-plugin-jasmine@^2.10.1:
+ version "2.10.1"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-jasmine/-/eslint-plugin-jasmine-2.10.1.tgz#5733b709e751f4bc40e31e1c16989bd2cdfbec97"
-eslint-plugin-promise@^3.8.0:
- version "3.8.0"
- resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-3.8.0.tgz#65ebf27a845e3c1e9d6f6a5622ddd3801694b621"
+eslint-plugin-promise@^4.0.1:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-4.0.1.tgz#2d074b653f35a23d1ba89d8e976a985117d1c6a2"
-eslint-plugin-vue@^4.5.0:
- version "4.5.0"
- resolved "https://registry.yarnpkg.com/eslint-plugin-vue/-/eslint-plugin-vue-4.5.0.tgz#09d6597f4849e31a3846c2c395fccf17685b69c3"
+eslint-plugin-vue@^5.0.0-beta.3:
+ version "5.0.0-beta.3"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-vue/-/eslint-plugin-vue-5.0.0-beta.3.tgz#f3fa9f109b76e20fc1e45a71ce7c6d567118924e"
dependencies:
- vue-eslint-parser "^2.0.3"
+ vue-eslint-parser "^3.2.1"
eslint-restricted-globals@^0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/eslint-restricted-globals/-/eslint-restricted-globals-0.1.1.tgz#35f0d5cbc64c2e3ed62e93b4b1a7af05ba7ed4d7"
-eslint-scope@^3.7.1, eslint-scope@~3.7.1:
+eslint-scope@3.7.1:
version "3.7.1"
resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-3.7.1.tgz#3d63c3edfda02e06e01a452ad88caacc7cdcb6e8"
dependencies:
esrecurse "^4.1.0"
estraverse "^4.1.1"
+eslint-scope@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.0.tgz#50bf3071e9338bcdc43331794a0cb533f0136172"
+ dependencies:
+ esrecurse "^4.1.0"
+ estraverse "^4.1.1"
+
+eslint-utils@^1.3.1:
+ version "1.3.1"
+ resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.3.1.tgz#9a851ba89ee7c460346f97cf8939c7298827e512"
+
eslint-visitor-keys@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#3f3180fb2e291017716acb4c9d6d5b5c34a6a81d"
-eslint@~4.12.1:
- version "4.12.1"
- resolved "https://registry.yarnpkg.com/eslint/-/eslint-4.12.1.tgz#5ec1973822b4a066b353770c3c6d69a2a188e880"
+eslint@~5.6.0:
+ version "5.6.0"
+ resolved "https://registry.yarnpkg.com/eslint/-/eslint-5.6.0.tgz#b6f7806041af01f71b3f1895cbb20971ea4b6223"
dependencies:
- ajv "^5.3.0"
- babel-code-frame "^6.22.0"
+ "@babel/code-frame" "^7.0.0"
+ ajv "^6.5.3"
chalk "^2.1.0"
- concat-stream "^1.6.0"
- cross-spawn "^5.1.0"
- debug "^3.0.1"
- doctrine "^2.0.2"
- eslint-scope "^3.7.1"
- espree "^3.5.2"
- esquery "^1.0.0"
- estraverse "^4.2.0"
+ cross-spawn "^6.0.5"
+ debug "^3.1.0"
+ doctrine "^2.1.0"
+ eslint-scope "^4.0.0"
+ eslint-utils "^1.3.1"
+ eslint-visitor-keys "^1.0.0"
+ espree "^4.0.0"
+ esquery "^1.0.1"
esutils "^2.0.2"
file-entry-cache "^2.0.0"
functional-red-black-tree "^1.0.1"
glob "^7.1.2"
- globals "^11.0.1"
- ignore "^3.3.3"
+ globals "^11.7.0"
+ ignore "^4.0.6"
imurmurhash "^0.1.4"
- inquirer "^3.0.6"
- is-resolvable "^1.0.0"
- js-yaml "^3.9.1"
+ inquirer "^6.1.0"
+ is-resolvable "^1.1.0"
+ js-yaml "^3.12.0"
json-stable-stringify-without-jsonify "^1.0.1"
levn "^0.3.0"
- lodash "^4.17.4"
- minimatch "^3.0.2"
+ lodash "^4.17.5"
+ minimatch "^3.0.4"
mkdirp "^0.5.1"
natural-compare "^1.4.0"
optionator "^0.8.2"
path-is-inside "^1.0.2"
pluralize "^7.0.0"
progress "^2.0.0"
+ regexpp "^2.0.0"
require-uncached "^1.0.3"
- semver "^5.3.0"
+ semver "^5.5.1"
strip-ansi "^4.0.0"
- strip-json-comments "~2.0.1"
- table "^4.0.1"
- text-table "~0.2.0"
+ strip-json-comments "^2.0.1"
+ table "^4.0.3"
+ text-table "^0.2.0"
-espree@^3.5.2:
- version "3.5.4"
- resolved "https://registry.yarnpkg.com/espree/-/espree-3.5.4.tgz#b0f447187c8a8bed944b815a660bddf5deb5d1a7"
+espree@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/espree/-/espree-4.0.0.tgz#253998f20a0f82db5d866385799d912a83a36634"
dependencies:
- acorn "^5.5.0"
- acorn-jsx "^3.0.0"
+ acorn "^5.6.0"
+ acorn-jsx "^4.1.1"
esprima@2.7.x, esprima@^2.7.1:
version "2.7.3"
resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581"
esprima@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.0.tgz#4499eddcd1110e0b218bacf2fa7f7f59f55ca804"
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71"
-esquery@^1.0.0:
+esquery@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.0.1.tgz#406c51658b1f5991a5f9b62b1dc25b00e3e5c708"
dependencies:
@@ -2818,7 +2892,7 @@ estraverse@^1.9.1:
version "1.9.3"
resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-1.9.3.tgz#af67f2dc922582415950926091a4005d29c9bb44"
-estraverse@^4.0.0, estraverse@^4.1.0, estraverse@^4.1.1, estraverse@^4.2.0:
+estraverse@^4.0.0, estraverse@^4.1.0, estraverse@^4.1.1:
version "4.2.0"
resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13"
@@ -2867,6 +2941,18 @@ evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3:
md5.js "^1.3.4"
safe-buffer "^5.1.1"
+execa@^0.10.0:
+ version "0.10.0"
+ resolved "https://registry.yarnpkg.com/execa/-/execa-0.10.0.tgz#ff456a8f53f90f8eccc71a96d11bdfc7f082cb50"
+ dependencies:
+ cross-spawn "^6.0.0"
+ get-stream "^3.0.0"
+ is-stream "^1.1.0"
+ npm-run-path "^2.0.0"
+ p-finally "^1.0.0"
+ signal-exit "^3.0.0"
+ strip-eof "^1.0.0"
+
execa@^0.7.0:
version "0.7.0"
resolved "https://registry.yarnpkg.com/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777"
@@ -2913,11 +2999,11 @@ exports-loader@^0.7.0:
loader-utils "^1.1.0"
source-map "0.5.0"
-express@^4.16.2:
- version "4.16.2"
- resolved "https://registry.yarnpkg.com/express/-/express-4.16.2.tgz#e35c6dfe2d64b7dca0a5cd4f21781be3299e076c"
+express@^4.16.2, express@^4.16.3:
+ version "4.16.3"
+ resolved "http://registry.npmjs.org/express/-/express-4.16.3.tgz#6af8a502350db3246ecc4becf6b5a34d22f7ed53"
dependencies:
- accepts "~1.3.4"
+ accepts "~1.3.5"
array-flatten "1.1.1"
body-parser "1.18.2"
content-disposition "0.5.2"
@@ -2925,26 +3011,26 @@ express@^4.16.2:
cookie "0.3.1"
cookie-signature "1.0.6"
debug "2.6.9"
- depd "~1.1.1"
- encodeurl "~1.0.1"
+ depd "~1.1.2"
+ encodeurl "~1.0.2"
escape-html "~1.0.3"
etag "~1.8.1"
- finalhandler "1.1.0"
+ finalhandler "1.1.1"
fresh "0.5.2"
merge-descriptors "1.0.1"
methods "~1.1.2"
on-finished "~2.3.0"
parseurl "~1.3.2"
path-to-regexp "0.1.7"
- proxy-addr "~2.0.2"
+ proxy-addr "~2.0.3"
qs "6.5.1"
range-parser "~1.2.0"
safe-buffer "5.1.1"
- send "0.16.1"
- serve-static "1.13.1"
+ send "0.16.2"
+ serve-static "1.13.2"
setprototypeof "1.1.0"
- statuses "~1.3.1"
- type-is "~1.6.15"
+ statuses "~1.4.0"
+ type-is "~1.6.16"
utils-merge "1.0.1"
vary "~1.1.2"
@@ -2965,7 +3051,7 @@ extend@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444"
-external-editor@^2.0.1, external-editor@^2.0.4:
+external-editor@^2.0.1:
version "2.2.0"
resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-2.2.0.tgz#045511cfd8d133f3846673d1047c154e214ad3d5"
dependencies:
@@ -2994,9 +3080,9 @@ extglob@^2.0.4:
snapdragon "^0.8.1"
to-regex "^3.0.1"
-fast-deep-equal@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz#96256a3bc975595eb36d82e9929d060d893439ff"
+fast-deep-equal@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49"
fast-json-stable-stringify@^2.0.0:
version "2.0.0"
@@ -3022,6 +3108,10 @@ faye-websocket@~0.11.0:
dependencies:
websocket-driver ">=0.5.1"
+figgy-pudding@^3.1.0, figgy-pudding@^3.5.1:
+ version "3.5.1"
+ resolved "https://registry.yarnpkg.com/figgy-pudding/-/figgy-pudding-3.5.1.tgz#862470112901c727a0e495a80744bd5baa1d6790"
+
figures@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962"
@@ -3035,12 +3125,12 @@ file-entry-cache@^2.0.0:
flat-cache "^1.2.1"
object-assign "^4.0.1"
-file-loader@^1.1.11:
- version "1.1.11"
- resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-1.1.11.tgz#6fe886449b0f2a936e43cabaac0cdbfb369506f8"
+file-loader@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-2.0.0.tgz#39749c82f020b9e85901dcff98e8004e6401cfde"
dependencies:
loader-utils "^1.0.2"
- schema-utils "^0.4.5"
+ schema-utils "^1.0.0"
fileset@^2.0.2:
version "2.0.3"
@@ -3049,9 +3139,9 @@ fileset@^2.0.2:
glob "^7.0.3"
minimatch "^3.0.3"
-filesize@^3.5.11:
- version "3.6.0"
- resolved "https://registry.yarnpkg.com/filesize/-/filesize-3.6.0.tgz#22d079615624bb6fd3c04026120628a41b3f4efa"
+filesize@^3.6.1:
+ version "3.6.1"
+ resolved "https://registry.yarnpkg.com/filesize/-/filesize-3.6.1.tgz#090bb3ee01b6f801a8a8be99d31710b3422bb317"
fill-range@^4.0.0:
version "4.0.0"
@@ -3074,6 +3164,18 @@ finalhandler@1.1.0:
statuses "~1.3.1"
unpipe "~1.0.0"
+finalhandler@1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.1.tgz#eebf4ed840079c83f4249038c9d703008301b105"
+ dependencies:
+ debug "2.6.9"
+ encodeurl "~1.0.2"
+ escape-html "~1.0.3"
+ on-finished "~2.3.0"
+ parseurl "~1.3.2"
+ statuses "~1.4.0"
+ unpipe "~1.0.0"
+
find-cache-dir@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-1.0.0.tgz#9288e3e9e3cc3748717d39eade17cf71fc30ee6f"
@@ -3082,6 +3184,14 @@ find-cache-dir@^1.0.0:
make-dir "^1.0.0"
pkg-dir "^2.0.0"
+find-cache-dir@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-2.0.0.tgz#4c1faed59f45184530fb9d7fa123a4d04a98472d"
+ dependencies:
+ commondir "^1.0.1"
+ make-dir "^1.0.0"
+ pkg-dir "^3.0.0"
+
find-root@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/find-root/-/find-root-1.1.0.tgz#abcfc8ba76f708c42a97b3d685b7e9450bfb9ce4"
@@ -3099,6 +3209,12 @@ find-up@^2.0.0, find-up@^2.1.0:
dependencies:
locate-path "^2.0.0"
+find-up@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73"
+ dependencies:
+ locate-path "^3.0.0"
+
flat-cache@^1.2.1:
version "1.2.2"
resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-1.2.2.tgz#fa86714e72c21db88601761ecf2f555d1abc6b96"
@@ -3125,10 +3241,6 @@ for-in@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"
-foreach@^2.0.5:
- version "2.0.5"
- resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99"
-
formdata-polyfill@^3.0.11:
version "3.0.11"
resolved "https://registry.yarnpkg.com/formdata-polyfill/-/formdata-polyfill-3.0.11.tgz#c82b4b4bea3356c0a6752219e54ce1edb2a7fb5b"
@@ -3190,7 +3302,7 @@ fsevents@^1.2.2:
nan "^2.9.2"
node-pre-gyp "^0.10.0"
-function-bind@^1.0.2, function-bind@^1.1.1:
+function-bind@^1.0.2, function-bind@^1.1.0, function-bind@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
@@ -3219,10 +3331,6 @@ get-caller-file@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.2.tgz#f702e63127e7e231c160a80c1554acb70d5047e5"
-get-stdin@^4.0.1:
- version "4.0.1"
- resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe"
-
get-stream@3.0.0, get-stream@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14"
@@ -3259,8 +3367,8 @@ glob-parent@^3.1.0:
path-dirname "^1.0.0"
"glob@5 - 7", glob@^7.0.3, glob@^7.0.5, glob@^7.1.1, glob@^7.1.2:
- version "7.1.2"
- resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15"
+ version "7.1.3"
+ resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1"
dependencies:
fs.realpath "^1.0.0"
inflight "^1.0.4"
@@ -3289,9 +3397,9 @@ global-modules-path@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/global-modules-path/-/global-modules-path-2.1.0.tgz#923ec524e8726bb0c1a4ed4b8e21e1ff80c88bbb"
-globals@^11.0.1, globals@^11.1.0:
- version "11.5.0"
- resolved "https://registry.yarnpkg.com/globals/-/globals-11.5.0.tgz#6bc840de6771173b191f13d3a9c94d441ee92642"
+globals@^11.1.0, globals@^11.7.0:
+ version "11.7.0"
+ resolved "https://registry.yarnpkg.com/globals/-/globals-11.7.0.tgz#a583faa43055b1aca771914bf68258e2fc125673"
globals@^9.18.0:
version "9.18.0"
@@ -3372,9 +3480,9 @@ graphlib@^2.1.1:
dependencies:
lodash "^4.11.1"
-gzip-size@^4.1.0:
- version "4.1.0"
- resolved "https://registry.yarnpkg.com/gzip-size/-/gzip-size-4.1.0.tgz#8ae096257eabe7d69c45be2b67c448124ffb517c"
+gzip-size@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/gzip-size/-/gzip-size-5.0.0.tgz#a55ecd99222f4c48fd8c01c625ce3b349d0a0e80"
dependencies:
duplexer "^0.1.1"
pify "^3.0.0"
@@ -3384,14 +3492,14 @@ handle-thing@^1.2.5:
resolved "https://registry.yarnpkg.com/handle-thing/-/handle-thing-1.2.5.tgz#fd7aad726bf1a5fd16dfc29b2f7a6601d27139c4"
handlebars@^4.0.1, handlebars@^4.0.3:
- version "4.0.6"
- resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.6.tgz#2ce4484850537f9c97a8026d5399b935c4ed4ed7"
+ version "4.0.12"
+ resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.12.tgz#2c15c8a96d46da5e266700518ba8cb8d919d5bc5"
dependencies:
- async "^1.4.0"
+ async "^2.5.0"
optimist "^0.6.1"
- source-map "^0.4.4"
+ source-map "^0.6.1"
optionalDependencies:
- uglify-js "^2.6"
+ uglify-js "^3.1.4"
has-ansi@^2.0.0:
version "2.0.0"
@@ -3421,6 +3529,10 @@ has-symbol-support-x@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/has-symbol-support-x/-/has-symbol-support-x-1.3.0.tgz#588bd6927eaa0e296afae24160659167fc2be4f8"
+has-symbols@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.0.tgz#ba1a8f1af2a0fc39650f5c850367704122063b44"
+
has-to-string-tag-x@^1.2.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/has-to-string-tag-x/-/has-to-string-tag-x-1.3.0.tgz#78e3d98c3c0ec9413e970eb8d766249a1e13058f"
@@ -3507,6 +3619,10 @@ home-or-tmp@^2.0.0:
os-homedir "^1.0.0"
os-tmpdir "^1.0.1"
+hoopy@^0.1.2:
+ version "0.1.4"
+ resolved "https://registry.yarnpkg.com/hoopy/-/hoopy-0.1.4.tgz#609207d661100033a9a9402ad3dea677381c1b1d"
+
hosted-git-info@^2.1.4:
version "2.2.0"
resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.2.0.tgz#7a0d097863d886c0fabbdcd37bf1758d8becf8a5"
@@ -3592,7 +3708,7 @@ icss-utils@^2.1.0:
dependencies:
postcss "^6.0.1"
-ieee754@^1.1.11, ieee754@^1.1.4:
+ieee754@^1.1.4:
version "1.1.11"
resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.11.tgz#c16384ffe00f5b7835824e67b6f2bd44a5229455"
@@ -3610,10 +3726,14 @@ ignore-walk@^3.0.1:
dependencies:
minimatch "^3.0.4"
-ignore@^3.3.3, ignore@^3.3.7:
+ignore@^3.3.7:
version "3.3.8"
resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.8.tgz#3f8e9c35d38708a3a7e0e9abb6c73e7ee7707b2b"
+ignore@^4.0.6:
+ version "4.0.6"
+ resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc"
+
immediate@~3.0.5:
version "3.0.6"
resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b"
@@ -3629,6 +3749,13 @@ import-local@^1.0.0:
pkg-dir "^2.0.0"
resolve-cwd "^2.0.0"
+import-local@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/import-local/-/import-local-2.0.0.tgz#55070be38a5993cf18ef6db7e961f5bee5c5a09d"
+ dependencies:
+ pkg-dir "^3.0.0"
+ resolve-cwd "^2.0.0"
+
imports-loader@^0.8.0:
version "0.8.0"
resolved "https://registry.yarnpkg.com/imports-loader/-/imports-loader-0.8.0.tgz#030ea51b8ca05977c40a3abfd9b4088fe0be9a69"
@@ -3640,12 +3767,6 @@ imurmurhash@^0.1.4:
version "0.1.4"
resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
-indent-string@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-2.1.0.tgz#8e2d48348742121b4a8218b7a137e9a52049dc80"
- dependencies:
- repeating "^2.0.0"
-
indexes-of@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/indexes-of/-/indexes-of-1.0.1.tgz#f30f716c8e2bd346c7b67d3df3915566a7c05607"
@@ -3691,28 +3812,9 @@ inquirer@3.0.6:
strip-ansi "^3.0.0"
through "^2.3.6"
-inquirer@^3.0.6:
- version "3.3.0"
- resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-3.3.0.tgz#9dd2f2ad765dcab1ff0443b491442a20ba227dc9"
- dependencies:
- ansi-escapes "^3.0.0"
- chalk "^2.0.0"
- cli-cursor "^2.1.0"
- cli-width "^2.0.0"
- external-editor "^2.0.4"
- figures "^2.0.0"
- lodash "^4.3.0"
- mute-stream "0.0.7"
- run-async "^2.2.0"
- rx-lite "^4.0.8"
- rx-lite-aggregates "^4.0.8"
- string-width "^2.1.0"
- strip-ansi "^4.0.0"
- through "^2.3.6"
-
-inquirer@^6.0.0:
- version "6.0.0"
- resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.0.0.tgz#e8c20303ddc15bbfc2c12a6213710ccd9e1413d8"
+inquirer@^6.0.0, inquirer@^6.1.0:
+ version "6.2.0"
+ resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.2.0.tgz#51adcd776f661369dc1e894859c2560a224abdd8"
dependencies:
ansi-escapes "^3.0.0"
chalk "^2.0.0"
@@ -3720,7 +3822,7 @@ inquirer@^6.0.0:
cli-width "^2.0.0"
external-editor "^3.0.0"
figures "^2.0.0"
- lodash "^4.3.0"
+ lodash "^4.17.10"
mute-stream "0.0.7"
run-async "^2.2.0"
rxjs "^6.1.0"
@@ -3728,11 +3830,12 @@ inquirer@^6.0.0:
strip-ansi "^4.0.0"
through "^2.3.6"
-internal-ip@1.2.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/internal-ip/-/internal-ip-1.2.0.tgz#ae9fbf93b984878785d50a8de1b356956058cf5c"
+internal-ip@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/internal-ip/-/internal-ip-3.0.1.tgz#df5c99876e1d2eb2ea2d74f520e3f669a00ece27"
dependencies:
- meow "^3.3.0"
+ default-gateway "^2.6.0"
+ ipaddr.js "^1.5.2"
interpret@^1.0.0, interpret@^1.1.0:
version "1.1.0"
@@ -3746,22 +3849,26 @@ into-stream@^3.1.0:
p-is-promise "^1.1.0"
invariant@^2.2.0, invariant@^2.2.2:
- version "2.2.2"
- resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.2.tgz#9e1f56ac0acdb6bf303306f338be3b204ae60360"
+ version "2.2.4"
+ resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6"
dependencies:
loose-envify "^1.0.0"
-invert-kv@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6"
+invert-kv@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-2.0.0.tgz#7393f5afa59ec9ff5f67a27620d11c226e3eec02"
+
+ip-regex@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9"
ip@^1.1.0, ip@^1.1.5:
version "1.1.5"
resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a"
-ipaddr.js@1.6.0:
- version "1.6.0"
- resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.6.0.tgz#e3fa357b773da619f26e95f049d055c72796f86b"
+ipaddr.js@1.8.0, ipaddr.js@^1.5.2:
+ version "1.8.0"
+ resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.8.0.tgz#eaa33d6ddd7ace8f7f6fe0c9ca0440e706738b1e"
is-accessor-descriptor@^0.1.6:
version "0.1.6"
@@ -3796,8 +3903,8 @@ is-builtin-module@^1.0.0:
builtin-modules "^1.0.0"
is-callable@^1.1.1, is-callable@^1.1.3:
- version "1.1.3"
- resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.3.tgz#86eb75392805ddc33af71c92a0eedf74ee7604b2"
+ version "1.1.4"
+ resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.4.tgz#1e1adf219e1eeb684d691f9d6a05ff0d30a24d75"
is-data-descriptor@^0.1.4:
version "0.1.4"
@@ -3952,11 +4059,9 @@ is-regex@^1.0.4:
dependencies:
has "^1.0.1"
-is-resolvable@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.0.0.tgz#8df57c61ea2e3c501408d100fb013cf8d6e0cc62"
- dependencies:
- tryit "^1.0.1"
+is-resolvable@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.1.0.tgz#fb18f87ce1feb925169c9a407c19318a3206ed88"
is-retry-allowed@^1.0.0, is-retry-allowed@^1.1.0:
version "1.1.0"
@@ -3967,8 +4072,10 @@ is-stream@^1.0.0, is-stream@^1.0.1, is-stream@^1.1.0:
resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
is-symbol@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.1.tgz#3cc59f00025194b6ab2e38dbae6689256b660572"
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.2.tgz#a055f6ae57192caee329e7a860118b497a950f38"
+ dependencies:
+ has-symbols "^1.0.0"
is-utf8@^0.2.0:
version "0.2.1"
@@ -4008,66 +4115,82 @@ isobject@^3.0.0, isobject@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df"
-istanbul-api@^1.1.14:
- version "1.2.1"
- resolved "https://registry.yarnpkg.com/istanbul-api/-/istanbul-api-1.2.1.tgz#0c60a0515eb11c7d65c6b50bba2c6e999acd8620"
+istanbul-api@^1.3.1:
+ version "1.3.7"
+ resolved "https://registry.yarnpkg.com/istanbul-api/-/istanbul-api-1.3.7.tgz#a86c770d2b03e11e3f778cd7aedd82d2722092aa"
dependencies:
async "^2.1.4"
fileset "^2.0.2"
- istanbul-lib-coverage "^1.1.1"
- istanbul-lib-hook "^1.1.0"
- istanbul-lib-instrument "^1.9.1"
- istanbul-lib-report "^1.1.2"
- istanbul-lib-source-maps "^1.2.2"
- istanbul-reports "^1.1.3"
+ istanbul-lib-coverage "^1.2.1"
+ istanbul-lib-hook "^1.2.2"
+ istanbul-lib-instrument "^1.10.2"
+ istanbul-lib-report "^1.1.5"
+ istanbul-lib-source-maps "^1.2.6"
+ istanbul-reports "^1.5.1"
js-yaml "^3.7.0"
mkdirp "^0.5.1"
once "^1.4.0"
-istanbul-lib-coverage@^1.1.1, istanbul-lib-coverage@^1.2.0:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-1.2.0.tgz#f7d8f2e42b97e37fe796114cb0f9d68b5e3a4341"
+istanbul-lib-coverage@^1.2.1:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-1.2.1.tgz#ccf7edcd0a0bb9b8f729feeb0930470f9af664f0"
-istanbul-lib-hook@^1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/istanbul-lib-hook/-/istanbul-lib-hook-1.1.0.tgz#8538d970372cb3716d53e55523dd54b557a8d89b"
+istanbul-lib-coverage@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.1.tgz#2aee0e073ad8c5f6a0b00e0dfbf52b4667472eda"
+
+istanbul-lib-hook@^1.2.2:
+ version "1.2.2"
+ resolved "https://registry.yarnpkg.com/istanbul-lib-hook/-/istanbul-lib-hook-1.2.2.tgz#bc6bf07f12a641fbf1c85391d0daa8f0aea6bf86"
dependencies:
append-transform "^0.4.0"
-istanbul-lib-instrument@^1.10.1, istanbul-lib-instrument@^1.9.1:
- version "1.10.1"
- resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-1.10.1.tgz#724b4b6caceba8692d3f1f9d0727e279c401af7b"
+istanbul-lib-instrument@^1.10.2:
+ version "1.10.2"
+ resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-1.10.2.tgz#1f55ed10ac3c47f2bdddd5307935126754d0a9ca"
dependencies:
babel-generator "^6.18.0"
babel-template "^6.16.0"
babel-traverse "^6.18.0"
babel-types "^6.18.0"
babylon "^6.18.0"
- istanbul-lib-coverage "^1.2.0"
+ istanbul-lib-coverage "^1.2.1"
semver "^5.3.0"
-istanbul-lib-report@^1.1.2:
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-1.1.2.tgz#922be27c13b9511b979bd1587359f69798c1d425"
+istanbul-lib-instrument@^2.2.0:
+ version "2.3.2"
+ resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-2.3.2.tgz#b287cbae2b5f65f3567b05e2e29b275eaf92d25e"
+ dependencies:
+ "@babel/generator" "7.0.0-beta.51"
+ "@babel/parser" "7.0.0-beta.51"
+ "@babel/template" "7.0.0-beta.51"
+ "@babel/traverse" "7.0.0-beta.51"
+ "@babel/types" "7.0.0-beta.51"
+ istanbul-lib-coverage "^2.0.1"
+ semver "^5.5.0"
+
+istanbul-lib-report@^1.1.5:
+ version "1.1.5"
+ resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-1.1.5.tgz#f2a657fc6282f96170aaf281eb30a458f7f4170c"
dependencies:
- istanbul-lib-coverage "^1.1.1"
+ istanbul-lib-coverage "^1.2.1"
mkdirp "^0.5.1"
path-parse "^1.0.5"
supports-color "^3.1.2"
-istanbul-lib-source-maps@^1.2.2:
- version "1.2.2"
- resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-1.2.2.tgz#750578602435f28a0c04ee6d7d9e0f2960e62c1c"
+istanbul-lib-source-maps@^1.2.6:
+ version "1.2.6"
+ resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-1.2.6.tgz#37b9ff661580f8fca11232752ee42e08c6675d8f"
dependencies:
debug "^3.1.0"
- istanbul-lib-coverage "^1.1.1"
+ istanbul-lib-coverage "^1.2.1"
mkdirp "^0.5.1"
rimraf "^2.6.1"
source-map "^0.5.3"
-istanbul-reports@^1.1.3:
- version "1.1.3"
- resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-1.1.3.tgz#3b9e1e8defb6d18b1d425da8e8b32c5a163f2d10"
+istanbul-reports@^1.5.1:
+ version "1.5.1"
+ resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-1.5.1.tgz#97e4dbf3b515e8c484caea15d6524eebd3ff4e1a"
dependencies:
handlebars "^4.0.3"
@@ -4145,9 +4268,13 @@ js-tokens@^3.0.0, js-tokens@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b"
-js-yaml@3.x, js-yaml@^3.7.0, js-yaml@^3.9.1:
- version "3.11.0"
- resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.11.0.tgz#597c1a8bd57152f26d622ce4117851a51f5ebaef"
+"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
+
+js-yaml@3.x, js-yaml@^3.12.0, js-yaml@^3.7.0:
+ version "3.12.0"
+ resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.12.0.tgz#eaed656ec8344f10f527c6bfa1b6e2244de167d1"
dependencies:
argparse "^1.0.7"
esprima "^4.0.0"
@@ -4168,13 +4295,13 @@ json-buffer@3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898"
-json-parse-better-errors@^1.0.2:
+json-parse-better-errors@^1.0.1, json-parse-better-errors@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9"
-json-schema-traverse@^0.3.0:
- version "0.3.1"
- resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340"
+json-schema-traverse@^0.4.1:
+ version "0.4.1"
+ resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
json-stable-stringify-without-jsonify@^1.0.1:
version "1.0.1"
@@ -4210,10 +4337,10 @@ karma-chrome-launcher@^2.2.0:
which "^1.2.1"
karma-coverage-istanbul-reporter@^1.4.2:
- version "1.4.2"
- resolved "https://registry.yarnpkg.com/karma-coverage-istanbul-reporter/-/karma-coverage-istanbul-reporter-1.4.2.tgz#a8d0c8815c7d6f6cea15a394a7c4b39ef151a939"
+ version "1.4.3"
+ resolved "https://registry.yarnpkg.com/karma-coverage-istanbul-reporter/-/karma-coverage-istanbul-reporter-1.4.3.tgz#3b5dff4664fa5b8d5196b9889e3f61c1fa2b80d9"
dependencies:
- istanbul-api "^1.1.14"
+ istanbul-api "^1.3.1"
minimatch "^3.0.4"
karma-jasmine@^1.1.2:
@@ -4242,15 +4369,14 @@ karma-sourcemap-loader@^0.3.7:
graceful-fs "^4.1.2"
karma-webpack@^4.0.0-beta.0:
- version "4.0.0-beta.0"
- resolved "https://registry.yarnpkg.com/karma-webpack/-/karma-webpack-4.0.0-beta.0.tgz#2b386df6c364f588f896ffbdae57c2e51513d1ba"
+ version "4.0.0-rc.2"
+ resolved "https://registry.yarnpkg.com/karma-webpack/-/karma-webpack-4.0.0-rc.2.tgz#4c194e94789842af7f0ffa0de77ee7715739c7c1"
dependencies:
async "^2.0.0"
- babel-runtime "^6.0.0"
- loader-utils "^1.0.0"
- lodash "^4.0.0"
+ loader-utils "^1.1.0"
+ lodash "^4.17.10"
source-map "^0.5.6"
- webpack-dev-middleware "^3.0.1"
+ webpack-dev-middleware "^3.2.0"
karma@^3.0.0:
version "3.0.0"
@@ -4326,21 +4452,17 @@ latest-version@^3.0.0:
dependencies:
package-json "^4.0.0"
-lazy-cache@^1.0.3:
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e"
-
lazy-cache@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-2.0.2.tgz#b9190a4f913354694840859f8a8f7084d8822264"
dependencies:
set-getter "^0.1.0"
-lcid@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835"
+lcid@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/lcid/-/lcid-2.0.0.tgz#6ef5d2df60e52f82eb228a4c373e8d1f397253cf"
dependencies:
- invert-kv "^1.0.0"
+ invert-kv "^2.0.0"
levn@^0.3.0, levn@~0.3.0:
version "0.3.0"
@@ -4355,16 +4477,6 @@ lie@~3.1.0:
dependencies:
immediate "~3.0.5"
-load-json-file@^1.0.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0"
- dependencies:
- graceful-fs "^4.1.2"
- parse-json "^2.2.0"
- pify "^2.0.0"
- pinkie-promise "^2.0.0"
- strip-bom "^2.0.0"
-
load-json-file@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-2.0.0.tgz#7947e42149af80d696cbf797bcaabcfe1fe29ca8"
@@ -4374,6 +4486,15 @@ load-json-file@^2.0.0:
pify "^2.0.0"
strip-bom "^3.0.0"
+load-json-file@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-4.0.0.tgz#2f5f45ab91e33216234fd53adab668eb4ec0993b"
+ dependencies:
+ graceful-fs "^4.1.2"
+ parse-json "^4.0.0"
+ pify "^3.0.0"
+ strip-bom "^3.0.0"
+
loader-runner@^2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.3.0.tgz#f482aea82d543e07921700d5a46ef26fdac6b8a2"
@@ -4393,6 +4514,13 @@ locate-path@^2.0.0:
p-locate "^2.0.0"
path-exists "^3.0.0"
+locate-path@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e"
+ dependencies:
+ p-locate "^3.0.0"
+ path-exists "^3.0.0"
+
lodash.camelcase@4.3.0, lodash.camelcase@^4.3.0:
version "4.3.0"
resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6"
@@ -4441,9 +4569,9 @@ lodash@4.17.4:
version "4.17.4"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae"
-lodash@^4.0.0, lodash@^4.11.1, lodash@^4.17.10, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.2.0, lodash@^4.3.0, lodash@^4.5.0:
- version "4.17.10"
- resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7"
+lodash@^4.11.1, lodash@^4.17.10, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.3.0, lodash@^4.5.0:
+ version "4.17.11"
+ resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d"
log-symbols@^2.1.0:
version "2.2.0"
@@ -4465,29 +4593,13 @@ loglevel@^1.4.1:
version "1.4.1"
resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.4.1.tgz#95b383f91a3c2756fd4ab093667e4309161f2bcd"
-loglevelnext@^1.0.1:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/loglevelnext/-/loglevelnext-1.0.3.tgz#0f69277e73bbbf2cd61b94d82313216bf87ac66e"
-
-long@4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/long/-/long-4.0.0.tgz#9a7b71cfb7d361a194ea555241c92f7468d5bf28"
-
-long@^3.2.0:
- version "3.2.0"
- resolved "https://registry.yarnpkg.com/long/-/long-3.2.0.tgz#d821b7138ca1cb581c172990ef14db200b5c474b"
-
-longest@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097"
-
loose-envify@^1.0.0:
- version "1.3.1"
- resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848"
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
dependencies:
- js-tokens "^3.0.0"
+ js-tokens "^3.0.0 || ^4.0.0"
-loud-rejection@^1.0.0, loud-rejection@^1.6.0:
+loud-rejection@^1.6.0:
version "1.6.0"
resolved "https://registry.yarnpkg.com/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f"
dependencies:
@@ -4502,7 +4614,7 @@ lru-cache@2.2.x:
version "2.2.4"
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-2.2.4.tgz#6c658619becf14031d0d0b594b16042ce4dc063d"
-lru-cache@^4.0.1, lru-cache@^4.1.1, lru-cache@^4.1.2:
+lru-cache@^4.0.1, lru-cache@^4.1.1, lru-cache@^4.1.2, lru-cache@^4.1.3:
version "4.1.3"
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.3.tgz#a1175cf3496dfc8436c156c334b4955992bce69c"
dependencies:
@@ -4523,14 +4635,16 @@ mamacro@^0.0.3:
version "0.0.3"
resolved "https://registry.yarnpkg.com/mamacro/-/mamacro-0.0.3.tgz#ad2c9576197c9f1abf308d0787865bd975a3f3e4"
+map-age-cleaner@^0.1.1:
+ version "0.1.2"
+ resolved "https://registry.yarnpkg.com/map-age-cleaner/-/map-age-cleaner-0.1.2.tgz#098fb15538fd3dbe461f12745b0ca8568d4e3f74"
+ dependencies:
+ p-defer "^1.0.0"
+
map-cache@^0.2.2:
version "0.2.2"
resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf"
-map-obj@^1.0.0, map-obj@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d"
-
map-stream@~0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/map-stream/-/map-stream-0.1.0.tgz#e56aa94c4c8055a16404a0674b78f215f7c8e194"
@@ -4560,11 +4674,13 @@ media-typer@0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
-mem@^1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/mem/-/mem-1.1.0.tgz#5edd52b485ca1d900fe64895505399a0dfa45f76"
+mem@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/mem/-/mem-4.0.0.tgz#6437690d9471678f6cc83659c00cbafcd6b0cdaf"
dependencies:
+ map-age-cleaner "^0.1.1"
mimic-fn "^1.0.0"
+ p-is-promise "^1.1.0"
memory-fs@^0.2.0:
version "0.2.0"
@@ -4577,21 +4693,6 @@ memory-fs@^0.4.0, memory-fs@~0.4.1:
errno "^0.1.3"
readable-stream "^2.0.1"
-meow@^3.3.0:
- version "3.7.0"
- resolved "https://registry.yarnpkg.com/meow/-/meow-3.7.0.tgz#72cb668b425228290abbfa856892587308a801fb"
- dependencies:
- camelcase-keys "^2.0.0"
- decamelize "^1.1.2"
- loud-rejection "^1.0.0"
- map-obj "^1.0.1"
- minimist "^1.1.3"
- normalize-package-data "^2.3.4"
- object-assign "^4.0.1"
- read-pkg-up "^1.0.1"
- redent "^1.0.0"
- trim-newlines "^1.0.0"
-
merge-descriptors@1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61"
@@ -4635,7 +4736,7 @@ miller-rabin@^4.0.0:
version "1.33.0"
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.33.0.tgz#a3492050a5cb9b63450541e39d9788d2272783db"
-mime-types@~2.1.15, mime-types@~2.1.16, mime-types@~2.1.18:
+mime-types@~2.1.15, mime-types@~2.1.18:
version "2.1.18"
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.18.tgz#6f323f60a83d11146f831ff11fd66e2fe5503bb8"
dependencies:
@@ -4645,7 +4746,7 @@ mime@1.4.1:
version "1.4.1"
resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6"
-mime@^2.0.3, mime@^2.1.0, mime@^2.3.1:
+mime@^2.0.3, mime@^2.3.1:
version "2.3.1"
resolved "https://registry.yarnpkg.com/mime/-/mime-2.3.1.tgz#b1621c54d63b97c47d3cfe7f7215f7d64517c369"
@@ -4673,15 +4774,15 @@ minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1:
minimist@0.0.8:
version "0.0.8"
- resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
+ resolved "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
-minimist@1.2.0, minimist@^1.1.3, minimist@^1.2.0:
+minimist@1.2.0, minimist@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
minimist@~0.0.1:
version "0.0.10"
- resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf"
+ resolved "http://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf"
minipass@^2.2.1, minipass@^2.3.3:
version "2.3.3"
@@ -4711,6 +4812,21 @@ mississippi@^2.0.0:
stream-each "^1.1.0"
through2 "^2.0.0"
+mississippi@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/mississippi/-/mississippi-3.0.0.tgz#ea0a3291f97e0b5e8776b363d5f0a12d94c67022"
+ dependencies:
+ concat-stream "^1.5.0"
+ duplexify "^3.4.2"
+ end-of-stream "^1.1.0"
+ flush-write-stream "^1.0.0"
+ from2 "^2.1.0"
+ parallel-transform "^1.1.0"
+ pump "^3.0.0"
+ pumpify "^1.3.3"
+ stream-each "^1.1.0"
+ through2 "^2.0.0"
+
mixin-deep@^1.2.0:
version "1.3.1"
resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.1.tgz#a49e7268dce1a0d9698e45326c5626df3543d0fe"
@@ -4720,7 +4836,7 @@ mixin-deep@^1.2.0:
mkdirp@0.5.x, mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0:
version "0.5.1"
- resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
+ resolved "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
dependencies:
minimist "0.0.8"
@@ -4728,9 +4844,9 @@ moment@2.x, moment@^2.18.1:
version "2.19.2"
resolved "https://registry.yarnpkg.com/moment/-/moment-2.19.2.tgz#8a7f774c95a64550b4c7ebd496683908f9419dbe"
-monaco-editor-webpack-plugin@^1.5.2:
- version "1.5.2"
- resolved "https://registry.yarnpkg.com/monaco-editor-webpack-plugin/-/monaco-editor-webpack-plugin-1.5.2.tgz#e113fa1d5759ede6fd776eb620cdd5930203b55a"
+monaco-editor-webpack-plugin@^1.5.4:
+ version "1.5.4"
+ resolved "https://registry.yarnpkg.com/monaco-editor-webpack-plugin/-/monaco-editor-webpack-plugin-1.5.4.tgz#6781a130e3e1379bb8f4cd190132f4af6dcd2c16"
monaco-editor@^0.14.3:
version "0.14.3"
@@ -4755,6 +4871,10 @@ ms@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
+ms@^2.1.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a"
+
multicast-dns-service-types@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz#899f11d9686e5e05cb91b35d5f0e63b773cfc901"
@@ -4869,9 +4989,9 @@ node-pre-gyp@^0.10.0:
semver "^5.3.0"
tar "^4"
-nodemon@^1.18.2:
- version "1.18.2"
- resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-1.18.2.tgz#36b89c790da70c4f270e2cc0718723131bc04abb"
+nodemon@^1.18.4:
+ version "1.18.4"
+ resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-1.18.4.tgz#873f65fdb53220eb166180cf106b1354ac5d714d"
dependencies:
chokidar "^2.0.2"
debug "^3.1.0"
@@ -4903,7 +5023,7 @@ nopt@~1.0.10:
dependencies:
abbrev "1"
-normalize-package-data@^2.3.2, normalize-package-data@^2.3.4:
+normalize-package-data@^2.3.2:
version "2.4.0"
resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.4.0.tgz#12f95a307d58352075a04907b84ac8be98ac012f"
dependencies:
@@ -4976,9 +5096,9 @@ object-copy@^0.1.0:
define-property "^0.2.5"
kind-of "^3.0.3"
-object-keys@^1.0.8:
- version "1.0.11"
- resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.0.11.tgz#c54601778ad560f1142ce0e01bcca8b56d13426d"
+object-keys@^1.0.11, object-keys@^1.0.12:
+ version "1.0.12"
+ resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.0.12.tgz#09c53855377575310cca62f55bb334abff7b3ed2"
object-visit@^1.0.0:
version "1.0.1"
@@ -4986,6 +5106,24 @@ object-visit@^1.0.0:
dependencies:
isobject "^3.0.0"
+object.assign@^4.1.0:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da"
+ dependencies:
+ define-properties "^1.1.2"
+ function-bind "^1.1.1"
+ has-symbols "^1.0.0"
+ object-keys "^1.0.11"
+
+object.entries@^1.0.4:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.0.4.tgz#1bf9a4dd2288f5b33f3a993d257661f05d161a5f"
+ dependencies:
+ define-properties "^1.1.2"
+ es-abstract "^1.6.1"
+ function-bind "^1.1.0"
+ has "^1.0.1"
+
object.pick@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747"
@@ -5029,9 +5167,9 @@ opencollective@^1.0.3:
node-fetch "1.6.3"
opn "4.0.2"
-opener@^1.4.3:
- version "1.4.3"
- resolved "https://registry.yarnpkg.com/opener/-/opener-1.4.3.tgz#5c6da2c5d7e5831e8ffa3964950f8d6674ac90b8"
+opener@^1.5.1:
+ version "1.5.1"
+ resolved "https://registry.yarnpkg.com/opener/-/opener-1.5.1.tgz#6d2f0e77f1a0af0032aca716c2c1fbb8e7e8abed"
opn@4.0.2:
version "4.0.2"
@@ -5078,13 +5216,13 @@ os-homedir@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3"
-os-locale@^2.0.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-2.1.0.tgz#42bc2900a6b5b8bd17376c8e882b65afccf24bf2"
+os-locale@^3.0.0:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-3.0.1.tgz#3b014fbf01d87f60a1e5348d80fe870dc82c4620"
dependencies:
- execa "^0.7.0"
- lcid "^1.0.0"
- mem "^1.1.0"
+ execa "^0.10.0"
+ lcid "^2.0.0"
+ mem "^4.0.0"
os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.2:
version "1.0.2"
@@ -5101,6 +5239,10 @@ p-cancelable@^0.4.0:
version "0.4.1"
resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-0.4.1.tgz#35f363d67d52081c8d9585e37bcceb7e0bbcb2a0"
+p-defer@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/p-defer/-/p-defer-1.0.0.tgz#9f6eb182f6c9aa8cd743004a7d4f96b196b0fb0c"
+
p-finally@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae"
@@ -5115,12 +5257,24 @@ p-limit@^1.1.0:
dependencies:
p-try "^1.0.0"
+p-limit@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.0.0.tgz#e624ed54ee8c460a778b3c9f3670496ff8a57aec"
+ dependencies:
+ p-try "^2.0.0"
+
p-locate@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43"
dependencies:
p-limit "^1.1.0"
+p-locate@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4"
+ dependencies:
+ p-limit "^2.0.0"
+
p-map@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/p-map/-/p-map-1.1.1.tgz#05f5e4ae97a068371bc2a5cc86bfbdbc19c4ae7a"
@@ -5135,6 +5289,10 @@ p-try@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3"
+p-try@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.0.0.tgz#85080bb87c64688fa47996fe8f7dfbe8211760b1"
+
package-json@^4.0.0:
version "4.0.1"
resolved "https://registry.yarnpkg.com/package-json/-/package-json-4.0.1.tgz#8869a0401253661c4c4ca3da6c2121ed555f5eed"
@@ -5172,6 +5330,13 @@ parse-json@^2.2.0:
dependencies:
error-ex "^1.2.0"
+parse-json@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0"
+ dependencies:
+ error-ex "^1.3.1"
+ json-parse-better-errors "^1.0.1"
+
parse5@^5:
version "5.0.0"
resolved "https://registry.yarnpkg.com/parse5/-/parse5-5.0.0.tgz#4d02710d44f3c3846197a11e205d4ef17842b81a"
@@ -5227,27 +5392,25 @@ path-key@^2.0.0, path-key@^2.0.1:
resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40"
path-parse@^1.0.5:
- version "1.0.5"
- resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1"
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c"
path-to-regexp@0.1.7:
version "0.1.7"
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c"
-path-type@^1.0.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441"
- dependencies:
- graceful-fs "^4.1.2"
- pify "^2.0.0"
- pinkie-promise "^2.0.0"
-
path-type@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73"
dependencies:
pify "^2.0.0"
+path-type@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f"
+ dependencies:
+ pify "^3.0.0"
+
pause-stream@0.0.11:
version "0.0.11"
resolved "https://registry.yarnpkg.com/pause-stream/-/pause-stream-0.0.11.tgz#fe5a34b0cbce12b5aa6a2b403ee2e73b602f1445"
@@ -5300,6 +5463,12 @@ pkg-dir@^2.0.0:
dependencies:
find-up "^2.1.0"
+pkg-dir@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-3.0.0.tgz#2749020f239ed990881b1f71210d51eb6523bea3"
+ dependencies:
+ find-up "^3.0.0"
+
pluralize@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-7.0.0.tgz#298b89df8b93b0221dbf421ad2b1b1ea23fc6777"
@@ -5383,10 +5552,14 @@ prepend-http@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897"
-prettier@1.12.1, prettier@^1.11.1:
+prettier@1.12.1:
version "1.12.1"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.12.1.tgz#c1ad20e803e7749faf905a409d2367e06bbe7325"
+prettier@1.13.7:
+ version "1.13.7"
+ resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.13.7.tgz#850f3b8af784a49a6ea2d2eaa7ed1428a34b7281"
+
prismjs@^1.6.0:
version "1.6.0"
resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.6.0.tgz#118d95fb7a66dba2272e343b345f5236659db365"
@@ -5417,12 +5590,12 @@ promise-inflight@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3"
-proxy-addr@~2.0.2:
- version "2.0.3"
- resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.3.tgz#355f262505a621646b3130a728eb647e22055341"
+proxy-addr@~2.0.3:
+ version "2.0.4"
+ resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.4.tgz#ecfc733bf22ff8c6f407fa275327b9ab67e48b93"
dependencies:
forwarded "~0.1.2"
- ipaddr.js "1.6.0"
+ ipaddr.js "1.8.0"
prr@~1.0.1:
version "1.0.1"
@@ -5461,6 +5634,13 @@ pump@^2.0.0, pump@^2.0.1:
end-of-stream "^1.1.0"
once "^1.3.1"
+pump@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64"
+ dependencies:
+ end-of-stream "^1.1.0"
+ once "^1.3.1"
+
pumpify@^1.3.3:
version "1.4.0"
resolved "https://registry.yarnpkg.com/pumpify/-/pumpify-1.4.0.tgz#80b7c5df7e24153d03f0e7ac8a05a5d068bd07fb"
@@ -5473,6 +5653,10 @@ punycode@1.3.2, punycode@^1.2.4:
version "1.3.2"
resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d"
+punycode@^2.1.0:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
+
qjobs@^1.1.4:
version "1.2.0"
resolved "https://registry.yarnpkg.com/qjobs/-/qjobs-1.2.0.tgz#c45e9c61800bd087ef88d7e256423bdd49e5d071"
@@ -5554,13 +5738,6 @@ rc@^1.0.1, rc@^1.1.6, rc@^1.1.7:
minimist "^1.2.0"
strip-json-comments "~2.0.1"
-read-pkg-up@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02"
- dependencies:
- find-up "^1.0.0"
- read-pkg "^1.0.0"
-
read-pkg-up@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-2.0.0.tgz#6b72a8048984e0c41e79510fd5e9fa99b3b549be"
@@ -5568,13 +5745,12 @@ read-pkg-up@^2.0.0:
find-up "^2.0.0"
read-pkg "^2.0.0"
-read-pkg@^1.0.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28"
+read-pkg-up@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-4.0.0.tgz#1b221c6088ba7799601c808f91161c66e58f8978"
dependencies:
- load-json-file "^1.0.0"
- normalize-package-data "^2.3.2"
- path-type "^1.0.0"
+ find-up "^3.0.0"
+ read-pkg "^3.0.0"
read-pkg@^2.0.0:
version "2.0.0"
@@ -5584,6 +5760,14 @@ read-pkg@^2.0.0:
normalize-package-data "^2.3.2"
path-type "^2.0.0"
+read-pkg@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-3.0.0.tgz#9cbc686978fee65d16c00e2b19c237fcf6e38389"
+ dependencies:
+ load-json-file "^4.0.0"
+ normalize-package-data "^2.3.2"
+ path-type "^3.0.0"
+
"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.4, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.2.9, readable-stream@^2.3.0, readable-stream@^2.3.3, readable-stream@^2.3.6:
version "2.3.6"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf"
@@ -5616,13 +5800,6 @@ readdirp@^2.0.0:
readable-stream "^2.0.2"
set-immediate-shim "^1.0.1"
-redent@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/redent/-/redent-1.0.0.tgz#cf916ab1fd5f1f16dfb20822dd6ec7f730c2afde"
- dependencies:
- indent-string "^2.1.0"
- strip-indent "^1.0.1"
-
regenerate@^1.2.1:
version "1.3.2"
resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.3.2.tgz#d1941c67bad437e1be76433add5b385f95b19260"
@@ -5632,8 +5809,8 @@ regenerator-runtime@^0.10.0:
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz#336c3efc1220adcedda2c9fab67b5a7955a33658"
regenerator-runtime@^0.11.0:
- version "0.11.0"
- resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.0.tgz#7e54fe5b5ccd5d6624ea6255c3473be090b802e1"
+ version "0.11.1"
+ resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9"
regenerator-transform@^0.10.0:
version "0.10.1"
@@ -5650,6 +5827,10 @@ regex-not@^1.0.0, regex-not@^1.0.2:
extend-shallow "^3.0.2"
safe-regex "^1.1.0"
+regexpp@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.0.tgz#b2a7534a85ca1b033bcf5ce9ff8e56d4e0755365"
+
regexpu-core@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-1.0.0.tgz#86a763f58ee4d7c2f6b102e4764050de7ed90c6b"
@@ -5701,7 +5882,7 @@ repeat-string@^0.2.2:
version "0.2.2"
resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-0.2.2.tgz#c7a8d3236068362059a7e4651fc6884e8b1fb4ae"
-repeat-string@^1.5.2, repeat-string@^1.6.1:
+repeat-string@^1.6.1:
version "1.6.1"
resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637"
@@ -5779,12 +5960,6 @@ rfdc@^1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.1.2.tgz#e6e72d74f5dc39de8f538f65e00c36c18018e349"
-right-align@^0.1.1:
- version "0.1.3"
- resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef"
- dependencies:
- align-text "^0.1.1"
-
rimraf@^2.2.8, rimraf@^2.5.4, rimraf@^2.6.0, rimraf@^2.6.1, rimraf@^2.6.2:
version "2.6.2"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36"
@@ -5814,16 +5989,6 @@ rw@1:
version "1.3.3"
resolved "https://registry.yarnpkg.com/rw/-/rw-1.3.3.tgz#3f862dfa91ab766b14885ef4d01124bfda074fb4"
-rx-lite-aggregates@^4.0.8:
- version "4.0.8"
- resolved "https://registry.yarnpkg.com/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz#753b87a89a11c95467c4ac1626c4efc4e05c67be"
- dependencies:
- rx-lite "*"
-
-rx-lite@*, rx-lite@^4.0.8:
- version "4.0.8"
- resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-4.0.8.tgz#0b1e11af8bc44836f04a6407e92da42467b79444"
-
rx@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/rx/-/rx-4.1.0.tgz#a5f13ff79ef3b740fe30aa803fb09f98805d4782"
@@ -5868,13 +6033,21 @@ sax@^1.2.4:
version "1.2.4"
resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
-schema-utils@^0.4.0, schema-utils@^0.4.2, schema-utils@^0.4.3, schema-utils@^0.4.4, schema-utils@^0.4.5:
+schema-utils@^0.4.0, schema-utils@^0.4.2, schema-utils@^0.4.4, schema-utils@^0.4.5:
version "0.4.5"
resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-0.4.5.tgz#21836f0608aac17b78f9e3e24daff14a5ca13a3e"
dependencies:
ajv "^6.1.0"
ajv-keywords "^3.1.0"
+schema-utils@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-1.0.0.tgz#0b79a93204d7b600d4b2850d1f66c2a34951c770"
+ dependencies:
+ ajv "^6.1.0"
+ ajv-errors "^1.0.0"
+ ajv-keywords "^3.1.0"
+
select-hose@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca"
@@ -5899,18 +6072,18 @@ semver-diff@^2.0.0:
dependencies:
semver "^5.0.3"
-"semver@2 || 3 || 4 || 5", semver@^5.0.3, semver@^5.1.0, semver@^5.3.0, semver@^5.5.0:
- version "5.5.0"
- resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab"
+"semver@2 || 3 || 4 || 5", semver@^5.0.3, semver@^5.1.0, semver@^5.3.0, semver@^5.5.0, semver@^5.5.1:
+ version "5.5.1"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.1.tgz#7dfdd8814bdb7cabc7be0fb1d734cfb66c940477"
-send@0.16.1:
- version "0.16.1"
- resolved "https://registry.yarnpkg.com/send/-/send-0.16.1.tgz#a70e1ca21d1382c11d0d9f6231deb281080d7ab3"
+send@0.16.2:
+ version "0.16.2"
+ resolved "https://registry.yarnpkg.com/send/-/send-0.16.2.tgz#6ecca1e0f8c156d141597559848df64730a6bbc1"
dependencies:
debug "2.6.9"
- depd "~1.1.1"
+ depd "~1.1.2"
destroy "~1.0.4"
- encodeurl "~1.0.1"
+ encodeurl "~1.0.2"
escape-html "~1.0.3"
etag "~1.8.1"
fresh "0.5.2"
@@ -5919,7 +6092,7 @@ send@0.16.1:
ms "2.0.0"
on-finished "~2.3.0"
range-parser "~1.2.0"
- statuses "~1.3.1"
+ statuses "~1.4.0"
serialize-javascript@^1.4.0:
version "1.4.0"
@@ -5937,14 +6110,14 @@ serve-index@^1.7.2:
mime-types "~2.1.15"
parseurl "~1.3.1"
-serve-static@1.13.1:
- version "1.13.1"
- resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.13.1.tgz#4c57d53404a761d8f2e7c1e8a18a47dbf278a719"
+serve-static@1.13.2:
+ version "1.13.2"
+ resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.13.2.tgz#095e8472fd5b46237db50ce486a43f4b86c6cec1"
dependencies:
- encodeurl "~1.0.1"
+ encodeurl "~1.0.2"
escape-html "~1.0.3"
parseurl "~1.3.2"
- send "0.16.1"
+ send "0.16.2"
set-blocking@^2.0.0, set-blocking@~2.0.0:
version "2.0.0"
@@ -6105,9 +6278,9 @@ socket.io@2.1.1:
socket.io-client "2.1.1"
socket.io-parser "~3.2.0"
-sockjs-client@1.1.4:
- version "1.1.4"
- resolved "https://registry.yarnpkg.com/sockjs-client/-/sockjs-client-1.1.4.tgz#5babe386b775e4cf14e7520911452654016c8b12"
+sockjs-client@1.1.5:
+ version "1.1.5"
+ resolved "https://registry.yarnpkg.com/sockjs-client/-/sockjs-client-1.1.5.tgz#1bb7c0f7222c40f42adf14f4442cbd1269771a83"
dependencies:
debug "^2.6.6"
eventsource "0.1.6"
@@ -6161,13 +6334,7 @@ source-map@0.5.0:
version "0.5.0"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.0.tgz#0fe96503ac86a5adb5de63f4e412ae4872cdbe86"
-source-map@^0.4.4:
- version "0.4.4"
- resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b"
- dependencies:
- amdefine ">=0.0.4"
-
-source-map@^0.5.0, source-map@^0.5.3, source-map@^0.5.6, source-map@^0.5.7, source-map@~0.5.1:
+source-map@^0.5.0, source-map@^0.5.3, source-map@^0.5.6, source-map@^0.5.7:
version "0.5.7"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
@@ -6251,6 +6418,12 @@ ssri@^5.2.4:
dependencies:
safe-buffer "^5.1.1"
+ssri@^6.0.0:
+ version "6.0.1"
+ resolved "https://registry.yarnpkg.com/ssri/-/ssri-6.0.1.tgz#2a3c41b28dd45b62b63676ecb74001265ae9edd8"
+ dependencies:
+ figgy-pudding "^3.5.1"
+
static-extend@^0.1.1:
version "0.1.2"
resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6"
@@ -6258,7 +6431,11 @@ static-extend@^0.1.1:
define-property "^0.2.5"
object-copy "^0.1.0"
-"statuses@>= 1.3.1 < 2", statuses@~1.3.1:
+"statuses@>= 1.3.1 < 2", statuses@~1.4.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087"
+
+statuses@~1.3.1:
version "1.3.1"
resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e"
@@ -6364,19 +6541,13 @@ strip-eof@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf"
-strip-indent@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-1.0.1.tgz#0c7962a6adefa7bbd4ac366460a638552ae1a0a2"
- dependencies:
- get-stdin "^4.0.1"
-
-strip-json-comments@~2.0.1:
+strip-json-comments@^2.0.1, strip-json-comments@~2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
-style-loader@^0.21.0:
- version "0.21.0"
- resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-0.21.0.tgz#68c52e5eb2afc9ca92b6274be277ee59aea3a852"
+style-loader@^0.23.0:
+ version "0.23.0"
+ resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-0.23.0.tgz#8377fefab68416a2e05f1cabd8c3a3acfcce74f1"
dependencies:
loader-utils "^1.1.0"
schema-utils "^0.4.5"
@@ -6392,8 +6563,8 @@ supports-color@^3.1.0, supports-color@^3.1.2:
has-flag "^1.0.0"
supports-color@^5.1.0, supports-color@^5.2.0, supports-color@^5.3.0, supports-color@^5.4.0:
- version "5.4.0"
- resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.4.0.tgz#1c6b337402c2137605efe19f10fec390f6faab54"
+ version "5.5.0"
+ resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
dependencies:
has-flag "^3.0.0"
@@ -6401,12 +6572,12 @@ svg4everybody@2.1.9:
version "2.1.9"
resolved "https://registry.yarnpkg.com/svg4everybody/-/svg4everybody-2.1.9.tgz#5bd9f6defc133859a044646d4743fabc28db7e2d"
-table@^4.0.1:
- version "4.0.2"
- resolved "https://registry.yarnpkg.com/table/-/table-4.0.2.tgz#a33447375391e766ad34d3486e6e2aedc84d2e36"
+table@^4.0.3:
+ version "4.0.3"
+ resolved "http://registry.npmjs.org/table/-/table-4.0.3.tgz#00b5e2b602f1794b9acaf9ca908a76386a7813bc"
dependencies:
- ajv "^5.2.3"
- ajv-keywords "^2.1.0"
+ ajv "^6.0.1"
+ ajv-keywords "^3.0.0"
chalk "^2.1.0"
lodash "^4.17.4"
slice-ansi "1.0.0"
@@ -6416,9 +6587,9 @@ tapable@^0.1.8:
version "0.1.10"
resolved "https://registry.yarnpkg.com/tapable/-/tapable-0.1.10.tgz#29c35707c2b70e50d07482b5d202e8ed446dafd4"
-tapable@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.0.0.tgz#cbb639d9002eed9c6b5975eb20598d7936f1f9f2"
+tapable@^1.0.0, tapable@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.0.tgz#0d076a172e3d9ba088fd2272b2668fb8d194b78c"
tar@^4:
version "4.4.4"
@@ -6438,17 +6609,16 @@ term-size@^1.2.0:
dependencies:
execa "^0.7.0"
-test-exclude@^4.2.1:
- version "4.2.1"
- resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-4.2.1.tgz#dfa222f03480bca69207ca728b37d74b45f724fa"
+test-exclude@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-5.0.0.tgz#cdce7cece785e0e829cd5c2b27baf18bc583cfb7"
dependencies:
arrify "^1.0.1"
- micromatch "^3.1.8"
- object-assign "^4.1.0"
- read-pkg-up "^1.0.1"
+ minimatch "^3.0.4"
+ read-pkg-up "^4.0.0"
require-main-filename "^1.0.1"
-text-table@~0.2.0:
+text-table@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
@@ -6557,10 +6727,6 @@ traverse@0.6.6:
version "0.6.6"
resolved "https://registry.yarnpkg.com/traverse/-/traverse-0.6.6.tgz#cbdf560fd7b9af632502fed40f918c157ea97137"
-trim-newlines@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613"
-
trim-right@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003"
@@ -6569,10 +6735,6 @@ tryer@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/tryer/-/tryer-1.0.0.tgz#027b69fa823225e551cace3ef03b11f6ab37c1d7"
-tryit@^1.0.1:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/tryit/-/tryit-1.0.3.tgz#393be730a9446fd1ead6da59a014308f36c289cb"
-
tslib@^1.9.0:
version "1.9.3"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286"
@@ -6587,7 +6749,7 @@ type-check@~0.3.2:
dependencies:
prelude-ls "~1.1.2"
-type-is@~1.6.15:
+type-is@~1.6.15, type-is@~1.6.16:
version "1.6.16"
resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.16.tgz#f89ce341541c672b25ee7ae3c73dee3b2be50194"
dependencies:
@@ -6609,18 +6771,12 @@ uglify-es@^3.3.4:
commander "~2.13.0"
source-map "~0.6.1"
-uglify-js@^2.6:
- version "2.8.29"
- resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.29.tgz#29c5733148057bb4e1f75df35b7a9cb72e6a59dd"
+uglify-js@^3.1.4:
+ version "3.4.9"
+ resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.4.9.tgz#af02f180c1207d76432e473ed24a28f4a782bae3"
dependencies:
- source-map "~0.5.1"
- yargs "~3.10.0"
- optionalDependencies:
- uglify-to-browserify "~1.0.0"
-
-uglify-to-browserify@~1.0.0:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7"
+ commander "~2.17.1"
+ source-map "~0.6.1"
uglifyjs-webpack-plugin@^1.2.4:
version "1.2.5"
@@ -6713,6 +6869,12 @@ update-notifier@^2.3.0:
semver-diff "^2.0.0"
xdg-basedir "^3.0.0"
+uri-js@^4.2.2:
+ version "4.2.2"
+ resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0"
+ dependencies:
+ punycode "^2.1.0"
+
urix@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72"
@@ -6721,13 +6883,13 @@ url-join@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/url-join/-/url-join-4.0.0.tgz#4d3340e807d3773bda9991f8305acdcc2a665d2a"
-url-loader@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/url-loader/-/url-loader-1.0.1.tgz#61bc53f1f184d7343da2728a1289ef8722ea45ee"
+url-loader@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/url-loader/-/url-loader-1.1.1.tgz#4d1f3b4f90dde89f02c008e662d604d7511167c1"
dependencies:
loader-utils "^1.1.0"
mime "^2.0.3"
- schema-utils "^0.4.3"
+ schema-utils "^1.0.0"
url-parse-lax@^1.0.0:
version "1.0.0"
@@ -6795,7 +6957,7 @@ utils-merge@1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"
-uuid@^3.0.1, uuid@^3.1.0:
+uuid@^3.0.1, uuid@^3.3.2:
version "3.3.2"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131"
@@ -6828,16 +6990,16 @@ void-elements@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-2.0.1.tgz#c066afb582bb1cb4128d60ea92392e94d5e9dbec"
-vue-eslint-parser@^2.0.3:
- version "2.0.3"
- resolved "https://registry.yarnpkg.com/vue-eslint-parser/-/vue-eslint-parser-2.0.3.tgz#c268c96c6d94cfe3d938a5f7593959b0ca3360d1"
+vue-eslint-parser@^3.2.1:
+ version "3.2.2"
+ resolved "https://registry.yarnpkg.com/vue-eslint-parser/-/vue-eslint-parser-3.2.2.tgz#47c971ee4c39b0ee7d7f5e154cb621beb22f7a34"
dependencies:
debug "^3.1.0"
- eslint-scope "^3.7.1"
+ eslint-scope "^4.0.0"
eslint-visitor-keys "^1.0.0"
- espree "^3.5.2"
- esquery "^1.0.0"
- lodash "^4.17.4"
+ espree "^4.0.0"
+ esquery "^1.0.1"
+ lodash "^4.17.10"
vue-functional-data-merge@^2.0.5:
version "2.0.6"
@@ -6847,11 +7009,11 @@ vue-hot-reload-api@^2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/vue-hot-reload-api/-/vue-hot-reload-api-2.3.0.tgz#97976142405d13d8efae154749e88c4e358cf926"
-vue-loader@^15.2.4:
- version "15.2.4"
- resolved "https://registry.yarnpkg.com/vue-loader/-/vue-loader-15.2.4.tgz#a7b923123d3cf87230a8ff54a1c16d31a6c5dbb4"
+vue-loader@^15.4.2:
+ version "15.4.2"
+ resolved "https://registry.yarnpkg.com/vue-loader/-/vue-loader-15.4.2.tgz#812bb26e447dd3b84c485eb634190d914ce125e2"
dependencies:
- "@vue/component-compiler-utils" "^1.2.1"
+ "@vue/component-compiler-utils" "^2.0.0"
hash-sum "^1.0.2"
loader-utils "^1.1.0"
vue-hot-reload-api "^2.3.0"
@@ -6874,9 +7036,9 @@ vue-style-loader@^4.1.0:
hash-sum "^1.0.2"
loader-utils "^1.0.2"
-vue-template-compiler@^2.5.0, vue-template-compiler@^2.5.16:
- version "2.5.16"
- resolved "https://registry.yarnpkg.com/vue-template-compiler/-/vue-template-compiler-2.5.16.tgz#93b48570e56c720cdf3f051cc15287c26fbd04cb"
+vue-template-compiler@^2.5.0, vue-template-compiler@^2.5.17:
+ version "2.5.17"
+ resolved "https://registry.yarnpkg.com/vue-template-compiler/-/vue-template-compiler-2.5.17.tgz#52a4a078c327deb937482a509ae85c06f346c3cb"
dependencies:
de-indent "^1.0.2"
he "^1.1.0"
@@ -6889,9 +7051,9 @@ vue-virtual-scroll-list@^1.2.5:
version "1.2.5"
resolved "https://registry.yarnpkg.com/vue-virtual-scroll-list/-/vue-virtual-scroll-list-1.2.5.tgz#bcbd010f7cdb035eba8958ebf807c6214d9a167a"
-vue@^2.5.16:
- version "2.5.16"
- resolved "https://registry.yarnpkg.com/vue/-/vue-2.5.16.tgz#07edb75e8412aaeed871ebafa99f4672584a0085"
+vue@^2.5.16, vue@^2.5.17:
+ version "2.5.17"
+ resolved "https://registry.yarnpkg.com/vue/-/vue-2.5.17.tgz#0f8789ad718be68ca1872629832ed533589c6ada"
vuex@^3.0.1:
version "3.0.1"
@@ -6911,26 +7073,26 @@ wbuf@^1.1.0, wbuf@^1.7.2:
dependencies:
minimalistic-assert "^1.0.0"
-webpack-bundle-analyzer@^2.13.1:
- version "2.13.1"
- resolved "https://registry.yarnpkg.com/webpack-bundle-analyzer/-/webpack-bundle-analyzer-2.13.1.tgz#07d2176c6e86c3cdce4c23e56fae2a7b6b4ad526"
+webpack-bundle-analyzer@^3.0.2:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/webpack-bundle-analyzer/-/webpack-bundle-analyzer-3.0.2.tgz#22f19ea6d1b5a15fd7a90baae0bc0f39bd1e4d48"
dependencies:
- acorn "^5.3.0"
- bfj-node4 "^5.2.0"
- chalk "^2.3.0"
- commander "^2.13.0"
- ejs "^2.5.7"
- express "^4.16.2"
- filesize "^3.5.11"
- gzip-size "^4.1.0"
- lodash "^4.17.4"
+ acorn "^5.7.3"
+ bfj "^6.1.1"
+ chalk "^2.4.1"
+ commander "^2.18.0"
+ ejs "^2.6.1"
+ express "^4.16.3"
+ filesize "^3.6.1"
+ gzip-size "^5.0.0"
+ lodash "^4.17.10"
mkdirp "^0.5.1"
- opener "^1.4.3"
- ws "^4.0.0"
+ opener "^1.5.1"
+ ws "^6.0.0"
-webpack-cli@^3.0.8:
- version "3.0.8"
- resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-3.0.8.tgz#90eddcf04a4bfc31aa8c0edc4c76785bc4f1ccd9"
+webpack-cli@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-3.1.0.tgz#d71a83687dcfeb758fdceeb0fe042f96bcf62994"
dependencies:
chalk "^2.4.1"
cross-spawn "^6.0.5"
@@ -6942,26 +7104,25 @@ webpack-cli@^3.0.8:
loader-utils "^1.1.0"
supports-color "^5.4.0"
v8-compile-cache "^2.0.0"
- yargs "^11.1.0"
+ yargs "^12.0.1"
-webpack-dev-middleware@3.1.3, webpack-dev-middleware@^3.0.1:
- version "3.1.3"
- resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-3.1.3.tgz#8b32aa43da9ae79368c1bf1183f2b6cf5e1f39ed"
+webpack-dev-middleware@3.2.0, webpack-dev-middleware@^3.2.0:
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-3.2.0.tgz#a20ceef194873710052da678f3c6ee0aeed92552"
dependencies:
loud-rejection "^1.6.0"
memory-fs "~0.4.1"
- mime "^2.1.0"
+ mime "^2.3.1"
path-is-absolute "^1.0.0"
range-parser "^1.0.3"
url-join "^4.0.0"
- webpack-log "^1.0.1"
+ webpack-log "^2.0.0"
-webpack-dev-server@^3.1.4:
- version "3.1.4"
- resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-3.1.4.tgz#9a08d13c4addd1e3b6d8ace116e86715094ad5b4"
+webpack-dev-server@^3.1.8:
+ version "3.1.8"
+ resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-3.1.8.tgz#eb7a95945d1108170f902604fb3b939533d9daeb"
dependencies:
ansi-html "0.0.7"
- array-includes "^3.0.3"
bonjour "^3.5.0"
chokidar "^2.0.0"
compression "^1.5.2"
@@ -6971,36 +7132,35 @@ webpack-dev-server@^3.1.4:
express "^4.16.2"
html-entities "^1.2.0"
http-proxy-middleware "~0.18.0"
- import-local "^1.0.0"
- internal-ip "1.2.0"
+ import-local "^2.0.0"
+ internal-ip "^3.0.1"
ip "^1.1.5"
killable "^1.0.0"
loglevel "^1.4.1"
opn "^5.1.0"
portfinder "^1.0.9"
+ schema-utils "^1.0.0"
selfsigned "^1.9.1"
serve-index "^1.7.2"
sockjs "0.3.19"
- sockjs-client "1.1.4"
+ sockjs-client "1.1.5"
spdy "^3.4.1"
strip-ansi "^3.0.0"
supports-color "^5.1.0"
- webpack-dev-middleware "3.1.3"
- webpack-log "^1.1.2"
- yargs "11.0.0"
+ webpack-dev-middleware "3.2.0"
+ webpack-log "^2.0.0"
+ yargs "12.0.2"
-webpack-log@^1.0.1, webpack-log@^1.1.2:
- version "1.2.0"
- resolved "https://registry.yarnpkg.com/webpack-log/-/webpack-log-1.2.0.tgz#a4b34cda6b22b518dbb0ab32e567962d5c72a43d"
+webpack-log@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/webpack-log/-/webpack-log-2.0.0.tgz#5b7928e0637593f119d32f6227c1e0ac31e1b47f"
dependencies:
- chalk "^2.1.0"
- log-symbols "^2.1.0"
- loglevelnext "^1.0.1"
- uuid "^3.1.0"
+ ansi-colors "^3.0.0"
+ uuid "^3.3.2"
-webpack-sources@^1.0.1, webpack-sources@^1.1.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.1.0.tgz#a101ebae59d6507354d71d8013950a3a8b7a5a54"
+webpack-sources@^1.0.1, webpack-sources@^1.1.0, webpack-sources@^1.2.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.3.0.tgz#2a28dcb9f1f45fe960d8f1493252b5ee6530fa85"
dependencies:
source-list-map "^2.0.0"
source-map "~0.6.1"
@@ -7009,22 +7169,21 @@ webpack-stats-plugin@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/webpack-stats-plugin/-/webpack-stats-plugin-0.2.1.tgz#1f5bac13fc25d62cbb5fd0ff646757dc802b8595"
-webpack@^4.16.0:
- version "4.16.0"
- resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.16.0.tgz#660dae90890e55b8ed17c6f9d17bebb01dab5b4c"
+webpack@^4.19.1:
+ version "4.19.1"
+ resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.19.1.tgz#096674bc3b573f8756c762754366e5b333d6576f"
dependencies:
- "@webassemblyjs/ast" "1.5.13"
- "@webassemblyjs/helper-module-context" "1.5.13"
- "@webassemblyjs/wasm-edit" "1.5.13"
- "@webassemblyjs/wasm-opt" "1.5.13"
- "@webassemblyjs/wasm-parser" "1.5.13"
+ "@webassemblyjs/ast" "1.7.6"
+ "@webassemblyjs/helper-module-context" "1.7.6"
+ "@webassemblyjs/wasm-edit" "1.7.6"
+ "@webassemblyjs/wasm-parser" "1.7.6"
acorn "^5.6.2"
acorn-dynamic-import "^3.0.0"
ajv "^6.1.0"
ajv-keywords "^3.1.0"
chrome-trace-event "^1.0.0"
enhanced-resolve "^4.1.0"
- eslint-scope "^3.7.1"
+ eslint-scope "^4.0.0"
json-parse-better-errors "^1.0.2"
loader-runner "^2.3.0"
loader-utils "^1.1.0"
@@ -7034,10 +7193,10 @@ webpack@^4.16.0:
neo-async "^2.5.0"
node-libs-browser "^2.0.0"
schema-utils "^0.4.4"
- tapable "^1.0.0"
+ tapable "^1.1.0"
uglifyjs-webpack-plugin "^1.2.4"
watchpack "^1.5.0"
- webpack-sources "^1.0.1"
+ webpack-sources "^1.2.0"
websocket-driver@>=0.5.1:
version "0.6.5"
@@ -7071,14 +7230,6 @@ widest-line@^2.0.0:
dependencies:
string-width "^2.1.1"
-window-size@0.1.0:
- version "0.1.0"
- resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d"
-
-wordwrap@0.0.2:
- version "0.0.2"
- resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f"
-
wordwrap@^1.0.0, wordwrap@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb"
@@ -7126,13 +7277,11 @@ write@^0.2.1:
dependencies:
mkdirp "^0.5.1"
-ws@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/ws/-/ws-4.0.0.tgz#bfe1da4c08eeb9780b986e0e4d10eccd7345999f"
+ws@^6.0.0:
+ version "6.0.0"
+ resolved "https://registry.yarnpkg.com/ws/-/ws-6.0.0.tgz#eaa494aded00ac4289d455bac8d84c7c651cef35"
dependencies:
async-limiter "~1.0.0"
- safe-buffer "~5.1.0"
- ultron "~1.1.0"
ws@~3.3.1:
version "3.3.3"
@@ -7158,6 +7307,10 @@ xmlhttprequest@1:
version "1.8.0"
resolved "https://registry.yarnpkg.com/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz#67fe075c5c24fef39f9d65f5f7b7fe75171968fc"
+xregexp@4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/xregexp/-/xregexp-4.0.0.tgz#e698189de49dd2a18cc5687b05e17c8e43943020"
+
xtend@^4.0.0, xtend@^4.0.1, xtend@~4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"
@@ -7166,11 +7319,7 @@ xterm@^3.5.0:
version "3.5.0"
resolved "https://registry.yarnpkg.com/xterm/-/xterm-3.5.0.tgz#ba3f464bc5730c9d259ebe62131862224db9ddcc"
-y18n@^3.2.1:
- version "3.2.1"
- resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41"
-
-y18n@^4.0.0:
+"y18n@^3.2.1 || ^4.0.0", y18n@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b"
@@ -7182,54 +7331,28 @@ yallist@^3.0.0, yallist@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.2.tgz#8452b4bb7e83c7c188d8041c1a837c773d6d8bb9"
-yargs-parser@^9.0.2:
- version "9.0.2"
- resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-9.0.2.tgz#9ccf6a43460fe4ed40a9bb68f48d43b8a68cc077"
+yargs-parser@^10.1.0:
+ version "10.1.0"
+ resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-10.1.0.tgz#7202265b89f7e9e9f2e5765e0fe735a905edbaa8"
dependencies:
camelcase "^4.1.0"
-yargs@11.0.0:
- version "11.0.0"
- resolved "https://registry.yarnpkg.com/yargs/-/yargs-11.0.0.tgz#c052931006c5eee74610e5fc0354bedfd08a201b"
- dependencies:
- cliui "^4.0.0"
- decamelize "^1.1.1"
- find-up "^2.1.0"
- get-caller-file "^1.0.1"
- os-locale "^2.0.0"
- require-directory "^2.1.1"
- require-main-filename "^1.0.1"
- set-blocking "^2.0.0"
- string-width "^2.0.0"
- which-module "^2.0.0"
- y18n "^3.2.1"
- yargs-parser "^9.0.2"
-
-yargs@^11.1.0:
- version "11.1.0"
- resolved "https://registry.yarnpkg.com/yargs/-/yargs-11.1.0.tgz#90b869934ed6e871115ea2ff58b03f4724ed2d77"
+yargs@12.0.2, yargs@^12.0.1:
+ version "12.0.2"
+ resolved "https://registry.yarnpkg.com/yargs/-/yargs-12.0.2.tgz#fe58234369392af33ecbef53819171eff0f5aadc"
dependencies:
cliui "^4.0.0"
- decamelize "^1.1.1"
- find-up "^2.1.0"
+ decamelize "^2.0.0"
+ find-up "^3.0.0"
get-caller-file "^1.0.1"
- os-locale "^2.0.0"
+ os-locale "^3.0.0"
require-directory "^2.1.1"
require-main-filename "^1.0.1"
set-blocking "^2.0.0"
string-width "^2.0.0"
which-module "^2.0.0"
- y18n "^3.2.1"
- yargs-parser "^9.0.2"
-
-yargs@~3.10.0:
- version "3.10.0"
- resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1"
- dependencies:
- camelcase "^1.0.2"
- cliui "^2.1.0"
- decamelize "^1.0.0"
- window-size "0.1.0"
+ y18n "^3.2.1 || ^4.0.0"
+ yargs-parser "^10.1.0"
yeast@0.1.2:
version "0.1.2"