summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.eslintrc.yml1
-rw-r--r--.gitlab/CODEOWNERS4
-rw-r--r--.gitlab/ci/docs.gitlab-ci.yml11
-rw-r--r--.gitlab/ci/frontend.gitlab-ci.yml30
-rw-r--r--.gitlab/ci/global.gitlab-ci.yml16
-rw-r--r--.gitlab/ci/memory.gitlab-ci.yml23
-rw-r--r--.gitlab/ci/rails.gitlab-ci.yml63
-rw-r--r--.gitlab/ci/review.gitlab-ci.yml4
-rw-r--r--.gitlab/ci/setup.gitlab-ci.yml14
-rw-r--r--.gitlab/ci/test-metadata.gitlab-ci.yml14
-rw-r--r--.mdlrc4
-rw-r--r--.mdlrc.style7
-rw-r--r--.rubocop_todo.yml3
-rw-r--r--CHANGELOG.md38
-rw-r--r--GITALY_SERVER_VERSION2
-rw-r--r--Gemfile11
-rw-r--r--Gemfile.lock32
-rw-r--r--app/assets/images/auth_buttons/salesforce_64.pngbin0 -> 8774 bytes
-rw-r--r--app/assets/javascripts/api.js6
-rw-r--r--app/assets/javascripts/boards/components/board_blank_state.vue8
-rw-r--r--app/assets/javascripts/boards/filtered_search_boards.js3
-rw-r--r--app/assets/javascripts/boards/index.js8
-rw-r--r--app/assets/javascripts/boards/models/issue.js6
-rw-r--r--app/assets/javascripts/boards/models/list.js8
-rw-r--r--app/assets/javascripts/boards/models/milestone.js4
-rw-r--r--app/assets/javascripts/boards/mount_multiple_boards_switcher.js2
-rw-r--r--app/assets/javascripts/boards/services/board_service.js76
-rw-r--r--app/assets/javascripts/boards/stores/boards_store.js111
-rw-r--r--app/assets/javascripts/branches/divergence_graph.js64
-rw-r--r--app/assets/javascripts/clusters/components/application_row.vue4
-rw-r--r--app/assets/javascripts/clusters/components/knative_domain_editor.vue10
-rw-r--r--app/assets/javascripts/clusters/components/uninstall_application_button.vue3
-rw-r--r--app/assets/javascripts/clusters/components/uninstall_application_confirmation_modal.vue4
-rw-r--r--app/assets/javascripts/commons/index.js3
-rw-r--r--app/assets/javascripts/commons/nav/user_merge_requests.js67
-rw-r--r--app/assets/javascripts/confidential_merge_request/components/dropdown.vue58
-rw-r--r--app/assets/javascripts/confidential_merge_request/components/project_form_group.vue132
-rw-r--r--app/assets/javascripts/confidential_merge_request/index.js30
-rw-r--r--app/assets/javascripts/confidential_merge_request/state.js5
-rw-r--r--app/assets/javascripts/create_merge_request_dropdown.js47
-rw-r--r--app/assets/javascripts/diff_notes/components/comment_resolve_btn.js8
-rw-r--r--app/assets/javascripts/diffs/components/diff_discussion_reply.vue55
-rw-r--r--app/assets/javascripts/diffs/components/diff_discussions.vue1
-rw-r--r--app/assets/javascripts/diffs/components/diff_file_header.vue8
-rw-r--r--app/assets/javascripts/diffs/components/diff_gutter_avatars.vue27
-rw-r--r--app/assets/javascripts/diffs/components/diff_line_gutter_content.vue17
-rw-r--r--app/assets/javascripts/diffs/components/inline_diff_comment_row.vue46
-rw-r--r--app/assets/javascripts/diffs/components/inline_diff_view.vue1
-rw-r--r--app/assets/javascripts/diffs/components/parallel_diff_comment_row.vue97
-rw-r--r--app/assets/javascripts/diffs/components/parallel_diff_view.vue2
-rw-r--r--app/assets/javascripts/diffs/mixins/draft_comments.js2
-rw-r--r--app/assets/javascripts/diffs/store/actions.js34
-rw-r--r--app/assets/javascripts/diffs/store/mutation_types.js2
-rw-r--r--app/assets/javascripts/diffs/store/mutations.js65
-rw-r--r--app/assets/javascripts/diffs/store/utils.js45
-rw-r--r--app/assets/javascripts/environments/components/environment_actions.vue12
-rw-r--r--app/assets/javascripts/environments/components/environment_item.vue19
-rw-r--r--app/assets/javascripts/environments/components/environment_monitoring.vue3
-rw-r--r--app/assets/javascripts/environments/components/environment_terminal_button.vue3
-rw-r--r--app/assets/javascripts/error_tracking_settings/components/error_tracking_form.vue9
-rw-r--r--app/assets/javascripts/event_tracking/notes.js1
-rw-r--r--app/assets/javascripts/filtered_search/components/recent_searches_dropdown_content.vue6
-rw-r--r--app/assets/javascripts/group.js4
-rw-r--r--app/assets/javascripts/ide/components/commit_sidebar/list_item.vue3
-rw-r--r--app/assets/javascripts/ide/components/external_link.vue2
-rw-r--r--app/assets/javascripts/ide/components/repo_editor.vue25
-rw-r--r--app/assets/javascripts/ide/components/repo_file_status_icon.vue5
-rw-r--r--app/assets/javascripts/ide/components/repo_tab.vue5
-rw-r--r--app/assets/javascripts/ide/lib/files.js5
-rw-r--r--app/assets/javascripts/ide/stores/actions.js3
-rw-r--r--app/assets/javascripts/ide/stores/modules/commit/actions.js2
-rw-r--r--app/assets/javascripts/ide/stores/mutation_types.js2
-rw-r--r--app/assets/javascripts/ide/stores/mutations.js13
-rw-r--r--app/assets/javascripts/ide/stores/mutations/file.js32
-rw-r--r--app/assets/javascripts/ide/stores/state.js1
-rw-r--r--app/assets/javascripts/ide/stores/utils.js6
-rw-r--r--app/assets/javascripts/issuable_bulk_update_actions.js4
-rw-r--r--app/assets/javascripts/issuable_index.js17
-rw-r--r--app/assets/javascripts/issuable_init_bulk_update_sidebar.js19
-rw-r--r--app/assets/javascripts/labels_select.js4
-rw-r--r--app/assets/javascripts/lib/utils/common_utils.js8
-rw-r--r--app/assets/javascripts/lib/utils/text_utility.js11
-rw-r--r--app/assets/javascripts/main.js6
-rw-r--r--app/assets/javascripts/main_ee.js1
-rw-r--r--app/assets/javascripts/manual_ordering.js2
-rw-r--r--app/assets/javascripts/monitoring/components/dashboard.vue17
-rw-r--r--app/assets/javascripts/monitoring/components/empty_state.vue65
-rw-r--r--app/assets/javascripts/monitoring/stores/utils.js17
-rw-r--r--app/assets/javascripts/notes/components/comment_form.vue54
-rw-r--r--app/assets/javascripts/notes/components/diff_with_note.vue2
-rw-r--r--app/assets/javascripts/notes/components/discussion_actions.vue26
-rw-r--r--app/assets/javascripts/notes/components/discussion_counter.vue6
-rw-r--r--app/assets/javascripts/notes/components/discussion_notes.vue51
-rw-r--r--app/assets/javascripts/notes/components/discussion_notes_replies_wrapper.vue27
-rw-r--r--app/assets/javascripts/notes/components/discussion_reply_placeholder.vue8
-rw-r--r--app/assets/javascripts/notes/components/discussion_resolve_with_issue_button.vue2
-rw-r--r--app/assets/javascripts/notes/components/note_awards_list.vue16
-rw-r--r--app/assets/javascripts/notes/components/note_form.vue36
-rw-r--r--app/assets/javascripts/notes/components/note_header.vue4
-rw-r--r--app/assets/javascripts/notes/components/note_signed_out_widget.vue19
-rw-r--r--app/assets/javascripts/notes/components/noteable_discussion.vue44
-rw-r--r--app/assets/javascripts/notes/components/noteable_note.vue18
-rw-r--r--app/assets/javascripts/notes/components/notes_app.vue3
-rw-r--r--app/assets/javascripts/notes/index.js5
-rw-r--r--app/assets/javascripts/notes/mixins/resolvable.js6
-rw-r--r--app/assets/javascripts/notes/services/notes_service.js4
-rw-r--r--app/assets/javascripts/notes/stores/actions.js16
-rw-r--r--app/assets/javascripts/pages/dashboard/todos/index/todos.js4
-rw-r--r--app/assets/javascripts/pages/groups/issues/index.js4
-rw-r--r--app/assets/javascripts/pages/projects/branches/index/index.js2
-rw-r--r--app/assets/javascripts/pages/projects/issues/form.js4
-rw-r--r--app/assets/javascripts/pages/projects/shared/permissions/components/project_feature_setting.vue5
-rw-r--r--app/assets/javascripts/pages/projects/shared/permissions/components/settings_panel.vue22
-rw-r--r--app/assets/javascripts/pages/projects/shared/permissions/constants.js27
-rw-r--r--app/assets/javascripts/performance_bar/components/performance_bar_app.vue15
-rw-r--r--app/assets/javascripts/performance_bar/components/simple_metric.vue33
-rw-r--r--app/assets/javascripts/pipelines/components/header_component.vue5
-rw-r--r--app/assets/javascripts/pipelines/components/pipeline_url.vue3
-rw-r--r--app/assets/javascripts/pipelines/components/pipelines_table.vue5
-rw-r--r--app/assets/javascripts/pipelines/components/pipelines_table_row.vue6
-rw-r--r--app/assets/javascripts/pipelines/mixins/pipelines.js6
-rw-r--r--app/assets/javascripts/projects/project_new.js4
-rw-r--r--app/assets/javascripts/projects/tree/components/commit_pipeline_status_component.vue4
-rw-r--r--app/assets/javascripts/registry/components/app.vue109
-rw-r--r--app/assets/javascripts/registry/components/svg_message.vue24
-rw-r--r--app/assets/javascripts/registry/index.js10
-rw-r--r--app/assets/javascripts/releases/components/release_block.vue14
-rw-r--r--app/assets/javascripts/repository/components/table/index.vue2
-rw-r--r--app/assets/javascripts/repository/components/table/row.vue4
-rw-r--r--app/assets/javascripts/serverless/components/area.vue15
-rw-r--r--app/assets/javascripts/serverless/components/function_details.vue4
-rw-r--r--app/assets/javascripts/serverless/components/functions.vue47
-rw-r--r--app/assets/javascripts/sidebar/components/assignees/assignee_title.vue10
-rw-r--r--app/assets/javascripts/sidebar/components/assignees/assignees.vue29
-rw-r--r--app/assets/javascripts/sidebar/components/assignees/sidebar_assignees.vue7
-rw-r--r--app/assets/javascripts/sidebar/components/confidential/edit_form_buttons.vue3
-rw-r--r--app/assets/javascripts/sidebar/components/time_tracking/collapsed_state.vue2
-rw-r--r--app/assets/javascripts/sidebar/components/time_tracking/comparison_pane.vue19
-rw-r--r--app/assets/javascripts/sidebar/components/time_tracking/spent_only_pane.vue19
-rw-r--r--app/assets/javascripts/sidebar/components/todo_toggle/todo.vue4
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/deployment.vue4
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/mr_widget_header.vue2
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_auto_merge_enabled.vue13
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_rebase.vue43
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/nothing_to_merge.vue30
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue5
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/unresolved_discussions.vue2
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/work_in_progress.vue20
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue7
-rw-r--r--app/assets/javascripts/vue_shared/components/changed_file_icon.vue3
-rw-r--r--app/assets/javascripts/vue_shared/components/commit.vue7
-rw-r--r--app/assets/javascripts/vue_shared/components/content_viewer/lib/viewer_utils.js1
-rw-r--r--app/assets/javascripts/vue_shared/components/content_viewer/viewers/image_viewer.vue4
-rw-r--r--app/assets/javascripts/vue_shared/components/content_viewer/viewers/markdown_viewer.vue2
-rw-r--r--app/assets/javascripts/vue_shared/components/deprecated_modal.vue6
-rw-r--r--app/assets/javascripts/vue_shared/components/droplab_dropdown_button.vue2
-rw-r--r--app/assets/javascripts/vue_shared/components/file_row.vue2
-rw-r--r--app/assets/javascripts/vue_shared/components/filtered_search_dropdown.vue4
-rw-r--r--app/assets/javascripts/vue_shared/components/header_ci_component.vue13
-rw-r--r--app/assets/javascripts/vue_shared/components/issue/issue_warning.vue8
-rw-r--r--app/assets/javascripts/vue_shared/components/issue/related_issuable_item.vue4
-rw-r--r--app/assets/javascripts/vue_shared/components/markdown/field.vue30
-rw-r--r--app/assets/javascripts/vue_shared/components/markdown/suggestions.vue3
-rw-r--r--app/assets/javascripts/vue_shared/components/markdown/toolbar.vue25
-rw-r--r--app/assets/javascripts/vue_shared/components/memory_graph.vue3
-rw-r--r--app/assets/javascripts/vue_shared/components/notes/placeholder_note.vue2
-rw-r--r--app/assets/javascripts/vue_shared/components/notes/system_note.vue2
-rw-r--r--app/assets/javascripts/vue_shared/components/project_avatar/image.vue4
-rw-r--r--app/assets/javascripts/vue_shared/components/sidebar/collapsed_grouped_date_picker.vue4
-rw-r--r--app/assets/javascripts/vue_shared/components/sidebar/date_picker.vue8
-rw-r--r--app/assets/javascripts/vue_shared/components/sidebar/toggle_sidebar.vue2
-rw-r--r--app/assets/javascripts/vue_shared/components/user_avatar/user_avatar_image.vue3
-rw-r--r--app/assets/javascripts/vue_shared/mixins/is_ee.js10
-rw-r--r--app/assets/stylesheets/framework/dropdowns.scss2
-rw-r--r--app/assets/stylesheets/framework/modal.scss7
-rw-r--r--app/assets/stylesheets/framework/variables.scss2
-rw-r--r--app/assets/stylesheets/pages/container_registry.scss6
-rw-r--r--app/assets/stylesheets/pages/diff.scss20
-rw-r--r--app/assets/stylesheets/pages/notes.scss42
-rw-r--r--app/assets/stylesheets/pages/wiki.scss4
-rw-r--r--app/controllers/admin/application_settings_controller.rb2
-rw-r--r--app/controllers/concerns/issuable_actions.rb4
-rw-r--r--app/controllers/concerns/issuable_collections.rb2
-rw-r--r--app/controllers/concerns/issuable_collections_action.rb4
-rw-r--r--app/controllers/concerns/notes_actions.rb14
-rw-r--r--app/controllers/dashboard/projects_controller.rb3
-rw-r--r--app/controllers/dashboard/todos_controller.rb4
-rw-r--r--app/controllers/graphql_controller.rb5
-rw-r--r--app/controllers/groups_controller.rb3
-rw-r--r--app/controllers/projects/application_controller.rb5
-rw-r--r--app/controllers/projects/branches_controller.rb16
-rw-r--r--app/controllers/projects/deployments_controller.rb14
-rw-r--r--app/controllers/projects/issues_controller.rb7
-rw-r--r--app/controllers/projects/merge_requests_controller.rb2
-rw-r--r--app/controllers/projects/registry/repositories_controller.rb2
-rw-r--r--app/controllers/projects/settings/repository_controller.rb2
-rw-r--r--app/controllers/projects/templates_controller.rb17
-rw-r--r--app/controllers/projects_controller.rb4
-rw-r--r--app/controllers/snippets/notes_controller.rb8
-rw-r--r--app/controllers/snippets_controller.rb2
-rw-r--r--app/controllers/uploads_controller.rb20
-rw-r--r--app/finders/issuable_finder.rb2
-rw-r--r--app/finders/runner_jobs_finder.rb19
-rw-r--r--app/graphql/gitlab_schema.rb1
-rw-r--r--app/graphql/types/base_field.rb19
-rw-r--r--app/graphql/types/ci/detailed_status_type.rb3
-rw-r--r--app/graphql/types/issue_state_enum.rb3
-rw-r--r--app/graphql/types/label_type.rb2
-rw-r--r--app/graphql/types/merge_request_state_enum.rb3
-rw-r--r--app/graphql/types/merge_request_type.rb2
-rw-r--r--app/graphql/types/metadata_type.rb2
-rw-r--r--app/graphql/types/mutation_type.rb2
-rw-r--r--app/graphql/types/namespace_type.rb2
-rw-r--r--app/graphql/types/notes/diff_position_type.rb3
-rw-r--r--app/graphql/types/permission_types/merge_request.rb4
-rw-r--r--app/graphql/types/project_type.rb8
-rw-r--r--app/graphql/types/query_type.rb5
-rw-r--r--app/graphql/types/repository_type.rb6
-rw-r--r--app/graphql/types/task_completion_status.rb4
-rw-r--r--app/graphql/types/tree/blob_type.rb3
-rw-r--r--app/graphql/types/tree/submodule_type.rb3
-rw-r--r--app/graphql/types/tree/tree_entry_type.rb3
-rw-r--r--app/graphql/types/tree/tree_type.rb9
-rw-r--r--app/helpers/application_settings_helper.rb6
-rw-r--r--app/helpers/auth_helper.rb2
-rw-r--r--app/helpers/branches_helper.rb8
-rw-r--r--app/helpers/issuables_helper.rb6
-rw-r--r--app/helpers/issues_helper.rb2
-rw-r--r--app/helpers/onboarding_experiment_helper.rb7
-rw-r--r--app/helpers/preferences_helper.rb2
-rw-r--r--app/helpers/projects_helper.rb2
-rw-r--r--app/helpers/snippets_helper.rb10
-rw-r--r--app/helpers/storage_helper.rb2
-rw-r--r--app/mailers/emails/notes.rb4
-rw-r--r--app/models/application_setting.rb13
-rw-r--r--app/models/ci/pipeline.rb4
-rw-r--r--app/models/clusters/applications/ingress.rb15
-rw-r--r--app/models/clusters/applications/jupyter.rb10
-rw-r--r--app/models/clusters/applications/prometheus.rb8
-rw-r--r--app/models/clusters/clusters_hierarchy.rb104
-rw-r--r--app/models/concerns/cacheable_attributes.rb10
-rw-r--r--app/models/concerns/deployment_platform.rb19
-rw-r--r--app/models/concerns/issuable.rb10
-rw-r--r--app/models/concerns/reactive_caching.rb8
-rw-r--r--app/models/concerns/update_project_statistics.rb19
-rw-r--r--app/models/deploy_token.rb14
-rw-r--r--app/models/deployment.rb42
-rw-r--r--app/models/deployment_metrics.rb61
-rw-r--r--app/models/environment_status.rb18
-rw-r--r--app/models/group.rb2
-rw-r--r--app/models/issue.rb4
-rw-r--r--app/models/label_note.rb18
-rw-r--r--app/models/merge_request.rb42
-rw-r--r--app/models/merge_requests_closing_issues.rb35
-rw-r--r--app/models/namespace.rb8
-rw-r--r--app/models/namespace/aggregation_schedule.rb48
-rw-r--r--app/models/namespace/root_storage_statistics.rb28
-rw-r--r--app/models/project.rb2
-rw-r--r--app/models/project_services/bugzilla_service.rb18
-rw-r--r--app/models/project_services/custom_issue_tracker_service.rb20
-rw-r--r--app/models/project_services/drone_ci_service.rb4
-rw-r--r--app/models/project_services/gitlab_issue_tracker_service.rb10
-rw-r--r--app/models/project_services/issue_tracker_service.rb33
-rw-r--r--app/models/project_services/jira_service.rb19
-rw-r--r--app/models/project_services/kubernetes_service.rb129
-rw-r--r--app/models/project_services/redmine_service.rb18
-rw-r--r--app/models/project_services/youtrack_service.rb12
-rw-r--r--app/models/project_statistics.rb25
-rw-r--r--app/models/release.rb10
-rw-r--r--app/models/repository.rb9
-rw-r--r--app/models/resource_label_event.rb7
-rw-r--r--app/models/service.rb2
-rw-r--r--app/models/user.rb11
-rw-r--r--app/policies/repository_policy.rb5
-rw-r--r--app/serializers/environment_status_entity.rb6
-rw-r--r--app/serializers/test_suite_comparer_entity.rb29
-rw-r--r--app/services/auto_merge/base_service.rb14
-rw-r--r--app/services/auto_merge/merge_when_pipeline_succeeds_service.rb10
-rw-r--r--app/services/auto_merge_service.rb6
-rw-r--r--app/services/branches/diverging_commit_counts_service.rb24
-rw-r--r--app/services/ci/compare_reports_base_service.rb6
-rw-r--r--app/services/ci/create_pipeline_service.rb2
-rw-r--r--app/services/deploy_tokens/create_service.rb4
-rw-r--r--app/services/discussions/update_diff_position_service.rb3
-rw-r--r--app/services/issuable/bulk_update_service.rb10
-rw-r--r--app/services/issuable_base_service.rb4
-rw-r--r--app/services/issues/update_service.rb4
-rw-r--r--app/services/merge_requests/base_service.rb4
-rw-r--r--app/services/merge_requests/close_service.rb2
-rw-r--r--app/services/merge_requests/create_from_issue_service.rb36
-rw-r--r--app/services/merge_requests/merge_to_ref_service.rb16
-rw-r--r--app/services/merge_requests/rebase_service.rb4
-rw-r--r--app/services/merge_requests/refresh_service.rb6
-rw-r--r--app/services/merge_requests/update_service.rb2
-rw-r--r--app/services/namespaces/statistics_refresher_service.rb22
-rw-r--r--app/services/prometheus/adapter_service.rb7
-rw-r--r--app/services/releases/concerns.rb4
-rw-r--r--app/services/releases/create_service.rb1
-rw-r--r--app/services/system_note_service.rb31
-rw-r--r--app/uploaders/file_mover.rb82
-rw-r--r--app/uploaders/file_uploader.rb2
-rw-r--r--app/uploaders/personal_file_uploader.rb2
-rw-r--r--app/validators/color_validator.rb2
-rw-r--r--app/views/admin/application_settings/_grafana.html.haml17
-rw-r--r--app/views/admin/application_settings/metrics_and_profiling.html.haml11
-rw-r--r--app/views/admin/groups/show.html.haml6
-rw-r--r--app/views/admin/projects/show.html.haml6
-rw-r--r--app/views/admin/services/_form.html.haml2
-rw-r--r--app/views/admin/users/show.html.haml2
-rw-r--r--app/views/clusters/clusters/_form.html.haml2
-rw-r--r--app/views/dashboard/todos/_todo.html.haml2
-rw-r--r--app/views/dashboard/todos/index.html.haml24
-rw-r--r--app/views/discussions/_discussion.html.haml4
-rw-r--r--app/views/discussions/_new_issue_for_discussion.html.haml4
-rw-r--r--app/views/groups/issues.html.haml9
-rw-r--r--app/views/groups/settings/_general.html.haml2
-rw-r--r--app/views/layouts/_search.html.haml2
-rw-r--r--app/views/layouts/fullscreen.html.haml2
-rw-r--r--app/views/layouts/header/_default.html.haml2
-rw-r--r--app/views/layouts/nav/sidebar/_admin.html.haml5
-rw-r--r--app/views/layouts/nav/sidebar/_project.html.haml2
-rw-r--r--app/views/layouts/snippets.html.haml5
-rw-r--r--app/views/notify/new_merge_request_email.text.erb2
-rw-r--r--app/views/profiles/preferences/show.html.haml12
-rw-r--r--app/views/projects/_commit_button.html.haml2
-rw-r--r--app/views/projects/_flash_messages.html.haml1
-rw-r--r--app/views/projects/blob/_editor.html.haml2
-rw-r--r--app/views/projects/branches/_branch.html.haml8
-rw-r--r--app/views/projects/branches/index.html.haml1
-rw-r--r--app/views/projects/deploy_tokens/_form.html.haml5
-rw-r--r--app/views/projects/edit.html.haml2
-rw-r--r--app/views/projects/issues/_new_branch.html.haml13
-rw-r--r--app/views/projects/registry/repositories/index.html.haml54
-rw-r--r--app/views/shared/_confirm_modal.html.haml6
-rw-r--r--app/views/shared/_issuable_meta_data.html.haml2
-rw-r--r--app/views/shared/_storage_counter_statistics.html.haml4
-rw-r--r--app/views/shared/boards/components/_board.html.haml6
-rw-r--r--app/views/shared/issuable/_form.html.haml9
-rw-r--r--app/views/shared/issuable/_sidebar.html.haml2
-rw-r--r--app/views/shared/notes/_comment_button.html.haml4
-rw-r--r--app/workers/all_queues.yml4
-rw-r--r--app/workers/concerns/application_worker.rb6
-rw-r--r--app/workers/namespaces/prune_aggregation_schedules_worker.rb22
-rw-r--r--app/workers/namespaces/root_statistics_worker.rb31
-rw-r--r--app/workers/namespaces/schedule_aggregation_worker.rb45
-rw-r--r--app/workers/rebase_worker.rb2
-rw-r--r--changelogs/unreleased/12533-shared-runners-warning.yml5
-rw-r--r--changelogs/unreleased/12550-fullscrean.yml5
-rw-r--r--changelogs/unreleased/12553-preferences.yml5
-rw-r--r--changelogs/unreleased/32452-multiple-discussions.yml5
-rw-r--r--changelogs/unreleased/40379-CJK-search-min-chars.yml5
-rw-r--r--changelogs/unreleased/44106-include-subgroups-in-group-activity.yml5
-rw-r--r--changelogs/unreleased/45104-special-characters-in-project-name-path-prevent-users-from-using-the-container-registry.yml5
-rw-r--r--changelogs/unreleased/50228-deploy-tokens-custom-username.yml5
-rw-r--r--changelogs/unreleased/51794-add-ordering-to-runner-jobs-api.yml5
-rw-r--r--changelogs/unreleased/53357-fix-plus-in-upload-file-names.yml5
-rw-r--r--changelogs/unreleased/54117-transactional-rebase.yml5
-rw-r--r--changelogs/unreleased/55487-enable-group-terminals-button.yml5
-rw-r--r--changelogs/unreleased/55953-renamed-discussion-to-thread.yml5
-rw-r--r--changelogs/unreleased/57793-fix-line-age.yml5
-rw-r--r--changelogs/unreleased/58808-fix-image-diff-on-text.yml5
-rw-r--r--changelogs/unreleased/60856-deleting-binary-file.yml5
-rw-r--r--changelogs/unreleased/60859-upload-after-delete.yml5
-rw-r--r--changelogs/unreleased/61005-grafanaInAdminSettingsMonitoringMenu.yml5
-rw-r--r--changelogs/unreleased/61284-frontend-follow-up-from-add-packages_size-to-projectstatistics.yml5
-rw-r--r--changelogs/unreleased/62124-new-threaded-discussion-design.yml5
-rw-r--r--changelogs/unreleased/63475-fix-n-1.yml5
-rw-r--r--changelogs/unreleased/63590-pipeline-actions-cause-full-refresh.yml5
-rw-r--r--changelogs/unreleased/63873-process-start-time.yml6
-rw-r--r--changelogs/unreleased/63971-remove-istanbul.yml5
-rw-r--r--changelogs/unreleased/64176-fix-error-handling.yml5
-rw-r--r--changelogs/unreleased/Remove-unresolved-class-in-discussion-header.yml5
-rw-r--r--changelogs/unreleased/add-salesforce-logo.yml5
-rw-r--r--changelogs/unreleased/add-strategies-column-to-scopes-table.yml5
-rw-r--r--changelogs/unreleased/allow-reactive-caching-of-nil.yml5
-rw-r--r--changelogs/unreleased/api-doc-negative-commit-message-push-rule.yml5
-rw-r--r--changelogs/unreleased/asciidoc-enable-syntax-highlighting.yml5
-rw-r--r--changelogs/unreleased/centralize-markdownlint-config.yml5
-rw-r--r--changelogs/unreleased/clusters-group-cte.yml5
-rw-r--r--changelogs/unreleased/create-merge-train-ref-ce.yml5
-rw-r--r--changelogs/unreleased/feature-uninstall_cluster_ingress.yml5
-rw-r--r--changelogs/unreleased/feature-uninstall_jupyter_hub_app.yml5
-rw-r--r--changelogs/unreleased/fix-median-counting-for-cycle-analytics.yml5
-rw-r--r--changelogs/unreleased/fix-sidekiq-transaction-check-race.yml5
-rw-r--r--changelogs/unreleased/fj-fix-subgroup-search-url.yml5
-rw-r--r--changelogs/unreleased/gitaly-version-v1.51.0.yml5
-rw-r--r--changelogs/unreleased/issue-63222.yml5
-rw-r--r--changelogs/unreleased/issue_64021.yml5
-rw-r--r--changelogs/unreleased/jc-detect-nfs-for-rugged.yml5
-rw-r--r--changelogs/unreleased/jramsay-enable-object-dedupe-by-default.yml5
-rw-r--r--changelogs/unreleased/limit-amount-of-tests-returned.yml5
-rw-r--r--changelogs/unreleased/mh-board-tooltips.yml5
-rw-r--r--changelogs/unreleased/osw-persist-tmp-snippet-uploads.yml5
-rw-r--r--changelogs/unreleased/patch-29.yml5
-rw-r--r--changelogs/unreleased/pre-releases-38105a.yml5
-rw-r--r--changelogs/unreleased/rj-fix-manual-order.yml5
-rw-r--r--changelogs/unreleased/security-2858-fix-color-validation.yml5
-rw-r--r--changelogs/unreleased/security-59581-related-merge-requests-count.yml5
-rw-r--r--changelogs/unreleased/security-DOS_issue_comments_banzai.yml5
-rw-r--r--changelogs/unreleased/security-bvl-enforce-graphql-type-authorization.yml5
-rw-r--r--changelogs/unreleased/security-fp-prevent-billion-laughs-attack.yml5
-rw-r--r--changelogs/unreleased/security-mr-head-pipeline-leak.yml5
-rw-r--r--changelogs/unreleased/security-notes-in-private-snippets.yml5
-rw-r--r--changelogs/unreleased/security-prevent-detection-of-merge-request-template-name.yml5
-rw-r--r--changelogs/unreleased/sh-add-thread-memory-cache.yml5
-rw-r--r--changelogs/unreleased/sh-cache-flipper-checks-in-memory.yml5
-rw-r--r--changelogs/unreleased/sh-cache-flipper-names-memory-cache.yml5
-rw-r--r--changelogs/unreleased/sh-disable-reactive-caching-automatic-retries.yml5
-rw-r--r--changelogs/unreleased/sh-fix-issue-63349.yml5
-rw-r--r--changelogs/unreleased/sh-fix-issue-63910.yml5
-rw-r--r--changelogs/unreleased/sh-improve-redis-peek.yml5
-rw-r--r--changelogs/unreleased/sh-upgrade-rouge-3-5-1.yml5
-rw-r--r--changelogs/unreleased/slugify.yml5
-rw-r--r--changelogs/unreleased/tz-update-mr-count-over-tabs.yml6
-rw-r--r--changelogs/unreleased/unicorn-sampler-fix.yml5
-rw-r--r--changelogs/unreleased/update-todo-in-ui.yml5
-rw-r--r--changelogs/unreleased/use-pg-9-6-11-on-ci.yml5
-rw-r--r--changelogs/unreleased/winh-jest-markdown-header.yml5
-rw-r--r--changelogs/unreleased/winh-notes-service-applySuggestion.yml5
-rw-r--r--changelogs/unreleased/winh-updateResolvableDiscussionsCounts-typo.yml5
-rw-r--r--config/README.md3
-rw-r--r--config/application.rb1
-rw-r--r--config/boot.rb2
-rw-r--r--config/initializers/0_license.rb19
-rw-r--r--config/initializers/0_thread_cache.rb3
-rw-r--r--config/initializers/1_settings.rb4
-rw-r--r--config/initializers/6_validations.rb21
-rw-r--r--config/initializers/7_prometheus_metrics.rb45
-rw-r--r--config/initializers/console_message.rb13
-rw-r--r--config/initializers/elastic_client_setup.rb50
-rw-r--r--config/initializers/forbid_sidekiq_in_transactions.rb13
-rw-r--r--config/initializers/geo.rb17
-rw-r--r--config/initializers/health_check.rb6
-rw-r--r--config/initializers/load_balancing.rb25
-rw-r--r--config/initializers/peek.rb3
-rw-r--r--config/initializers/rack_attack_logging.rb14
-rw-r--r--config/initializers/sidekiq.rb13
-rw-r--r--config/initializers/sidekiq_cluster.rb20
-rw-r--r--config/no_todos_messages.yml8
-rw-r--r--config/routes/api.rb6
-rw-r--r--config/routes/project.rb5
-rw-r--r--config/routes/uploads.rb4
-rw-r--r--config/sidekiq_queues.yml1
-rw-r--r--config/unicorn.rb.example16
-rw-r--r--config/unicorn.rb.example.development16
-rw-r--r--config/webpack.config.js3
-rw-r--r--danger/database/Dangerfile32
-rw-r--r--danger/only_documentation/Dangerfile2
-rw-r--r--db/fixtures/development/17_cycle_analytics.rb12
-rw-r--r--db/fixtures/development/24_forks.rb4
-rw-r--r--db/migrate/20140313092127_init_schema.rb338
-rw-r--r--db/migrate/20140407135544_fix_namespaces.rb16
-rw-r--r--db/migrate/20140414131055_change_state_to_allow_empty_merge_request_diffs.rb11
-rw-r--r--db/migrate/20140415124820_limits_to_mysql.rb1
-rw-r--r--db/migrate/20140416074002_add_index_on_iid.rb33
-rw-r--r--db/migrate/20140416185734_index_on_current_sign_in_at.rb6
-rw-r--r--db/migrate/20140428105831_add_notes_index_updated_at.rb6
-rw-r--r--db/migrate/20140502115131_add_repo_size_to_db.rb6
-rw-r--r--db/migrate/20140502125220_migrate_repo_size.rb31
-rw-r--r--db/migrate/20140611135229_add_position_to_merge_request.rb6
-rw-r--r--db/migrate/20140625115202_create_users_star_projects.rb18
-rw-r--r--db/migrate/20140729134820_create_labels.rb14
-rw-r--r--db/migrate/20140729140420_create_label_links.rb14
-rw-r--r--db/migrate/20140729145339_migrate_project_tags.rb9
-rw-r--r--db/migrate/20140729152420_migrate_taggable_labels.rb36
-rw-r--r--db/migrate/20140730111702_add_index_to_labels.rb8
-rw-r--r--db/migrate/20140903115954_migrate_to_new_shell.rb13
-rw-r--r--db/migrate/20140907220153_serialize_service_properties.rb43
-rw-r--r--db/migrate/20140914113604_add_members_table.rb22
-rw-r--r--db/migrate/20140914145549_migrate_to_new_members_model.rb12
-rw-r--r--db/migrate/20140914173417_remove_old_member_tables.rb29
-rw-r--r--db/migrate/20141006143943_move_slack_service_to_webhook.rb22
-rw-r--r--db/migrate/20141007100818_add_visibility_level_to_snippet.rb24
-rw-r--r--db/migrate/20141118150935_add_audit_event.rb25
-rw-r--r--db/migrate/20141121133009_add_timestamps_to_members.rb15
-rw-r--r--db/migrate/20141121161704_add_identity_table.rb47
-rw-r--r--db/migrate/20141126120926_add_merge_request_rebase_enabled_to_projects.rb17
-rw-r--r--db/migrate/20141205134006_add_locked_at_to_merge_request.rb6
-rw-r--r--db/migrate/20141216155758_create_doorkeeper_tables.rb45
-rw-r--r--db/migrate/20141217125223_add_owner_to_application.rb8
-rw-r--r--db/migrate/20141223135007_add_import_data_to_project_table.rb8
-rw-r--r--db/migrate/20141226080412_add_developers_can_push_to_protected_branches.rb6
-rw-r--r--db/migrate/20150108073740_create_application_settings.rb16
-rw-r--r--db/migrate/20150116234544_add_home_page_url_for_application_settings.rb5
-rw-r--r--db/migrate/20150116234545_add_gitlab_access_token_to_user.rb5
-rw-r--r--db/migrate/20150125163100_add_default_branch_protection_setting.rb6
-rw-r--r--db/migrate/20150205211843_add_timestamps_to_identities.rb6
-rw-r--r--db/migrate/20150206181414_add_index_to_created_at.rb17
-rw-r--r--db/migrate/20150206222854_add_notification_email_to_user.rb11
-rw-r--r--db/migrate/20150209222013_add_missing_index.rb6
-rw-r--r--db/migrate/20150211172122_add_template_to_service.rb6
-rw-r--r--db/migrate/20150211174341_allow_null_in_services_project_id.rb5
-rw-r--r--db/migrate/20150213104043_add_twitter_sharing_enabled_to_application_settings.rb6
-rw-r--r--db/migrate/20150213114800_add_hide_no_password_to_user.rb6
-rw-r--r--db/migrate/20150213121042_add_password_automatically_set_to_user.rb6
-rw-r--r--db/migrate/20150217123345_add_bitbucket_access_token_and_secret_to_user.rb6
-rw-r--r--db/migrate/20150219004514_add_events_to_services.rb9
-rw-r--r--db/migrate/20150223022001_set_missing_last_activity_at.rb8
-rw-r--r--db/migrate/20150225065047_add_note_events_to_services.rb6
-rw-r--r--db/migrate/20150301014758_add_restricted_visibility_levels_to_application_settings.rb5
-rw-r--r--db/migrate/20150306023106_fix_namespace_duplication.rb22
-rw-r--r--db/migrate/20150306023112_add_unique_index_to_namespace.rb10
-rw-r--r--db/migrate/20150310194358_add_version_check_to_application_settings.rb6
-rw-r--r--db/migrate/20150313012111_create_subscriptions_table.rb19
-rw-r--r--db/migrate/20150320234437_add_location_to_user.rb5
-rw-r--r--db/migrate/20150324155957_set_incorrect_assignee_id_to_null.rb6
-rw-r--r--db/migrate/20150327122227_add_public_to_key.rb6
-rw-r--r--db/migrate/20150327150017_add_import_data_to_project.rb5
-rw-r--r--db/migrate/20150327223628_add_devise_two_factor_to_users.rb8
-rw-r--r--db/migrate/20150328132231_add_max_attachment_size_to_application_settings.rb5
-rw-r--r--db/migrate/20150331183602_add_devise_two_factor_backupable_to_users.rb5
-rw-r--r--db/migrate/20150406133311_add_invite_data_to_member.rb24
-rw-r--r--db/migrate/20150411000035_fix_identities.rb45
-rw-r--r--db/migrate/20150411180045_rename_buildbox_service.rb9
-rw-r--r--db/migrate/20150413192223_add_public_email_to_users.rb6
-rw-r--r--db/migrate/20150417121913_create_project_import_data.rb8
-rw-r--r--db/migrate/20150417122318_remove_import_data_from_project.rb10
-rw-r--r--db/migrate/20150421120000_remove_periods_at_ends_of_usernames.rb89
-rw-r--r--db/migrate/20150423033240_add_default_project_visibililty_to_application_settings.rb11
-rw-r--r--db/migrate/20150425164646_gitlab_change_collation_for_tag_names.acts_as_taggable_on_engine.rb10
-rw-r--r--db/migrate/20150425164647_remove_duplicate_tags.rb18
-rw-r--r--db/migrate/20150425164648_add_missing_unique_indices.acts_as_taggable_on_engine.rb28
-rw-r--r--db/migrate/20150425164649_add_taggings_counter_cache_to_tags.acts_as_taggable_on_engine.rb16
-rw-r--r--db/migrate/20150425164650_add_missing_taggable_index.acts_as_taggable_on_engine.rb10
-rw-r--r--db/migrate/20150425164651_change_collation_for_tag_names.acts_as_taggable_on_engine.rb10
-rw-r--r--db/migrate/20150425173433_add_default_snippet_visibility_to_app_settings.rb11
-rw-r--r--db/migrate/20150429002313_remove_abandoned_group_members_records.rb9
-rw-r--r--db/migrate/20150502064022_add_restricted_signup_domains_to_application_settings.rb5
-rw-r--r--db/migrate/20150509180749_convert_legacy_reference_notes.rb17
-rw-r--r--db/migrate/20150516060434_add_note_events_to_web_hooks.rb10
-rw-r--r--db/migrate/20150529111607_add_user_oauth_applications_to_application_settings.rb5
-rw-r--r--db/migrate/20150529150354_add_after_sign_out_path_for_application_settings.rb6
-rw-r--r--db/migrate/20150609141121_add_session_expire_delay_for_application_settings.rb7
-rw-r--r--db/migrate/20150610065936_add_dashboard_to_users.rb10
-rw-r--r--db/migrate/20150620233230_add_default_otp_required_for_login_value.rb11
-rw-r--r--db/migrate/20150713160110_add_project_view_to_users.rb6
-rw-r--r--db/migrate/20150717130904_add_commits_count_to_project.rb6
-rw-r--r--db/migrate/20150730122406_add_updated_by_to_issuables_and_notes.rb7
-rw-r--r--db/migrate/20150806104937_create_abuse_reports.rb14
-rw-r--r--db/migrate/20150812080800_add_settings_import_sources.rb12
-rw-r--r--db/migrate/20150814065925_remove_oauth_tokens_from_users.rb9
-rw-r--r--db/migrate/20150817163600_deduplicate_user_identities.rb15
-rw-r--r--db/migrate/20150818213832_add_sent_notifications.rb13
-rw-r--r--db/migrate/20150824002011_add_enable_ssl_verification.rb6
-rw-r--r--db/migrate/20150826001931_add_ci_tables.rb191
-rw-r--r--db/migrate/20150827121444_add_fast_forward_option_to_project.rb23
-rw-r--r--db/migrate/20150902001023_add_template_to_label.rb6
-rw-r--r--db/migrate/20150914215247_add_ci_tags.rb24
-rw-r--r--db/migrate/20150915001905_enable_ssl_verification_by_default.rb5
-rw-r--r--db/migrate/20150916000405_enable_ssl_verification_for_web_hooks.rb8
-rw-r--r--db/migrate/20150916114643_add_help_page_text_to_application_settings.rb5
-rw-r--r--db/migrate/20150916145038_add_index_for_committed_at_and_id.rb6
-rw-r--r--db/migrate/20150918084513_add_ci_enabled_to_application_settings.rb5
-rw-r--r--db/migrate/20150918161719_remove_invalid_milestones_from_merge_requests.rb5
-rw-r--r--db/migrate/20150920010715_add_consumed_timestep_to_users.rb5
-rw-r--r--db/migrate/20150920161119_add_line_code_to_sent_notification.rb5
-rw-r--r--db/migrate/20150924125150_add_project_id_to_ci_commit.rb5
-rw-r--r--db/migrate/20150924125436_migrate_project_id_for_ci_commits.rb6
-rw-r--r--db/migrate/20150930001110_merge_request_error_field.rb5
-rw-r--r--db/migrate/20150930095736_add_null_to_name_for_ci_projects.rb9
-rw-r--r--db/migrate/20150930110012_add_group_share_lock.rb6
-rw-r--r--db/migrate/20151002112914_add_stage_idx_to_builds.rb5
-rw-r--r--db/migrate/20151002121400_add_index_for_builds.rb6
-rw-r--r--db/migrate/20151002122929_add_ref_and_tag_to_builds.rb6
-rw-r--r--db/migrate/20151002122943_migrate_ref_and_tag_to_build.rb7
-rw-r--r--db/migrate/20151005075649_add_user_id_to_build.rb5
-rw-r--r--db/migrate/20151005150751_add_layout_option_for_users.rb6
-rw-r--r--db/migrate/20151005162154_remove_ci_enabled_from_application_settings.rb6
-rw-r--r--db/migrate/20151007120511_namespaces_projects_path_lower_indexes.rb18
-rw-r--r--db/migrate/20151008110232_add_users_lower_username_email_indexes.rb18
-rw-r--r--db/migrate/20151008123042_add_type_and_description_to_builds.rb10
-rw-r--r--db/migrate/20151008130321_migrate_name_to_description_for_builds.rb6
-rw-r--r--db/migrate/20151008143519_add_admin_notification_email_setting.rb5
-rw-r--r--db/migrate/20151012173029_set_jira_service_api_url.rb51
-rw-r--r--db/migrate/20151013092124_add_artifacts_file_to_builds.rb5
-rw-r--r--db/migrate/20151016131433_add_ci_projects_gl_project_id_index.rb6
-rw-r--r--db/migrate/20151016195451_add_ci_builds_and_projects_indexes.rb10
-rw-r--r--db/migrate/20151016195706_add_notes_line_code_index.rb6
-rw-r--r--db/migrate/20151019111551_fix_build_tags.rb9
-rw-r--r--db/migrate/20151019111703_fail_build_without_names.rb8
-rw-r--r--db/migrate/20151020145526_add_services_template_index.rb6
-rw-r--r--db/migrate/20151020173516_ci_limits_to_mysql.rb9
-rw-r--r--db/migrate/20151020173906_add_ci_builds_index_for_status.rb6
-rw-r--r--db/migrate/20151023112551_fail_build_with_empty_name.rb8
-rw-r--r--db/migrate/20151023144219_remove_satellites.rb17
-rw-r--r--db/migrate/20151026182941_add_project_path_index.rb10
-rw-r--r--db/migrate/20151028152939_add_merge_when_build_succeeds_to_merge_request.rb8
-rw-r--r--db/migrate/20151103001141_add_public_to_group.rb6
-rw-r--r--db/migrate/20151103133339_add_shared_runners_setting.rb5
-rw-r--r--db/migrate/20151103134857_create_lfs_objects.rb13
-rw-r--r--db/migrate/20151103134958_create_lfs_objects_projects.rb15
-rw-r--r--db/migrate/20151104105513_add_file_to_lfs_objects.rb5
-rw-r--r--db/migrate/20151105094515_create_releases.rb17
-rw-r--r--db/migrate/20151106000015_add_is_award_to_notes.rb7
-rw-r--r--db/migrate/20151109100728_add_max_artifacts_size_to_application_settings.rb5
-rw-r--r--db/migrate/20151109134526_add_issues_state_index.rb6
-rw-r--r--db/migrate/20151109134916_add_projects_visibility_level_index.rb6
-rw-r--r--db/migrate/20151110125604_add_import_error_to_project.rb5
-rw-r--r--db/migrate/20151114113410_add_index_for_lfs_oid_and_size.rb7
-rw-r--r--db/migrate/20151116144118_add_unique_for_lfs_oid_index.rb8
-rw-r--r--db/migrate/20151118162244_add_projects_public_index.rb6
-rw-r--r--db/migrate/20151201203948_raise_hook_url_limit.rb5
-rw-r--r--db/migrate/20151203162133_add_hide_project_limit_to_users.rb6
-rw-r--r--db/migrate/20151203162134_add_build_events_to_services.rb7
-rw-r--r--db/migrate/20151209144329_migrate_ci_web_hooks.rb16
-rw-r--r--db/migrate/20151209145909_migrate_ci_emails.rb45
-rw-r--r--db/migrate/20151210030143_add_unlock_token_to_user.rb5
-rw-r--r--db/migrate/20151210072243_add_runners_registration_token_to_application_settings.rb5
-rw-r--r--db/migrate/20151210125232_migrate_ci_slack_service.rb33
-rw-r--r--db/migrate/20151210125927_migrate_ci_hip_chat_service.rb34
-rw-r--r--db/migrate/20151210125928_add_ci_to_project.rb12
-rw-r--r--db/migrate/20151210125929_add_project_id_to_ci.rb8
-rw-r--r--db/migrate/20151210125930_migrate_ci_to_project.rb42
-rw-r--r--db/migrate/20151210125931_add_index_to_ci_tables.rb13
-rw-r--r--db/migrate/20151210125932_drop_null_for_ci_tables.rb10
-rw-r--r--db/migrate/20151215132013_add_pages_size_to_application_settings.rb14
-rw-r--r--db/migrate/20151218154042_add_tfa_to_application_settings.rb8
-rw-r--r--db/migrate/20151221234414_add_tfa_additional_fields.rb7
-rw-r--r--db/migrate/20151224123230_rename_emojis.rb15
-rw-r--r--db/migrate/20151228111122_remove_public_from_namespace.rb7
-rw-r--r--db/migrate/20151228150906_influxdb_settings.rb19
-rw-r--r--db/migrate/20151228175719_add_recaptcha_to_application_settings.rb9
-rw-r--r--db/migrate/20151229102248_influxdb_udp_port_setting.rb5
-rw-r--r--db/migrate/20151229112614_influxdb_remote_database_setting.rb6
-rw-r--r--db/migrate/20151230132518_add_artifacts_metadata_to_ci_build.rb5
-rw-r--r--db/migrate/20151231152326_add_akismet_to_application_settings.rb8
-rw-r--r--db/migrate/20151231202530_remove_alert_type_from_broadcast_messages.rb6
-rw-r--r--db/migrate/20160106162223_add_index_milestones_title.rb6
-rw-r--r--db/migrate/20160106164438_remove_influxdb_credentials.rb7
-rw-r--r--db/migrate/20160109054846_create_spam_logs.rb17
-rw-r--r--db/migrate/20160113111034_add_metrics_sample_interval.rb6
-rw-r--r--db/migrate/20160118155830_add_sentry_to_application_settings.rb8
-rw-r--r--db/migrate/20160118232755_add_ip_blocking_settings_to_application_settings.rb7
-rw-r--r--db/migrate/20160119111158_add_services_category.rb40
-rw-r--r--db/migrate/20160119112418_add_services_default.rb21
-rw-r--r--db/migrate/20160119145451_add_ldap_email_to_users.rb31
-rw-r--r--db/migrate/20160120172143_add_base_commit_sha_to_merge_request_diffs.rb5
-rw-r--r--db/migrate/20160121030729_add_email_author_in_body_to_application_settings.rb6
-rw-r--r--db/migrate/20160122185421_add_pending_delete_to_project.rb6
-rw-r--r--db/migrate/20160128212447_remove_ip_blocking_settings_from_application_settings.rb7
-rw-r--r--db/migrate/20160128233227_change_lfs_objects_size_column.rb5
-rw-r--r--db/migrate/20160129135155_remove_dot_atom_path_ending_of_projects.rb80
-rw-r--r--db/migrate/20160129155512_add_merge_commit_sha_to_merge_requests.rb5
-rw-r--r--db/migrate/20160202091601_add_erasable_to_ci_build.rb7
-rw-r--r--db/migrate/20160202164642_add_allow_guest_to_access_builds_project.rb6
-rw-r--r--db/migrate/20160204144558_add_real_size_to_merge_request_diffs.rb5
-rw-r--r--db/migrate/20160209130428_add_index_to_snippet.rb6
-rw-r--r--db/migrate/20160210105555_create_pages_domain.rb16
-rw-r--r--db/migrate/20160212123307_create_tasks.rb17
-rw-r--r--db/migrate/20160217100506_add_description_to_label.rb5
-rw-r--r--db/migrate/20160217174422_add_note_to_tasks.rb5
-rw-r--r--db/migrate/20160220123949_rename_tasks_to_todos.rb5
-rw-r--r--db/migrate/20160222153918_create_appearances_ce.rb15
-rw-r--r--db/migrate/20160223192159_add_confidential_to_issues.rb7
-rw-r--r--db/migrate/20160225090018_add_delete_at_to_issues.rb7
-rw-r--r--db/migrate/20160225101956_add_delete_at_to_merge_requests.rb7
-rw-r--r--db/migrate/20160226114608_add_trigram_indexes_for_searching.rb65
-rw-r--r--db/migrate/20160227120001_add_event_field_for_web_hook.rb6
-rw-r--r--db/migrate/20160227120047_add_event_to_services.rb6
-rw-r--r--db/migrate/20160229193553_add_main_language_to_repository.rb5
-rw-r--r--db/migrate/20160301124843_add_visibility_level_to_groups.rb30
-rw-r--r--db/migrate/20160301174731_add_fingerprint_index.rb17
-rw-r--r--db/migrate/20160302151724_add_import_credentials_to_project_import_data.rb7
-rw-r--r--db/migrate/20160302152808_remove_wrong_import_url_from_projects.rb138
-rw-r--r--db/migrate/20160305220806_remove_expires_at_from_snippets.rb6
-rw-r--r--db/migrate/20160307221555_disallow_blank_line_code_on_note.rb9
-rw-r--r--db/migrate/20160308212903_add_default_group_visibility_to_application_settings.rb32
-rw-r--r--db/migrate/20160309140734_fix_todos.rb17
-rw-r--r--db/migrate/20160310124959_add_due_date_to_issues.rb7
-rw-r--r--db/migrate/20160310185910_add_external_flag_to_users.rb6
-rw-r--r--db/migrate/20160314094147_add_priority_to_label.rb7
-rw-r--r--db/migrate/20160314114439_add_requested_at_to_members.rb6
-rw-r--r--db/migrate/20160314143402_projects_add_pushes_since_gc.rb6
-rw-r--r--db/migrate/20160315135439_project_add_repository_check.rb9
-rw-r--r--db/migrate/20160316123110_ci_runners_token_index.rb14
-rw-r--r--db/migrate/20160316192622_change_target_id_to_null_on_todos.rb5
-rw-r--r--db/migrate/20160316204731_add_commit_id_to_todos.rb7
-rw-r--r--db/migrate/20160317092222_add_moved_to_to_issue.rb5
-rw-r--r--db/migrate/20160320204112_index_namespaces_on_visibility_level.rb8
-rw-r--r--db/migrate/20160324020319_remove_todos_for_deleted_issues.rb17
-rw-r--r--db/migrate/20160328112808_create_notification_settings.rb12
-rw-r--r--db/migrate/20160328115649_migrate_new_notification_setting.rb17
-rw-r--r--db/migrate/20160328121138_add_notification_setting_index.rb7
-rw-r--r--db/migrate/20160329144452_add_index_on_pending_delete_projects.rb7
-rw-r--r--db/migrate/20160331133914_remove_todos_for_deleted_merge_requests.rb17
-rw-r--r--db/migrate/20160331223143_remove_twitter_sharing_enabled_from_application_settings.rb6
-rw-r--r--db/migrate/20160407120251_add_images_enabled_for_project.rb5
-rw-r--r--db/migrate/20160412140240_add_repository_checks_enabled_setting.rb6
-rw-r--r--db/migrate/20160412173416_add_fields_to_ci_commit.rb9
-rw-r--r--db/migrate/20160412173417_update_ci_commit.rb36
-rw-r--r--db/migrate/20160412173418_add_ci_commit_indexes.rb20
-rw-r--r--db/migrate/20160413115152_add_token_to_web_hooks.rb5
-rw-r--r--db/migrate/20160415062917_create_personal_access_tokens.rb14
-rw-r--r--db/migrate/20160415133440_add_shared_runners_text_to_application_settings.rb5
-rw-r--r--db/migrate/20160416180807_add_award_emoji.rb17
-rw-r--r--db/migrate/20160416182152_convert_award_note_to_emoji_award.rb36
-rw-r--r--db/migrate/20160419120017_add_metrics_packet_size.rb5
-rw-r--r--db/migrate/20160419122101_add_only_allow_merge_if_build_succeeds_to_projects.rb16
-rw-r--r--db/migrate/20160421130527_disable_repository_checks.rb12
-rw-r--r--db/migrate/20160425045124_create_u2f_registrations.rb14
-rw-r--r--db/migrate/20160504091942_add_disabled_oauth_sign_in_sources_to_application_settings.rb5
-rw-r--r--db/migrate/20160504112519_add_run_untagged_to_ci_runner.rb13
-rw-r--r--db/migrate/20160508194200_remove_wall_enabled_from_projects.rb6
-rw-r--r--db/migrate/20160508202603_add_head_commit_id_to_merge_request_diffs.rb5
-rw-r--r--db/migrate/20160508215820_add_type_to_notes.rb5
-rw-r--r--db/migrate/20160508215920_add_positions_to_diff_notes.rb6
-rw-r--r--db/migrate/20160508221410_set_type_on_legacy_diff_notes.rb6
-rw-r--r--db/migrate/20160509091049_add_locked_to_ci_runner.rb13
-rw-r--r--db/migrate/20160509201028_add_health_check_access_token_to_application_settings.rb5
-rw-r--r--db/migrate/20160516174813_add_send_user_confirmation_email_to_application_settings.rb13
-rw-r--r--db/migrate/20160516224534_add_start_commit_id_to_merge_request_diffs.rb5
-rw-r--r--db/migrate/20160518200441_add_artifacts_expire_date_to_ci_builds.rb6
-rw-r--r--db/migrate/20160519203051_add_developers_can_merge_to_protected_branches.rb15
-rw-r--r--db/migrate/20160522215720_add_note_type_and_position_to_sent_notification.rb22
-rw-r--r--db/migrate/20160525205328_remove_main_language_from_projects.rb22
-rw-r--r--db/migrate/20160527020117_remove_notification_settings_for_deleted_projects.rb13
-rw-r--r--db/migrate/20160528043124_add_users_state_index.rb10
-rw-r--r--db/migrate/20160530150109_add_container_registry_token_expire_delay_to_application_settings.rb9
-rw-r--r--db/migrate/20160603075128_add_has_external_issue_tracker_to_projects.rb10
-rw-r--r--db/migrate/20160603180330_remove_duplicated_notification_settings.rb32
-rw-r--r--db/migrate/20160603182247_add_index_to_notification_settings.rb10
-rw-r--r--db/migrate/20160608155312_add_after_sign_up_text_to_application_settings.rb5
-rw-r--r--db/migrate/20160608195742_add_repository_storage_to_projects.rb13
-rw-r--r--db/migrate/20160608211215_add_user_default_external_to_application_settings.rb13
-rw-r--r--db/migrate/20160610140403_remove_notification_setting_not_null_constraints.rb11
-rw-r--r--db/migrate/20160610194713_remove_deprecated_issues_tracker_columns_from_projects.rb7
-rw-r--r--db/migrate/20160610201627_migrate_users_notification_level.rb25
-rw-r--r--db/migrate/20160610204157_add_deployments.rb26
-rw-r--r--db/migrate/20160610204158_add_environments.rb16
-rw-r--r--db/migrate/20160610211845_add_environment_to_builds.rb10
-rw-r--r--db/migrate/20160610301627_remove_notification_level_from_users.rb8
-rw-r--r--db/migrate/20160614182521_add_repository_storage_to_application_settings.rb5
-rw-r--r--db/migrate/20160615142710_add_index_on_requested_at_to_members.rb16
-rw-r--r--db/migrate/20160615173316_add_enabled_git_access_protocols_to_application_settings.rb10
-rw-r--r--db/migrate/20160615191922_set_missing_stage_on_ci_builds.rb13
-rw-r--r--db/migrate/20160616084004_change_project_of_environment.rb21
-rw-r--r--db/migrate/20160616102642_remove_duplicated_keys.rb18
-rw-r--r--db/migrate/20160616103005_remove_keys_fingerprint_index_if_exists.rb22
-rw-r--r--db/migrate/20160616103948_add_unique_index_to_keys_fingerprint.rb14
-rw-r--r--db/migrate/20160617301627_add_events_to_notification_settings.rb7
-rw-r--r--db/migrate/20160620115026_add_index_on_runners_locked.rb19
-rw-r--r--db/migrate/20160621123729_add_rebase_commit_sha_to_merge_requests.rb22
-rw-r--r--db/migrate/20160628085157_add_artifacts_size_to_ci_builds.rb7
-rw-r--r--db/migrate/20160629025435_add_column_in_progress_merge_commit_sha_to_merge_requests.rb8
-rw-r--r--db/migrate/20160703180340_add_index_on_award_emoji_user_and_name.rb11
-rw-r--r--db/migrate/20160705054938_add_protected_branches_push_access.rb18
-rw-r--r--db/migrate/20160705054952_add_protected_branches_merge_access.rb18
-rw-r--r--db/migrate/20160705055254_move_from_developers_can_merge_to_protected_branches_merge_access.rb29
-rw-r--r--db/migrate/20160705055308_move_from_developers_can_push_to_protected_branches_push_access.rb29
-rw-r--r--db/migrate/20160705055809_remove_developers_can_push_from_protected_branches.rb20
-rw-r--r--db/migrate/20160705055813_remove_developers_can_merge_from_protected_branches.rb20
-rw-r--r--db/migrate/20160705163108_remove_requesters_that_are_owners.rb40
-rw-r--r--db/migrate/20160707104333_add_lock_to_issuables.rb18
-rw-r--r--db/migrate/20160712171823_remove_award_emojis_with_no_user.rb21
-rw-r--r--db/migrate/20160713200638_add_repository_read_only_to_projects.rb9
-rw-r--r--db/migrate/20160713205315_add_domain_blacklist_to_application_settings.rb23
-rw-r--r--db/migrate/20160713222618_add_usage_ping_to_application_settings.rb9
-rw-r--r--db/migrate/20160715132507_add_user_id_to_pipeline.rb7
-rw-r--r--db/migrate/20160715134306_add_index_for_pipeline_user_id.rb16
-rw-r--r--db/migrate/20160715154212_add_request_access_enabled_to_projects.rb13
-rw-r--r--db/migrate/20160715204316_add_request_access_enabled_to_groups.rb13
-rw-r--r--db/migrate/20160715230841_rename_application_settings_restricted_signup_domains.rb21
-rw-r--r--db/migrate/20160716115710_add_when_and_yaml_variables_to_ci_builds.rb8
-rw-r--r--db/migrate/20160716115711_add_queued_at_to_ci_builds.rb10
-rw-r--r--db/migrate/20160718153603_add_has_external_wiki_to_projects.rb7
-rw-r--r--db/migrate/20160721081015_drop_and_readd_has_external_wiki_in_projects.rb19
-rw-r--r--db/migrate/20160722221922_nullify_blank_type_on_notes.rb9
-rw-r--r--db/migrate/20160724205507_add_resolved_to_notes.rb11
-rw-r--r--db/migrate/20160725083350_add_external_url_to_enviroments.rb9
-rw-r--r--db/migrate/20160725104020_merge_request_diff_remove_uniq.rb36
-rw-r--r--db/migrate/20160725104452_merge_request_diff_add_index.rb18
-rw-r--r--db/migrate/20160727163552_create_user_agent_details.rb19
-rw-r--r--db/migrate/20160727191041_create_boards.rb14
-rw-r--r--db/migrate/20160727193336_create_lists.rb17
-rw-r--r--db/migrate/20160728081025_add_pipeline_events_to_web_hooks.rb16
-rw-r--r--db/migrate/20160728103734_add_pipeline_events_to_services.rb16
-rw-r--r--db/migrate/20160729173930_remove_project_id_from_spam_logs.rb30
-rw-r--r--db/migrate/20160801163421_add_expires_at_to_member.rb29
-rw-r--r--db/migrate/20160801163709_add_submitted_as_ham_to_spam_logs.rb24
-rw-r--r--db/migrate/20160802010328_remove_builds_enable_index_on_projects.rb10
-rw-r--r--db/migrate/20160803161903_add_unique_index_to_lists_label_id.rb16
-rw-r--r--db/migrate/20160804142904_add_ci_config_file_to_project.rb11
-rw-r--r--db/migrate/20160804150737_add_timestamps_to_members_again.rb21
-rw-r--r--db/migrate/20160805041956_add_deleted_at_to_namespaces.rb21
-rw-r--r--db/migrate/20160808085531_add_token_to_build.rb10
-rw-r--r--db/migrate/20160808085602_add_index_for_build_token.rb17
-rw-r--r--db/migrate/20160810102349_remove_ci_runner_trigram_indexes.rb27
-rw-r--r--db/migrate/20160810142633_remove_redundant_indexes.rb113
-rw-r--r--db/migrate/20160811172945_add_can_push_to_keys.rb14
-rw-r--r--db/migrate/20160816161312_add_column_name_to_u2f_registrations.rb29
-rw-r--r--db/migrate/20160817133006_add_koding_to_application_settings.rb11
-rw-r--r--db/migrate/20160817154936_add_discussion_ids_to_notes.rb13
-rw-r--r--db/migrate/20160818205718_add_expires_at_to_project_group_links.rb29
-rw-r--r--db/migrate/20160819221631_add_index_to_note_discussion_id.rb19
-rw-r--r--db/migrate/20160819221833_reset_diff_note_discussion_id_because_it_was_calculated_wrongly.rb12
-rw-r--r--db/migrate/20160819232256_add_incoming_email_token_to_users.rb24
-rw-r--r--db/migrate/20160823081327_change_merge_error_to_text.rb10
-rw-r--r--db/migrate/20160823083941_add_column_scopes_to_personal_access_tokens.rb19
-rw-r--r--db/migrate/20160823213309_add_lfs_enabled_to_projects.rb29
-rw-r--r--db/migrate/20160824103857_drop_unused_ci_tables.rb11
-rw-r--r--db/migrate/20160824124900_add_table_issue_metrics.rb37
-rw-r--r--db/migrate/20160825052008_add_table_merge_request_metrics.rb38
-rw-r--r--db/migrate/20160827011312_ensure_lock_version_has_no_default.rb16
-rw-r--r--db/migrate/20160829114652_add_markdown_cache_columns.rb38
-rw-r--r--db/migrate/20160830203109_add_confidential_issues_events_to_web_hooks.rb15
-rw-r--r--db/migrate/20160830211132_add_confidential_issues_events_to_services.rb15
-rw-r--r--db/migrate/20160830232601_change_lock_version_not_null.rb13
-rw-r--r--db/migrate/20160831214002_create_project_features.rb17
-rw-r--r--db/migrate/20160831214543_migrate_project_features.rb44
-rw-r--r--db/migrate/20160831223750_remove_features_enabled_from_projects.rb31
-rw-r--r--db/migrate/20160901141443_set_confidential_issues_events_on_webhooks.rb18
-rw-r--r--db/migrate/20160901213340_add_lfs_enabled_to_namespaces.rb12
-rw-r--r--db/migrate/20160902122721_drop_gitorious_field_from_application_settings.rb39
-rw-r--r--db/migrate/20160907131111_add_environment_type_to_environments.rb9
-rw-r--r--db/migrate/20160913162434_remove_projects_pushes_since_gc.rb21
-rw-r--r--db/migrate/20160913212128_change_artifacts_size_column.rb15
-rw-r--r--db/migrate/20160914131004_only_allow_merge_if_all_discussions_are_resolved.rb14
-rw-r--r--db/migrate/20160915042921_create_merge_requests_closing_issues.rb35
-rw-r--r--db/migrate/20160919144305_add_type_to_labels.rb17
-rw-r--r--db/migrate/20160919145149_add_group_id_to_labels.rb20
-rw-r--r--db/migrate/20160920160832_add_index_to_labels_title.rb16
-rw-r--r--db/migrate/20160926145521_add_organization_to_user.rb12
-rw-r--r--db/migrate/20161006104309_add_state_to_environment.rb15
-rw-r--r--db/migrate/20161007073613_create_user_activities.rb28
-rw-r--r--db/migrate/20161007133303_precalculate_trending_projects.rb38
-rw-r--r--db/migrate/20161010142410_create_project_authorizations.rb15
-rw-r--r--db/migrate/20161012180455_add_repository_access_level_to_project_feature.rb14
-rw-r--r--db/migrate/20161014173530_create_label_priorities.rb26
-rw-r--r--db/migrate/20161017091941_add_authorized_projects_populated_to_users.rb9
-rw-r--r--db/migrate/20161017095000_add_properties_to_deployment.rb9
-rw-r--r--db/migrate/20161017125927_add_unique_index_to_labels.rb33
-rw-r--r--db/migrate/20161018024215_migrate_labels_priority.rb36
-rw-r--r--db/migrate/20161018024550_remove_priority_from_labels.rb18
-rw-r--r--db/migrate/20161018124658_make_project_owners_masters.rb18
-rw-r--r--db/migrate/20161019190736_migrate_sidekiq_queues_from_default.rb109
-rw-r--r--db/migrate/20161019213545_generate_project_feature_for_projects.rb28
-rw-r--r--db/migrate/20161020075734_default_request_access_groups.rb12
-rw-r--r--db/migrate/20161020075830_default_request_access_projects.rb12
-rw-r--r--db/migrate/20161020083353_add_pipeline_id_to_merge_request_metrics.rb40
-rw-r--r--db/migrate/20161020180657_add_minimum_key_length_to_application_settings.rb29
-rw-r--r--db/migrate/20161021114307_add_lock_version_to_build_and_pipelines.rb14
-rw-r--r--db/migrate/20161024042317_migrate_mailroom_queue_from_default.rb63
-rw-r--r--db/migrate/20161025231710_migrate_jira_to_gem.rb73
-rw-r--r--db/migrate/20161031155516_add_housekeeping_to_application_settings.rb32
-rw-r--r--db/migrate/20161031171301_add_project_id_to_subscriptions.rb15
-rw-r--r--db/migrate/20161031174110_migrate_subscriptions_project_id.rb44
-rw-r--r--db/migrate/20161031181638_add_unique_index_to_subscriptions.rb19
-rw-r--r--db/migrate/20161103171205_rename_repository_storage_column.rb29
-rw-r--r--db/migrate/20161103191444_add_sidekiq_throttling_to_application_settings.rb32
-rw-r--r--db/migrate/20161106185620_add_project_import_data_project_index.rb17
-rw-r--r--db/migrate/20161113184239_create_user_chat_names_table.rb22
-rw-r--r--db/migrate/20161114024742_add_coverage_regex_to_builds.rb13
-rw-r--r--db/migrate/20161115173905_add_start_date_to_milestones.rb12
-rw-r--r--db/migrate/20161118183841_add_commit_events_to_services.rb15
-rw-r--r--db/migrate/20161124111390_add_parent_id_to_namespace.rb12
-rw-r--r--db/migrate/20161124111395_add_index_to_parent_id.rb19
-rw-r--r--db/migrate/20161124111402_add_routes_table.rb19
-rw-r--r--db/migrate/20161124141322_migrate_process_commit_worker_jobs.rb105
-rw-r--r--db/migrate/20161128095517_add_in_reply_to_discussion_id_to_sent_notifications.rb29
-rw-r--r--db/migrate/20161128142110_remove_unnecessary_indexes.rb34
-rw-r--r--db/migrate/20161128161412_add_html_emails_enabled_to_application_settings.rb30
-rw-r--r--db/migrate/20161130095245_fill_routes_table.rb21
-rw-r--r--db/migrate/20161130101252_fill_projects_routes_table.rb30
-rw-r--r--db/migrate/20161201001911_add_plant_uml_url_to_application_settings.rb12
-rw-r--r--db/migrate/20161201155511_create_project_statistics.rb20
-rw-r--r--db/migrate/20161201160452_migrate_project_statistics.rb25
-rw-r--r--db/migrate/20161202152031_remove_duplicates_from_routes.rb29
-rw-r--r--db/migrate/20161202152035_add_index_to_routes.rb22
-rw-r--r--db/migrate/20161206003819_add_plant_uml_enabled_to_application_settings.rb13
-rw-r--r--db/migrate/20161206153749_remove_uniq_path_index_from_namespace.rb37
-rw-r--r--db/migrate/20161206153751_add_path_index_to_namespace.rb21
-rw-r--r--db/migrate/20161206153753_remove_uniq_name_index_from_namespace.rb37
-rw-r--r--db/migrate/20161206153754_add_name_index_to_namespace.rb21
-rw-r--r--db/migrate/20161207231620_fixup_environment_name_uniqueness.rb53
-rw-r--r--db/migrate/20161207231621_create_environment_name_unique_index.rb19
-rw-r--r--db/migrate/20161207231626_add_environment_slug.rb68
-rw-r--r--db/migrate/20161209153400_add_unique_index_for_environment_slug.rb20
-rw-r--r--db/migrate/20161209165216_create_doorkeeper_openid_connect_tables.rb37
-rw-r--r--db/migrate/20161212142807_add_lower_path_index_to_routes.rb23
-rw-r--r--db/migrate/20161213172958_change_slack_service_to_slack_notification_service.rb11
-rw-r--r--db/migrate/20161220141214_remove_dot_git_from_group_names.rb82
-rw-r--r--db/migrate/20161221152132_add_last_used_at_to_key.rb10
-rw-r--r--db/migrate/20161223034433_add_estimate_to_issuables_ce.rb25
-rw-r--r--db/migrate/20161223034646_create_timelogs_ce.rb25
-rw-r--r--db/migrate/20161226122833_remove_dot_git_from_usernames.rb110
-rw-r--r--db/migrate/20161227192806_rename_slack_and_mattermost_notification_services.rb28
-rw-r--r--db/migrate/20161228124936_change_expires_at_to_date_in_personal_access_tokens.rb19
-rw-r--r--db/migrate/20161228135550_add_impersonation_to_personal_access_tokens.rb18
-rw-r--r--db/migrate/20170120131253_create_chat_teams.rb19
-rw-r--r--db/migrate/20170121123724_add_index_to_ci_builds_for_status_runner_id_and_type.rb18
-rw-r--r--db/migrate/20170121130655_add_index_to_ci_runners_for_is_shared.rb18
-rw-r--r--db/migrate/20170124174637_add_foreign_keys_to_timelogs.rb57
-rw-r--r--db/migrate/20170124193147_add_two_factor_columns_to_namespaces.rb22
-rw-r--r--db/migrate/20170124193205_add_two_factor_columns_to_users.rb18
-rw-r--r--db/migrate/20170126174819_add_terminal_max_session_time_to_application_settings.rb33
-rw-r--r--db/migrate/20170127032550_remove_backlog_lists_from_boards.rb17
-rw-r--r--db/migrate/20170130204620_add_index_to_project_authorizations.rb19
-rw-r--r--db/migrate/20170130221926_create_uploads.rb20
-rw-r--r--db/migrate/20170131221752_add_relative_position_to_issues.rb38
-rw-r--r--db/migrate/20170204172458_add_name_to_route.rb12
-rw-r--r--db/migrate/20170204181513_add_index_to_labels_for_type_and_project.rb16
-rw-r--r--db/migrate/20170206071414_add_recaptcha_verified_to_spam_logs.rb15
-rw-r--r--db/migrate/20170206115204_add_column_ghost_to_users.rb11
-rw-r--r--db/migrate/20170210062829_add_index_to_labels_for_title_and_project.rb18
-rw-r--r--db/migrate/20170210075922_add_index_to_ci_trigger_requests_for_commit_id.rb16
-rw-r--r--db/migrate/20170210103609_add_index_to_user_agent_detail.rb19
-rw-r--r--db/migrate/20170210131347_add_unique_ips_limit_to_application_settings.rb17
-rw-r--r--db/migrate/20170214084746_add_default_artifacts_expiration_to_application_settings.rb11
-rw-r--r--db/migrate/20170216135621_add_index_for_latest_successful_pipeline.rb15
-rw-r--r--db/migrate/20170216141440_drop_index_for_builds_project_status.rb9
-rw-r--r--db/migrate/20170217132157_rename_merge_when_build_succeeds.rb29
-rw-r--r--db/migrate/20170217151947_rename_only_allow_merge_if_build_succeeds.rb29
-rw-r--r--db/migrate/20170217151948_add_owner_id_to_triggers.rb9
-rw-r--r--db/migrate/20170217151949_add_description_to_triggers.rb9
-rw-r--r--db/migrate/20170222111732_create_gpg_keys.rb21
-rw-r--r--db/migrate/20170222143317_drop_ci_projects.rb34
-rw-r--r--db/migrate/20170222143500_remove_old_project_id_columns.rb30
-rw-r--r--db/migrate/20170222143603_rename_gl_project_id_to_project_id.rb14
-rw-r--r--db/migrate/20170301101006_add_ci_runner_namespaces.rb17
-rw-r--r--db/migrate/20170301125302_add_printing_merge_request_link_enabled_to_project.rb19
-rw-r--r--db/migrate/20170301195939_rename_ci_commits_to_ci_pipelines.rb10
-rw-r--r--db/migrate/20170301205639_remove_unused_ci_tables_and_columns.rb84
-rw-r--r--db/migrate/20170305180853_add_auto_cancel_pending_pipelines_to_project.rb16
-rw-r--r--db/migrate/20170305203726_add_owner_id_foreign_key.rb15
-rw-r--r--db/migrate/20170307125949_add_last_activity_on_to_users.rb9
-rw-r--r--db/migrate/20170309173138_create_protected_tags.rb28
-rw-r--r--db/migrate/20170312114329_add_auto_canceled_by_id_to_pipeline.rb9
-rw-r--r--db/migrate/20170312114529_add_auto_canceled_by_id_foreign_key_to_pipeline.rb22
-rw-r--r--db/migrate/20170313213916_add_index_to_user_ghost.rb25
-rw-r--r--db/migrate/20170314082049_create_system_note_metadata.rb24
-rw-r--r--db/migrate/20170315174634_revert_add_notified_of_own_activity_to_users.rb26
-rw-r--r--db/migrate/20170315194013_add_closed_at_to_issues.rb8
-rw-r--r--db/migrate/20170316061730_readd_notified_of_own_activity_to_users.rb10
-rw-r--r--db/migrate/20170316163845_move_uploads_to_system_dir.rb59
-rw-r--r--db/migrate/20170317203554_index_routes_path_for_like.rb28
-rw-r--r--db/migrate/20170320173259_migrate_assignees.rb43
-rw-r--r--db/migrate/20170322013926_create_container_repository.rb17
-rw-r--r--db/migrate/20170327091750_add_created_at_index_to_deployments.rb15
-rw-r--r--db/migrate/20170328010804_add_uuid_to_application_settings.rb16
-rw-r--r--db/migrate/20170329095325_add_ref_to_triggers.rb9
-rw-r--r--db/migrate/20170329095907_create_ci_trigger_schedules.rb21
-rw-r--r--db/migrate/20170329124448_add_polling_interval_multiplier_to_application_settings.rb33
-rw-r--r--db/migrate/20170330141723_disable_invalid_service_templates2.rb18
-rw-r--r--db/migrate/20170402231018_remove_index_for_users_current_sign_in_at.rb18
-rw-r--r--db/migrate/20170404163427_add_trigger_id_foreign_key.rb15
-rw-r--r--db/migrate/20170405080720_add_import_jid_to_projects.rb9
-rw-r--r--db/migrate/20170406114958_add_auto_canceled_by_id_to_ci_builds.rb9
-rw-r--r--db/migrate/20170406115029_add_auto_canceled_by_id_foreign_key_to_ci_builds.rb22
-rw-r--r--db/migrate/20170407114956_add_ref_to_ci_trigger_schedule.rb9
-rw-r--r--db/migrate/20170407122426_add_active_to_ci_trigger_schedule.rb9
-rw-r--r--db/migrate/20170407135259_add_foreigh_key_trigger_requests_trigger.rb15
-rw-r--r--db/migrate/20170407140450_add_index_to_next_run_at_and_active.rb18
-rw-r--r--db/migrate/20170410133135_add_version_field_to_markdown_cache.rb25
-rw-r--r--db/migrate/20170413035209_add_preferred_language_to_users.rb16
-rw-r--r--db/migrate/20170418103908_delete_orphan_notification_settings.rb24
-rw-r--r--db/migrate/20170419001229_add_index_to_system_note_metadata.rb17
-rw-r--r--db/migrate/20170421102337_remove_nil_type_services.rb12
-rw-r--r--db/migrate/20170423064036_add_index_on_ci_builds_updated_at.rb19
-rw-r--r--db/migrate/20170424095707_add_index_on_ci_builds_user_id.rb19
-rw-r--r--db/migrate/20170424142900_add_index_to_web_hooks_type.rb15
-rw-r--r--db/migrate/20170425112128_create_pipeline_schedules_table.rb29
-rw-r--r--db/migrate/20170425112628_remove_foreigh_key_ci_trigger_schedules.rb23
-rw-r--r--db/migrate/20170425114731_add_pipeline_schedule_id_to_pipelines.rb9
-rw-r--r--db/migrate/20170426175636_fill_missing_uuid_on_application_settings.rb10
-rw-r--r--db/migrate/20170426181740_add_index_on_ci_runners_contacted_at.rb19
-rw-r--r--db/migrate/20170427103502_create_web_hook_logs.rb22
-rw-r--r--db/migrate/20170427215854_create_redirect_routes.rb15
-rw-r--r--db/migrate/20170428064307_add_column_delete_error_to_projects.rb7
-rw-r--r--db/migrate/20170502065653_make_auto_cancel_pending_pipelines_on_by_default.rb13
-rw-r--r--db/migrate/20170502091007_markdown_cache_limits_to_mysql.rb1
-rw-r--r--db/migrate/20170502135553_create_index_ci_pipelines_auto_canceled_by_id.rb21
-rw-r--r--db/migrate/20170502140503_create_index_ci_builds_auto_canceled_by_id.rb21
-rw-r--r--db/migrate/20170503004125_add_last_repository_updated_at_to_projects.rb8
-rw-r--r--db/migrate/20170503004425_add_index_to_last_repository_updated_at_on_projects.rb15
-rw-r--r--db/migrate/20170503004426_add_retried_to_ci_build.rb9
-rw-r--r--db/migrate/20170503021915_add_last_edited_at_and_last_edited_by_id_to_issues.rb15
-rw-r--r--db/migrate/20170503022548_add_last_edited_at_and_last_edited_by_id_to_merge_requests.rb15
-rw-r--r--db/migrate/20170503023315_add_repository_update_events_to_web_hooks.rb15
-rw-r--r--db/migrate/20170503114228_add_description_to_snippets.rb12
-rw-r--r--db/migrate/20170503140201_reschedule_project_authorizations.rb44
-rw-r--r--db/migrate/20170503140202_turn_nested_groups_into_regular_groups_for_mysql.rb116
-rw-r--r--db/migrate/20170503184421_add_index_to_redirect_routes.rb21
-rw-r--r--db/migrate/20170503185032_index_redirect_routes_path_for_like.rb28
-rw-r--r--db/migrate/20170504102911_add_clientside_sentry_to_application_settings.rb33
-rw-r--r--db/migrate/20170504182103_add_index_project_group_links_group_id.rb19
-rw-r--r--db/migrate/20170506085040_add_index_to_pipeline_pipeline_schedule_id.rb19
-rw-r--r--db/migrate/20170506091344_add_foreign_key_to_pipeline_schedules.rb15
-rw-r--r--db/migrate/20170506185517_add_foreign_key_pipeline_schedules_and_pipelines.rb23
-rw-r--r--db/migrate/20170507205316_add_head_pipeline_id_to_merge_requests.rb7
-rw-r--r--db/migrate/20170508153950_add_not_null_contraints_to_ci_variables.rb12
-rw-r--r--db/migrate/20170508190732_add_foreign_key_to_ci_variables.rb24
-rw-r--r--db/migrate/20170511082759_rename_web_hooks_build_events_to_job_events.rb18
-rw-r--r--db/migrate/20170511083824_rename_services_build_events_to_job_events.rb18
-rw-r--r--db/migrate/20170516153305_migrate_assignee_to_separate_table.rb83
-rw-r--r--db/migrate/20170516183131_add_indices_to_issue_assignees.rb41
-rw-r--r--db/migrate/20170519102115_add_prometheus_settings_to_metrics_settings.rb16
-rw-r--r--db/migrate/20170521184006_add_change_position_to_notes.rb13
-rw-r--r--db/migrate/20170523091700_add_rss_token_to_users.rb19
-rw-r--r--db/migrate/20170523121229_create_conversational_development_index_metrics.rb40
-rw-r--r--db/migrate/20170524125940_add_source_to_ci_pipeline.rb9
-rw-r--r--db/migrate/20170524161101_add_protected_to_ci_variables.rb15
-rw-r--r--db/migrate/20170525130346_create_group_variables_table.rb23
-rw-r--r--db/migrate/20170525130758_add_foreign_key_to_group_variables.rb15
-rw-r--r--db/migrate/20170525132202_create_pipeline_stages.rb26
-rw-r--r--db/migrate/20170525174156_create_feature_tables.rb26
-rw-r--r--db/migrate/20170526185602_add_stage_id_to_ci_builds.rb13
-rw-r--r--db/migrate/20170530130129_project_foreign_keys_with_cascading_deletes.rb198
-rw-r--r--db/migrate/20170531180233_add_authorized_keys_enabled_to_application_settings.rb19
-rw-r--r--db/migrate/20170531202042_rename_users_ldap_email_to_external_email.rb16
-rw-r--r--db/migrate/20170601163708_add_artifacts_store_to_ci_build.rb10
-rw-r--r--db/migrate/20170602154736_add_help_page_hide_commercial_content_to_application_settings.rb10
-rw-r--r--db/migrate/20170602154813_add_help_page_support_url_to_application_settings.rb9
-rw-r--r--db/migrate/20170603200744_add_email_provider_to_users.rb9
-rw-r--r--db/migrate/20170606154216_add_notification_setting_columns.rb26
-rw-r--r--db/migrate/20170608152747_prepare_events_table_for_push_events_migration.rb51
-rw-r--r--db/migrate/20170608152748_create_push_event_payloads_tables.rb46
-rw-r--r--db/migrate/20170608171156_create_merge_request_diff_files.rb22
-rw-r--r--db/migrate/20170613154149_create_gpg_signatures.rb25
-rw-r--r--db/migrate/20170614115405_merge_request_diff_file_limits_to_mysql.rb1
-rw-r--r--db/migrate/20170616133147_create_merge_request_diff_commits.rb20
-rw-r--r--db/migrate/20170619144837_add_index_for_head_pipeline_merge_request.rb15
-rw-r--r--db/migrate/20170620064728_create_ci_pipeline_schedule_variables.rb25
-rw-r--r--db/migrate/20170620065449_add_foreign_key_to_ci_pipeline_schedule_variables.rb15
-rw-r--r--db/migrate/20170622130029_correct_protected_branches_foreign_keys.rb40
-rw-r--r--db/migrate/20170622132212_add_foreign_key_for_merge_request_diffs.rb30
-rw-r--r--db/migrate/20170622135451_rename_duplicated_variable_key.rb38
-rw-r--r--db/migrate/20170622135628_add_environment_scope_to_ci_variables.rb15
-rw-r--r--db/migrate/20170622135728_add_unique_constraint_to_ci_variables.rb35
-rw-r--r--db/migrate/20170622162730_add_ref_fetched_to_merge_request.rb9
-rw-r--r--db/migrate/20170623080805_remove_ci_variables_project_id_index.rb19
-rw-r--r--db/migrate/20170629171610_rename_application_settings_signin_enabled_to_password_authentication_enabled.rb15
-rw-r--r--db/migrate/20170703102400_add_stage_id_foreign_key_to_builds.rb27
-rw-r--r--db/migrate/20170706151212_add_performance_bar_allowed_group_id_to_application_settings.rb9
-rw-r--r--db/migrate/20170707183807_add_group_id_to_milestones.rb20
-rw-r--r--db/migrate/20170707184243_add_group_milestone_id_indexes.rb21
-rw-r--r--db/migrate/20170707184244_remove_wrong_versions_from_schema_versions.rb10
-rw-r--r--db/migrate/20170710083355_clean_stage_id_reference_migration.rb18
-rw-r--r--db/migrate/20170711145320_add_status_to_ci_stages.rb9
-rw-r--r--db/migrate/20170713104829_add_foreign_key_to_merge_requests.rb37
-rw-r--r--db/migrate/20170717074009_move_system_upload_folder.rb70
-rw-r--r--db/migrate/20170717200542_add_trusted_column_to_oauth_applications.rb15
-rw-r--r--db/migrate/20170720111708_add_lock_version_to_ci_stages.rb9
-rw-r--r--db/migrate/20170720122741_create_user_custom_attributes.rb17
-rw-r--r--db/migrate/20170720130522_create_ci_pipeline_variables.rb20
-rw-r--r--db/migrate/20170720130749_add_foreign_key_to_ci_pipeline_variables.rb15
-rw-r--r--db/migrate/20170724214302_add_lower_path_index_to_redirect_routes.rb35
-rw-r--r--db/migrate/20170725145659_add_binary_to_merge_request_diff_files.rb9
-rw-r--r--db/migrate/20170727123534_add_index_on_events_project_id_id.rb37
-rw-r--r--db/migrate/20170731175128_add_percentages_to_conv_dev.rb32
-rw-r--r--db/migrate/20170731183033_add_merge_jid_to_merge_requests.rb7
-rw-r--r--db/migrate/20170802013652_add_storage_fields_to_project.rb16
-rw-r--r--db/migrate/20170803130232_reorganise_issues_indexes_for_faster_sorting.rb43
-rw-r--r--db/migrate/20170807071105_add_hashed_storage_to_settings.rb18
-rw-r--r--db/migrate/20170809133343_add_broadcast_messages_index.rb21
-rw-r--r--db/migrate/20170809134534_add_broadcast_message_not_null_constraints.rb29
-rw-r--r--db/migrate/20170809142252_cleanup_appearances_schema.rb33
-rw-r--r--db/migrate/20170809161910_add_project_export_enabled_to_application_settings.rb14
-rw-r--r--db/migrate/20170815221154_add_discussion_locked_to_issuable.rb13
-rw-r--r--db/migrate/20170816133938_add_access_level_to_ci_runners.rb16
-rw-r--r--db/migrate/20170816133940_add_protected_to_ci_builds.rb7
-rw-r--r--db/migrate/20170816143940_add_protected_to_ci_pipelines.rb7
-rw-r--r--db/migrate/20170816153940_add_index_on_ci_builds_protected.rb15
-rw-r--r--db/migrate/20170816234252_add_theme_id_to_users.rb10
-rw-r--r--db/migrate/20170817123339_add_verification_status_to_gpg_signatures.rb20
-rw-r--r--db/migrate/20170820100558_correct_protected_tags_foreign_keys.rb35
-rw-r--r--db/migrate/20170820120108_create_user_synced_attributes_metadata.rb15
-rw-r--r--db/migrate/20170824101926_add_auto_devops_enabled_to_application_settings.rb15
-rw-r--r--db/migrate/20170824162758_allow_appearances_description_html_null.rb18
-rw-r--r--db/migrate/20170825015534_add_file_store_to_lfs_objects.rb31
-rw-r--r--db/migrate/20170825104051_migrate_issues_to_ghost_user.rb37
-rw-r--r--db/migrate/20170825154015_resolve_outdated_diff_discussions.rb9
-rw-r--r--db/migrate/20170827123848_add_index_on_merge_request_diff_commit_sha.rb17
-rw-r--r--db/migrate/20170828093725_create_project_auto_dev_ops.rb19
-rw-r--r--db/migrate/20170828135939_migrate_user_external_mail_data.rb57
-rw-r--r--db/migrate/20170830125940_add_failure_reason_to_ci_builds.rb9
-rw-r--r--db/migrate/20170830130119_steal_remaining_event_migration_jobs.rb18
-rw-r--r--db/migrate/20170830131015_swap_event_migration_tables.rb47
-rw-r--r--db/migrate/20170831092813_add_config_source_to_pipelines.rb7
-rw-r--r--db/migrate/20170901071411_add_foreign_key_to_issue_author.rb14
-rw-r--r--db/migrate/20170904092148_add_email_confirmation.rb33
-rw-r--r--db/migrate/20170905112933_add_resolved_by_push_to_notes.rb9
-rw-r--r--db/migrate/20170906133745_add_runners_token_to_groups.rb9
-rw-r--r--db/migrate/20170909090114_add_email_confirmation_index.rb36
-rw-r--r--db/migrate/20170909150936_add_spent_at_to_timelogs.rb11
-rw-r--r--db/migrate/20170912113435_clean_stages_statuses_migration.rb26
-rw-r--r--db/migrate/20170913131410_environments_project_id_not_null.rb16
-rw-r--r--db/migrate/20170914135630_add_index_for_recent_push_events.rb40
-rw-r--r--db/migrate/20170918072948_create_job_artifacts.rb23
-rw-r--r--db/migrate/20170918072949_add_file_store_job_artifacts.rb10
-rw-r--r--db/migrate/20170918111708_create_project_custom_attributes.rb15
-rw-r--r--db/migrate/20170918140927_create_group_custom_attributes.rb19
-rw-r--r--db/migrate/20170918222253_reorganize_deployments_indexes.rb28
-rw-r--r--db/migrate/20170918223303_add_deployments_index_for_last_deployment.rb21
-rw-r--r--db/migrate/20170919211300_remove_temporary_ci_builds_index.rb28
-rw-r--r--db/migrate/20170921115009_add_project_repository_storage_index.rb19
-rw-r--r--db/migrate/20170924094327_create_gcp_clusters.rb45
-rw-r--r--db/migrate/20170925184228_add_favicon_to_appearances.rb7
-rw-r--r--db/migrate/20170927095921_add_ci_builds_index_for_jobscontroller.rb39
-rw-r--r--db/migrate/20170927122209_add_partial_index_for_labels_template.rb45
-rw-r--r--db/migrate/20170927161718_create_gpg_key_subkeys.rb25
-rw-r--r--db/migrate/20170928100231_add_composite_index_on_merge_requests_merge_commit_sha.rb33
-rw-r--r--db/migrate/20170928124105_create_fork_networks.rb29
-rw-r--r--db/migrate/20170928133643_create_fork_network_members.rb27
-rw-r--r--db/migrate/20170929080234_add_failure_reason_to_pipelines.rb9
-rw-r--r--db/migrate/20170929131201_populate_fork_networks.rb16
-rw-r--r--db/migrate/20171004121444_make_sure_fast_forward_option_exists.rb25
-rw-r--r--db/migrate/20171006090001_create_ci_build_trace_sections.rb19
-rw-r--r--db/migrate/20171006090010_add_build_foreign_key_to_ci_build_trace_sections.rb15
-rw-r--r--db/migrate/20171006090100_create_ci_build_trace_section_names.rb19
-rw-r--r--db/migrate/20171006091000_add_name_foreign_key_to_ci_build_trace_sections.rb15
-rw-r--r--db/migrate/20171006220837_add_global_rate_limits_to_application_settings.rb38
-rw-r--r--db/migrate/20171012101043_add_circuit_breaker_properties_to_application_settings.rb27
-rw-r--r--db/migrate/20171012125712_migrate_user_authentication_token_to_personal_access_token.rb78
-rw-r--r--db/migrate/20171013094327_create_new_clusters_architectures.rb68
-rw-r--r--db/migrate/20171017145932_add_new_circuitbreaker_settings_to_application_settings.rb16
-rw-r--r--db/migrate/20171019141859_fix_dev_timezone_schema.rb25
-rw-r--r--db/migrate/20171025110159_add_latest_merge_request_diff_id_to_merge_requests.rb26
-rw-r--r--db/migrate/20171031100710_create_clusters_kubernetes_helm_apps.rb18
-rw-r--r--db/migrate/20171101130535_add_gitaly_timeout_properties_to_application_settings.rb31
-rw-r--r--db/migrate/20171103000000_set_uploads_path_size_for_mysql.rb25
-rw-r--r--db/migrate/20171106101200_create_clusters_kubernetes_ingress_apps.rb21
-rw-r--r--db/migrate/20171106132212_issues_confidential_not_null.rb23
-rw-r--r--db/migrate/20171106133143_rename_application_settings_password_authentication_enabled_to_password_authentication_enabled_for_web.rb15
-rw-r--r--db/migrate/20171106133911_add_password_authentication_enabled_for_git_to_application_settings.rb9
-rw-r--r--db/migrate/20171106135924_issues_milestone_id_foreign_key.rb39
-rw-r--r--db/migrate/20171106150657_issues_updated_by_id_foreign_key.rb45
-rw-r--r--db/migrate/20171106151218_issues_moved_to_id_foreign_key.rb56
-rw-r--r--db/migrate/20171106155656_turn_issues_due_date_index_to_partial_index.rb35
-rw-r--r--db/migrate/20171106171453_add_timezone_to_issues_closed_at.rb20
-rw-r--r--db/migrate/20171114150259_merge_requests_author_id_foreign_key.rb43
-rw-r--r--db/migrate/20171114160005_merge_requests_assignee_id_foreign_key.rb39
-rw-r--r--db/migrate/20171114160904_merge_requests_updated_by_id_foreign_key.rb46
-rw-r--r--db/migrate/20171114161720_merge_requests_merge_user_id_foreign_key.rb46
-rw-r--r--db/migrate/20171114161914_merge_requests_source_project_id_foreign_key.rb45
-rw-r--r--db/migrate/20171114162227_merge_requests_milestone_id_foreign_key.rb39
-rw-r--r--db/migrate/20171115164540_populate_merge_requests_latest_merge_request_diff_id_take_two.rb30
-rw-r--r--db/migrate/20171116135628_add_environment_scope_to_clusters.rb15
-rw-r--r--db/migrate/20171121144800_ci_pipelines_index_on_project_id_ref_status_id.rb35
-rw-r--r--db/migrate/20171122131600_add_new_project_guidelines_to_appearances.rb18
-rw-r--r--db/migrate/20171123094802_add_circuitbreaker_check_interval_to_application_settings.rb20
-rw-r--r--db/migrate/20171124125042_add_default_values_to_merge_request_states.rb19
-rw-r--r--db/migrate/20171124125748_populate_missing_merge_request_statuses.rb50
-rw-r--r--db/migrate/20171124132536_make_merge_request_statuses_not_null.rb14
-rw-r--r--db/migrate/20171127151038_add_events_related_columns_to_merge_request_metrics.rb37
-rw-r--r--db/migrate/20171204204233_add_permanent_to_redirect_route.rb18
-rw-r--r--db/migrate/20171206221519_add_permanent_index_to_redirect_route.rb19
-rw-r--r--db/migrate/20171207185153_add_merge_request_state_index.rb18
-rw-r--r--db/migrate/20171211131502_add_external_classification_authorization_settings_to_appliction_settings.rb29
-rw-r--r--db/migrate/20171211145425_add_can_push_to_deploy_keys_projects.rb15
-rw-r--r--db/migrate/20171212203433_create_clusters_applications_prometheus.rb18
-rw-r--r--db/migrate/20171214144320_add_store_column_to_uploads.rb12
-rw-r--r--db/migrate/20171215113714_populate_can_push_from_deploy_keys_projects.rb64
-rw-r--r--db/migrate/20171216112339_add_foreign_key_for_members.rb21
-rw-r--r--db/migrate/20171218140451_add_external_authorization_service_classification_label_to_projects.rb11
-rw-r--r--db/migrate/20171220191323_add_index_on_namespaces_lower_name.rb32
-rw-r--r--db/migrate/20171222115326_add_confidential_note_events_to_web_hooks.rb15
-rw-r--r--db/migrate/20171222183504_add_jobs_cache_index_to_project.rb13
-rw-r--r--db/migrate/20171229225929_change_user_project_limit_not_null_and_remove_default.rb38
-rw-r--r--db/migrate/20171230123729_add_rebase_commit_sha_to_merge_requests_ce.rb15
-rw-r--r--db/migrate/20171230123729_init_schema.rb1854
-rw-r--r--db/migrate/20190613044655_add_username_to_deploy_tokens.rb9
-rw-r--r--db/migrate/20190617123615_add_grafana_to_settings.rb18
-rw-r--r--db/migrate/20190621022810_add_last_ci_minutes_usage_notification_level_to_namespaces.rb9
-rw-r--r--db/migrate/20190621151636_add_merge_request_rebase_jid.rb9
-rw-r--r--db/migrate/20190624123615_add_grafana_url_to_settings.rb18
-rw-r--r--db/migrate/20190625115224_add_description_to_services.rb14
-rw-r--r--db/migrate/20190628145246_add_strategies_to_operations_feature_flag_scopes.rb17
-rw-r--r--db/migrate/20190628185000_add_released_at_to_releases_table.rb11
-rw-r--r--db/migrate/20190628185004_backfill_and_add_not_null_constraint_to_released_at_column_on_releases_table.rb18
-rw-r--r--db/migrate/20190703130053_remove_gitaly_feature_flags.rb48
-rw-r--r--db/post_migrate/20160824121037_change_personal_access_tokens_default_back_to_empty_array.rb19
-rw-r--r--db/post_migrate/20161011222551_remove_inactive_jira_service_properties.rb10
-rw-r--r--db/post_migrate/20161109150329_fix_project_records_with_invalid_visibility.rb49
-rw-r--r--db/post_migrate/20161128170531_drop_user_activities_table.rb33
-rw-r--r--db/post_migrate/20161221140236_remove_unneeded_services.rb15
-rw-r--r--db/post_migrate/20161221153951_rename_reserved_project_names.rb137
-rw-r--r--db/post_migrate/20170104150317_requeue_pending_delete_projects.rb49
-rw-r--r--db/post_migrate/20170106142508_fill_authorized_projects.rb30
-rw-r--r--db/post_migrate/20170106172224_remove_project_authorizations_id_column.rb12
-rw-r--r--db/post_migrate/20170131214021_reset_users_authorized_projects_populated.rb18
-rw-r--r--db/post_migrate/20170206040400_remove_inactive_default_email_services.rb41
-rw-r--r--db/post_migrate/20170206101007_remove_trackable_columns_from_timelogs.rb24
-rw-r--r--db/post_migrate/20170206101030_validate_foreign_keys_on_timelogs.rb32
-rw-r--r--db/post_migrate/20170209140523_validate_foreign_keys_on_oauth_openid_requests.rb20
-rw-r--r--db/post_migrate/20170211073944_disable_invalid_service_templates.rb13
-rw-r--r--db/post_migrate/20170214111112_delete_deprecated_gitlab_ci_service.rb15
-rw-r--r--db/post_migrate/20170215200045_remove_theme_id_from_users.rb9
-rw-r--r--db/post_migrate/20170301205640_migrate_build_events_to_pipeline_events.rb86
-rw-r--r--db/post_migrate/20170306170512_migrate_legacy_manual_actions.rb23
-rw-r--r--db/post_migrate/20170309171644_reset_relative_position_for_issue.rb19
-rw-r--r--db/post_migrate/20170313133418_rename_more_reserved_project_names.rb79
-rw-r--r--db/post_migrate/20170317162059_update_upload_paths_to_system.rb57
-rw-r--r--db/post_migrate/20170324160416_migrate_user_activities_to_users_last_activity_on.rb88
-rw-r--r--db/post_migrate/20170404170532_remove_notes_original_discussion_id.rb23
-rw-r--r--db/post_migrate/20170406111121_clean_upload_symlinks.rb53
-rw-r--r--db/post_migrate/20170406142253_migrate_user_project_view.rb22
-rw-r--r--db/post_migrate/20170408033905_remove_old_cache_directories.rb23
-rw-r--r--db/post_migrate/20170412174900_rename_reserved_dynamic_paths.rb62
-rw-r--r--db/post_migrate/20170425121605_migrate_trigger_schedules_to_pipeline_schedules.rb48
-rw-r--r--db/post_migrate/20170425130047_drop_ci_trigger_schedules_table.rb32
-rw-r--r--db/post_migrate/20170502070007_enable_auto_cancel_pending_pipelines_for_all.rb19
-rw-r--r--db/post_migrate/20170503004427_update_retried_for_ci_build.rb69
-rw-r--r--db/post_migrate/20170503120310_remove_users_authorized_projects_populated.rb15
-rw-r--r--db/post_migrate/20170508170547_add_head_pipeline_for_each_merge_request.rb28
-rw-r--r--db/post_migrate/20170510101043_add_foreign_key_on_pipeline_schedule_owner.rb35
-rw-r--r--db/post_migrate/20170511100900_cleanup_rename_web_hooks_build_events_to_job_events.rb18
-rw-r--r--db/post_migrate/20170511101000_cleanup_rename_services_build_events_to_job_events.rb18
-rw-r--r--db/post_migrate/20170516165238_cleanup_trigger_for_issues.rb39
-rw-r--r--db/post_migrate/20170516181025_add_constraints_to_issue_assignees_table.rb37
-rw-r--r--db/post_migrate/20170518200835_rename_users_with_renamed_namespace.rb51
-rw-r--r--db/post_migrate/20170518231126_fix_wrongly_renamed_routes.rb105
-rw-r--r--db/post_migrate/20170523073948_remove_assignee_id_from_issue.rb48
-rw-r--r--db/post_migrate/20170523083112_migrate_old_artifacts.rb72
-rw-r--r--db/post_migrate/20170525140254_rename_all_reserved_paths_again.rb102
-rw-r--r--db/post_migrate/20170526185842_migrate_pipeline_stages.rb22
-rw-r--r--db/post_migrate/20170526185858_create_index_in_pipeline_stages.rb15
-rw-r--r--db/post_migrate/20170526185901_remove_stage_id_index_from_builds.rb18
-rw-r--r--db/post_migrate/20170526185921_migrate_build_stage_reference.rb19
-rw-r--r--db/post_migrate/20170526190000_migrate_build_stage_reference_again.rb28
-rw-r--r--db/post_migrate/20170531203055_cleanup_users_ldap_email_rename.rb16
-rw-r--r--db/post_migrate/20170606202615_move_appearance_to_system_dir.rb57
-rw-r--r--db/post_migrate/20170607121233_convert_custom_notification_settings_to_columns.rb55
-rw-r--r--db/post_migrate/20170609183112_remove_position_from_issuables.rb8
-rw-r--r--db/post_migrate/20170612071012_move_personal_snippets_files.rb92
-rw-r--r--db/post_migrate/20170613111224_clean_appearance_symlinks.rb53
-rw-r--r--db/post_migrate/20170621102400_add_stage_id_index_to_builds.rb17
-rw-r--r--db/post_migrate/20170627101016_schedule_event_migrations.rb40
-rw-r--r--db/post_migrate/20170628080858_migrate_stage_id_reference_in_background.rb33
-rw-r--r--db/post_migrate/20170629180131_cleanup_application_settings_signin_enabled_rename.rb15
-rw-r--r--db/post_migrate/20170711145558_migrate_stages_statuses.rb34
-rw-r--r--db/post_migrate/20170717111152_cleanup_move_system_upload_folder_symlink.rb40
-rw-r--r--db/post_migrate/20170717150329_enqueue_migrate_system_uploads_to_new_folder.rb20
-rw-r--r--db/post_migrate/20170719150301_merge_issuable_reopened_into_opened_state.rb32
-rw-r--r--db/post_migrate/20170728101014_remove_events_from_notification_settings.rb9
-rw-r--r--db/post_migrate/20170803090603_calculate_conv_dev_index_percentages.rb30
-rw-r--r--db/post_migrate/20170807160457_remove_locked_at_column_from_merge_requests.rb11
-rw-r--r--db/post_migrate/20170807190736_move_personal_snippet_files_into_correct_folder.rb29
-rw-r--r--db/post_migrate/20170815060945_remove_duplicate_mr_events.rb26
-rw-r--r--db/post_migrate/20170816102555_cleanup_nonexisting_namespace_pending_delete_projects.rb54
-rw-r--r--db/post_migrate/20170822101017_migrate_pipeline_sidekiq_queues.rb17
-rw-r--r--db/post_migrate/20170828170502_post_deploy_migrate_user_external_mail_data.rb57
-rw-r--r--db/post_migrate/20170828170513_remove_user_email_provider_column.rb12
-rw-r--r--db/post_migrate/20170828170516_remove_user_external_mail_columns.rb12
-rw-r--r--db/post_migrate/20170830084744_destroy_gpg_signatures.rb10
-rw-r--r--db/post_migrate/20170830150306_drop_events_for_migration_table.rb47
-rw-r--r--db/post_migrate/20170831195038_remove_valid_signature_from_gpg_signatures.rb11
-rw-r--r--db/post_migrate/20170907170235_delete_conflicting_redirect_routes.rb13
-rw-r--r--db/post_migrate/20170913180600_fix_projects_without_project_feature.rb33
-rw-r--r--db/post_migrate/20170921101004_normalize_ldap_extern_uids.rb29
-rw-r--r--db/post_migrate/20170927112318_update_legacy_diff_notes_type_for_import.rb17
-rw-r--r--db/post_migrate/20170927112319_update_notes_type_for_import.rb17
-rw-r--r--db/post_migrate/20171012150314_remove_user_authentication_token.rb20
-rw-r--r--db/post_migrate/20171013104327_migrate_gcp_clusters_to_new_clusters_architectures.rb98
-rw-r--r--db/post_migrate/20171026082505_schedule_merge_request_latest_merge_request_diff_id_migrations.rb29
-rw-r--r--db/post_migrate/20171101134435_remove_ref_fetched_from_merge_requests.rb14
-rw-r--r--db/post_migrate/20171103140253_track_untracked_uploads.rb21
-rw-r--r--db/post_migrate/20171106133144_cleanup_application_settings_password_authentication_enabled_rename.rb15
-rw-r--r--db/post_migrate/20171106154015_remove_issues_branch_name.rb13
-rw-r--r--db/post_migrate/20171106180641_cleanup_add_timezone_to_issues_closed_at.rb20
-rw-r--r--db/post_migrate/20171114104051_remove_empty_fork_networks.rb36
-rw-r--r--db/post_migrate/20171121160421_remove_merge_request_diff_st_commits_and_st_diffs.rb10
-rw-r--r--db/post_migrate/20171123101020_update_circuitbreaker_defaults.rb34
-rw-r--r--db/post_migrate/20171123101046_remove_old_circuitbreaker_config.rb26
-rw-r--r--db/post_migrate/20171124095655_add_index_on_merge_request_diffs_merge_request_id_and_id.rb17
-rw-r--r--db/post_migrate/20171124100152_remove_index_on_merge_request_diffs_merge_request_diff_id.rb17
-rw-r--r--db/post_migrate/20171124104327_migrate_kubernetes_service_to_new_clusters_architectures.rb151
-rw-r--r--db/post_migrate/20171124150326_reschedule_fork_network_creation.rb13
-rw-r--r--db/post_migrate/20171205190711_reschedule_fork_network_creation_caller.rb27
-rw-r--r--db/post_migrate/20171207150300_remove_project_labels_group_id_copy.rb21
-rw-r--r--db/post_migrate/20171207150344_remove_deleted_at_columns.rb31
-rw-r--r--db/post_migrate/20171213160445_migrate_github_importer_advance_stage_sidekiq_queue.rb16
-rw-r--r--db/post_migrate/20171215121205_post_populate_can_push_from_deploy_keys_projects.rb63
-rw-r--r--db/post_migrate/20171215121259_remove_can_push_from_keys.rb17
-rw-r--r--db/post_migrate/20171219121201_normalize_extern_uid_from_identities.rb29
-rw-r--r--db/post_migrate/20171221140220_schedule_issues_closed_at_type_change.rb45
-rw-r--r--db/post_migrate/20180202111106_remove_project_labels_group_id.rb19
-rw-r--r--db/schema.rb10
-rw-r--r--doc/README.md62
-rw-r--r--doc/administration/audit_events.md10
-rw-r--r--doc/administration/auditor_users.md4
-rw-r--r--doc/administration/auth/README.md4
-rw-r--r--doc/administration/auth/google_secure_ldap.md5
-rw-r--r--doc/administration/auth/how_to_configure_ldap_gitlab_ce/index.md4
-rw-r--r--doc/administration/auth/how_to_configure_ldap_gitlab_ee/index.md2
-rw-r--r--doc/administration/auth/ldap-ee.md14
-rw-r--r--doc/administration/auth/ldap.md12
-rw-r--r--doc/administration/auth/smartcard.md30
-rw-r--r--doc/administration/container_registry.md308
-rw-r--r--doc/administration/database_load_balancing.md30
-rw-r--r--doc/administration/dependency_proxy.md4
-rw-r--r--doc/administration/geo/disaster_recovery/background_verification.md12
-rw-r--r--doc/administration/geo/disaster_recovery/bring_primary_back.md30
-rw-r--r--doc/administration/geo/disaster_recovery/index.md231
-rw-r--r--doc/administration/geo/disaster_recovery/planned_failover.md43
-rw-r--r--doc/administration/geo/replication/configuration.md177
-rw-r--r--doc/administration/geo/replication/database.md602
-rw-r--r--doc/administration/geo/replication/docker_registry.md2
-rw-r--r--doc/administration/geo/replication/external_database.md162
-rw-r--r--doc/administration/geo/replication/faq.md2
-rw-r--r--doc/administration/geo/replication/high_availability.md252
-rw-r--r--doc/administration/geo/replication/index.md12
-rw-r--r--doc/administration/geo/replication/object_storage.md6
-rw-r--r--doc/administration/geo/replication/remove_geo_node.md47
-rw-r--r--doc/administration/geo/replication/security_review.md4
-rw-r--r--doc/administration/geo/replication/troubleshooting.md328
-rw-r--r--doc/administration/geo/replication/tuning.md2
-rw-r--r--doc/administration/geo/replication/updating_the_geo_nodes.md333
-rw-r--r--doc/administration/geo/replication/using_a_geo_server.md2
-rw-r--r--doc/administration/gitaly/index.md26
-rw-r--r--doc/administration/high_availability/README.md10
-rw-r--r--doc/administration/high_availability/consul.md70
-rw-r--r--doc/administration/high_availability/database.md77
-rw-r--r--doc/administration/high_availability/gitlab.md2
-rw-r--r--doc/administration/high_availability/monitoring_node.md2
-rw-r--r--doc/administration/high_availability/redis.md25
-rw-r--r--doc/administration/img/audit_log.png (renamed from doc/administration/audit_log.png)bin25767 -> 25767 bytes
-rw-r--r--doc/administration/img/auditor_access_form.png (renamed from doc/administration/auditor_access_form.png)bin11910 -> 11910 bytes
-rw-r--r--doc/administration/incoming_email.md44
-rw-r--r--doc/administration/index.md48
-rw-r--r--doc/administration/instance_review.md2
-rw-r--r--doc/administration/integration/plantuml.md2
-rw-r--r--doc/administration/issue_closing_pattern.md17
-rw-r--r--doc/administration/job_artifacts.md154
-rw-r--r--doc/administration/job_traces.md48
-rw-r--r--doc/administration/logs.md5
-rw-r--r--doc/administration/merge_request_diffs.md130
-rw-r--r--doc/administration/monitoring/performance/grafana_configuration.md19
-rw-r--r--doc/administration/monitoring/performance/influxdb_configuration.md2
-rw-r--r--doc/administration/monitoring/prometheus/gitlab_metrics.md6
-rw-r--r--doc/administration/operations/extra_sidekiq_processes.md2
-rw-r--r--doc/administration/operations/fast_ssh_key_lookup.md4
-rw-r--r--doc/administration/operations/index.md2
-rw-r--r--doc/administration/operations/unicorn.md2
-rw-r--r--doc/administration/packages.md144
-rw-r--r--doc/administration/pseudonymizer.md70
-rw-r--r--doc/administration/raketasks/geo.md2
-rw-r--r--doc/administration/raketasks/maintenance.md2
-rw-r--r--doc/administration/raketasks/project_import_export.md2
-rw-r--r--doc/administration/reply_by_email_postfix_setup.md384
-rw-r--r--doc/administration/repository_storage_paths.md42
-rw-r--r--doc/administration/repository_storage_types.md33
-rw-r--r--doc/administration/restart_gitlab.md4
-rw-r--r--doc/administration/uploads.md90
-rw-r--r--doc/api/README.md38
-rw-r--r--doc/api/boards.md11
-rw-r--r--doc/api/deploy_keys.md4
-rw-r--r--doc/api/discussions.md4
-rw-r--r--doc/api/epic_issues.md2
-rw-r--r--doc/api/epic_links.md2
-rw-r--r--doc/api/epics.md4
-rw-r--r--doc/api/geo_nodes.md2
-rw-r--r--doc/api/graphql/index.md18
-rw-r--r--doc/api/group_boards.md289
-rw-r--r--doc/api/group_milestones.md29
-rw-r--r--doc/api/groups.md213
-rw-r--r--doc/api/issue_links.md5
-rw-r--r--doc/api/issues.md163
-rw-r--r--doc/api/issues_statistics.md19
-rw-r--r--doc/api/jobs.md13
-rw-r--r--doc/api/license.md3
-rw-r--r--doc/api/lint.md38
-rw-r--r--doc/api/managed_licenses.md4
-rw-r--r--doc/api/merge_request_approvals.md6
-rw-r--r--doc/api/merge_requests.md208
-rw-r--r--doc/api/milestones.md29
-rw-r--r--doc/api/namespaces.md16
-rw-r--r--doc/api/notes.md4
-rw-r--r--doc/api/notification_settings.md52
-rw-r--r--doc/api/oauth2.md2
-rw-r--r--doc/api/packages.md4
-rw-r--r--doc/api/pages_domains.md2
-rw-r--r--doc/api/pipeline_schedules.md12
-rw-r--r--doc/api/pipelines.md10
-rw-r--r--doc/api/project_aliases.md18
-rw-r--r--doc/api/project_badges.md2
-rw-r--r--doc/api/project_clusters.md4
-rw-r--r--doc/api/project_level_variables.md4
-rw-r--r--doc/api/project_snippets.md8
-rw-r--r--doc/api/project_statistics.md2
-rw-r--r--doc/api/project_templates.md6
-rw-r--r--doc/api/projects.md235
-rw-r--r--doc/api/protected_branches.md154
-rw-r--r--doc/api/repositories.md6
-rw-r--r--doc/api/resource_label_events.md2
-rw-r--r--doc/api/runners.md46
-rw-r--r--doc/api/scim.md4
-rw-r--r--doc/api/search.md16
-rw-r--r--doc/api/services.md11
-rw-r--r--doc/api/settings.md79
-rw-r--r--doc/api/users.md246
-rw-r--r--doc/api/v3_to_v4.md4
-rw-r--r--doc/api/vulnerabilities.md16
-rw-r--r--doc/ci/README.md23
-rw-r--r--doc/ci/ci_cd_for_external_repos/bitbucket_integration.md2
-rw-r--r--doc/ci/ci_cd_for_external_repos/github_integration.md4
-rw-r--r--doc/ci/ci_cd_for_external_repos/index.md2
-rw-r--r--doc/ci/docker/using_docker_images.md105
-rw-r--r--doc/ci/environments.md6
-rw-r--r--doc/ci/environments/protected_environments.md2
-rw-r--r--doc/ci/examples/README.md4
-rw-r--r--doc/ci/examples/artifactory_and_gitlab/index.md2
-rw-r--r--doc/ci/examples/end_to_end_testing_webdriverio/index.md8
-rw-r--r--doc/ci/examples/php.md6
-rw-r--r--doc/ci/examples/test-clojure-application.md2
-rw-r--r--doc/ci/examples/test-scala-application.md2
-rw-r--r--doc/ci/examples/test_phoenix_app_with_gitlab_ci_cd/index.md10
-rw-r--r--doc/ci/git_submodules.md16
-rw-r--r--doc/ci/interactive_web_terminal/index.md2
-rw-r--r--doc/ci/introduction/index.md18
-rw-r--r--doc/ci/merge_request_pipelines/index.md147
-rw-r--r--doc/ci/merge_request_pipelines/pipelines_for_merged_results/img/merge_request_pipeline.png (renamed from doc/ci/merge_request_pipelines/img/merge_request_pipeline.png)bin10152 -> 10152 bytes
-rw-r--r--doc/ci/merge_request_pipelines/pipelines_for_merged_results/img/merge_request_pipeline_config.png (renamed from doc/ci/merge_request_pipelines/img/merge_request_pipeline_config.png)bin10889 -> 10889 bytes
-rw-r--r--doc/ci/merge_request_pipelines/pipelines_for_merged_results/index.md78
-rw-r--r--doc/ci/merge_request_pipelines/pipelines_for_merged_results/merge_trains/img/merge_train_cancel_v12_0.png (renamed from doc/ci/merge_request_pipelines/img/merge_train_cancel.png)bin19577 -> 19577 bytes
-rw-r--r--doc/ci/merge_request_pipelines/pipelines_for_merged_results/merge_trains/img/merge_train_config_v12_0.png (renamed from doc/ci/merge_request_pipelines/img/merge_train_config.png)bin24267 -> 24267 bytes
-rw-r--r--doc/ci/merge_request_pipelines/pipelines_for_merged_results/merge_trains/img/merge_train_start_v12_0.png (renamed from doc/ci/merge_request_pipelines/img/merge_train_start.png)bin8365 -> 8365 bytes
-rw-r--r--doc/ci/merge_request_pipelines/pipelines_for_merged_results/merge_trains/img/merge_train_start_when_pipeline_succeeds_v12_0.png (renamed from doc/ci/merge_request_pipelines/img/merge_train_start_when_pipeline_succeeds.png)bin10323 -> 10323 bytes
-rw-r--r--doc/ci/merge_request_pipelines/pipelines_for_merged_results/merge_trains/index.md88
-rw-r--r--doc/ci/metrics_reports.md4
-rw-r--r--doc/ci/multi_project_pipelines.md2
-rw-r--r--doc/ci/pipelines.md2
-rw-r--r--doc/ci/quick_start/README.md2
-rw-r--r--doc/ci/review_apps/img/toolbar_feeback_form.pngbin71676 -> 24599 bytes
-rw-r--r--doc/ci/review_apps/index.md126
-rw-r--r--doc/ci/services/postgres.md2
-rw-r--r--doc/ci/triggers/README.md4
-rw-r--r--doc/ci/variables/README.md2
-rw-r--r--doc/ci/variables/predefined_variables.md2
-rw-r--r--doc/ci/yaml/README.md32
-rw-r--r--doc/customization/index.md2
-rw-r--r--doc/customization/issue_closing.md4
-rw-r--r--doc/customization/libravatar.md12
-rw-r--r--doc/customization/system_header_and_footer_messages.md7
-rw-r--r--doc/development/README.md1
-rw-r--r--doc/development/api_graphql_styleguide.md15
-rw-r--r--doc/development/api_styleguide.md2
-rw-r--r--doc/development/architecture.md16
-rw-r--r--doc/development/automatic_ce_ee_merge.md53
-rw-r--r--doc/development/changelog.md16
-rw-r--r--doc/development/chatops_on_gitlabcom.md8
-rw-r--r--doc/development/code_comments.md6
-rw-r--r--doc/development/code_review.md2
-rw-r--r--doc/development/contributing/community_roles.md4
-rw-r--r--doc/development/contributing/index.md2
-rw-r--r--doc/development/contributing/issue_workflow.md98
-rw-r--r--doc/development/contributing/merge_request_workflow.md3
-rw-r--r--doc/development/contributing/style_guides.md8
-rw-r--r--doc/development/database_debugging.md2
-rw-r--r--doc/development/documentation/site_architecture/global_nav.md34
-rw-r--r--doc/development/documentation/styleguide.md42
-rw-r--r--doc/development/ee_features.md84
-rw-r--r--doc/development/elasticsearch.md6
-rw-r--r--doc/development/emails.md96
-rw-r--r--doc/development/fe_guide/architecture.md2
-rw-r--r--doc/development/fe_guide/development_process.md24
-rw-r--r--doc/development/fe_guide/emojis.md4
-rw-r--r--doc/development/fe_guide/graphql.md4
-rw-r--r--doc/development/fe_guide/security.md7
-rw-r--r--doc/development/fe_guide/style_guide_scss.md9
-rw-r--r--doc/development/fe_guide/vue.md9
-rw-r--r--doc/development/feature_flags/controls.md4
-rw-r--r--doc/development/feature_flags/development.md2
-rw-r--r--doc/development/feature_flags/process.md19
-rw-r--r--doc/development/file_storage.md6
-rw-r--r--doc/development/geo.md2
-rw-r--r--doc/development/git_object_deduplication.md6
-rw-r--r--doc/development/go_guide/index.md8
-rw-r--r--doc/development/gotchas.md8
-rw-r--r--doc/development/integrations/jira_connect.md4
-rw-r--r--doc/development/licensed_feature_availability.md22
-rw-r--r--doc/development/logging.md82
-rw-r--r--doc/development/migration_style_guide.md2
-rw-r--r--doc/development/new_fe_guide/development/components.md2
-rw-r--r--doc/development/new_fe_guide/development/performance.md4
-rw-r--r--doc/development/new_fe_guide/development/testing.md4
-rw-r--r--doc/development/new_fe_guide/style/html.md2
-rw-r--r--doc/development/newlines_styleguide.md4
-rw-r--r--doc/development/packages.md40
-rw-r--r--doc/development/performance.md2
-rw-r--r--doc/development/profiling.md8
-rw-r--r--doc/development/pry_debugging.md2
-rw-r--r--doc/development/python_guide/index.md3
-rw-r--r--doc/development/query_recorder.md4
-rw-r--r--doc/development/rake_tasks.md2
-rw-r--r--doc/development/routing.md34
-rw-r--r--doc/development/sql.md4
-rw-r--r--doc/development/testing_guide/best_practices.md2
-rw-r--r--doc/development/testing_guide/ci.md4
-rw-r--r--doc/development/testing_guide/end_to_end/index.md2
-rw-r--r--doc/development/testing_guide/end_to_end/quick_start_guide.md8
-rw-r--r--doc/development/testing_guide/frontend_testing.md1
-rw-r--r--doc/development/testing_guide/index.md5
-rw-r--r--doc/development/understanding_explain_plans.md1
-rw-r--r--doc/development/ux_guide/resources.md4
-rw-r--r--doc/downgrade_ee_to_ce/README.md2
-rw-r--r--doc/gitlab-basics/README.md2
-rw-r--r--doc/gitlab-basics/create-issue.md4
-rw-r--r--doc/gitlab-basics/create-project.md4
-rw-r--r--doc/install/README.md2
-rw-r--r--doc/install/google_cloud_platform/index.md8
-rw-r--r--doc/install/installation.md8
-rw-r--r--doc/install/kubernetes/gitlab_chart.md2
-rw-r--r--doc/install/kubernetes/gitlab_omnibus.md2
-rw-r--r--doc/install/kubernetes/gitlab_runner_chart.md2
-rw-r--r--doc/install/kubernetes/index.md2
-rw-r--r--doc/install/kubernetes/preparation/connect.md2
-rw-r--r--doc/install/kubernetes/preparation/eks.md2
-rw-r--r--doc/install/kubernetes/preparation/networking.md2
-rw-r--r--doc/install/kubernetes/preparation/rbac.md2
-rw-r--r--doc/install/kubernetes/preparation/tiller.md2
-rw-r--r--doc/install/kubernetes/preparation/tools_installation.md2
-rw-r--r--doc/install/openshift_and_gitlab/index.md17
-rw-r--r--doc/install/pivotal/index.md2
-rw-r--r--doc/install/requirements.md2
-rw-r--r--doc/integration/akismet.md2
-rw-r--r--doc/integration/azure.md96
-rw-r--r--doc/integration/elasticsearch.md32
-rw-r--r--doc/integration/jenkins.md2
-rw-r--r--doc/integration/jira_development_panel.md2
-rw-r--r--doc/integration/kerberos.md2
-rw-r--r--doc/integration/oauth2_generic.md10
-rw-r--r--doc/integration/oauth_provider.md4
-rw-r--r--doc/integration/openid_connect_provider.md6
-rw-r--r--doc/integration/shibboleth.md4
-rw-r--r--doc/integration/twitter.md99
-rw-r--r--doc/intro/README.md6
-rw-r--r--doc/policy/maintenance.md2
-rw-r--r--doc/public_access/public_access.md6
-rw-r--r--doc/push_rules/push_rules.md2
-rw-r--r--doc/raketasks/README.md4
-rw-r--r--doc/raketasks/web_hooks.md2
-rw-r--r--doc/subscriptions/index.md2
-rw-r--r--doc/tools/email.md2
-rw-r--r--doc/topics/application_development_platform/index.md30
-rw-r--r--doc/topics/authentication/index.md10
-rw-r--r--doc/topics/autodevops/index.md81
-rw-r--r--doc/topics/autodevops/quick_start_guide.md14
-rw-r--r--doc/university/README.md2
-rw-r--r--doc/university/support/README.md2
-rw-r--r--doc/university/training/index.md6
-rw-r--r--doc/update/mysql_to_postgresql.md4
-rw-r--r--doc/update/patch_versions.md2
-rw-r--r--doc/update/upgrading_from_ce_to_ee.md2
-rw-r--r--doc/update/upgrading_from_source.md2
-rw-r--r--doc/user/admin_area/custom_project_templates.md4
-rw-r--r--doc/user/admin_area/geo_nodes.md10
-rw-r--r--doc/user/admin_area/index.md10
-rw-r--r--doc/user/admin_area/labels.md2
-rw-r--r--doc/user/admin_area/license.md2
-rw-r--r--doc/user/admin_area/settings/account_and_limit_settings.md6
-rw-r--r--doc/user/admin_area/settings/continuous_integration.md12
-rw-r--r--doc/user/admin_area/settings/email.md2
-rw-r--r--doc/user/admin_area/settings/external_authorization.md4
-rw-r--r--doc/user/admin_area/settings/index.md6
-rw-r--r--doc/user/admin_area/settings/instance_template_repository.md4
-rw-r--r--doc/user/admin_area/settings/usage_statistics.md6
-rw-r--r--doc/user/admin_area/settings/visibility_and_access_controls.md2
-rw-r--r--doc/user/application_security/container_scanning/index.md2
-rw-r--r--doc/user/application_security/dast/index.md2
-rw-r--r--doc/user/application_security/dependency_scanning/analyzers.md2
-rw-r--r--doc/user/application_security/dependency_scanning/index.md2
-rw-r--r--doc/user/application_security/index.md14
-rw-r--r--doc/user/application_security/license_management/index.md13
-rw-r--r--doc/user/application_security/sast/index.md2
-rw-r--r--doc/user/application_security/security_dashboard/index.md2
-rw-r--r--doc/user/asciidoc.md4
-rw-r--r--doc/user/clusters/applications.md5
-rw-r--r--doc/user/discussions/index.md4
-rw-r--r--doc/user/gitlab_com/index.md18
-rw-r--r--doc/user/group/clusters/index.md4
-rw-r--r--doc/user/group/contribution_analytics/index.md2
-rw-r--r--doc/user/group/custom_project_templates.md4
-rw-r--r--doc/user/group/dependency_proxy/index.md2
-rw-r--r--doc/user/group/epics/index.md2
-rw-r--r--doc/user/group/index.md24
-rw-r--r--doc/user/group/insights/index.md2
-rw-r--r--doc/user/group/issues_analytics/index.md2
-rw-r--r--doc/user/group/roadmap/index.md6
-rw-r--r--doc/user/group/saml_sso/index.md2
-rw-r--r--doc/user/group/saml_sso/scim_setup.md2
-rw-r--r--doc/user/index.md2
-rw-r--r--doc/user/markdown.md82
-rw-r--r--doc/user/operations_dashboard/index.md2
-rw-r--r--doc/user/permissions.md42
-rw-r--r--doc/user/profile/preferences.md2
-rw-r--r--doc/user/project/canary_deployments.md5
-rw-r--r--doc/user/project/clusters/index.md17
-rw-r--r--doc/user/project/clusters/kubernetes_pod_logs.md2
-rw-r--r--doc/user/project/clusters/serverless/index.md47
-rw-r--r--doc/user/project/code_owners.md17
-rw-r--r--doc/user/project/container_registry.md15
-rw-r--r--doc/user/project/cycle_analytics.md2
-rw-r--r--doc/user/project/deploy_boards.md4
-rw-r--r--doc/user/project/deploy_tokens/img/deploy_tokens.pngbin23087 -> 218635 bytes
-rw-r--r--doc/user/project/deploy_tokens/index.md9
-rw-r--r--doc/user/project/description_templates.md2
-rw-r--r--doc/user/project/file_lock.md2
-rw-r--r--doc/user/project/import/gemnasium.md6
-rw-r--r--doc/user/project/import/github.md4
-rw-r--r--doc/user/project/import/index.md2
-rw-r--r--doc/user/project/import/svn.md2
-rw-r--r--doc/user/project/import/tfs.md10
-rw-r--r--doc/user/project/index.md24
-rw-r--r--doc/user/project/insights/index.md2
-rw-r--r--doc/user/project/integrations/github.md6
-rw-r--r--doc/user/project/integrations/img/jira_api_token.pngbin61394 -> 21318 bytes
-rw-r--r--doc/user/project/integrations/img/jira_api_token_menu.pngbin25056 -> 41876 bytes
-rw-r--r--doc/user/project/integrations/img/jira_issue_reference.pngbin18399 -> 64064 bytes
-rw-r--r--doc/user/project/integrations/img/jira_merge_request_close.pngbin21172 -> 64305 bytes
-rw-r--r--doc/user/project/integrations/img/jira_service_close_comment.pngbin11890 -> 0 bytes
-rw-r--r--doc/user/project/integrations/img/jira_service_close_issue.pngbin30570 -> 29632 bytes
-rw-r--r--doc/user/project/integrations/img/jira_service_page.pngbin30395 -> 70807 bytes
-rw-r--r--doc/user/project/integrations/jira.md26
-rw-r--r--doc/user/project/integrations/jira_cloud_configuration.md16
-rw-r--r--doc/user/project/integrations/project_services.md6
-rw-r--r--doc/user/project/integrations/prometheus.md15
-rw-r--r--doc/user/project/integrations/prometheus_library/cloudwatch.md4
-rw-r--r--doc/user/project/integrations/prometheus_library/haproxy.md4
-rw-r--r--doc/user/project/integrations/prometheus_library/kubernetes.md2
-rw-r--r--doc/user/project/integrations/prometheus_library/nginx.md6
-rw-r--r--doc/user/project/integrations/prometheus_library/nginx_ingress.md6
-rw-r--r--doc/user/project/integrations/prometheus_library/nginx_ingress_vts.md6
-rw-r--r--doc/user/project/integrations/slack.md2
-rw-r--r--doc/user/project/integrations/slack_slash_commands.md2
-rw-r--r--doc/user/project/integrations/webhooks.md2
-rw-r--r--doc/user/project/issue_board.md18
-rw-r--r--doc/user/project/issues/automatic_issue_closing.md62
-rw-r--r--doc/user/project/issues/closing_issues.md62
-rw-r--r--doc/user/project/issues/create_new_issue.md107
-rw-r--r--doc/user/project/issues/crosslinking_issues.md23
-rw-r--r--doc/user/project/issues/csv_export.md2
-rw-r--r--doc/user/project/issues/csv_import.md55
-rw-r--r--doc/user/project/issues/deleting_issues.md16
-rw-r--r--doc/user/project/issues/due_dates.md29
-rw-r--r--doc/user/project/issues/index.md99
-rw-r--r--doc/user/project/issues/issue_data_and_actions.md29
-rw-r--r--doc/user/project/issues/managing_issues.md225
-rw-r--r--doc/user/project/issues/moving_issues.md38
-rw-r--r--doc/user/project/issues/multiple_assignees_for_issues.md2
-rw-r--r--doc/user/project/issues/related_issues.md2
-rw-r--r--doc/user/project/issues/similar_issues.md19
-rw-r--r--doc/user/project/labels.md10
-rw-r--r--doc/user/project/merge_requests/browser_performance_testing.md4
-rw-r--r--doc/user/project/merge_requests/code_quality.md2
-rw-r--r--doc/user/project/merge_requests/index.md40
-rw-r--r--doc/user/project/merge_requests/merge_request_approvals.md12
-rw-r--r--doc/user/project/merge_requests/squash_and_merge.md5
-rw-r--r--doc/user/project/merge_requests/work_in_progress_merge_requests.md4
-rw-r--r--doc/user/project/milestones/burndown_charts.md2
-rw-r--r--doc/user/project/milestones/index.md10
-rw-r--r--doc/user/project/new_ci_build_permissions_model.md2
-rw-r--r--doc/user/project/operations/feature_flags.md2
-rw-r--r--doc/user/project/operations/index.md4
-rw-r--r--doc/user/project/operations/tracing.md10
-rw-r--r--doc/user/project/packages/maven_repository.md4
-rw-r--r--doc/user/project/packages/npm_registry.md19
-rw-r--r--doc/user/project/pages/getting_started_part_four.md2
-rw-r--r--doc/user/project/pages/index.md2
-rw-r--r--doc/user/project/pages/introduction.md2
-rw-r--r--doc/user/project/pipelines/job_artifacts.md10
-rw-r--r--doc/user/project/protected_branches.md2
-rw-r--r--doc/user/project/quick_actions.md30
-rw-r--r--doc/user/project/repository/branches/index.md2
-rw-r--r--doc/user/project/repository/gpg_signed_commits/index.md2
-rw-r--r--doc/user/project/repository/index.md15
-rw-r--r--doc/user/project/repository/web_editor.md3
-rw-r--r--doc/user/project/service_desk.md2
-rw-r--r--doc/user/project/settings/import_export.md7
-rw-r--r--doc/user/project/settings/index.md12
-rw-r--r--doc/user/project/web_ide/index.md4
-rw-r--r--doc/user/search/advanced_global_search.md2
-rw-r--r--doc/user/search/advanced_search_syntax.md2
-rw-r--r--doc/user/search/index.md10
-rw-r--r--doc/workflow/README.md14
-rw-r--r--doc/workflow/gitlab_flow.md37
-rw-r--r--doc/workflow/img/ci_mr.png (renamed from doc/workflow/ci_mr.png)bin12024 -> 12024 bytes
-rw-r--r--doc/workflow/img/close_issue_mr.png (renamed from doc/workflow/close_issue_mr.png)bin42108 -> 42108 bytes
-rw-r--r--doc/workflow/img/environment_branches.png (renamed from doc/workflow/environment_branches.png)bin12354 -> 12354 bytes
-rw-r--r--doc/workflow/img/four_stages.png (renamed from doc/workflow/four_stages.png)bin7124 -> 7124 bytes
-rw-r--r--doc/workflow/img/git_pull.png (renamed from doc/workflow/git_pull.png)bin28701 -> 28701 bytes
-rw-r--r--doc/workflow/img/gitdashflow.png (renamed from doc/workflow/gitdashflow.png)bin68177 -> 68177 bytes
-rw-r--r--doc/workflow/img/github_flow.png (renamed from doc/workflow/github_flow.png)bin6173 -> 6173 bytes
-rw-r--r--doc/workflow/img/gitlab_flow.png (renamed from doc/workflow/gitlab_flow.png)bin47430 -> 47430 bytes
-rw-r--r--doc/workflow/img/good_commit.png (renamed from doc/workflow/good_commit.png)bin8740 -> 8740 bytes
-rw-r--r--doc/workflow/img/merge_commits.png (renamed from doc/workflow/merge_commits.png)bin7564 -> 7564 bytes
-rw-r--r--doc/workflow/img/merge_request.png (renamed from doc/workflow/merge_request.png)bin47225 -> 47225 bytes
-rw-r--r--doc/workflow/img/messy_flow.png (renamed from doc/workflow/messy_flow.png)bin11663 -> 11663 bytes
-rw-r--r--doc/workflow/img/mr_inline_comments.png (renamed from doc/workflow/mr_inline_comments.png)bin52503 -> 52503 bytes
-rw-r--r--doc/workflow/img/production_branch.png (renamed from doc/workflow/production_branch.png)bin7262 -> 7262 bytes
-rw-r--r--doc/workflow/img/rebase.png (renamed from doc/workflow/rebase.png)bin28939 -> 28939 bytes
-rw-r--r--doc/workflow/img/release_branches.png (renamed from doc/workflow/release_branches.png)bin12736 -> 12736 bytes
-rw-r--r--doc/workflow/img/remove_checkbox.png (renamed from doc/workflow/remove_checkbox.png)bin6904 -> 6904 bytes
-rw-r--r--doc/workflow/issue_weight.md2
-rw-r--r--doc/workflow/lfs/lfs_administration.md2
-rw-r--r--doc/workflow/notifications.md36
-rw-r--r--doc/workflow/repository_mirroring.md30
-rw-r--r--doc/workflow/shortcuts.md2
-rw-r--r--doc/workflow/timezone.md8
-rw-r--r--doc/workflow/todos.md140
-rw-r--r--lib/api/api.rb6
-rw-r--r--lib/api/entities.rb12
-rw-r--r--lib/api/helpers/graphql_helpers.rb2
-rw-r--r--lib/api/issues.rb6
-rw-r--r--lib/api/merge_requests.rb5
-rw-r--r--lib/api/projects.rb2
-rw-r--r--lib/api/releases.rb2
-rw-r--r--lib/api/runners.rb2
-rw-r--r--lib/api/settings.rb2
-rw-r--r--lib/api/todos.rb2
-rw-r--r--lib/api/user_counts.rb18
-rw-r--r--lib/banzai/filter/relative_link_filter.rb8
-rw-r--r--lib/banzai/filter/syntax_highlight_filter.rb2
-rw-r--r--lib/banzai/pipeline/ascii_doc_pipeline.rb1
-rw-r--r--lib/feature.rb27
-rw-r--r--lib/feature/gitaly.rb7
-rw-r--r--lib/gitlab/asciidoc.rb3
-rw-r--r--lib/gitlab/asciidoc/syntax_highlighter/html_pipeline_adapter.rb15
-rw-r--r--lib/gitlab/background_migration/create_fork_network_memberships_range.rb85
-rw-r--r--lib/gitlab/background_migration/delete_conflicting_redirect_routes_range.rb13
-rw-r--r--lib/gitlab/background_migration/migrate_events_to_push_event_payloads.rb179
-rw-r--r--lib/gitlab/background_migration/migrate_system_uploads_to_new_folder.rb29
-rw-r--r--lib/gitlab/background_migration/move_personal_snippet_files.rb82
-rw-r--r--lib/gitlab/background_migration/normalize_ldap_extern_uids_range.rb319
-rw-r--r--lib/gitlab/background_migration/populate_fork_networks_range.rb128
-rw-r--r--lib/gitlab/background_migration/populate_merge_requests_latest_merge_request_diff_id.rb33
-rw-r--r--lib/gitlab/ci/config.rb5
-rw-r--r--lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml20
-rw-r--r--lib/gitlab/ci/templates/Jobs/Deploy.gitlab-ci.yml1
-rw-r--r--lib/gitlab/ci/templates/PHP.gitlab-ci.yml2
-rw-r--r--lib/gitlab/ci/templates/Pages/Jekyll.gitlab-ci.yml1
-rw-r--r--lib/gitlab/ci/templates/Security/SAST.gitlab-ci.yml1
-rw-r--r--lib/gitlab/cluster/lifecycle_events.rb3
-rw-r--r--lib/gitlab/config/loader/yaml.rb34
-rw-r--r--lib/gitlab/danger/helper.rb6
-rw-r--r--lib/gitlab/database/median.rb2
-rw-r--r--lib/gitlab/diff/lines_unfolder.rb2
-rw-r--r--lib/gitlab/diff/position.rb4
-rw-r--r--lib/gitlab/diff/position_tracer.rb192
-rw-r--r--lib/gitlab/diff/position_tracer/base_strategy.rb26
-rw-r--r--lib/gitlab/diff/position_tracer/image_strategy.rb50
-rw-r--r--lib/gitlab/diff/position_tracer/line_strategy.rb201
-rw-r--r--lib/gitlab/git/repository.rb4
-rw-r--r--lib/gitlab/git/rugged_impl/blob.rb3
-rw-r--r--lib/gitlab/git/rugged_impl/commit.rb8
-rw-r--r--lib/gitlab/git/rugged_impl/repository.rb3
-rw-r--r--lib/gitlab/git/rugged_impl/tree.rb3
-rw-r--r--lib/gitlab/git/rugged_impl/use_rugged.rb16
-rw-r--r--lib/gitlab/gitaly_client.rb49
-rw-r--r--lib/gitlab/gitaly_client/operation_service.rb5
-rw-r--r--lib/gitlab/gon_helper.rb5
-rw-r--r--lib/gitlab/graphql.rb4
-rw-r--r--lib/gitlab/graphql/authorize.rb2
-rw-r--r--lib/gitlab/graphql/authorize/authorize_field_service.rb2
-rw-r--r--lib/gitlab/graphql/calls_gitaly.rb15
-rw-r--r--lib/gitlab/graphql/calls_gitaly/instrumentation.rb40
-rw-r--r--lib/gitlab/graphql/find_argument_in_parent.rb32
-rw-r--r--lib/gitlab/graphql/mount_mutation.rb5
-rw-r--r--lib/gitlab/http.rb6
-rw-r--r--lib/gitlab/import_export/import_export.yml1
-rw-r--r--lib/gitlab/issuable_metadata.rb4
-rw-r--r--lib/gitlab/legacy_github_import/release_formatter.rb1
-rw-r--r--lib/gitlab/metrics/samplers/ruby_sampler.rb7
-rw-r--r--lib/gitlab/metrics/system.rb12
-rw-r--r--lib/gitlab/namespaced_session_store.rb15
-rw-r--r--lib/gitlab/performance_bar.rb28
-rw-r--r--lib/gitlab/performance_bar/redis_adapter_when_peek_enabled.rb12
-rw-r--r--lib/gitlab/quick_actions/issuable_actions.rb4
-rw-r--r--lib/gitlab/search/found_blob.rb2
-rw-r--r--lib/gitlab/sidekiq_status.rb6
-rw-r--r--lib/gitlab/sql/pattern.rb24
-rw-r--r--lib/gitlab/thread_memory_cache.rb15
-rw-r--r--lib/gitlab/user_extractor.rb56
-rw-r--r--lib/gitlab/utils/deep_size.rb79
-rw-r--r--lib/peek/views/redis.rb86
-rw-r--r--lib/tasks/migrate/setup_postgresql.rake14
-rw-r--r--lib/tasks/yarn.rake2
-rw-r--r--locale/gitlab.pot466
-rw-r--r--package.json5
-rw-r--r--qa/.rspec_parallel5
-rw-r--r--qa/Gemfile2
-rw-r--r--qa/Gemfile.lock6
-rw-r--r--qa/qa.rb6
-rw-r--r--qa/qa/page/component/confirm_modal.rb25
-rw-r--r--qa/qa/page/component/select2.rb4
-rw-r--r--qa/qa/page/file/edit.rb13
-rw-r--r--qa/qa/page/file/form.rb27
-rw-r--r--qa/qa/page/file/shared/commit_button.rb21
-rw-r--r--qa/qa/page/file/shared/editor.rb33
-rw-r--r--qa/qa/page/file/show.rb2
-rw-r--r--qa/qa/page/project/operations/kubernetes/show.rb8
-rw-r--r--qa/qa/page/project/settings/advanced.rb16
-rw-r--r--qa/qa/page/project/settings/main.rb2
-rw-r--r--qa/qa/page/project/show.rb1
-rw-r--r--qa/qa/page/project/sub_menus/ci_cd.rb2
-rw-r--r--qa/qa/page/project/sub_menus/issues.rb2
-rw-r--r--qa/qa/page/project/sub_menus/operations.rb2
-rw-r--r--qa/qa/page/project/sub_menus/project.rb29
-rw-r--r--qa/qa/page/project/sub_menus/repository.rb2
-rw-r--r--qa/qa/page/project/sub_menus/settings.rb11
-rw-r--r--qa/qa/resource/group.rb4
-rw-r--r--qa/qa/resource/issue.rb6
-rw-r--r--qa/qa/resource/kubernetes_cluster.rb2
-rw-r--r--qa/qa/runtime/browser.rb6
-rw-r--r--qa/qa/runtime/env.rb8
-rw-r--r--qa/qa/runtime/scenario.rb6
-rw-r--r--qa/qa/scenario/shared_attributes.rb1
-rw-r--r--qa/qa/service/shellout.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/1_manage/group/transfer_project_spec.rb57
-rw-r--r--qa/qa/specs/features/browser_ui/2_plan/issue/check_mentions_for_xss_spec.rb44
-rw-r--r--qa/qa/specs/features/browser_ui/2_plan/issue/collapse_comments_in_discussions_spec.rb24
-rw-r--r--qa/qa/specs/features/browser_ui/2_plan/issue/filter_issue_comments_spec.rb21
-rw-r--r--qa/qa/specs/features/browser_ui/2_plan/issue/issue_suggestions_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/merge_request/view_merge_request_diff_patch_spec.rb3
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/repository/push_mirroring_over_http_spec.rb3
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/repository/push_over_http_file_size_spec.rb3
-rw-r--r--qa/qa/specs/features/browser_ui/7_configure/auto_devops/create_project_with_auto_devops_spec.rb55
-rw-r--r--qa/qa/specs/parallel_runner.rb33
-rw-r--r--qa/qa/specs/runner.rb58
-rw-r--r--qa/qa/tools/generate_perf_testdata.rb65
-rw-r--r--qa/spec/page/logging_spec.rb8
-rw-r--r--qa/spec/spec_helper.rb4
-rw-r--r--qa/spec/specs/parallel_runner_spec.rb58
-rw-r--r--qa/spec/specs/runner_spec.rb8
-rw-r--r--rubocop/cop/graphql/authorize_types.rb61
-rw-r--r--rubocop/rubocop.rb1
-rwxr-xr-xscripts/generate-memory-metrics-on-boot11
-rw-r--r--scripts/prepare_build.sh10
-rwxr-xr-xscripts/review_apps/review-apps.sh128
-rwxr-xr-xscripts/trigger-build-docs4
-rw-r--r--spec/controllers/dashboard/projects_controller_spec.rb18
-rw-r--r--spec/controllers/groups_controller_spec.rb7
-rw-r--r--spec/controllers/projects/branches_controller_spec.rb71
-rw-r--r--spec/controllers/projects/deployments_controller_spec.rb74
-rw-r--r--spec/controllers/projects/issues_controller_spec.rb44
-rw-r--r--spec/controllers/projects/merge_requests_controller_spec.rb16
-rw-r--r--spec/controllers/projects/notes_controller_spec.rb2
-rw-r--r--spec/controllers/projects/settings/repository_controller_spec.rb20
-rw-r--r--spec/controllers/projects/templates_controller_spec.rb110
-rw-r--r--spec/controllers/projects_controller_spec.rb47
-rw-r--r--spec/controllers/snippets/notes_controller_spec.rb113
-rw-r--r--spec/controllers/snippets_controller_spec.rb4
-rw-r--r--spec/controllers/uploads_controller_spec.rb177
-rw-r--r--spec/factories/clusters/clusters.rb2
-rw-r--r--spec/factories/project_statistics.rb15
-rw-r--r--spec/factories/releases.rb1
-rw-r--r--spec/factories/services.rb34
-rw-r--r--spec/features/admin/admin_sees_project_statistics_spec.rb2
-rw-r--r--spec/features/admin/admin_settings_spec.rb70
-rw-r--r--spec/features/container_registry_spec.rb2
-rw-r--r--spec/features/dashboard/shortcuts_spec.rb2
-rw-r--r--spec/features/dashboard/todos/todos_spec.rb14
-rw-r--r--spec/features/discussion_comments/commit_spec.rb4
-rw-r--r--spec/features/discussion_comments/issue_spec.rb4
-rw-r--r--spec/features/discussion_comments/merge_request_spec.rb4
-rw-r--r--spec/features/discussion_comments/snippets_spec.rb4
-rw-r--r--spec/features/groups/issues_spec.rb19
-rw-r--r--spec/features/issues/create_issue_for_discussions_in_merge_request_spec.rb32
-rw-r--r--spec/features/issues/create_issue_for_single_discussion_in_merge_request_spec.rb24
-rw-r--r--spec/features/issues/todo_spec.rb8
-rw-r--r--spec/features/issues/user_creates_confidential_merge_request_spec.rb54
-rw-r--r--spec/features/merge_request/user_comments_on_merge_request_spec.rb2
-rw-r--r--spec/features/merge_request/user_resolves_diff_notes_and_discussions_resolve_spec.rb174
-rw-r--r--spec/features/merge_request/user_sees_discussions_spec.rb8
-rw-r--r--spec/features/merge_request/user_sees_merge_button_depending_on_unresolved_discussions_spec.rb12
-rw-r--r--spec/features/merge_request/user_sees_merge_widget_spec.rb62
-rw-r--r--spec/features/merge_request/user_suggests_changes_on_diff_spec.rb4
-rw-r--r--spec/features/oauth_login_spec.rb12
-rw-r--r--spec/features/projects/clusters/applications_spec.rb23
-rw-r--r--spec/features/projects/releases/user_views_releases_spec.rb12
-rw-r--r--spec/features/projects/settings/repository_settings_spec.rb6
-rw-r--r--spec/features/search/user_uses_header_search_field_spec.rb124
-rw-r--r--spec/features/snippets/user_creates_snippet_spec.rb2
-rw-r--r--spec/features/users/terms_spec.rb15
-rw-r--r--spec/finders/releases_finder_spec.rb6
-rw-r--r--spec/finders/runner_jobs_finder_spec.rb22
-rw-r--r--spec/fixtures/api/schemas/public_api/v4/release.json4
-rw-r--r--spec/fixtures/api/schemas/public_api/v4/release/release_for_guest.json4
-rw-r--r--spec/frontend/api_spec.js16
-rw-r--r--spec/frontend/boards/services/board_service_spec.js4
-rw-r--r--spec/frontend/branches/divergence_graph_spec.js40
-rw-r--r--spec/frontend/commons/nav/user_merge_requests_spec.js113
-rw-r--r--spec/frontend/confidential_merge_request/components/__snapshots__/project_form_group_spec.js.snap67
-rw-r--r--spec/frontend/confidential_merge_request/components/dropdown_spec.js56
-rw-r--r--spec/frontend/confidential_merge_request/components/project_form_group_spec.js77
-rw-r--r--spec/frontend/create_merge_request_dropdown_spec.js69
-rw-r--r--spec/frontend/diffs/components/diff_discussion_reply_spec.js90
-rw-r--r--spec/frontend/diffs/components/diff_gutter_avatars_spec.js113
-rw-r--r--spec/frontend/diffs/mock_data/diff_discussions.js529
-rw-r--r--spec/frontend/error_tracking_settings/components/app_spec.js63
-rw-r--r--spec/frontend/error_tracking_settings/components/error_tracking_form_spec.js (renamed from spec/javascripts/error_tracking_settings/components/error_tracking_form_spec.js)0
-rw-r--r--spec/frontend/error_tracking_settings/components/project_dropdown_spec.js (renamed from spec/javascripts/error_tracking_settings/components/project_dropdown_spec.js)0
-rw-r--r--spec/frontend/error_tracking_settings/mock.js92
-rw-r--r--spec/frontend/error_tracking_settings/store/actions_spec.js194
-rw-r--r--spec/frontend/error_tracking_settings/store/getters_spec.js (renamed from spec/javascripts/error_tracking_settings/store/getters_spec.js)0
-rw-r--r--spec/frontend/error_tracking_settings/store/mutation_spec.js82
-rw-r--r--spec/frontend/error_tracking_settings/utils_spec.js (renamed from spec/javascripts/error_tracking_settings/utils_spec.js)0
-rw-r--r--spec/frontend/ide/lib/files_spec.js4
-rw-r--r--spec/frontend/lib/utils/text_utility_spec.js19
-rw-r--r--spec/frontend/monitoring/__snapshots__/dashboard_state_spec.js.snap37
-rw-r--r--spec/frontend/monitoring/dashboard_state_spec.js43
-rw-r--r--spec/frontend/notes/components/discussion_notes_replies_wrapper_spec.js51
-rw-r--r--spec/frontend/notes/components/discussion_notes_spec.js2
-rw-r--r--spec/frontend/notes/components/discussion_reply_placeholder_spec.js14
-rw-r--r--spec/frontend/vue_shared/components/markdown/header_spec.js107
-rw-r--r--spec/graphql/gitlab_schema_spec.rb4
-rw-r--r--spec/graphql/types/base_field_spec.rb59
-rw-r--r--spec/graphql/types/label_type_spec.rb2
-rw-r--r--spec/graphql/types/metadata_type_spec.rb1
-rw-r--r--spec/graphql/types/namespace_type_spec.rb2
-rw-r--r--spec/graphql/types/query_type_spec.rb4
-rw-r--r--spec/helpers/markup_helper_spec.rb37
-rw-r--r--spec/helpers/onboarding_experiment_helper_spec.rb38
-rw-r--r--spec/helpers/preferences_helper_spec.rb2
-rw-r--r--spec/helpers/storage_helper_spec.rb2
-rw-r--r--spec/initializers/6_validations_spec.rb20
-rw-r--r--spec/javascripts/boards/mock_data.js5
-rw-r--r--spec/javascripts/collapsed_sidebar_todo_spec.js16
-rw-r--r--spec/javascripts/create_merge_request_dropdown_spec.js68
-rw-r--r--spec/javascripts/diffs/components/diff_file_header_spec.js6
-rw-r--r--spec/javascripts/diffs/components/diff_gutter_avatars_spec.js146
-rw-r--r--spec/javascripts/diffs/components/inline_diff_view_spec.js4
-rw-r--r--spec/javascripts/diffs/store/actions_spec.js1
-rw-r--r--spec/javascripts/environments/environment_terminal_button_spec.js40
-rw-r--r--spec/javascripts/error_tracking_settings/components/app_spec.js63
-rw-r--r--spec/javascripts/error_tracking_settings/mock.js92
-rw-r--r--spec/javascripts/error_tracking_settings/store/actions_spec.js191
-rw-r--r--spec/javascripts/error_tracking_settings/store/mutation_spec.js82
-rw-r--r--spec/javascripts/ide/components/repo_editor_spec.js40
-rw-r--r--spec/javascripts/ide/stores/actions_spec.js43
-rw-r--r--spec/javascripts/ide/stores/mutations/file_spec.js33
-rw-r--r--spec/javascripts/ide/stores/mutations_spec.js68
-rw-r--r--spec/javascripts/ide/stores/utils_spec.js26
-rw-r--r--spec/javascripts/issuable_spec.js12
-rw-r--r--spec/javascripts/monitoring/dashboard_state_spec.js101
-rw-r--r--spec/javascripts/monitoring/store/utils_spec.js37
-rw-r--r--spec/javascripts/notes/components/comment_form_spec.js15
-rw-r--r--spec/javascripts/notes/components/noteable_discussion_spec.js52
-rw-r--r--spec/javascripts/notes/stores/actions_spec.js24
-rw-r--r--spec/javascripts/performance_bar/components/simple_metric_spec.js47
-rw-r--r--spec/javascripts/pipelines/pipelines_spec.js8
-rw-r--r--spec/javascripts/registry/components/app_spec.js33
-rw-r--r--spec/javascripts/releases/components/release_block_spec.js12
-rw-r--r--spec/javascripts/sidebar/todo_spec.js8
-rw-r--r--spec/javascripts/test_bundle.js2
-rw-r--r--spec/javascripts/vue_mr_widget/components/states/mr_widget_ready_to_merge_spec.js3
-rw-r--r--spec/javascripts/vue_mr_widget/components/states/mr_widget_unresolved_discussions_spec.js8
-rw-r--r--spec/javascripts/vue_shared/components/file_row_spec.js13
-rw-r--r--spec/javascripts/vue_shared/components/markdown/header_spec.js111
-rw-r--r--spec/lib/banzai/filter/relative_link_filter_spec.rb5
-rw-r--r--spec/lib/feature_spec.rb64
-rw-r--r--spec/lib/gitlab/asciidoc_spec.rb68
-rw-r--r--spec/lib/gitlab/auth_spec.rb9
-rw-r--r--spec/lib/gitlab/background_migration/create_fork_network_memberships_range_spec.rb125
-rw-r--r--spec/lib/gitlab/background_migration/delete_conflicting_redirect_routes_range_spec.rb35
-rw-r--r--spec/lib/gitlab/background_migration/migrate_events_to_push_event_payloads_spec.rb433
-rw-r--r--spec/lib/gitlab/background_migration/migrate_stage_status_spec.rb92
-rw-r--r--spec/lib/gitlab/background_migration/migrate_system_uploads_to_new_folder_spec.rb21
-rw-r--r--spec/lib/gitlab/background_migration/move_personal_snippet_files_spec.rb74
-rw-r--r--spec/lib/gitlab/background_migration/normalize_ldap_extern_uids_range_spec.rb36
-rw-r--r--spec/lib/gitlab/background_migration/populate_fork_networks_range_spec.rb97
-rw-r--r--spec/lib/gitlab/background_migration/populate_merge_requests_latest_merge_request_diff_id_spec.rb62
-rw-r--r--spec/lib/gitlab/cache/ci/project_pipeline_status_spec.rb1
-rw-r--r--spec/lib/gitlab/ci/config_spec.rb21
-rw-r--r--spec/lib/gitlab/ci/reports/test_reports_comparer_spec.rb8
-rw-r--r--spec/lib/gitlab/ci/reports/test_suite_comparer_spec.rb23
-rw-r--r--spec/lib/gitlab/config/loader/yaml_spec.rb72
-rw-r--r--spec/lib/gitlab/cycle_analytics/test_stage_spec.rb34
-rw-r--r--spec/lib/gitlab/danger/helper_spec.rb21
-rw-r--r--spec/lib/gitlab/diff/lines_unfolder_spec.rb33
-rw-r--r--spec/lib/gitlab/diff/position_spec.rb13
-rw-r--r--spec/lib/gitlab/diff/position_tracer/image_strategy_spec.rb238
-rw-r--r--spec/lib/gitlab/diff/position_tracer/line_strategy_spec.rb1805
-rw-r--r--spec/lib/gitlab/diff/position_tracer_spec.rb1918
-rw-r--r--spec/lib/gitlab/git/commit_spec.rb2
-rw-r--r--spec/lib/gitlab/git/repository_spec.rb7
-rw-r--r--spec/lib/gitlab/git/rugged_impl/use_rugged_spec.rb97
-rw-r--r--spec/lib/gitlab/gitaly_client/operation_service_spec.rb4
-rw-r--r--spec/lib/gitlab/graphql/authorize/authorize_field_service_spec.rb82
-rw-r--r--spec/lib/gitlab/graphql/calls_gitaly/instrumentation_spec.rb23
-rw-r--r--spec/lib/gitlab/graphql/find_argument_in_parent_spec.rb44
-rw-r--r--spec/lib/gitlab/import_export/safe_model_attributes.yml2
-rw-r--r--spec/lib/gitlab/issuable_metadata_spec.rb8
-rw-r--r--spec/lib/gitlab/legacy_github_import/importer_spec.rb2
-rw-r--r--spec/lib/gitlab/legacy_github_import/release_formatter_spec.rb4
-rw-r--r--spec/lib/gitlab/metrics/samplers/ruby_sampler_spec.rb16
-rw-r--r--spec/lib/gitlab/metrics/system_spec.rb12
-rw-r--r--spec/lib/gitlab/namespaced_session_store_spec.rb30
-rw-r--r--spec/lib/gitlab/performance_bar_spec.rb27
-rw-r--r--spec/lib/gitlab/sql/pattern_spec.rb12
-rw-r--r--spec/lib/gitlab/user_extractor_spec.rb78
-rw-r--r--spec/lib/gitlab/utils/deep_size_spec.rb43
-rw-r--r--spec/lib/peek/views/redis_detailed_spec.rb36
-rw-r--r--spec/mailers/notify_spec.rb14
-rw-r--r--spec/migrations/add_foreign_key_to_merge_requests_spec.rb39
-rw-r--r--spec/migrations/add_head_pipeline_for_each_merge_request_spec.rb32
-rw-r--r--spec/migrations/backfill_and_add_not_null_constraint_to_released_at_column_on_releases_table_spec.rb28
-rw-r--r--spec/migrations/backfill_store_project_full_path_in_repo_spec.rb2
-rw-r--r--spec/migrations/calculate_conv_dev_index_percentages_spec.rb59
-rw-r--r--spec/migrations/clean_appearance_symlinks_spec.rb46
-rw-r--r--spec/migrations/clean_stage_id_reference_migration_spec.rb34
-rw-r--r--spec/migrations/clean_stages_statuses_migration_spec.rb51
-rw-r--r--spec/migrations/clean_upload_symlinks_spec.rb46
-rw-r--r--spec/migrations/cleanup_move_system_upload_folder_symlink_spec.rb35
-rw-r--r--spec/migrations/cleanup_nonexisting_namespace_pending_delete_projects_spec.rb29
-rw-r--r--spec/migrations/convert_custom_notification_settings_to_columns_spec.rb120
-rw-r--r--spec/migrations/delete_conflicting_redirect_routes_spec.rb42
-rw-r--r--spec/migrations/fix_wrongly_renamed_routes_spec.rb86
-rw-r--r--spec/migrations/issues_moved_to_id_foreign_key_spec.rb24
-rw-r--r--spec/migrations/migrate_build_stage_reference_again_spec.rb62
-rw-r--r--spec/migrations/migrate_gcp_clusters_to_new_clusters_architectures_spec.rb181
-rw-r--r--spec/migrations/migrate_issues_to_ghost_user_spec.rb51
-rw-r--r--spec/migrations/migrate_kubernetes_service_to_new_clusters_architectures_spec.rb312
-rw-r--r--spec/migrations/migrate_old_artifacts_spec.rb140
-rw-r--r--spec/migrations/migrate_pipeline_sidekiq_queues_spec.rb49
-rw-r--r--spec/migrations/migrate_pipeline_stages_spec.rb56
-rw-r--r--spec/migrations/migrate_process_commit_worker_jobs_spec.rb197
-rw-r--r--spec/migrations/migrate_stage_id_reference_in_background_spec.rb55
-rw-r--r--spec/migrations/migrate_stages_statuses_spec.rb68
-rw-r--r--spec/migrations/migrate_user_activities_to_users_last_activity_on_spec.rb49
-rw-r--r--spec/migrations/migrate_user_authentication_token_to_personal_access_token_spec.rb25
-rw-r--r--spec/migrations/migrate_user_project_view_spec.rb17
-rw-r--r--spec/migrations/move_personal_snippets_files_spec.rb197
-rw-r--r--spec/migrations/move_system_upload_folder_spec.rb80
-rw-r--r--spec/migrations/move_uploads_to_system_dir_spec.rb68
-rw-r--r--spec/migrations/normalize_ldap_extern_uids_spec.rb56
-rw-r--r--spec/migrations/populate_can_push_from_deploy_keys_projects_spec.rb43
-rw-r--r--spec/migrations/remove_assignee_id_from_issue_spec.rb37
-rw-r--r--spec/migrations/remove_dot_git_from_usernames_spec.rb58
-rw-r--r--spec/migrations/remove_duplicate_mr_events_spec.rb26
-rw-r--r--spec/migrations/remove_empty_fork_networks_spec.rb35
-rw-r--r--spec/migrations/remove_project_labels_group_id_spec.rb21
-rw-r--r--spec/migrations/rename_duplicated_variable_key_spec.rb34
-rw-r--r--spec/migrations/rename_more_reserved_project_names_spec.rb57
-rw-r--r--spec/migrations/rename_reserved_project_names_spec.rb61
-rw-r--r--spec/migrations/rename_users_with_renamed_namespace_spec.rb22
-rw-r--r--spec/migrations/schedule_merge_request_latest_merge_request_diff_id_migrations_spec.rb64
-rw-r--r--spec/migrations/track_untracked_uploads_spec.rb15
-rw-r--r--spec/migrations/turn_nested_groups_into_regular_groups_for_mysql_spec.rb70
-rw-r--r--spec/migrations/update_legacy_diff_notes_type_for_import_spec.rb22
-rw-r--r--spec/migrations/update_notes_type_for_import_spec.rb22
-rw-r--r--spec/migrations/update_retried_for_ci_build_spec.rb17
-rw-r--r--spec/migrations/update_upload_paths_to_system_spec.rb59
-rw-r--r--spec/models/ci/pipeline_spec.rb24
-rw-r--r--spec/models/clusters/applications/ingress_spec.rb16
-rw-r--r--spec/models/clusters/applications/jupyter_spec.rb2
-rw-r--r--spec/models/clusters/clusters_hierarchy_spec.rb73
-rw-r--r--spec/models/concerns/cacheable_attributes_spec.rb9
-rw-r--r--spec/models/concerns/deployment_platform_spec.rb18
-rw-r--r--spec/models/concerns/issuable_spec.rb10
-rw-r--r--spec/models/concerns/reactive_caching_spec.rb61
-rw-r--r--spec/models/deploy_token_spec.rb35
-rw-r--r--spec/models/deployment_metrics_spec.rb126
-rw-r--r--spec/models/deployment_spec.rb153
-rw-r--r--spec/models/environment_status_spec.rb3
-rw-r--r--spec/models/merge_request_spec.rb145
-rw-r--r--spec/models/namespace/aggregation_schedule_spec.rb102
-rw-r--r--spec/models/namespace/root_storage_statistics_spec.rb65
-rw-r--r--spec/models/namespace_spec.rb16
-rw-r--r--spec/models/project_services/bugzilla_service_spec.rb45
-rw-r--r--spec/models/project_services/custom_issue_tracker_service_spec.rb43
-rw-r--r--spec/models/project_services/drone_ci_service_spec.rb9
-rw-r--r--spec/models/project_services/gitlab_issue_tracker_service_spec.rb43
-rw-r--r--spec/models/project_services/jira_service_spec.rb138
-rw-r--r--spec/models/project_services/kubernetes_service_spec.rb229
-rw-r--r--spec/models/project_services/redmine_service_spec.rb43
-rw-r--r--spec/models/project_services/youtrack_service_spec.rb43
-rw-r--r--spec/models/project_statistics_spec.rb43
-rw-r--r--spec/models/release_spec.rb10
-rw-r--r--spec/models/repository_spec.rb5
-rw-r--r--spec/models/service_spec.rb9
-rw-r--r--spec/models/user_spec.rb4
-rw-r--r--spec/requests/api/graphql/namespace/projects_spec.rb4
-rw-r--r--spec/requests/api/graphql/project/repository_spec.rb24
-rw-r--r--spec/requests/api/graphql_spec.rb41
-rw-r--r--spec/requests/api/issues/get_group_issues_spec.rb30
-rw-r--r--spec/requests/api/issues/get_project_issues_spec.rb58
-rw-r--r--spec/requests/api/issues/issues_spec.rb31
-rw-r--r--spec/requests/api/merge_requests_spec.rb38
-rw-r--r--spec/requests/api/project_clusters_spec.rb61
-rw-r--r--spec/requests/api/projects_spec.rb2
-rw-r--r--spec/requests/api/releases_spec.rb81
-rw-r--r--spec/requests/api/runners_spec.rb44
-rw-r--r--spec/requests/api/user_counts_spec.rb40
-rw-r--r--spec/requests/rack_attack_global_spec.rb43
-rw-r--r--spec/routing/api_routing_spec.rb23
-rw-r--r--spec/routing/project_routing_spec.rb20
-rw-r--r--spec/routing/uploads_routing_spec.rb13
-rw-r--r--spec/rubocop/cop/graphql/authorize_types_spec.rb66
-rw-r--r--spec/serializers/environment_status_entity_spec.rb10
-rw-r--r--spec/serializers/test_case_entity_spec.rb2
-rw-r--r--spec/serializers/test_reports_comparer_entity_spec.rb8
-rw-r--r--spec/serializers/test_reports_comparer_serializer_spec.rb8
-rw-r--r--spec/serializers/test_suite_comparer_entity_spec.rb92
-rw-r--r--spec/services/auto_merge/base_service_spec.rb45
-rw-r--r--spec/services/auto_merge/merge_when_pipeline_succeeds_service_spec.rb16
-rw-r--r--spec/services/auto_merge_service_spec.rb25
-rw-r--r--spec/services/branches/diverging_commit_counts_service_spec.rb33
-rw-r--r--spec/services/deploy_tokens/create_service_spec.rb16
-rw-r--r--spec/services/issuable/bulk_update_service_spec.rb496
-rw-r--r--spec/services/issues/update_service_spec.rb16
-rw-r--r--spec/services/merge_requests/create_from_issue_service_spec.rb205
-rw-r--r--spec/services/merge_requests/merge_to_ref_service_spec.rb64
-rw-r--r--spec/services/merge_requests/rebase_service_spec.rb28
-rw-r--r--spec/services/namespaces/statistics_refresher_service_spec.rb58
-rw-r--r--spec/services/system_note_service_spec.rb76
-rw-r--r--spec/spec_helper.rb2
-rw-r--r--spec/support/features/discussion_comments_shared_example.rb40
-rw-r--r--spec/support/features/resolving_discussions_in_issues_shared_examples.rb2
-rw-r--r--spec/support/helpers/devise_helpers.rb12
-rw-r--r--spec/support/helpers/email_helpers.rb15
-rw-r--r--spec/support/helpers/fake_u2f_device.rb4
-rw-r--r--spec/support/helpers/git_http_helpers.rb4
-rw-r--r--spec/support/helpers/login_helpers.rb12
-rw-r--r--spec/support/helpers/position_tracer_helpers.rb93
-rw-r--r--spec/support/helpers/reactive_caching_helpers.rb2
-rw-r--r--spec/support/matchers/gitaly_matchers.rb2
-rw-r--r--spec/support/shared_examples/features/comments_on_merge_request_files_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/models/services_fields_shared_examples.rb31
-rw-r--r--spec/support/shared_examples/models/update_project_statistics_shared_examples.rb90
-rw-r--r--spec/support/shared_examples/requests/api/issues/merge_requests_count_shared_examples.rb37
-rw-r--r--spec/support/test_reports/test_reports_helper.rb34
-rw-r--r--spec/tasks/migrate/schema_check_rake_spec.rb12
-rw-r--r--spec/uploaders/file_mover_spec.rb132
-rw-r--r--spec/uploaders/file_uploader_spec.rb62
-rw-r--r--spec/validators/color_validator_spec.rb43
-rw-r--r--spec/workers/namespaces/prune_aggregation_schedules_worker_spec.rb35
-rw-r--r--spec/workers/namespaces/root_statistics_worker_spec.rb88
-rw-r--r--spec/workers/namespaces/schedule_aggregation_worker_spec.rb77
-rw-r--r--spec/workers/project_cache_worker_spec.rb14
-rw-r--r--tmp/prometheus_multiproc_dir/puma/.gitkeep0
-rw-r--r--tmp/prometheus_multiproc_dir/sidekiq/.gitkeep0
-rw-r--r--tmp/prometheus_multiproc_dir/unicorn/.gitkeep0
-rw-r--r--yarn.lock116
2133 files changed, 23294 insertions, 33939 deletions
diff --git a/.eslintrc.yml b/.eslintrc.yml
index 2b881d5f201..2612fd3371d 100644
--- a/.eslintrc.yml
+++ b/.eslintrc.yml
@@ -5,6 +5,7 @@ globals:
gl: false
gon: false
localStorage: false
+ IS_EE: false
plugins:
- import
- html
diff --git a/.gitlab/CODEOWNERS b/.gitlab/CODEOWNERS
index f65e62068d6..b865b212ac0 100644
--- a/.gitlab/CODEOWNERS
+++ b/.gitlab/CODEOWNERS
@@ -6,8 +6,8 @@
/doc/ @axil @marcia @eread @mikelewis
# Frontend maintainers should see everything in `app/assets/`
-app/assets/ @ClemMakesApps @fatihacet @filipa @iamphill @mikegreiling @timzallmann @kushalpandya
-*.scss @annabeldunstone @ClemMakesApps @fatihacet @filipa @iamphill @mikegreiling @timzallmann @kushalpandya
+app/assets/ @ClemMakesApps @fatihacet @filipa @iamphill @mikegreiling @timzallmann @kushalpandya @pslaughter
+*.scss @annabeldunstone @ClemMakesApps @fatihacet @filipa @iamphill @mikegreiling @timzallmann @kushalpandya @pslaughter
# Someone from the database team should review changes in `db/`
db/ @abrandl @NikolayS
diff --git a/.gitlab/ci/docs.gitlab-ci.yml b/.gitlab/ci/docs.gitlab-ci.yml
index 4747e51f776..5bc109f2b7f 100644
--- a/.gitlab/ci/docs.gitlab-ci.yml
+++ b/.gitlab/ci/docs.gitlab-ci.yml
@@ -12,7 +12,9 @@
# Trigger a manual docs build in gitlab-docs only on non docs-only branches.
# Useful to preview the docs changes live.
review-docs-deploy-manual:
- <<: *review-docs
+ extends:
+ - .review-docs
+ - .no-docs-and-no-qa
stage: build
script:
- gem install gitlab --no-document
@@ -21,9 +23,6 @@ review-docs-deploy-manual:
only:
- branches@gitlab-org/gitlab-ce
- branches@gitlab-org/gitlab-ee
- except:
- - /(^docs[\/-].*|.*-docs$)/
- - /(^qa[\/-].*|.*-qa$)/
# Always trigger a docs build in gitlab-docs only on docs-only branches.
# Useful to preview the docs changes live.
@@ -67,9 +66,7 @@ docs lint:
- mv doc/ /tmp/gitlab-docs/content/$DOCS_GITLAB_REPO_SUFFIX
- cd /tmp/gitlab-docs
# Lint Markdown
- # https://github.com/markdownlint/markdownlint/blob/master/docs/RULES.md
- - bundle exec mdl content/$DOCS_GITLAB_REPO_SUFFIX/**/*.md --rules \
- MD004,MD032
+ - bundle exec mdl content/$DOCS_GITLAB_REPO_SUFFIX -c $CI_PROJECT_DIR/.mdlrc
# Build HTML from Markdown
- bundle exec nanoc
# Check the internal links
diff --git a/.gitlab/ci/frontend.gitlab-ci.yml b/.gitlab/ci/frontend.gitlab-ci.yml
index cd6953a6ac2..45a6a177943 100644
--- a/.gitlab/ci/frontend.gitlab-ci.yml
+++ b/.gitlab/ci/frontend.gitlab-ci.yml
@@ -8,7 +8,7 @@
.use-pg: &use-pg
services:
- - name: postgres:9.6
+ - name: postgres:9.6.11
command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"]
- name: redis:alpine
@@ -32,7 +32,7 @@
DOCKER_HOST: tcp://docker:2375
script:
- node --version
- - retry yarn install --frozen-lockfile --production --cache-folder .yarn-cache
+ - retry yarn install --frozen-lockfile --production --cache-folder .yarn-cache --prefer-offline
- free -m
- retry bundle exec rake gitlab:assets:compile
- time scripts/build_assets_image
@@ -70,9 +70,10 @@ gitlab:assets:compile pull-cache:
cache:
policy: pull
except:
- - master@gitlab-org/gitlab-ce
- - master@gitlab-org/gitlab-ee
- - /(^docs[\/-].*|.*-docs$)/
+ refs:
+ - master@gitlab-org/gitlab-ce
+ - master@gitlab-org/gitlab-ee
+ - /(^docs[\/-].*|.*-docs$)/
.compile-assets-metadata:
extends: .dedicated-runner
@@ -81,7 +82,7 @@ gitlab:assets:compile pull-cache:
stage: prepare
script:
- node --version
- - retry yarn install --frozen-lockfile --cache-folder .yarn-cache
+ - retry yarn install --frozen-lockfile --cache-folder .yarn-cache --prefer-offline
- free -m
- retry bundle exec rake gitlab:assets:compile
- scripts/clean-old-cached-assets
@@ -107,9 +108,10 @@ compile-assets pull-cache:
cache:
policy: pull
except:
- - master@gitlab-org/gitlab-ce
- - master@gitlab-org/gitlab-ee
- - /(^docs[\/-].*|.*-docs$)/
+ refs:
+ - master@gitlab-org/gitlab-ce
+ - master@gitlab-org/gitlab-ee
+ - /(^docs[\/-].*|.*-docs$)/
gitlab:ui:visual:
extends: .dedicated-runner
@@ -166,8 +168,8 @@ karma:
paths:
- chrome_debug.log
- coverage-javascript/
- reports:
- junit: junit_karma.xml
+# reports:
+# junit: junit_karma.xml
jest:
extends: .dedicated-no-docs-and-no-qa-pull-cache-job
@@ -189,8 +191,8 @@ jest:
paths:
- coverage-frontend/
- junit_jest.xml
- reports:
- junit: junit_jest.xml
+# reports:
+# junit: junit_jest.xml
cache:
key: jest
paths:
@@ -229,7 +231,7 @@ qa:selectors:
before_script: []
script:
- date
- - yarn install --frozen-lockfile --cache-folder .yarn-cache
+ - yarn install --frozen-lockfile --cache-folder .yarn-cache --prefer-offline
- date
- yarn run webpack-prod
diff --git a/.gitlab/ci/global.gitlab-ci.yml b/.gitlab/ci/global.gitlab-ci.yml
index eb50f08c1a7..4da7f404767 100644
--- a/.gitlab/ci/global.gitlab-ci.yml
+++ b/.gitlab/ci/global.gitlab-ci.yml
@@ -30,7 +30,14 @@
.no-docs:
except:
- - /(^docs[\/-].*|.*-docs$)/
+ refs:
+ - /(^docs[\/-].*|.*-docs$)/
+
+.no-docs-and-no-qa:
+ except:
+ refs:
+ - /(^docs[\/-].*|.*-docs$)/
+ - /(^qa[\/-].*|.*-qa$)/
.dedicated-no-docs-pull-cache-job:
extends:
@@ -38,10 +45,9 @@
- .no-docs
.dedicated-no-docs-and-no-qa-pull-cache-job:
- extends: .dedicated-pull-cache-job
- except:
- - /(^docs[\/-].*|.*-docs$)/
- - /(^qa[\/-].*|.*-qa$)/
+ extends:
+ - .dedicated-pull-cache-job
+ - .no-docs-and-no-qa
# Jobs that do not need a DB
.dedicated-no-docs-no-db-pull-cache-job:
diff --git a/.gitlab/ci/memory.gitlab-ci.yml b/.gitlab/ci/memory.gitlab-ci.yml
index 2f3907a331a..ffe5dbdc31b 100644
--- a/.gitlab/ci/memory.gitlab-ci.yml
+++ b/.gitlab/ci/memory.gitlab-ci.yml
@@ -17,3 +17,26 @@ memory-static:
- tmp/memory_*.txt
reports:
metrics: tmp/memory_metrics.txt
+
+# Show memory usage caused by invoking require per gem.
+# Unlike `memory-static`, it hits the app with one request to ensure that any last minute require-s have been called.
+# The application is booted in `production` environment.
+# All tests are run without a webserver (directly using Rack::Mock by default).
+memory-on-boot:
+ extends: .rspec-metadata-pg-10
+ variables:
+ NODE_ENV: "production"
+ RAILS_ENV: "production"
+ SETUP_DB: "true"
+ SKIP_STORAGE_VALIDATION: "true"
+ # we override the max_old_space_size to prevent OOM errors
+ NODE_OPTIONS: --max_old_space_size=3584
+ script:
+ # Both bootsnap and derailed monkey-patch Kernel#require, which leads to circular dependency
+ - DISABLE_BOOTSNAP=true PATH_TO_HIT="/users/sign_in" CUT_OFF=0.3 bundle exec derailed exec perf:mem >> 'tmp/memory_on_boot.txt'
+ - scripts/generate-memory-metrics-on-boot tmp/memory_on_boot.txt >> 'tmp/memory_on_boot_metrics.txt'
+ artifacts:
+ paths:
+ - tmp/memory_*.txt
+ reports:
+ metrics: tmp/memory_on_boot_metrics.txt
diff --git a/.gitlab/ci/rails.gitlab-ci.yml b/.gitlab/ci/rails.gitlab-ci.yml
index 9dcc9479cca..2d06a8acc58 100644
--- a/.gitlab/ci/rails.gitlab-ci.yml
+++ b/.gitlab/ci/rails.gitlab-ci.yml
@@ -1,6 +1,6 @@
.use-pg: &use-pg
services:
- - name: postgres:9.6
+ - name: postgres:9.6.11
command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"]
- name: redis:alpine
@@ -20,8 +20,9 @@
- master@gitlab/gitlab-ee
.gitlab-setup: &gitlab-setup
- extends: .dedicated-no-docs-and-no-qa-pull-cache-job
- <<: *use-pg
+ extends:
+ - .dedicated-no-docs-and-no-qa-pull-cache-job
+ - .use-pg
variables:
SETUP_DB: "false"
script:
@@ -43,7 +44,9 @@
- bundle exec rake $CI_JOB_NAME
.rspec-metadata: &rspec-metadata
- extends: .dedicated-pull-cache-job
+ extends:
+ - .dedicated-pull-cache-job
+ - .no-docs-and-no-qa
stage: test
script:
- JOB_NAME=( $CI_JOB_NAME )
@@ -74,11 +77,8 @@
- rspec_flaky/
- rspec_profiling/
- tmp/capybara/
- reports:
- junit: junit_rspec.xml
- except:
- - /(^docs[\/-].*|.*-docs$)/
- - /(^qa[\/-].*|.*-qa$)/
+# reports:
+# junit: junit_rspec.xml
.rspec-metadata-pg: &rspec-metadata-pg
<<: *rspec-metadata
@@ -122,8 +122,10 @@
- setup-test-env
setup-test-env:
- extends: .dedicated-runner-default-cache
- <<: *use-pg
+ extends:
+ - .dedicated-runner-default-cache
+ - .no-docs
+ - .use-pg
stage: prepare
script:
- bundle exec ruby -Ispec -e 'require "spec_helper" ; TestEnv.init'
@@ -134,12 +136,10 @@ setup-test-env:
- tmp/tests
- config/secrets.yml
- vendor/gitaly-ruby
- except:
- - /(^docs[\/-].*|.*-docs$)/
rspec unit pg:
<<: *rspec-metadata-pg
- parallel: 25
+ parallel: 20
rspec integration pg:
<<: *rspec-metadata-pg
@@ -152,7 +152,7 @@ rspec system pg:
rspec unit pg-10:
<<: *rspec-metadata-pg-10
<<: *only-schedules-master
- parallel: 25
+ parallel: 20
rspec integration pg-10:
<<: *rspec-metadata-pg-10
@@ -200,11 +200,12 @@ static-analysis:
downtime_check:
<<: *rake-exec
except:
- - master
- - tags
- - /^[\d-]+-stable(-ee)?$/
- - /(^docs[\/-].*|.*-docs$)/
- - /(^qa[\/-].*|.*-qa$)/
+ refs:
+ - master
+ - tags
+ - /^[\d-]+-stable(-ee)?$/
+ - /(^docs[\/-].*|.*-docs$)/
+ - /(^qa[\/-].*|.*-qa$)/
dependencies:
- setup-test-env
@@ -212,12 +213,13 @@ ee_compat_check:
<<: *rake-exec
dependencies: []
except:
- - master
- - tags
- - /[\d-]+-stable(-ee)?/
- - /^security-/
- - branches@gitlab-org/gitlab-ee
- - branches@gitlab/gitlab-ee
+ refs:
+ - master
+ - tags
+ - /[\d-]+-stable(-ee)?/
+ - /^security-/
+ - branches@gitlab-org/gitlab-ee
+ - branches@gitlab/gitlab-ee
retry: 0
artifacts:
name: "${CI_JOB_NAME}_${CI_COMIT_REF_NAME}_${CI_COMMIT_SHA}"
@@ -243,7 +245,7 @@ migration:path-pg:
.db-rollback: &db-rollback
extends: .dedicated-no-docs-and-no-qa-pull-cache-job
script:
- - bundle exec rake db:migrate VERSION=20170523121229
+ - bundle exec rake db:migrate VERSION=20180101160629
- bundle exec rake db:migrate SKIP_SCHEMA_VERSION_CHECK=true
dependencies:
- setup-test-env
@@ -261,7 +263,9 @@ gitlab:setup-pg:
coverage:
# Don't include dedicated-no-docs-no-db-pull-cache-job here since we need to
# download artifacts from all the rspec jobs instead of from setup-test-env only
- extends: .dedicated-runner-default-cache
+ extends:
+ - .dedicated-runner-default-cache
+ - .no-docs-and-no-qa
cache:
policy: pull
variables:
@@ -276,6 +280,3 @@ coverage:
paths:
- coverage/index.html
- coverage/assets/
- except:
- - /(^docs[\/-].*|.*-docs$)/
- - /(^qa[\/-].*|.*-qa$)/
diff --git a/.gitlab/ci/review.gitlab-ci.yml b/.gitlab/ci/review.gitlab-ci.yml
index 933af90c85a..ce019de213b 100644
--- a/.gitlab/ci/review.gitlab-ci.yml
+++ b/.gitlab/ci/review.gitlab-ci.yml
@@ -77,7 +77,7 @@ schedule:review-build-cng:
.review-deploy-base: &review-deploy-base
<<: *review-base
allow_failure: true
- retry: 2
+ retry: 1
stage: review
variables:
HOST_SUFFIX: "${CI_ENVIRONMENT_SLUG}"
@@ -236,5 +236,5 @@ danger-review:
script:
- git version
- node --version
- - yarn install --frozen-lockfile --cache-folder .yarn-cache
+ - yarn install --frozen-lockfile --cache-folder .yarn-cache --prefer-offline
- danger --fail-on-errors=true
diff --git a/.gitlab/ci/setup.gitlab-ci.yml b/.gitlab/ci/setup.gitlab-ci.yml
index debc90a1cb0..c1fc3a893ca 100644
--- a/.gitlab/ci/setup.gitlab-ci.yml
+++ b/.gitlab/ci/setup.gitlab-ci.yml
@@ -15,7 +15,9 @@ cache gems:
- setup-test-env
gitlab_git_test:
- extends: .dedicated-runner
+ extends:
+ - .dedicated-runner
+ - .no-docs-and-no-qa
variables:
SETUP_DB: "false"
before_script: []
@@ -23,12 +25,11 @@ gitlab_git_test:
cache: {}
script:
- spec/support/prepare-gitlab-git-test-for-commit --check-for-changes
- except:
- - /(^docs[\/-].*|.*-docs$)/
- - /(^qa[\/-].*|.*-qa$)/
no_ee_check:
- extends: .dedicated-runner
+ extends:
+ - .dedicated-runner
+ - .no-docs-and-no-qa
variables:
SETUP_DB: "false"
before_script: []
@@ -38,6 +39,3 @@ no_ee_check:
- scripts/no-ee-check
only:
- /.+/@gitlab-org/gitlab-ce
- except:
- - /(^docs[\/-].*|.*-docs$)/
- - /(^qa[\/-].*|.*-qa$)/
diff --git a/.gitlab/ci/test-metadata.gitlab-ci.yml b/.gitlab/ci/test-metadata.gitlab-ci.yml
index c51f825f831..2454ea85652 100644
--- a/.gitlab/ci/test-metadata.gitlab-ci.yml
+++ b/.gitlab/ci/test-metadata.gitlab-ci.yml
@@ -12,7 +12,9 @@
- rspec_profiling/
retrieve-tests-metadata:
- <<: *tests-metadata-state
+ extends:
+ - .tests-metadata-state
+ - .no-docs-and-no-qa
stage: prepare
cache:
key: tests_metadata
@@ -25,9 +27,6 @@ retrieve-tests-metadata:
- mkdir -p rspec_profiling/
- wget -O $FLAKY_RSPEC_SUITE_REPORT_PATH http://${TESTS_METADATA_S3_BUCKET}.s3.amazonaws.com/$FLAKY_RSPEC_SUITE_REPORT_PATH || rm $FLAKY_RSPEC_SUITE_REPORT_PATH
- '[[ -f $FLAKY_RSPEC_SUITE_REPORT_PATH ]] || echo "{}" > ${FLAKY_RSPEC_SUITE_REPORT_PATH}'
- except:
- - /(^docs[\/-].*|.*-docs$)/
- - /(^qa[\/-].*|.*-qa$)/
update-tests-metadata:
<<: *tests-metadata-state
@@ -69,9 +68,10 @@ flaky-examples-check:
only:
- branches
except:
- - master
- - /(^docs[\/-].*|.*-docs$)/
- - /(^qa[\/-].*|.*-qa$)/
+ refs:
+ - master
+ - /(^docs[\/-].*|.*-docs$)/
+ - /(^qa[\/-].*|.*-qa$)/
artifacts:
expire_in: 30d
paths:
diff --git a/.mdlrc b/.mdlrc
new file mode 100644
index 00000000000..b2127dadc22
--- /dev/null
+++ b/.mdlrc
@@ -0,0 +1,4 @@
+# See https://github.com/markdownlint/markdownlint/blob/master/docs/configuration.md
+
+ignore_front_matter true
+style File.expand_path('.mdlrc.style', __dir__)
diff --git a/.mdlrc.style b/.mdlrc.style
new file mode 100644
index 00000000000..30abf03f462
--- /dev/null
+++ b/.mdlrc.style
@@ -0,0 +1,7 @@
+# See https://github.com/markdownlint/markdownlint/blob/master/docs/RULES.md
+
+rule 'MD001'
+# False positives, see https://github.com/markdownlint/markdownlint/issues/261
+# rule 'MD004', style: :dash
+rule 'MD032'
+rule 'MD034'
diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml
index 698570efb07..41714eefa97 100644
--- a/.rubocop_todo.yml
+++ b/.rubocop_todo.yml
@@ -466,12 +466,10 @@ Rails/LinkToBlank:
Rails/Presence:
Exclude:
- 'app/models/ci/pipeline.rb'
- - 'app/models/clusters/platforms/kubernetes.rb'
- 'app/models/concerns/mentionable.rb'
- 'app/models/project_services/hipchat_service.rb'
- 'app/models/project_services/irker_service.rb'
- 'app/models/project_services/jira_service.rb'
- - 'app/models/project_services/kubernetes_service.rb'
- 'app/models/project_services/packagist_service.rb'
- 'app/models/wiki_page.rb'
- 'lib/gitlab/github_import/importer/releases_importer.rb'
@@ -514,7 +512,6 @@ Security/YAMLLoad:
- 'spec/config/mail_room_spec.rb'
- 'spec/initializers/secret_token_spec.rb'
- 'spec/lib/gitlab/prometheus/additional_metrics_parser_spec.rb'
- - 'spec/models/project_services/kubernetes_service_spec.rb'
# Offense count: 34
# Configuration parameters: EnforcedStyle.
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8d4509e370d..0b73585722f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,23 @@
documentation](doc/development/changelog.md) for instructions on adding your own
entry.
+## 12.0.3 (2019-06-27)
+
+- No changes.
+### Security (10 changes)
+
+- Persist tmp snippet uploads at users.
+- Gate MR head_pipeline behind read_pipeline ability.
+- Fix DoS vulnerability in color validation regex.
+- Expose merge requests count based on user access.
+- Fix Denial of Service for comments when rendering issues/MR comments.
+- Add missing authorizations in GraphQL.
+- Disable Rails SQL query cache when applying service templates.
+- Prevent Billion Laughs attack.
+- Correctly check permissions when creating snippet notes.
+- Prevent the detection of merge request templates by unauthorized users.
+
+
## 12.0.2 (2019-06-25)
### Fixed (7 changes, 1 of them is from the community)
@@ -555,6 +572,27 @@ entry.
- Add some frozen string to spec/**/*.rb. (gfyoung)
+## 11.10.8 (2019-06-27)
+
+- No changes.
+### Security (10 changes)
+
+- Fix Denial of Service for comments when rendering issues/MR comments.
+- Gate MR head_pipeline behind read_pipeline ability.
+- Fix DoS vulnerability in color validation regex.
+- Expose merge requests count based on user access.
+- Persist tmp snippet uploads at users.
+- Add missing authorizations in GraphQL.
+- Disable Rails SQL query cache when applying service templates.
+- Prevent Billion Laughs attack.
+- Correctly check permissions when creating snippet notes.
+- Prevent the detection of merge request templates by unauthorized users.
+
+### Performance (1 change)
+
+- Add improvements to global search of issues and merge requests. !27817
+
+
## 11.10.6 (2019-06-04)
### Fixed (7 changes, 1 of them is from the community)
diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION
index 7f3a46a841e..ba0a719118c 100644
--- a/GITALY_SERVER_VERSION
+++ b/GITALY_SERVER_VERSION
@@ -1 +1 @@
-1.49.0
+1.51.0
diff --git a/Gemfile b/Gemfile
index 5caae0c2ca9..f32e899342b 100644
--- a/Gemfile
+++ b/Gemfile
@@ -11,7 +11,7 @@ gem 'responders', '~> 2.0'
gem 'sprockets', '~> 3.7.0'
# Default values for AR models
-gem 'gitlab-default_value_for', '~> 3.1.1', require: 'default_value_for'
+gem 'default_value_for', '~> 3.2.0'
# Supported DBs
gem 'mysql2', '~> 0.4.10', group: :mysql
@@ -132,7 +132,7 @@ gem 'wikicloth', '0.8.1'
gem 'asciidoctor', '~> 2.0.10'
gem 'asciidoctor-include-ext', '~> 0.3.1', require: false
gem 'asciidoctor-plantuml', '0.0.9'
-gem 'rouge', '~> 3.1'
+gem 'rouge', '~> 3.5'
gem 'truncato', '~> 0.7.11'
gem 'bootstrap_form', '~> 4.2.0'
gem 'nokogiri', '~> 1.10.3'
@@ -309,7 +309,7 @@ group :metrics do
gem 'influxdb', '~> 0.2', require: false
# Prometheus
- gem 'prometheus-client-mmap', '~> 0.9.6'
+ gem 'prometheus-client-mmap', '~> 0.9.8'
gem 'raindrops', '~> 0.18'
end
@@ -368,6 +368,7 @@ group :development, :test do
gem 'haml_lint', '~> 0.31.0', require: false
gem 'simplecov', '~> 0.16.1', require: false
gem 'bundler-audit', '~> 0.5.0', require: false
+ gem 'mdl', '~> 0.5.0', require: false
gem 'benchmark-ips', '~> 2.3.0', require: false
@@ -419,7 +420,7 @@ gem 'vmstat', '~> 2.3.0'
gem 'sys-filesystem', '~> 1.1.6'
# SSH host key support
-gem 'net-ssh', '~> 5.0'
+gem 'net-ssh', '~> 5.2'
gem 'sshkey', '~> 2.0'
# Required for ED25519 SSH host key support
@@ -429,7 +430,7 @@ group :ed25519 do
end
# Gitaly GRPC client
-gem 'gitaly-proto', '~> 1.32.0', require: 'gitaly'
+gem 'gitaly-proto', '~> 1.36.0', require: 'gitaly'
gem 'grpc', '~> 1.19.0'
diff --git a/Gemfile.lock b/Gemfile.lock
index fd366ac16b0..85b4c32f168 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -163,6 +163,8 @@ GEM
html-pipeline
declarative (0.0.10)
declarative-option (0.1.0)
+ default_value_for (3.2.0)
+ activerecord (>= 3.2.0, < 6.0)
derailed_benchmarks (1.3.5)
benchmark-ips (~> 2)
get_process_mem (~> 0)
@@ -301,11 +303,9 @@ GEM
gettext_i18n_rails (>= 0.7.1)
po_to_json (>= 1.0.0)
rails (>= 3.2.0)
- gitaly-proto (1.32.0)
+ gitaly-proto (1.36.0)
grpc (~> 1.0)
github-markup (1.7.0)
- gitlab-default_value_for (3.1.1)
- activerecord (>= 3.2.0, < 6.0)
gitlab-labkit (0.3.0)
actionpack (~> 5)
activesupport (~> 5)
@@ -459,6 +459,7 @@ GEM
kgio (2.11.2)
knapsack (1.17.0)
rake
+ kramdown (1.17.0)
kubeclient (4.2.2)
http (~> 3.0)
recursive-open-struct (~> 1.0, >= 1.0.4)
@@ -492,6 +493,10 @@ GEM
mail (2.7.1)
mini_mime (>= 0.1.1)
mail_room (0.9.1)
+ mdl (0.5.0)
+ kramdown (~> 1.12, >= 1.12.0)
+ mixlib-cli (~> 1.7, >= 1.7.0)
+ mixlib-config (~> 2.2, >= 2.2.1)
memoist (0.16.0)
memoizable (0.4.2)
thread_safe (~> 0.3, >= 0.3.1)
@@ -505,6 +510,9 @@ GEM
mini_mime (1.0.1)
mini_portile2 (2.4.0)
minitest (5.11.3)
+ mixlib-cli (1.7.0)
+ mixlib-config (2.2.18)
+ tomlrb
msgpack (1.2.10)
multi_json (1.13.1)
multi_xml (0.6.0)
@@ -515,7 +523,7 @@ GEM
mysql2 (0.4.10)
nakayoshi_fork (0.0.4)
net-ldap (0.16.0)
- net-ssh (5.0.1)
+ net-ssh (5.2.0)
netrc (0.11.0)
nio4r (2.3.1)
nokogiri (1.10.3)
@@ -652,7 +660,7 @@ GEM
parser
unparser
procto (0.0.3)
- prometheus-client-mmap (0.9.6)
+ prometheus-client-mmap (0.9.8)
pry (0.11.3)
coderay (~> 1.1.0)
method_source (~> 0.9.0)
@@ -770,7 +778,7 @@ GEM
retriable (3.1.2)
rinku (2.0.0)
rotp (2.1.2)
- rouge (3.4.1)
+ rouge (3.5.1)
rqrcode (0.7.0)
chunky_png
rqrcode-rails3 (0.1.7)
@@ -943,6 +951,7 @@ GEM
parslet (~> 1.8.0)
toml-rb (1.0.0)
citrus (~> 3.0, > 3.0)
+ tomlrb (1.2.8)
truncato (0.7.11)
htmlentities (~> 4.3.1)
nokogiri (>= 1.7.0, <= 2.0)
@@ -1056,6 +1065,7 @@ DEPENDENCIES
creole (~> 0.5.0)
database_cleaner (~> 1.7.0)
deckar01-task_list (= 2.2.0)
+ default_value_for (~> 3.2.0)
derailed_benchmarks
device_detector
devise (~> 4.6)
@@ -1091,9 +1101,8 @@ DEPENDENCIES
gettext (~> 3.2.2)
gettext_i18n_rails (~> 1.8.0)
gettext_i18n_rails_js (~> 1.3)
- gitaly-proto (~> 1.32.0)
+ gitaly-proto (~> 1.36.0)
github-markup (~> 1.7.0)
- gitlab-default_value_for (~> 3.1.1)
gitlab-labkit (~> 0.3.0)
gitlab-markup (~> 1.7.0)
gitlab-sidekiq-fetcher (~> 0.4.0)
@@ -1134,6 +1143,7 @@ DEPENDENCIES
lograge (~> 0.5)
loofah (~> 2.2)
mail_room (~> 0.9.1)
+ mdl (~> 0.5.0)
memory_profiler (~> 0.9)
method_source (~> 0.8)
mimemagic (~> 0.3.2)
@@ -1142,7 +1152,7 @@ DEPENDENCIES
mysql2 (~> 0.4.10)
nakayoshi_fork (~> 0.0.4)
net-ldap
- net-ssh (~> 5.0)
+ net-ssh (~> 5.2)
nokogiri (~> 1.10.3)
oauth2 (~> 1.4)
octokit (~> 4.9)
@@ -1173,7 +1183,7 @@ DEPENDENCIES
peek-redis (~> 1.2.0)
pg (~> 1.1)
premailer-rails (~> 1.9.7)
- prometheus-client-mmap (~> 0.9.6)
+ prometheus-client-mmap (~> 0.9.8)
pry-byebug (~> 3.5.1)
pry-rails (~> 0.3.4)
puma (~> 3.12)
@@ -1199,7 +1209,7 @@ DEPENDENCIES
redis-rails (~> 5.0.2)
request_store (~> 1.3)
responders (~> 2.0)
- rouge (~> 3.1)
+ rouge (~> 3.5)
rqrcode-rails3 (~> 0.1.7)
rspec-parameterized
rspec-rails (~> 3.7.0)
diff --git a/app/assets/images/auth_buttons/salesforce_64.png b/app/assets/images/auth_buttons/salesforce_64.png
new file mode 100644
index 00000000000..c8a86a0c515
--- /dev/null
+++ b/app/assets/images/auth_buttons/salesforce_64.png
Binary files differ
diff --git a/app/assets/javascripts/api.js b/app/assets/javascripts/api.js
index 4f66a5d080c..a649c521405 100644
--- a/app/assets/javascripts/api.js
+++ b/app/assets/javascripts/api.js
@@ -24,6 +24,7 @@ const Api = {
issuableTemplatePath: '/:namespace_path/:project_path/templates/:type/:key',
projectTemplatePath: '/api/:version/projects/:id/templates/:type/:key',
projectTemplatesPath: '/api/:version/projects/:id/templates/:type',
+ userCountsPath: '/api/:version/user_counts',
usersPath: '/api/:version/users.json',
userPath: '/api/:version/users/:id',
userStatusPath: '/api/:version/users/:id/status',
@@ -312,6 +313,11 @@ const Api = {
});
},
+ userCounts() {
+ const url = Api.buildUrl(this.userCountsPath);
+ return axios.get(url);
+ },
+
userStatus(id, options) {
const url = Api.buildUrl(this.userStatusPath).replace(':id', encodeURIComponent(id));
return axios.get(url, {
diff --git a/app/assets/javascripts/boards/components/board_blank_state.vue b/app/assets/javascripts/boards/components/board_blank_state.vue
index f58149c9f7b..d8b0b60c183 100644
--- a/app/assets/javascripts/boards/components/board_blank_state.vue
+++ b/app/assets/javascripts/boards/components/board_blank_state.vue
@@ -61,7 +61,7 @@ export default {
<div class="board-blank-state p-3">
<p>
{{
- __('BoardBlankState|Add the following default lists to your Issue Board with one click:')
+ s__('BoardBlankState|Add the following default lists to your Issue Board with one click:')
}}
</p>
<ul class="list-unstyled board-blank-state-list">
@@ -76,7 +76,7 @@ export default {
</ul>
<p>
{{
- __(
+ s__(
'BoardBlankState|Starting out with the default set of lists will get you right on the way to making the most of your board.',
)
}}
@@ -86,10 +86,10 @@ export default {
type="button"
@click.stop="addDefaultLists"
>
- {{ __('BoardBlankState|Add default lists') }}
+ {{ s__('BoardBlankState|Add default lists') }}
</button>
<button class="btn btn-default btn-block" type="button" @click.stop="clearBlankState">
- {{ __("BoardBlankState|Nevermind, I'll use my own") }}
+ {{ s__("BoardBlankState|Nevermind, I'll use my own") }}
</button>
</div>
</template>
diff --git a/app/assets/javascripts/boards/filtered_search_boards.js b/app/assets/javascripts/boards/filtered_search_boards.js
index 6b54e8baefb..b1b4b1c5508 100644
--- a/app/assets/javascripts/boards/filtered_search_boards.js
+++ b/app/assets/javascripts/boards/filtered_search_boards.js
@@ -2,7 +2,6 @@ import IssuableFilteredSearchTokenKeys from 'ee_else_ce/filtered_search/issuable
import FilteredSearchContainer from '../filtered_search/container';
import FilteredSearchManager from '../filtered_search/filtered_search_manager';
import boardsStore from './stores/boards_store';
-import { isEE } from '~/lib/utils/common_utils';
export default class FilteredSearchBoards extends FilteredSearchManager {
constructor(store, updateUrl = false, cantEdit = []) {
@@ -10,7 +9,7 @@ export default class FilteredSearchBoards extends FilteredSearchManager {
page: 'boards',
isGroupDecendent: true,
stateFiltersSelector: '.issues-state-filters',
- isGroup: isEE(),
+ isGroup: IS_EE,
filteredSearchTokenKeys: IssuableFilteredSearchTokenKeys,
});
diff --git a/app/assets/javascripts/boards/index.js b/app/assets/javascripts/boards/index.js
index a020765f335..23b107abefa 100644
--- a/app/assets/javascripts/boards/index.js
+++ b/app/assets/javascripts/boards/index.js
@@ -1,6 +1,7 @@
import $ from 'jquery';
import Vue from 'vue';
+import mountMultipleBoardsSwitcher from 'ee_else_ce/boards/mount_multiple_boards_switcher';
import Flash from '~/flash';
import { __ } from '~/locale';
import './models/label';
@@ -20,7 +21,7 @@ import modalMixin from './mixins/modal_mixins';
import './filters/due_date_filters';
import Board from './components/board';
import BoardSidebar from './components/board_sidebar';
-import initNewListDropdown from './components/new_list_dropdown';
+import initNewListDropdown from 'ee_else_ce/boards/components/new_list_dropdown';
import BoardAddIssuesModal from './components/modal/index.vue';
import '~/vue_shared/vue_resource_interceptor';
import {
@@ -78,13 +79,14 @@ export default () => {
},
},
created() {
- gl.boardService = new BoardService({
+ boardsStore.setEndpoints({
boardsEndpoint: this.boardsEndpoint,
recentBoardsEndpoint: this.recentBoardsEndpoint,
listsEndpoint: this.listsEndpoint,
bulkUpdatePath: this.bulkUpdatePath,
boardId: this.boardId,
});
+ gl.boardService = new BoardService();
boardsStore.rootPath = this.boardsEndpoint;
eventHub.$on('updateTokens', this.updateTokens);
@@ -278,4 +280,6 @@ export default () => {
`,
});
}
+
+ mountMultipleBoardsSwitcher();
};
diff --git a/app/assets/javascripts/boards/models/issue.js b/app/assets/javascripts/boards/models/issue.js
index f858b162c6b..9069b35db9a 100644
--- a/app/assets/javascripts/boards/models/issue.js
+++ b/app/assets/javascripts/boards/models/issue.js
@@ -5,7 +5,7 @@
import Vue from 'vue';
import './label';
-import { isEE, convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
+import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
import IssueProject from './project';
import boardsStore from '../stores/boards_store';
@@ -91,13 +91,13 @@ class ListIssue {
addMilestone(milestone) {
const miletoneId = this.milestone ? this.milestone.id : null;
- if (isEE && milestone.id !== miletoneId) {
+ if (IS_EE && milestone.id !== miletoneId) {
this.milestone = new ListMilestone(milestone);
}
}
removeMilestone(removeMilestone) {
- if (isEE && removeMilestone && removeMilestone.id === this.milestone.id) {
+ if (IS_EE && removeMilestone && removeMilestone.id === this.milestone.id) {
this.milestone = {};
}
}
diff --git a/app/assets/javascripts/boards/models/list.js b/app/assets/javascripts/boards/models/list.js
index cd553d0c4af..7e0ccb9bd2a 100644
--- a/app/assets/javascripts/boards/models/list.js
+++ b/app/assets/javascripts/boards/models/list.js
@@ -4,7 +4,7 @@
import { __ } from '~/locale';
import ListLabel from './label';
import ListAssignee from './assignee';
-import { isEE, urlParamsToObject } from '~/lib/utils/common_utils';
+import { urlParamsToObject } from '~/lib/utils/common_utils';
import boardsStore from '../stores/boards_store';
import ListMilestone from './milestone';
@@ -58,7 +58,7 @@ class List {
} else if (obj.user) {
this.assignee = new ListAssignee(obj.user);
this.title = this.assignee.name;
- } else if (isEE && obj.milestone) {
+ } else if (IS_EE && obj.milestone) {
this.milestone = new ListMilestone(obj.milestone);
this.title = this.milestone.title;
}
@@ -85,7 +85,7 @@ class List {
entityType = 'label_id';
} else if (this.assignee) {
entityType = 'assignee_id';
- } else if (isEE && this.milestone) {
+ } else if (IS_EE && this.milestone) {
entityType = 'milestone_id';
}
@@ -205,7 +205,7 @@ class List {
issue.addAssignee(this.assignee);
}
- if (isEE && this.milestone) {
+ if (IS_EE && this.milestone) {
if (listFrom && listFrom.type === 'milestone') {
issue.removeMilestone(listFrom.milestone);
}
diff --git a/app/assets/javascripts/boards/models/milestone.js b/app/assets/javascripts/boards/models/milestone.js
index 6f81d6bc6f8..7201b6e91f5 100644
--- a/app/assets/javascripts/boards/models/milestone.js
+++ b/app/assets/javascripts/boards/models/milestone.js
@@ -1,11 +1,9 @@
-import { isEE } from '~/lib/utils/common_utils';
-
export default class ListMilestone {
constructor(obj) {
this.id = obj.id;
this.title = obj.title;
- if (isEE) {
+ if (IS_EE) {
this.path = obj.path;
this.state = obj.state;
this.webUrl = obj.web_url || obj.webUrl;
diff --git a/app/assets/javascripts/boards/mount_multiple_boards_switcher.js b/app/assets/javascripts/boards/mount_multiple_boards_switcher.js
new file mode 100644
index 00000000000..bdb14a7f2f2
--- /dev/null
+++ b/app/assets/javascripts/boards/mount_multiple_boards_switcher.js
@@ -0,0 +1,2 @@
+// this will be moved from EE to CE as part of https://gitlab.com/gitlab-org/gitlab-ce/issues/53811
+export default () => {};
diff --git a/app/assets/javascripts/boards/services/board_service.js b/app/assets/javascripts/boards/services/board_service.js
index 7d463f17ab1..580d04a3649 100644
--- a/app/assets/javascripts/boards/services/board_service.js
+++ b/app/assets/javascripts/boards/services/board_service.js
@@ -1,106 +1,66 @@
-import axios from '../../lib/utils/axios_utils';
-import { mergeUrlParams } from '../../lib/utils/url_utility';
+/* eslint-disable class-methods-use-this */
-export default class BoardService {
- constructor({ boardsEndpoint, listsEndpoint, bulkUpdatePath, boardId, recentBoardsEndpoint }) {
- this.boardsEndpoint = boardsEndpoint;
- this.boardId = boardId;
- this.listsEndpoint = listsEndpoint;
- this.listsEndpointGenerate = `${listsEndpoint}/generate.json`;
- this.bulkUpdatePath = bulkUpdatePath;
- this.recentBoardsEndpoint = `${recentBoardsEndpoint}.json`;
- }
+import boardsStore from '~/boards/stores/boards_store';
+export default class BoardService {
generateBoardsPath(id) {
- return `${this.boardsEndpoint}${id ? `/${id}` : ''}.json`;
+ return boardsStore.generateBoardsPath(id);
}
generateIssuesPath(id) {
- return `${this.listsEndpoint}${id ? `/${id}` : ''}/issues`;
+ return boardsStore.generateIssuesPath(id);
}
static generateIssuePath(boardId, id) {
- return `${gon.relative_url_root}/-/boards/${boardId ? `${boardId}` : ''}/issues${
- id ? `/${id}` : ''
- }`;
+ return boardsStore.generateIssuePath(boardId, id);
}
all() {
- return axios.get(this.listsEndpoint);
+ return boardsStore.all();
}
generateDefaultLists() {
- return axios.post(this.listsEndpointGenerate, {});
+ return boardsStore.generateDefaultLists();
}
createList(entityId, entityType) {
- const list = {
- [entityType]: entityId,
- };
-
- return axios.post(this.listsEndpoint, {
- list,
- });
+ return boardsStore.createList(entityId, entityType);
}
updateList(id, position) {
- return axios.put(`${this.listsEndpoint}/${id}`, {
- list: {
- position,
- },
- });
+ return boardsStore.updateList(id, position);
}
destroyList(id) {
- return axios.delete(`${this.listsEndpoint}/${id}`);
+ return boardsStore.destroyList(id);
}
getIssuesForList(id, filter = {}) {
- const data = { id };
- Object.keys(filter).forEach(key => {
- data[key] = filter[key];
- });
-
- return axios.get(mergeUrlParams(data, this.generateIssuesPath(id)));
+ return boardsStore.getIssuesForList(id, filter);
}
moveIssue(id, fromListId = null, toListId = null, moveBeforeId = null, moveAfterId = null) {
- return axios.put(BoardService.generateIssuePath(this.boardId, id), {
- from_list_id: fromListId,
- to_list_id: toListId,
- move_before_id: moveBeforeId,
- move_after_id: moveAfterId,
- });
+ return boardsStore.moveIssue(id, fromListId, toListId, moveBeforeId, moveAfterId);
}
newIssue(id, issue) {
- return axios.post(this.generateIssuesPath(id), {
- issue,
- });
+ return boardsStore.newIssue(id, issue);
}
getBacklog(data) {
- return axios.get(
- mergeUrlParams(data, `${gon.relative_url_root}/-/boards/${this.boardId}/issues.json`),
- );
+ return boardsStore.getBacklog(data);
}
bulkUpdate(issueIds, extraData = {}) {
- const data = {
- update: Object.assign(extraData, {
- issuable_ids: issueIds.join(','),
- }),
- };
-
- return axios.post(this.bulkUpdatePath, data);
+ return boardsStore.bulkUpdate(issueIds, extraData);
}
static getIssueInfo(endpoint) {
- return axios.get(endpoint);
+ return boardsStore.getIssueInfo(endpoint);
}
static toggleIssueSubscription(endpoint) {
- return axios.post(endpoint);
+ return boardsStore.toggleIssueSubscription(endpoint);
}
}
diff --git a/app/assets/javascripts/boards/stores/boards_store.js b/app/assets/javascripts/boards/stores/boards_store.js
index 4ba4cde6bae..b9cd4a143ef 100644
--- a/app/assets/javascripts/boards/stores/boards_store.js
+++ b/app/assets/javascripts/boards/stores/boards_store.js
@@ -8,6 +8,8 @@ import Cookies from 'js-cookie';
import BoardsStoreEE from 'ee_else_ce/boards/stores/boards_store_ee';
import { getUrlParamsArray, parseBoolean } from '~/lib/utils/common_utils';
import { __ } from '~/locale';
+import axios from '~/lib/utils/axios_utils';
+import { mergeUrlParams } from '~/lib/utils/url_utility';
import eventHub from '../eventhub';
const boardsStore = {
@@ -28,6 +30,7 @@ const boardsStore = {
},
currentPage: '',
reload: false,
+ endpoints: {},
},
detail: {
issue: {},
@@ -36,6 +39,19 @@ const boardsStore = {
issue: {},
list: {},
},
+
+ setEndpoints({ boardsEndpoint, listsEndpoint, bulkUpdatePath, boardId, recentBoardsEndpoint }) {
+ const listsEndpointGenerate = `${listsEndpoint}/generate.json`;
+ this.state.endpoints = {
+ boardsEndpoint,
+ boardId,
+ listsEndpoint,
+ listsEndpointGenerate,
+ bulkUpdatePath,
+ recentBoardsEndpoint: `${recentBoardsEndpoint}.json`,
+ };
+ },
+
create() {
this.state.lists = [];
this.filter.path = getUrlParamsArray().join('&');
@@ -229,6 +245,101 @@ const boardsStore = {
setTimeTrackingLimitToHours(limitToHours) {
this.timeTracking.limitToHours = parseBoolean(limitToHours);
},
+
+ generateBoardsPath(id) {
+ return `${this.state.endpoints.boardsEndpoint}${id ? `/${id}` : ''}.json`;
+ },
+
+ generateIssuesPath(id) {
+ return `${this.state.endpoints.listsEndpoint}${id ? `/${id}` : ''}/issues`;
+ },
+
+ generateIssuePath(boardId, id) {
+ return `${gon.relative_url_root}/-/boards/${boardId ? `${boardId}` : ''}/issues${
+ id ? `/${id}` : ''
+ }`;
+ },
+
+ all() {
+ return axios.get(this.state.endpoints.listsEndpoint);
+ },
+
+ generateDefaultLists() {
+ return axios.post(this.state.endpoints.listsEndpointGenerate, {});
+ },
+
+ createList(entityId, entityType) {
+ const list = {
+ [entityType]: entityId,
+ };
+
+ return axios.post(this.state.endpoints.listsEndpoint, {
+ list,
+ });
+ },
+
+ updateList(id, position) {
+ return axios.put(`${this.state.endpoints.listsEndpoint}/${id}`, {
+ list: {
+ position,
+ },
+ });
+ },
+
+ destroyList(id) {
+ return axios.delete(`${this.state.endpoints.listsEndpoint}/${id}`);
+ },
+
+ getIssuesForList(id, filter = {}) {
+ const data = { id };
+ Object.keys(filter).forEach(key => {
+ data[key] = filter[key];
+ });
+
+ return axios.get(mergeUrlParams(data, this.generateIssuesPath(id)));
+ },
+
+ moveIssue(id, fromListId = null, toListId = null, moveBeforeId = null, moveAfterId = null) {
+ return axios.put(this.generateIssuePath(this.state.endpoints.boardId, id), {
+ from_list_id: fromListId,
+ to_list_id: toListId,
+ move_before_id: moveBeforeId,
+ move_after_id: moveAfterId,
+ });
+ },
+
+ newIssue(id, issue) {
+ return axios.post(this.generateIssuesPath(id), {
+ issue,
+ });
+ },
+
+ getBacklog(data) {
+ return axios.get(
+ mergeUrlParams(
+ data,
+ `${gon.relative_url_root}/-/boards/${this.state.endpoints.boardId}/issues.json`,
+ ),
+ );
+ },
+
+ bulkUpdate(issueIds, extraData = {}) {
+ const data = {
+ update: Object.assign(extraData, {
+ issuable_ids: issueIds.join(','),
+ }),
+ };
+
+ return axios.post(this.state.endpoints.bulkUpdatePath, data);
+ },
+
+ getIssueInfo(endpoint) {
+ return axios.get(endpoint);
+ },
+
+ toggleIssueSubscription(endpoint) {
+ return axios.post(endpoint);
+ },
};
BoardsStoreEE.initEESpecific(boardsStore);
diff --git a/app/assets/javascripts/branches/divergence_graph.js b/app/assets/javascripts/branches/divergence_graph.js
index 670e8e9eb60..7dbaf984acf 100644
--- a/app/assets/javascripts/branches/divergence_graph.js
+++ b/app/assets/javascripts/branches/divergence_graph.js
@@ -1,23 +1,51 @@
import Vue from 'vue';
+import { __ } from '../locale';
+import createFlash from '../flash';
+import axios from '../lib/utils/axios_utils';
import DivergenceGraph from './components/divergence_graph.vue';
-export default () => {
- document.querySelectorAll('.js-branch-divergence-graph').forEach(el => {
- const { distance, aheadCount, behindCount, defaultBranch, maxCommits } = el.dataset;
-
- return new Vue({
- el,
- render(h) {
- return h(DivergenceGraph, {
- props: {
- defaultBranch,
- distance: distance ? parseInt(distance, 10) : null,
- aheadCount: parseInt(aheadCount, 10),
- behindCount: parseInt(behindCount, 10),
- maxCommits: parseInt(maxCommits, 10),
- },
- });
- },
- });
+export function createGraphVueApp(el, data, maxCommits) {
+ return new Vue({
+ el,
+ render(h) {
+ return h(DivergenceGraph, {
+ props: {
+ defaultBranch: 'master',
+ distance: data.distance ? parseInt(data.distance, 10) : null,
+ aheadCount: parseInt(data.ahead, 10),
+ behindCount: parseInt(data.behind, 10),
+ maxCommits,
+ },
+ });
+ },
});
+}
+
+export default endpoint => {
+ const names = [...document.querySelectorAll('.js-branch-item')].map(
+ ({ dataset }) => dataset.name,
+ );
+ return axios
+ .get(endpoint, {
+ params: { names },
+ })
+ .then(({ data }) => {
+ const maxCommits = Object.entries(data).reduce((acc, [, val]) => {
+ const max = Math.max(...Object.values(val));
+ return max > acc ? max : acc;
+ }, 100);
+
+ Object.entries(data).forEach(([branchName, val]) => {
+ const el = document.querySelector(
+ `[data-name="${branchName}"] .js-branch-divergence-graph`,
+ );
+
+ if (!el) return;
+
+ createGraphVueApp(el, val, maxCommits);
+ });
+ })
+ .catch(() =>
+ createFlash(__('Error fetching diverging counts for branches. Please try again.')),
+ );
};
diff --git a/app/assets/javascripts/clusters/components/application_row.vue b/app/assets/javascripts/clusters/components/application_row.vue
index 4771090aa7e..cd2121db3b2 100644
--- a/app/assets/javascripts/clusters/components/application_row.vue
+++ b/app/assets/javascripts/clusters/components/application_row.vue
@@ -207,7 +207,7 @@ export default {
return __('Updating');
}
- return __('Updated');
+ return this.updateSuccessful ? __('Updated to') : __('Updated');
},
updateFailureDescription() {
return s__('ClusterIntegration|Update failed. Please check the logs and try again.');
@@ -331,8 +331,6 @@ export default {
class="form-text text-muted label p-0 js-cluster-application-update-details"
>
{{ versionLabel }}
- <span v-if="updateSuccessful">to</span>
-
<gl-link
v-if="updateSuccessful"
:href="chartRepo"
diff --git a/app/assets/javascripts/clusters/components/knative_domain_editor.vue b/app/assets/javascripts/clusters/components/knative_domain_editor.vue
index 480228619a5..e26ef135bc5 100644
--- a/app/assets/javascripts/clusters/components/knative_domain_editor.vue
+++ b/app/assets/javascripts/clusters/components/knative_domain_editor.vue
@@ -2,7 +2,7 @@
import LoadingButton from '~/vue_shared/components/loading_button.vue';
import ClipboardButton from '../../vue_shared/components/clipboard_button.vue';
import { GlLoadingIcon } from '@gitlab/ui';
-import { s__ } from '~/locale';
+import { __, s__ } from '~/locale';
import { APPLICATION_STATUS } from '~/clusters/constants';
@@ -32,7 +32,7 @@ export default {
return [UPDATING].includes(this.knative.status);
},
saveButtonLabel() {
- return this.saving ? this.__('Saving') : this.__('Save changes');
+ return this.saving ? __('Saving') : __('Save changes');
},
knativeInstalled() {
return this.knative.installed;
@@ -122,9 +122,9 @@ export default {
`ClusterIntegration|To access your application after deployment, point a wildcard DNS to the Knative Endpoint.`,
)
}}
- <a :href="ingressDnsHelpPath" target="_blank" rel="noopener noreferrer">
- {{ __('More information') }}
- </a>
+ <a :href="ingressDnsHelpPath" target="_blank" rel="noopener noreferrer">{{
+ __('More information')
+ }}</a>
</p>
<p
diff --git a/app/assets/javascripts/clusters/components/uninstall_application_button.vue b/app/assets/javascripts/clusters/components/uninstall_application_button.vue
index ef4bcbe14dd..8465312d84d 100644
--- a/app/assets/javascripts/clusters/components/uninstall_application_button.vue
+++ b/app/assets/javascripts/clusters/components/uninstall_application_button.vue
@@ -1,6 +1,7 @@
<script>
import LoadingButton from '~/vue_shared/components/loading_button.vue';
import { APPLICATION_STATUS } from '~/clusters/constants';
+import { __ } from '~/locale';
const { UPDATING, UNINSTALLING } = APPLICATION_STATUS;
@@ -22,7 +23,7 @@ export default {
return this.status === UNINSTALLING;
},
label() {
- return this.loading ? this.__('Uninstalling') : this.__('Uninstall');
+ return this.loading ? __('Uninstalling') : __('Uninstall');
},
},
};
diff --git a/app/assets/javascripts/clusters/components/uninstall_application_confirmation_modal.vue b/app/assets/javascripts/clusters/components/uninstall_application_confirmation_modal.vue
index 65827f1cb6a..920439ebb23 100644
--- a/app/assets/javascripts/clusters/components/uninstall_application_confirmation_modal.vue
+++ b/app/assets/javascripts/clusters/components/uninstall_application_confirmation_modal.vue
@@ -14,7 +14,9 @@ const CUSTOM_APP_WARNING_TEXT = {
[PROMETHEUS]: s__('ClusterIntegration|All data will be deleted and cannot be restored.'),
[RUNNER]: s__('ClusterIntegration|Any running pipelines will be canceled.'),
[KNATIVE]: s__('ClusterIntegration|The associated IP will be deleted and cannot be restored.'),
- [JUPYTER]: '',
+ [JUPYTER]: s__(
+ 'ClusterIntegration|All data not committed to GitLab will be deleted and cannot be restored.',
+ ),
};
export default {
diff --git a/app/assets/javascripts/commons/index.js b/app/assets/javascripts/commons/index.js
index 0d2fe2925d8..ad0f6cc1496 100644
--- a/app/assets/javascripts/commons/index.js
+++ b/app/assets/javascripts/commons/index.js
@@ -4,3 +4,6 @@ import './jquery';
import './bootstrap';
import './vue';
import '../lib/utils/axios_utils';
+import { openUserCountsBroadcast } from './nav/user_merge_requests';
+
+openUserCountsBroadcast();
diff --git a/app/assets/javascripts/commons/nav/user_merge_requests.js b/app/assets/javascripts/commons/nav/user_merge_requests.js
new file mode 100644
index 00000000000..8e694cca6a1
--- /dev/null
+++ b/app/assets/javascripts/commons/nav/user_merge_requests.js
@@ -0,0 +1,67 @@
+import Api from '~/api';
+
+let channel;
+
+function broadcastCount(newCount) {
+ if (!channel) {
+ return;
+ }
+
+ channel.postMessage(newCount);
+}
+
+function updateUserMergeRequestCounts(newCount) {
+ const mergeRequestsCountEl = document.querySelector('.merge-requests-count');
+ mergeRequestsCountEl.textContent = newCount.toLocaleString();
+ mergeRequestsCountEl.classList.toggle('hidden', Number(newCount) === 0);
+}
+
+/**
+ * Refresh user counts (and broadcast if open)
+ */
+export function refreshUserMergeRequestCounts() {
+ return Api.userCounts()
+ .then(({ data }) => {
+ const count = data.merge_requests;
+
+ updateUserMergeRequestCounts(count);
+ broadcastCount(count);
+ })
+ .catch(ex => {
+ console.error(ex); // eslint-disable-line no-console
+ });
+}
+
+/**
+ * Close the broadcast channel for user counts
+ */
+export function closeUserCountsBroadcast() {
+ if (!channel) {
+ return;
+ }
+
+ channel.close();
+ channel = null;
+}
+
+/**
+ * Open the broadcast channel for user counts, adds user id so we only update
+ *
+ * **Please note:**
+ * Not supported in all browsers, but not polyfilling for now
+ * to keep bundle size small and
+ * no special functionality lost except cross tab notifications
+ */
+export function openUserCountsBroadcast() {
+ closeUserCountsBroadcast();
+
+ if (window.BroadcastChannel) {
+ const currentUserId = typeof gon !== 'undefined' && gon && gon.current_user_id;
+ if (currentUserId) {
+ channel = new BroadcastChannel(`mr_count_channel_${currentUserId}`);
+ channel.onmessage = ev => {
+ updateUserMergeRequestCounts(ev.data);
+ };
+ }
+ }
+}
diff --git a/app/assets/javascripts/confidential_merge_request/components/dropdown.vue b/app/assets/javascripts/confidential_merge_request/components/dropdown.vue
new file mode 100644
index 00000000000..444640980af
--- /dev/null
+++ b/app/assets/javascripts/confidential_merge_request/components/dropdown.vue
@@ -0,0 +1,58 @@
+<script>
+import { GlDropdown, GlDropdownItem } from '@gitlab/ui';
+import { __ } from '~/locale';
+import Icon from '~/vue_shared/components/icon.vue';
+
+export default {
+ components: {
+ GlDropdown,
+ GlDropdownItem,
+ Icon,
+ },
+ props: {
+ projects: {
+ type: Array,
+ required: true,
+ },
+ selectedProject: {
+ type: Object,
+ required: false,
+ default: () => ({}),
+ },
+ },
+ computed: {
+ dropdownText() {
+ if (Object.keys(this.selectedProject).length) {
+ return this.selectedProject.name;
+ }
+
+ return __('Select private project');
+ },
+ },
+ methods: {
+ selectProject(project) {
+ this.$emit('click', project);
+ },
+ },
+};
+</script>
+
+<template>
+ <gl-dropdown toggle-class="d-flex align-items-center w-100" class="w-100">
+ <template slot="button-content">
+ <span class="str-truncated-100 mr-2">
+ <icon name="lock" />
+ {{ dropdownText }}
+ </span>
+ <icon name="chevron-down" class="ml-auto" />
+ </template>
+ <gl-dropdown-item v-for="project in projects" :key="project.id" @click="selectProject(project)">
+ <icon
+ name="mobile-issue-close"
+ :class="{ icon: project.id !== selectedProject.id }"
+ class="js-active-project-check"
+ />
+ <span class="ml-1">{{ project.name }}</span>
+ </gl-dropdown-item>
+ </gl-dropdown>
+</template>
diff --git a/app/assets/javascripts/confidential_merge_request/components/project_form_group.vue b/app/assets/javascripts/confidential_merge_request/components/project_form_group.vue
new file mode 100644
index 00000000000..99d77a75c23
--- /dev/null
+++ b/app/assets/javascripts/confidential_merge_request/components/project_form_group.vue
@@ -0,0 +1,132 @@
+<script>
+import { GlLink } from '@gitlab/ui';
+import { __, sprintf } from '../../locale';
+import createFlash from '../../flash';
+import Api from '../../api';
+import state from '../state';
+import Dropdown from './dropdown.vue';
+
+export default {
+ components: {
+ GlLink,
+ Dropdown,
+ },
+ props: {
+ namespacePath: {
+ type: String,
+ required: true,
+ },
+ projectPath: {
+ type: String,
+ required: true,
+ },
+ newForkPath: {
+ type: String,
+ required: true,
+ },
+ helpPagePath: {
+ type: String,
+ required: true,
+ },
+ },
+ data() {
+ return {
+ projects: [],
+ };
+ },
+ computed: {
+ selectedProject() {
+ return state.selectedProject;
+ },
+ noForkText() {
+ return sprintf(
+ __(
+ "To protect this issue's confidentiality, %{link_start}fork the project%{link_end} and set the forks visiblity to private.",
+ ),
+ { link_start: `<a href="${this.newForkPath}" class="help-link">`, link_end: '</a>' },
+ false,
+ );
+ },
+ },
+ mounted() {
+ this.fetchProjects();
+ this.createBtn = document.querySelector('.js-create-target');
+ this.warningText = document.querySelector('.js-exposed-info-warning');
+ },
+ methods: {
+ selectProject(project) {
+ if (project) {
+ Object.assign(state, {
+ selectedProject: project,
+ });
+
+ if (project.namespaceFullPath !== this.namespacePath) {
+ this.showWarning();
+ }
+ } else if (this.createBtn) {
+ this.createBtn.setAttribute('disabled', 'disabled');
+ }
+ },
+ normalizeProjectData(data) {
+ return data.map(p => ({
+ id: p.id,
+ name: p.name_with_namespace,
+ pathWithNamespace: p.path_with_namespace,
+ namespaceFullpath: p.namespace.full_path,
+ }));
+ },
+ fetchProjects() {
+ Api.projectForks(this.projectPath, {
+ with_merge_requests_enabled: true,
+ min_access_level: 30,
+ visibility: 'private',
+ })
+ .then(({ data }) => {
+ this.projects = this.normalizeProjectData(data);
+ this.selectProject(this.projects[0]);
+ })
+ .catch(e => {
+ createFlash(__('Error fetching forked projects. Please try again.'));
+ throw e;
+ });
+ },
+ showWarning() {
+ if (this.warningText) {
+ this.warningText.classList.remove('hidden');
+ }
+
+ if (this.createBtn) {
+ this.createBtn.classList.add('btn-warning');
+ this.createBtn.classList.remove('btn-success');
+ }
+ },
+ },
+};
+</script>
+
+<template>
+ <div class="form-group">
+ <label>{{ __('Project') }}</label>
+ <div>
+ <dropdown
+ v-if="projects.length"
+ :projects="projects"
+ :selected-project="selectedProject"
+ @click="selectProject"
+ />
+ <p class="text-muted mt-1 mb-0">
+ <template v-if="projects.length">
+ {{
+ __(
+ "To protect this issue's confidentiality, a private fork of this project was selected.",
+ )
+ }}
+ </template>
+ <template v-else>
+ {{ __('No forks available to you.') }}<br />
+ <span v-html="noForkText"></span>
+ </template>
+ </p>
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/confidential_merge_request/index.js b/app/assets/javascripts/confidential_merge_request/index.js
new file mode 100644
index 00000000000..9672821d30e
--- /dev/null
+++ b/app/assets/javascripts/confidential_merge_request/index.js
@@ -0,0 +1,30 @@
+import Vue from 'vue';
+import { parseBoolean } from '../lib/utils/common_utils';
+import ProjectFormGroup from './components/project_form_group.vue';
+import state from './state';
+
+export function isConfidentialIssue() {
+ return parseBoolean(document.querySelector('.js-create-mr').dataset.isConfidential);
+}
+
+export function canCreateConfidentialMergeRequest() {
+ return isConfidentialIssue() && Object.keys(state.selectedProject).length > 0;
+}
+
+export function init() {
+ const el = document.getElementById('js-forked-project');
+
+ return new Vue({
+ el,
+ render(h) {
+ return h(ProjectFormGroup, {
+ props: {
+ namespacePath: el.dataset.namespacePath,
+ projectPath: el.dataset.projectPath,
+ newForkPath: el.dataset.newForkPath,
+ helpPagePath: el.dataset.helpPagePath,
+ },
+ });
+ },
+ });
+}
diff --git a/app/assets/javascripts/confidential_merge_request/state.js b/app/assets/javascripts/confidential_merge_request/state.js
new file mode 100644
index 00000000000..95b0580f4b9
--- /dev/null
+++ b/app/assets/javascripts/confidential_merge_request/state.js
@@ -0,0 +1,5 @@
+import Vue from 'vue';
+
+export default Vue.observable({
+ selectedProject: {},
+});
diff --git a/app/assets/javascripts/create_merge_request_dropdown.js b/app/assets/javascripts/create_merge_request_dropdown.js
index 8f5cece0788..052168bb21c 100644
--- a/app/assets/javascripts/create_merge_request_dropdown.js
+++ b/app/assets/javascripts/create_merge_request_dropdown.js
@@ -5,6 +5,12 @@ import Flash from './flash';
import DropLab from './droplab/drop_lab';
import ISetter from './droplab/plugins/input_setter';
import { __, sprintf } from './locale';
+import {
+ init as initConfidentialMergeRequest,
+ isConfidentialIssue,
+ canCreateConfidentialMergeRequest,
+} from './confidential_merge_request';
+import confidentialMergeRequestState from './confidential_merge_request/state';
// Todo: Remove this when fixing issue in input_setter plugin
const InputSetter = Object.assign({}, ISetter);
@@ -12,6 +18,17 @@ const InputSetter = Object.assign({}, ISetter);
const CREATE_MERGE_REQUEST = 'create-mr';
const CREATE_BRANCH = 'create-branch';
+function createEndpoint(projectPath, endpoint) {
+ if (canCreateConfidentialMergeRequest()) {
+ return endpoint.replace(
+ projectPath,
+ confidentialMergeRequestState.selectedProject.pathWithNamespace,
+ );
+ }
+
+ return endpoint;
+}
+
export default class CreateMergeRequestDropdown {
constructor(wrapperEl) {
this.wrapperEl = wrapperEl;
@@ -42,6 +59,8 @@ export default class CreateMergeRequestDropdown {
this.refIsValid = true;
this.refsPath = this.wrapperEl.dataset.refsPath;
this.suggestedRef = this.refInput.value;
+ this.projectPath = this.wrapperEl.dataset.projectPath;
+ this.projectId = this.wrapperEl.dataset.projectId;
// These regexps are used to replace
// a backend generated new branch name and its source (ref)
@@ -58,6 +77,14 @@ export default class CreateMergeRequestDropdown {
};
this.init();
+
+ if (isConfidentialIssue()) {
+ this.createMergeRequestButton.setAttribute(
+ 'data-dropdown-trigger',
+ '#create-merge-request-dropdown',
+ );
+ initConfidentialMergeRequest();
+ }
}
available() {
@@ -113,7 +140,9 @@ export default class CreateMergeRequestDropdown {
this.isCreatingBranch = true;
return axios
- .post(this.createBranchPath)
+ .post(createEndpoint(this.projectPath, this.createBranchPath), {
+ confidential_issue_project_id: canCreateConfidentialMergeRequest() ? this.projectId : null,
+ })
.then(({ data }) => {
this.branchCreated = true;
window.location.href = data.url;
@@ -125,7 +154,11 @@ export default class CreateMergeRequestDropdown {
this.isCreatingMergeRequest = true;
return axios
- .post(this.createMrPath)
+ .post(this.createMrPath, {
+ target_project_id: canCreateConfidentialMergeRequest()
+ ? confidentialMergeRequestState.selectedProject.id
+ : null,
+ })
.then(({ data }) => {
this.mergeRequestCreated = true;
window.location.href = data.url;
@@ -149,6 +182,8 @@ export default class CreateMergeRequestDropdown {
}
enable() {
+ if (!canCreateConfidentialMergeRequest()) return;
+
this.createMergeRequestButton.classList.remove('disabled');
this.createMergeRequestButton.removeAttribute('disabled');
@@ -205,7 +240,7 @@ export default class CreateMergeRequestDropdown {
if (!ref) return false;
return axios
- .get(`${this.refsPath}${encodeURIComponent(ref)}`)
+ .get(`${createEndpoint(this.projectPath, this.refsPath)}${encodeURIComponent(ref)}`)
.then(({ data }) => {
const branches = data[Object.keys(data)[0]];
const tags = data[Object.keys(data)[1]];
@@ -325,6 +360,12 @@ export default class CreateMergeRequestDropdown {
let xhr = null;
event.preventDefault();
+ if (isConfidentialIssue() && !event.target.classList.contains('js-create-target')) {
+ this.droplab.hooks.forEach(hook => hook.list.toggle());
+
+ return;
+ }
+
if (this.isBusy()) {
return;
}
diff --git a/app/assets/javascripts/diff_notes/components/comment_resolve_btn.js b/app/assets/javascripts/diff_notes/components/comment_resolve_btn.js
index f66e07ba31a..7817b41514d 100644
--- a/app/assets/javascripts/diff_notes/components/comment_resolve_btn.js
+++ b/app/assets/javascripts/diff_notes/components/comment_resolve_btn.js
@@ -32,15 +32,15 @@ const CommentAndResolveBtn = Vue.extend({
buttonText: function() {
if (this.isDiscussionResolved) {
if (this.textareaIsEmpty) {
- return __('Unresolve discussion');
+ return __('Unresolve thread');
} else {
- return __('Comment & unresolve discussion');
+ return __('Comment & unresolve thread');
}
} else {
if (this.textareaIsEmpty) {
- return __('Resolve discussion');
+ return __('Resolve thread');
} else {
- return __('Comment & resolve discussion');
+ return __('Comment & resolve thread');
}
}
},
diff --git a/app/assets/javascripts/diffs/components/diff_discussion_reply.vue b/app/assets/javascripts/diffs/components/diff_discussion_reply.vue
new file mode 100644
index 00000000000..2aa5e9b3339
--- /dev/null
+++ b/app/assets/javascripts/diffs/components/diff_discussion_reply.vue
@@ -0,0 +1,55 @@
+<script>
+import { mapGetters } from 'vuex';
+import NoteSignedOutWidget from '~/notes/components/note_signed_out_widget.vue';
+import ReplyPlaceholder from '~/notes/components/discussion_reply_placeholder.vue';
+import UserAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link.vue';
+
+export default {
+ name: 'DiffDiscussionReply',
+ components: {
+ NoteSignedOutWidget,
+ ReplyPlaceholder,
+ UserAvatarLink,
+ },
+ props: {
+ hasForm: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ renderReplyPlaceholder: {
+ type: Boolean,
+ required: true,
+ },
+ },
+ computed: {
+ ...mapGetters({
+ currentUser: 'getUserData',
+ userCanReply: 'userCanReply',
+ }),
+ },
+};
+</script>
+
+<template>
+ <div class="discussion-reply-holder d-flex clearfix">
+ <template v-if="userCanReply">
+ <slot v-if="hasForm" name="form"></slot>
+ <template v-else-if="renderReplyPlaceholder">
+ <user-avatar-link
+ :link-href="currentUser.path"
+ :img-src="currentUser.avatar_url"
+ :img-alt="currentUser.name"
+ :img-size="40"
+ class="d-none d-sm-block"
+ />
+ <reply-placeholder
+ class="qa-discussion-reply"
+ :button-text="__('Start a new discussion...')"
+ @onClick="$emit('showNewDiscussionForm')"
+ />
+ </template>
+ </template>
+ <note-signed-out-widget v-else />
+ </div>
+</template>
diff --git a/app/assets/javascripts/diffs/components/diff_discussions.vue b/app/assets/javascripts/diffs/components/diff_discussions.vue
index 4c73eea4049..b0460bacff2 100644
--- a/app/assets/javascripts/diffs/components/diff_discussions.vue
+++ b/app/assets/javascripts/diffs/components/diff_discussions.vue
@@ -80,7 +80,6 @@ export default {
v-show="isExpanded(discussion)"
:discussion="discussion"
:render-diff-file="false"
- :always-expanded="true"
:discussions-by-diff-order="true"
:line="line"
:help-page-path="helpPagePath"
diff --git a/app/assets/javascripts/diffs/components/diff_file_header.vue b/app/assets/javascripts/diffs/components/diff_file_header.vue
index eb9f1465945..4b226e30699 100644
--- a/app/assets/javascripts/diffs/components/diff_file_header.vue
+++ b/app/assets/javascripts/diffs/components/diff_file_header.vue
@@ -151,7 +151,11 @@ export default {
stickyMonitor(this.$refs.header, contentTop() - fileHeaderHeight - 1, false);
},
methods: {
- ...mapActions('diffs', ['toggleFileDiscussions', 'toggleFullDiff']),
+ ...mapActions('diffs', [
+ 'toggleFileDiscussions',
+ 'toggleFileDiscussionWrappers',
+ 'toggleFullDiff',
+ ]),
handleToggleFile(e, checkTarget) {
if (
!checkTarget ||
@@ -165,7 +169,7 @@ export default {
this.$emit('showForkMessage');
},
handleToggleDiscussions() {
- this.toggleFileDiscussions(this.diffFile);
+ this.toggleFileDiscussionWrappers(this.diffFile);
},
handleFileNameClick(e) {
const isLinkToOtherPage =
diff --git a/app/assets/javascripts/diffs/components/diff_gutter_avatars.vue b/app/assets/javascripts/diffs/components/diff_gutter_avatars.vue
index e28909b7be3..af5550aec3b 100644
--- a/app/assets/javascripts/diffs/components/diff_gutter_avatars.vue
+++ b/app/assets/javascripts/diffs/components/diff_gutter_avatars.vue
@@ -1,5 +1,4 @@
<script>
-import { mapActions } from 'vuex';
import Icon from '~/vue_shared/components/icon.vue';
import { pluralize, truncate } from '~/lib/utils/text_utility';
import UserAvatarImage from '~/vue_shared/components/user_avatar/user_avatar_image.vue';
@@ -19,11 +18,13 @@ export default {
type: Array,
required: true,
},
+ discussionsExpanded: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
},
computed: {
- discussionsExpanded() {
- return this.discussions.every(discussion => discussion.expanded);
- },
allDiscussions() {
return this.discussions.reduce((acc, note) => acc.concat(note.notes), []);
},
@@ -45,26 +46,14 @@ export default {
},
},
methods: {
- ...mapActions(['toggleDiscussion']),
getTooltipText(noteData) {
let { note } = noteData;
-
if (note.length > LENGTH_OF_AVATAR_TOOLTIP) {
note = truncate(note, LENGTH_OF_AVATAR_TOOLTIP);
}
return `${noteData.author.name}: ${note}`;
},
- toggleDiscussions() {
- const forceExpanded = this.discussions.some(discussion => !discussion.expanded);
-
- this.discussions.forEach(discussion => {
- this.toggleDiscussion({
- discussionId: discussion.id,
- forceExpanded,
- });
- });
- },
},
};
</script>
@@ -76,7 +65,7 @@ export default {
type="button"
:aria-label="__('Show comments')"
class="diff-notes-collapse js-diff-comment-avatar js-diff-comment-button"
- @click="toggleDiscussions"
+ @click="$emit('toggleLineDiscussions')"
>
<icon :size="12" name="collapse" />
</button>
@@ -87,7 +76,7 @@ export default {
:img-src="note.author.avatar_url"
:tooltip-text="getTooltipText(note)"
class="diff-comment-avatar js-diff-comment-avatar"
- @click.native="toggleDiscussions"
+ @click.native="$emit('toggleLineDiscussions')"
/>
<span
v-if="moreText"
@@ -97,7 +86,7 @@ export default {
data-container="body"
data-placement="top"
role="button"
- @click="toggleDiscussions"
+ @click="$emit('toggleLineDiscussions')"
>+{{ moreCount }}</span
>
</template>
diff --git a/app/assets/javascripts/diffs/components/diff_line_gutter_content.vue b/app/assets/javascripts/diffs/components/diff_line_gutter_content.vue
index 1281f9b17ef..351110f0a87 100644
--- a/app/assets/javascripts/diffs/components/diff_line_gutter_content.vue
+++ b/app/assets/javascripts/diffs/components/diff_line_gutter_content.vue
@@ -105,7 +105,13 @@ export default {
},
},
methods: {
- ...mapActions('diffs', ['loadMoreLines', 'showCommentForm', 'setHighlightedRow']),
+ ...mapActions('diffs', [
+ 'loadMoreLines',
+ 'showCommentForm',
+ 'setHighlightedRow',
+ 'toggleLineDiscussions',
+ 'toggleLineDiscussionWrappers',
+ ]),
handleCommentButton() {
this.showCommentForm({ lineCode: this.line.line_code, fileHash: this.fileHash });
},
@@ -184,7 +190,14 @@ export default {
@click="setHighlightedRow(lineCode)"
>
</a>
- <diff-gutter-avatars v-if="shouldShowAvatarsOnGutter" :discussions="line.discussions" />
+ <diff-gutter-avatars
+ v-if="shouldShowAvatarsOnGutter"
+ :discussions="line.discussions"
+ :discussions-expanded="line.discussionsExpanded"
+ @toggleLineDiscussions="
+ toggleLineDiscussions({ lineCode, fileHash, expanded: !line.discussionsExpanded })
+ "
+ />
</template>
</div>
</template>
diff --git a/app/assets/javascripts/diffs/components/inline_diff_comment_row.vue b/app/assets/javascripts/diffs/components/inline_diff_comment_row.vue
index 1faa0493e79..a06dbd70ac5 100644
--- a/app/assets/javascripts/diffs/components/inline_diff_comment_row.vue
+++ b/app/assets/javascripts/diffs/components/inline_diff_comment_row.vue
@@ -1,11 +1,14 @@
<script>
-import diffDiscussions from './diff_discussions.vue';
-import diffLineNoteForm from './diff_line_note_form.vue';
+import { mapActions } from 'vuex';
+import DiffDiscussions from './diff_discussions.vue';
+import DiffLineNoteForm from './diff_line_note_form.vue';
+import DiffDiscussionReply from './diff_discussion_reply.vue';
export default {
components: {
- diffDiscussions,
- diffLineNoteForm,
+ DiffDiscussions,
+ DiffLineNoteForm,
+ DiffDiscussionReply,
},
props: {
line: {
@@ -21,6 +24,11 @@ export default {
required: false,
default: '',
},
+ hasDraft: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
},
computed: {
className() {
@@ -32,10 +40,12 @@ export default {
if (!this.line.discussions || !this.line.discussions.length) {
return false;
}
-
- return this.line.discussions.every(discussion => discussion.expanded);
+ return this.line.discussionsExpanded;
},
},
+ methods: {
+ ...mapActions('diffs', ['showCommentForm']),
+ },
};
</script>
@@ -49,13 +59,23 @@ export default {
:discussions="line.discussions"
:help-page-path="helpPagePath"
/>
- <diff-line-note-form
- v-if="line.hasForm"
- :diff-file-hash="diffFileHash"
- :line="line"
- :note-target-line="line"
- :help-page-path="helpPagePath"
- />
+ <diff-discussion-reply
+ v-if="!hasDraft"
+ :has-form="line.hasForm"
+ :render-reply-placeholder="Boolean(line.discussions.length)"
+ @showNewDiscussionForm="
+ showCommentForm({ lineCode: line.line_code, fileHash: diffFileHash })
+ "
+ >
+ <template #form>
+ <diff-line-note-form
+ :diff-file-hash="diffFileHash"
+ :line="line"
+ :note-target-line="line"
+ :help-page-path="helpPagePath"
+ />
+ </template>
+ </diff-discussion-reply>
</div>
</td>
</tr>
diff --git a/app/assets/javascripts/diffs/components/inline_diff_view.vue b/app/assets/javascripts/diffs/components/inline_diff_view.vue
index 8c76a555b62..b2bc3d9914f 100644
--- a/app/assets/javascripts/diffs/components/inline_diff_view.vue
+++ b/app/assets/javascripts/diffs/components/inline_diff_view.vue
@@ -57,6 +57,7 @@ export default {
:diff-file-hash="diffFile.file_hash"
:line="line"
:help-page-path="helpPagePath"
+ :has-draft="shouldRenderDraftRow(diffFile.file_hash, line) || false"
/>
<inline-draft-comment-row
v-if="shouldRenderDraftRow(diffFile.file_hash, line)"
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 d2e54edca85..65b41b0e456 100644
--- a/app/assets/javascripts/diffs/components/parallel_diff_comment_row.vue
+++ b/app/assets/javascripts/diffs/components/parallel_diff_comment_row.vue
@@ -1,11 +1,14 @@
<script>
-import diffDiscussions from './diff_discussions.vue';
-import diffLineNoteForm from './diff_line_note_form.vue';
+import { mapActions } from 'vuex';
+import DiffDiscussions from './diff_discussions.vue';
+import DiffLineNoteForm from './diff_line_note_form.vue';
+import DiffDiscussionReply from './diff_discussion_reply.vue';
export default {
components: {
- diffDiscussions,
- diffLineNoteForm,
+ DiffDiscussions,
+ DiffLineNoteForm,
+ DiffDiscussionReply,
},
props: {
line: {
@@ -25,28 +28,44 @@ export default {
required: false,
default: '',
},
+ hasDraftLeft: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ hasDraftRight: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
},
computed: {
hasExpandedDiscussionOnLeft() {
return this.line.left && this.line.left.discussions.length
- ? this.line.left.discussions.every(discussion => discussion.expanded)
+ ? this.line.left.discussionsExpanded
: false;
},
hasExpandedDiscussionOnRight() {
return this.line.right && this.line.right.discussions.length
- ? this.line.right.discussions.every(discussion => discussion.expanded)
+ ? this.line.right.discussionsExpanded
: false;
},
hasAnyExpandedDiscussion() {
return this.hasExpandedDiscussionOnLeft || this.hasExpandedDiscussionOnRight;
},
shouldRenderDiscussionsOnLeft() {
- return this.line.left && this.line.left.discussions && this.hasExpandedDiscussionOnLeft;
+ return (
+ this.line.left &&
+ this.line.left.discussions &&
+ this.line.left.discussions.length &&
+ this.hasExpandedDiscussionOnLeft
+ );
},
shouldRenderDiscussionsOnRight() {
return (
this.line.right &&
this.line.right.discussions &&
+ this.line.right.discussions.length &&
this.hasExpandedDiscussionOnRight &&
this.line.right.type
);
@@ -81,6 +100,22 @@ export default {
return hasCommentFormOnLeft || hasCommentFormOnRight;
},
+ shouldRenderReplyPlaceholderOnLeft() {
+ return Boolean(
+ this.line.left && this.line.left.discussions && this.line.left.discussions.length,
+ );
+ },
+ shouldRenderReplyPlaceholderOnRight() {
+ return Boolean(
+ this.line.right && this.line.right.discussions && this.line.right.discussions.length,
+ );
+ },
+ },
+ methods: {
+ ...mapActions('diffs', ['showCommentForm']),
+ showNewDiscussionForm() {
+ this.showCommentForm({ lineCode: this.line.line_code, fileHash: this.diffFileHash });
+ },
},
};
</script>
@@ -90,37 +125,51 @@ export default {
<td class="notes-content parallel old" colspan="2">
<div v-if="shouldRenderDiscussionsOnLeft" class="content">
<diff-discussions
- v-if="line.left.discussions.length"
:discussions="line.left.discussions"
:line="line.left"
:help-page-path="helpPagePath"
/>
</div>
- <diff-line-note-form
- v-if="showLeftSideCommentForm"
- :diff-file-hash="diffFileHash"
- :line="line.left"
- :note-target-line="line.left"
- :help-page-path="helpPagePath"
- line-position="left"
- />
+ <diff-discussion-reply
+ v-if="!hasDraftLeft"
+ :has-form="showLeftSideCommentForm"
+ :render-reply-placeholder="shouldRenderReplyPlaceholderOnLeft"
+ @showNewDiscussionForm="showNewDiscussionForm"
+ >
+ <template #form>
+ <diff-line-note-form
+ :diff-file-hash="diffFileHash"
+ :line="line.left"
+ :note-target-line="line.left"
+ :help-page-path="helpPagePath"
+ line-position="left"
+ />
+ </template>
+ </diff-discussion-reply>
</td>
<td class="notes-content parallel new" colspan="2">
<div v-if="shouldRenderDiscussionsOnRight" class="content">
<diff-discussions
- v-if="line.right.discussions.length"
:discussions="line.right.discussions"
:line="line.right"
:help-page-path="helpPagePath"
/>
</div>
- <diff-line-note-form
- v-if="showRightSideCommentForm"
- :diff-file-hash="diffFileHash"
- :line="line.right"
- :note-target-line="line.right"
- line-position="right"
- />
+ <diff-discussion-reply
+ v-if="!hasDraftRight"
+ :has-form="showRightSideCommentForm"
+ :render-reply-placeholder="shouldRenderReplyPlaceholderOnRight"
+ @showNewDiscussionForm="showNewDiscussionForm"
+ >
+ <template #form>
+ <diff-line-note-form
+ :diff-file-hash="diffFileHash"
+ :line="line.right"
+ :note-target-line="line.right"
+ line-position="right"
+ />
+ </template>
+ </diff-discussion-reply>
</td>
</tr>
</template>
diff --git a/app/assets/javascripts/diffs/components/parallel_diff_view.vue b/app/assets/javascripts/diffs/components/parallel_diff_view.vue
index 41a80d99850..c477e68c33c 100644
--- a/app/assets/javascripts/diffs/components/parallel_diff_view.vue
+++ b/app/assets/javascripts/diffs/components/parallel_diff_view.vue
@@ -58,6 +58,8 @@ export default {
:diff-file-hash="diffFile.file_hash"
:line-index="index"
:help-page-path="helpPagePath"
+ :has-draft-left="hasParallelDraftLeft(diffFile.file_hash, line) || false"
+ :has-draft-right="hasParallelDraftRight(diffFile.file_hash, line) || false"
/>
<parallel-draft-comment-row
v-if="shouldRenderParallelDraftRow(diffFile.file_hash, line)"
diff --git a/app/assets/javascripts/diffs/mixins/draft_comments.js b/app/assets/javascripts/diffs/mixins/draft_comments.js
index dfb71bf38ce..b6c9b132aeb 100644
--- a/app/assets/javascripts/diffs/mixins/draft_comments.js
+++ b/app/assets/javascripts/diffs/mixins/draft_comments.js
@@ -6,5 +6,7 @@ export default {
imageDiscussions() {
return this.diffFile.discussions;
},
+ hasParallelDraftLeft: () => () => false,
+ hasParallelDraftRight: () => () => false,
},
};
diff --git a/app/assets/javascripts/diffs/store/actions.js b/app/assets/javascripts/diffs/store/actions.js
index 88d7b4bba63..32e0d8f42ee 100644
--- a/app/assets/javascripts/diffs/store/actions.js
+++ b/app/assets/javascripts/diffs/store/actions.js
@@ -12,6 +12,7 @@ import {
getNoteFormData,
convertExpandLines,
idleCallback,
+ allDiscussionWrappersExpanded,
} from './utils';
import * as types from './mutation_types';
import {
@@ -79,6 +80,7 @@ export const assignDiscussionsToDiff = (
discussions = rootState.notes.discussions,
) => {
const diffPositionByLineCode = getDiffPositionByLineCode(state.diffFiles);
+ const hash = getLocationHash();
discussions
.filter(discussion => discussion.diff_discussion)
@@ -86,6 +88,7 @@ export const assignDiscussionsToDiff = (
commit(types.SET_LINE_DISCUSSIONS_FOR_FILE, {
discussion,
diffPositionByLineCode,
+ hash,
});
});
@@ -99,6 +102,10 @@ export const removeDiscussionsFromDiff = ({ commit }, removeDiscussion) => {
commit(types.REMOVE_LINE_DISCUSSIONS_FOR_FILE, { fileHash: file_hash, lineCode: line_code, id });
};
+export const toggleLineDiscussions = ({ commit }, options) => {
+ commit(types.TOGGLE_LINE_DISCUSSIONS, options);
+};
+
export const renderFileForDiscussionId = ({ commit, rootState, state }, discussionId) => {
const discussion = rootState.notes.discussions.find(d => d.id === discussionId);
@@ -257,6 +264,31 @@ export const toggleFileDiscussions = ({ getters, dispatch }, diff) => {
});
};
+export const toggleFileDiscussionWrappers = ({ commit }, diff) => {
+ const discussionWrappersExpanded = allDiscussionWrappersExpanded(diff);
+ let linesWithDiscussions;
+ if (diff.highlighted_diff_lines) {
+ linesWithDiscussions = diff.highlighted_diff_lines.filter(line => line.discussions.length);
+ }
+ if (diff.parallel_diff_lines) {
+ linesWithDiscussions = diff.parallel_diff_lines.filter(
+ line =>
+ (line.left && line.left.discussions.length) ||
+ (line.right && line.right.discussions.length),
+ );
+ }
+
+ if (linesWithDiscussions.length) {
+ linesWithDiscussions.forEach(line => {
+ commit(types.TOGGLE_LINE_DISCUSSIONS, {
+ fileHash: diff.file_hash,
+ lineCode: line.line_code,
+ expanded: !discussionWrappersExpanded,
+ });
+ });
+ }
+};
+
export const saveDiffDiscussion = ({ state, dispatch }, { note, formData }) => {
const postData = getNoteFormData({
commit: state.commit,
@@ -267,7 +299,7 @@ export const saveDiffDiscussion = ({ state, dispatch }, { note, formData }) => {
return dispatch('saveNote', postData, { root: true })
.then(result => dispatch('updateDiscussion', result.discussion, { root: true }))
.then(discussion => dispatch('assignDiscussionsToDiff', [discussion]))
- .then(() => dispatch('updateResolvableDiscussonsCounts', null, { root: true }))
+ .then(() => dispatch('updateResolvableDiscussionsCounts', null, { root: true }))
.then(() => dispatch('closeDiffFileCommentForm', formData.diffFile.file_hash))
.catch(() => createFlash(s__('MergeRequests|Saving the comment failed')));
};
diff --git a/app/assets/javascripts/diffs/store/mutation_types.js b/app/assets/javascripts/diffs/store/mutation_types.js
index 8d6111da500..9db56331faa 100644
--- a/app/assets/javascripts/diffs/store/mutation_types.js
+++ b/app/assets/javascripts/diffs/store/mutation_types.js
@@ -35,3 +35,5 @@ export const ADD_CURRENT_VIEW_DIFF_FILE_LINES = 'ADD_CURRENT_VIEW_DIFF_FILE_LINE
export const TOGGLE_DIFF_FILE_RENDERING_MORE = 'TOGGLE_DIFF_FILE_RENDERING_MORE';
export const SET_SHOW_SUGGEST_POPOVER = 'SET_SHOW_SUGGEST_POPOVER';
+
+export const TOGGLE_LINE_DISCUSSIONS = 'TOGGLE_LINE_DISCUSSIONS';
diff --git a/app/assets/javascripts/diffs/store/mutations.js b/app/assets/javascripts/diffs/store/mutations.js
index 00181a63c43..a66f205bbbd 100644
--- a/app/assets/javascripts/diffs/store/mutations.js
+++ b/app/assets/javascripts/diffs/store/mutations.js
@@ -6,6 +6,7 @@ import {
addContextLines,
prepareDiffData,
isDiscussionApplicableToLine,
+ updateLineInFile,
} from './utils';
import * as types from './mutation_types';
@@ -109,7 +110,7 @@ export default {
}));
},
- [types.SET_LINE_DISCUSSIONS_FOR_FILE](state, { discussion, diffPositionByLineCode }) {
+ [types.SET_LINE_DISCUSSIONS_FOR_FILE](state, { discussion, diffPositionByLineCode, hash }) {
const { latestDiff } = state;
const discussionLineCode = discussion.line_code;
@@ -130,13 +131,27 @@ export default {
: [],
});
+ const setDiscussionsExpanded = line => {
+ const isLineNoteTargeted = line.discussions.some(
+ disc => disc.notes && disc.notes.find(note => hash === `note_${note.id}`),
+ );
+
+ return {
+ ...line,
+ discussionsExpanded:
+ line.discussions && line.discussions.length
+ ? line.discussions.some(disc => !disc.resolved) || isLineNoteTargeted
+ : false,
+ };
+ };
+
state.diffFiles = state.diffFiles.map(diffFile => {
if (diffFile.file_hash === fileHash) {
const file = { ...diffFile };
if (file.highlighted_diff_lines) {
file.highlighted_diff_lines = file.highlighted_diff_lines.map(line =>
- lineCheck(line) ? mapDiscussions(line) : line,
+ setDiscussionsExpanded(lineCheck(line) ? mapDiscussions(line) : line),
);
}
@@ -148,8 +163,10 @@ export default {
if (left || right) {
return {
...line,
- left: line.left ? mapDiscussions(line.left) : null,
- right: line.right ? mapDiscussions(line.right, () => !left) : null,
+ left: line.left ? setDiscussionsExpanded(mapDiscussions(line.left)) : null,
+ right: line.right
+ ? setDiscussionsExpanded(mapDiscussions(line.right, () => !left))
+ : null,
};
}
@@ -173,32 +190,11 @@ export default {
[types.REMOVE_LINE_DISCUSSIONS_FOR_FILE](state, { fileHash, lineCode }) {
const selectedFile = state.diffFiles.find(f => f.file_hash === fileHash);
if (selectedFile) {
- if (selectedFile.parallel_diff_lines) {
- const targetLine = selectedFile.parallel_diff_lines.find(
- line =>
- (line.left && line.left.line_code === lineCode) ||
- (line.right && line.right.line_code === lineCode),
- );
- if (targetLine) {
- const side = targetLine.left && targetLine.left.line_code === lineCode ? 'left' : 'right';
-
- Object.assign(targetLine[side], {
- discussions: targetLine[side].discussions.filter(discussion => discussion.notes.length),
- });
- }
- }
-
- if (selectedFile.highlighted_diff_lines) {
- const targetInlineLine = selectedFile.highlighted_diff_lines.find(
- line => line.line_code === lineCode,
- );
-
- if (targetInlineLine) {
- Object.assign(targetInlineLine, {
- discussions: targetInlineLine.discussions.filter(discussion => discussion.notes.length),
- });
- }
- }
+ updateLineInFile(selectedFile, lineCode, line =>
+ Object.assign(line, {
+ discussions: line.discussions.filter(discussion => discussion.notes.length),
+ }),
+ );
if (selectedFile.discussions && selectedFile.discussions.length) {
selectedFile.discussions = selectedFile.discussions.filter(
@@ -207,6 +203,15 @@ export default {
}
}
},
+
+ [types.TOGGLE_LINE_DISCUSSIONS](state, { fileHash, lineCode, expanded }) {
+ const selectedFile = state.diffFiles.find(f => f.file_hash === fileHash);
+
+ updateLineInFile(selectedFile, lineCode, line =>
+ Object.assign(line, { discussionsExpanded: expanded }),
+ );
+ },
+
[types.TOGGLE_FOLDER_OPEN](state, path) {
state.treeEntries[path].opened = !state.treeEntries[path].opened;
},
diff --git a/app/assets/javascripts/diffs/store/utils.js b/app/assets/javascripts/diffs/store/utils.js
index 71956255eef..1c3ed84001c 100644
--- a/app/assets/javascripts/diffs/store/utils.js
+++ b/app/assets/javascripts/diffs/store/utils.js
@@ -454,3 +454,48 @@ export const convertExpandLines = ({
};
export const idleCallback = cb => requestIdleCallback(cb);
+
+export const updateLineInFile = (selectedFile, lineCode, updateFn) => {
+ if (selectedFile.parallel_diff_lines) {
+ const targetLine = selectedFile.parallel_diff_lines.find(
+ line =>
+ (line.left && line.left.line_code === lineCode) ||
+ (line.right && line.right.line_code === lineCode),
+ );
+ if (targetLine) {
+ const side = targetLine.left && targetLine.left.line_code === lineCode ? 'left' : 'right';
+
+ updateFn(targetLine[side]);
+ }
+ }
+ if (selectedFile.highlighted_diff_lines) {
+ const targetInlineLine = selectedFile.highlighted_diff_lines.find(
+ line => line.line_code === lineCode,
+ );
+
+ if (targetInlineLine) {
+ updateFn(targetInlineLine);
+ }
+ }
+};
+
+export const allDiscussionWrappersExpanded = diff => {
+ const discussionsExpandedArray = [];
+ if (diff.parallel_diff_lines) {
+ diff.parallel_diff_lines.forEach(line => {
+ if (line.left && line.left.discussions.length) {
+ discussionsExpandedArray.push(line.left.discussionsExpanded);
+ }
+ if (line.right && line.right.discussions.length) {
+ discussionsExpandedArray.push(line.right.discussionsExpanded);
+ }
+ });
+ } else if (diff.highlighted_diff_lines) {
+ diff.parallel_diff_lines.forEach(line => {
+ if (line.discussions.length) {
+ discussionsExpandedArray.push(line.discussionsExpanded);
+ }
+ });
+ }
+ return discussionsExpandedArray.every(el => el);
+};
diff --git a/app/assets/javascripts/environments/components/environment_actions.vue b/app/assets/javascripts/environments/components/environment_actions.vue
index 208bd19f6b0..21244c14977 100644
--- a/app/assets/javascripts/environments/components/environment_actions.vue
+++ b/app/assets/javascripts/environments/components/environment_actions.vue
@@ -1,5 +1,5 @@
<script>
-import { s__, sprintf } from '~/locale';
+import { __, s__, sprintf } from '~/locale';
import { formatTime } from '~/lib/utils/datetime_utility';
import Icon from '~/vue_shared/components/icon.vue';
import eventHub from '../event_hub';
@@ -28,7 +28,7 @@ export default {
},
computed: {
title() {
- return 'Deploy to...';
+ return __('Deploy to...');
},
},
methods: {
@@ -80,7 +80,8 @@ export default {
data-toggle="dropdown"
>
<span>
- <icon name="play" /> <icon name="chevron-down" />
+ <icon name="play" />
+ <icon name="chevron-down" />
<gl-loading-icon v-if="isLoading" />
</span>
</button>
@@ -94,9 +95,10 @@ export default {
class="js-manual-action-link no-btn btn d-flex align-items-center"
@click="onClickAction(action)"
>
- <span class="flex-fill"> {{ action.name }} </span>
+ <span class="flex-fill">{{ action.name }}</span>
<span v-if="action.scheduledAt" class="text-secondary">
- <icon name="clock" /> {{ remainingTime(action) }}
+ <icon name="clock" />
+ {{ remainingTime(action) }}
</span>
</button>
</li>
diff --git a/app/assets/javascripts/environments/components/environment_item.vue b/app/assets/javascripts/environments/components/environment_item.vue
index f0e80cba753..813045cb5e4 100644
--- a/app/assets/javascripts/environments/components/environment_item.vue
+++ b/app/assets/javascripts/environments/components/environment_item.vue
@@ -1,4 +1,5 @@
<script>
+import { __, sprintf } from '~/locale';
import Timeago from 'timeago.js';
import _ from 'underscore';
import { GlTooltipDirective } from '@gitlab/ui';
@@ -14,7 +15,6 @@ import MonitoringButtonComponent from './environment_monitoring.vue';
import CommitComponent from '../../vue_shared/components/commit.vue';
import eventHub from '../event_hub';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
-import { CLUSTER_TYPE } from '~/clusters/constants';
/**
* Environment Item Component
@@ -80,15 +80,6 @@ export default {
},
/**
- * Hide group cluster features which are not currently implemented.
- *
- * @returns {Boolean}
- */
- disableGroupClusterFeatures() {
- return this.model && this.model.cluster_type === CLUSTER_TYPE.GROUP;
- },
-
- /**
* Returns whether the environment can be stopped.
*
* @returns {Boolean}
@@ -172,7 +163,9 @@ export default {
this.model.last_deployment.user &&
this.model.last_deployment.user.username
) {
- return `${this.model.last_deployment.user.username}'s avatar'`;
+ return sprintf(__("%{username}'s avatar"), {
+ username: this.model.last_deployment.user.username,
+ });
}
return '';
},
@@ -293,6 +286,9 @@ export default {
* @returns {Boolean|Undefined}
*/
isLastDeployment() {
+ // TODO: when the vue i18n rules are merged need to disable @gitlab/i18n/no-non-i18n-strings
+ // name: 'last?' is a false positive: https://gitlab.com/gitlab-org/frontend/eslint-plugin-i18n/issues/26#possible-false-positives
+ // Vue i18n ESLint rules issue: https://gitlab.com/gitlab-org/gitlab-ce/issues/63560
return this.model && this.model.last_deployment && this.model.last_deployment['last?'];
},
@@ -575,7 +571,6 @@ export default {
<terminal-button-component
v-if="model && model.terminal_path"
:terminal-path="model.terminal_path"
- :disabled="disableGroupClusterFeatures"
/>
<rollback-component
diff --git a/app/assets/javascripts/environments/components/environment_monitoring.vue b/app/assets/javascripts/environments/components/environment_monitoring.vue
index ae4f07a71cd..886490847ea 100644
--- a/app/assets/javascripts/environments/components/environment_monitoring.vue
+++ b/app/assets/javascripts/environments/components/environment_monitoring.vue
@@ -1,4 +1,5 @@
<script>
+import { __ } from '~/locale';
/**
* Renders the Monitoring (Metrics) link in environments table.
*/
@@ -21,7 +22,7 @@ export default {
},
computed: {
title() {
- return 'Monitoring';
+ return __('Monitoring');
},
},
};
diff --git a/app/assets/javascripts/environments/components/environment_terminal_button.vue b/app/assets/javascripts/environments/components/environment_terminal_button.vue
index 13195d32cc4..37f94f9f5ab 100644
--- a/app/assets/javascripts/environments/components/environment_terminal_button.vue
+++ b/app/assets/javascripts/environments/components/environment_terminal_button.vue
@@ -5,6 +5,7 @@
*/
import { GlTooltipDirective } from '@gitlab/ui';
import Icon from '~/vue_shared/components/icon.vue';
+import { __ } from '~/locale';
export default {
components: {
@@ -27,7 +28,7 @@ export default {
},
computed: {
title() {
- return 'Terminal';
+ return __('Terminal');
},
},
};
diff --git a/app/assets/javascripts/error_tracking_settings/components/error_tracking_form.vue b/app/assets/javascripts/error_tracking_settings/components/error_tracking_form.vue
index 060d8e25227..ef1d1e49320 100644
--- a/app/assets/javascripts/error_tracking_settings/components/error_tracking_form.vue
+++ b/app/assets/javascripts/error_tracking_settings/components/error_tracking_form.vue
@@ -49,9 +49,9 @@ export default {
</p>
</div>
<div class="form-group" :class="{ 'gl-show-field-errors': connectError }">
- <label class="label-bold" for="error-tracking-token">{{
- s__('ErrorTracking|Auth Token')
- }}</label>
+ <label class="label-bold" for="error-tracking-token">
+ {{ s__('ErrorTracking|Auth Token') }}
+ </label>
<div class="row">
<div class="col-8 col-md-9 gl-pr-0">
<gl-form-input
@@ -65,9 +65,8 @@ export default {
<gl-button
class="js-error-tracking-connect prepend-left-5"
@click="$emit('handle-connect')"
+ >{{ __('Connect') }}</gl-button
>
- {{ __('Connect') }}
- </gl-button>
<icon
v-show="connectSuccessful"
class="js-error-tracking-connect-success prepend-left-5 text-success align-middle"
diff --git a/app/assets/javascripts/event_tracking/notes.js b/app/assets/javascripts/event_tracking/notes.js
index 2d1ec238274..1f70290c397 100644
--- a/app/assets/javascripts/event_tracking/notes.js
+++ b/app/assets/javascripts/event_tracking/notes.js
@@ -1 +1,2 @@
+// Noop function which has a EE counter-part
export default () => {};
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 19bc3313373..4757c4b1e43 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
@@ -59,7 +59,7 @@ export default {
<template>
<div>
<div v-if="!isLocalStorageAvailable" class="dropdown-info-note">
- This feature requires local storage to be enabled
+ {{ __('This feature requires local storage to be enabled') }}
</div>
<ul v-else-if="hasItems">
<li v-for="(item, index) in processedItems" :key="`processed-items-${index}`">
@@ -90,10 +90,10 @@ export default {
class="filtered-search-history-clear-button"
@click="onRequestClearRecentSearches($event)"
>
- Clear recent searches
+ {{ __('Clear recent searches') }}
</button>
</li>
</ul>
- <div v-else class="dropdown-info-note">You don't have any recent searches</div>
+ <div v-else class="dropdown-info-note">{{ __("You don't have any recent searches") }}</div>
</div>
</template>
diff --git a/app/assets/javascripts/group.js b/app/assets/javascripts/group.js
index 903c838e266..460174caf4d 100644
--- a/app/assets/javascripts/group.js
+++ b/app/assets/javascripts/group.js
@@ -1,5 +1,5 @@
import $ from 'jquery';
-import { slugifyWithHyphens } from './lib/utils/text_utility';
+import { slugify } from './lib/utils/text_utility';
export default class Group {
constructor() {
@@ -14,7 +14,7 @@ export default class Group {
}
update() {
- const slug = slugifyWithHyphens(this.groupName.val());
+ const slug = slugify(this.groupName.val());
this.groupPath.val(slug);
}
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 4be4b02ac1e..c8fbc3cb9f1 100644
--- a/app/assets/javascripts/ide/components/commit_sidebar/list_item.vue
+++ b/app/assets/javascripts/ide/components/commit_sidebar/list_item.vue
@@ -107,7 +107,8 @@ export default {
@click="openFileInEditor"
>
<span class="multi-file-commit-list-file-path d-flex align-items-center">
- <file-icon :file-name="file.name" class="append-right-8" />{{ file.name }}
+ <file-icon :file-name="file.name" class="append-right-8" />
+ {{ file.name }}
</span>
<div class="ml-auto d-flex align-items-center">
<div class="d-flex align-items-center ide-commit-list-changed-icon">
diff --git a/app/assets/javascripts/ide/components/external_link.vue b/app/assets/javascripts/ide/components/external_link.vue
index 954f84cea17..d1857f0176a 100644
--- a/app/assets/javascripts/ide/components/external_link.vue
+++ b/app/assets/javascripts/ide/components/external_link.vue
@@ -27,7 +27,7 @@ export default {
target="_blank"
rel="noopener noreferrer"
>
- <span class="vertical-align-middle">Open in file view</span>
+ <span class="vertical-align-middle">{{ __('Open in file view') }}</span>
<icon :size="16" name="external-link" css-classes="vertical-align-middle space-right" />
</a>
</div>
diff --git a/app/assets/javascripts/ide/components/repo_editor.vue b/app/assets/javascripts/ide/components/repo_editor.vue
index f952b1e7b80..03756a634d5 100644
--- a/app/assets/javascripts/ide/components/repo_editor.vue
+++ b/app/assets/javascripts/ide/components/repo_editor.vue
@@ -8,6 +8,7 @@ import { activityBarViews, viewerTypes } from '../constants';
import Editor from '../lib/editor';
import ExternalLink from './external_link.vue';
import FileTemplatesBar from './file_templates/bar.vue';
+import { __ } from '~/locale';
export default {
components: {
@@ -143,7 +144,9 @@ export default {
'triggerFilesChange',
]),
initEditor() {
- if (this.shouldHideEditor) return;
+ if (this.shouldHideEditor && (this.file.content || this.file.raw)) {
+ return;
+ }
this.editor.clearEditor();
@@ -160,7 +163,14 @@ export default {
this.createEditorInstance();
})
.catch(err => {
- flash('Error setting up editor. Please try again.', 'alert', document, null, false, true);
+ flash(
+ __('Error setting up editor. Please try again.'),
+ 'alert',
+ document,
+ null,
+ false,
+ true,
+ );
throw err;
});
},
@@ -247,12 +257,8 @@ export default {
role="button"
@click.prevent="setFileViewMode({ file, viewMode: 'editor' })"
>
- <template v-if="viewer === $options.viewerTypes.edit">
- {{ __('Edit') }}
- </template>
- <template v-else>
- {{ __('Review') }}
- </template>
+ <template v-if="viewer === $options.viewerTypes.edit">{{ __('Edit') }}</template>
+ <template v-else>{{ __('Review') }}</template>
</a>
</li>
<li v-if="file.previewMode" :class="previewTabCSS">
@@ -260,9 +266,8 @@ export default {
href="javascript:void(0);"
role="button"
@click.prevent="setFileViewMode({ file, viewMode: 'preview' })"
+ >{{ file.previewMode.previewTitle }}</a
>
- {{ file.previewMode.previewTitle }}
- </a>
</li>
</ul>
<external-link :file="file" />
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 a964d90b090..84a962bfc7d 100644
--- a/app/assets/javascripts/ide/components/repo_file_status_icon.vue
+++ b/app/assets/javascripts/ide/components/repo_file_status_icon.vue
@@ -1,4 +1,5 @@
<script>
+import { __, sprintf } from '~/locale';
import icon from '~/vue_shared/components/icon.vue';
import tooltip from '~/vue_shared/directives/tooltip';
import '~/lib/utils/datetime_utility';
@@ -18,7 +19,9 @@ export default {
},
computed: {
lockTooltip() {
- return `Locked by ${this.file.file_lock.user.name}`;
+ return sprintf(__(`Locked by %{fileLockUserName}`), {
+ fileLockUserName: this.file.file_lock.user.name,
+ });
},
},
};
diff --git a/app/assets/javascripts/ide/components/repo_tab.vue b/app/assets/javascripts/ide/components/repo_tab.vue
index f6aa2295844..7615cfc966e 100644
--- a/app/assets/javascripts/ide/components/repo_tab.vue
+++ b/app/assets/javascripts/ide/components/repo_tab.vue
@@ -1,4 +1,5 @@
<script>
+import { __, sprintf } from '~/locale';
import { mapActions } from 'vuex';
import FileIcon from '~/vue_shared/components/file_icon.vue';
@@ -27,9 +28,9 @@ export default {
computed: {
closeLabel() {
if (this.fileHasChanged) {
- return `${this.tab.name} changed`;
+ return sprintf(__(`%{tabname} changed`), { tabname: this.tab.name });
}
- return `Close ${this.tab.name}`;
+ return sprintf(__(`Close %{tabname}`, { tabname: this.tab.name }));
},
showChangedIcon() {
if (this.tab.pending) return true;
diff --git a/app/assets/javascripts/ide/lib/files.js b/app/assets/javascripts/ide/lib/files.js
index b8abaa41f23..51278640b5b 100644
--- a/app/assets/javascripts/ide/lib/files.js
+++ b/app/assets/javascripts/ide/lib/files.js
@@ -77,6 +77,7 @@ export const decorateFiles = ({
const fileFolder = parent && insertParent(parent);
if (name) {
+ const previewMode = viewerInformationForPath(name);
parentPath = fileFolder && fileFolder.path;
file = decorateData({
@@ -92,9 +93,9 @@ export const decorateFiles = ({
changed: tempFile,
content,
base64,
- binary,
+ binary: (previewMode && previewMode.binary) || binary,
rawPath,
- previewMode: viewerInformationForPath(name),
+ previewMode,
parentPath,
});
diff --git a/app/assets/javascripts/ide/stores/actions.js b/app/assets/javascripts/ide/stores/actions.js
index 507dc363529..8c0119a1fed 100644
--- a/app/assets/javascripts/ide/stores/actions.js
+++ b/app/assets/javascripts/ide/stores/actions.js
@@ -62,7 +62,7 @@ export const createTempEntry = (
new Promise(resolve => {
const fullName = name.slice(-1) !== '/' && type === 'tree' ? `${name}/` : name;
- if (state.entries[name]) {
+ if (state.entries[name] && !state.entries[name].deleted) {
flash(
`The name "${name.split('/').pop()}" is already taken in this directory.`,
'alert',
@@ -208,6 +208,7 @@ export const deleteEntry = ({ commit, dispatch, state }, path) => {
}
commit(types.DELETE_ENTRY, path);
+ dispatch('stageChange', path);
dispatch('triggerFilesChange');
};
diff --git a/app/assets/javascripts/ide/stores/modules/commit/actions.js b/app/assets/javascripts/ide/stores/modules/commit/actions.js
index 01ca6a6b12f..ac34491c1ad 100644
--- a/app/assets/javascripts/ide/stores/modules/commit/actions.js
+++ b/app/assets/javascripts/ide/stores/modules/commit/actions.js
@@ -186,6 +186,8 @@ export const commitChanges = ({ commit, state, getters, dispatch, rootState, roo
commit(rootTypes.CLEAR_STAGED_CHANGES, null, { root: true });
+ commit(rootTypes.CLEAR_REPLACED_FILES, null, { root: true });
+
setTimeout(() => {
commit(rootTypes.SET_LAST_COMMIT_MSG, '', { root: true });
}, 5000);
diff --git a/app/assets/javascripts/ide/stores/mutation_types.js b/app/assets/javascripts/ide/stores/mutation_types.js
index 86ab76136df..f021729c451 100644
--- a/app/assets/javascripts/ide/stores/mutation_types.js
+++ b/app/assets/javascripts/ide/stores/mutation_types.js
@@ -60,6 +60,8 @@ export const CLEAR_STAGED_CHANGES = 'CLEAR_STAGED_CHANGES';
export const STAGE_CHANGE = 'STAGE_CHANGE';
export const UNSTAGE_CHANGE = 'UNSTAGE_CHANGE';
+export const CLEAR_REPLACED_FILES = 'CLEAR_REPLACED_FILES';
+
export const UPDATE_FILE_AFTER_COMMIT = 'UPDATE_FILE_AFTER_COMMIT';
export const ADD_PENDING_TAB = 'ADD_PENDING_TAB';
export const REMOVE_PENDING_TAB = 'REMOVE_PENDING_TAB';
diff --git a/app/assets/javascripts/ide/stores/mutations.js b/app/assets/javascripts/ide/stores/mutations.js
index ec4c2fdcde2..ea125214ebb 100644
--- a/app/assets/javascripts/ide/stores/mutations.js
+++ b/app/assets/javascripts/ide/stores/mutations.js
@@ -56,6 +56,11 @@ export default {
stagedFiles: [],
});
},
+ [types.CLEAR_REPLACED_FILES](state) {
+ Object.assign(state, {
+ replacedFiles: [],
+ });
+ },
[types.SET_ENTRIES](state, entries) {
Object.assign(state, {
entries,
@@ -70,6 +75,13 @@ export default {
Object.assign(state.entries, {
[key]: entry,
});
+ } else if (foundEntry.deleted) {
+ Object.assign(state.entries, {
+ [key]: {
+ ...entry,
+ replaces: true,
+ },
+ });
} else {
const tree = entry.tree.filter(
f => foundEntry.tree.find(e => e.path === f.path) === undefined,
@@ -144,6 +156,7 @@ export default {
raw: file.content,
changed: Boolean(changedFile),
staged: false,
+ replaces: false,
prevPath: '',
moved: false,
lastCommitSha: lastCommit.commit.id,
diff --git a/app/assets/javascripts/ide/stores/mutations/file.js b/app/assets/javascripts/ide/stores/mutations/file.js
index 6ca246c1d63..a52f1e235ed 100644
--- a/app/assets/javascripts/ide/stores/mutations/file.js
+++ b/app/assets/javascripts/ide/stores/mutations/file.js
@@ -1,6 +1,7 @@
import * as types from '../mutation_types';
import { sortTree } from '../utils';
import { diffModes } from '../../constants';
+import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
export default {
[types.SET_FILE_ACTIVE](state, { path, active }) {
@@ -35,19 +36,18 @@ export default {
}
},
[types.SET_FILE_DATA](state, { data, file }) {
- Object.assign(state.entries[file.path], {
- id: data.id,
- blamePath: data.blame_path,
- commitsPath: data.commits_path,
- permalink: data.permalink,
- rawPath: data.raw_path,
- binary: data.binary,
- renderError: data.render_error,
- raw: (state.entries[file.path] && state.entries[file.path].raw) || null,
- baseRaw: null,
- html: data.html,
- size: data.size,
- lastCommitSha: data.last_commit_sha,
+ const stateEntry = state.entries[file.path];
+ const stagedFile = state.stagedFiles.find(f => f.path === file.path);
+ const openFile = state.openFiles.find(f => f.path === file.path);
+ const changedFile = state.changedFiles.find(f => f.path === file.path);
+
+ [stateEntry, stagedFile, openFile, changedFile].forEach(f => {
+ if (f) {
+ Object.assign(f, convertObjectPropsToCamelCase(data, { dropKeys: ['raw', 'baseRaw'] }), {
+ raw: (stateEntry && stateEntry.raw) || null,
+ baseRaw: null,
+ });
+ }
});
},
[types.SET_FILE_RAW_DATA](state, { file, raw }) {
@@ -170,12 +170,16 @@ export default {
entries: Object.assign(state.entries, {
[path]: Object.assign(state.entries[path], {
staged: true,
- changed: false,
}),
}),
});
if (stagedFile) {
+ Object.assign(state, {
+ replacedFiles: state.replacedFiles.concat({
+ ...stagedFile,
+ }),
+ });
Object.assign(stagedFile, {
...state.entries[path],
});
diff --git a/app/assets/javascripts/ide/stores/state.js b/app/assets/javascripts/ide/stores/state.js
index d400b9831a9..c4da482bf0a 100644
--- a/app/assets/javascripts/ide/stores/state.js
+++ b/app/assets/javascripts/ide/stores/state.js
@@ -6,6 +6,7 @@ export default () => ({
currentMergeRequestId: '',
changedFiles: [],
stagedFiles: [],
+ replacedFiles: [],
endpoints: {},
lastCommitMsg: '',
lastCommitPath: '',
diff --git a/app/assets/javascripts/ide/stores/utils.js b/app/assets/javascripts/ide/stores/utils.js
index fb132c1afc1..01f78a29cf6 100644
--- a/app/assets/javascripts/ide/stores/utils.js
+++ b/app/assets/javascripts/ide/stores/utils.js
@@ -18,6 +18,7 @@ export const dataStructure = () => ({
active: false,
changed: false,
staged: false,
+ replaces: false,
lastCommitPath: '',
lastCommitSha: '',
lastCommit: {
@@ -119,7 +120,7 @@ export const commitActionForFile = file => {
return commitActionTypes.move;
} else if (file.deleted) {
return commitActionTypes.delete;
- } else if (file.tempFile) {
+ } else if (file.tempFile && !file.replaces) {
return commitActionTypes.create;
}
@@ -151,7 +152,8 @@ export const createCommitPayload = ({
previous_path: f.prevPath === '' ? undefined : f.prevPath,
content: f.prevPath ? null : f.content || undefined,
encoding: f.base64 ? 'base64' : 'text',
- last_commit_id: newBranch || f.deleted || f.prevPath ? undefined : f.lastCommitSha,
+ last_commit_id:
+ newBranch || f.deleted || f.prevPath || f.replaces ? undefined : f.lastCommitSha,
})),
start_sha: newBranch ? rootGetters.lastCommit.short_id : undefined,
});
diff --git a/app/assets/javascripts/issuable_bulk_update_actions.js b/app/assets/javascripts/issuable_bulk_update_actions.js
index bc9d7fcf30d..c855f3973b0 100644
--- a/app/assets/javascripts/issuable_bulk_update_actions.js
+++ b/app/assets/javascripts/issuable_bulk_update_actions.js
@@ -1,4 +1,4 @@
-/* eslint-disable consistent-return, func-names, array-callback-return, prefer-arrow-callback, no-unused-vars */
+/* eslint-disable consistent-return, func-names, array-callback-return, prefer-arrow-callback */
import $ from 'jquery';
import _ from 'underscore';
@@ -7,7 +7,7 @@ import Flash from './flash';
import { __ } from './locale';
export default {
- init({ container, form, issues, prefixId } = {}) {
+ init({ form, issues, prefixId } = {}) {
this.prefixId = prefixId || 'issue_';
this.form = form || this.getElement('.bulk-update');
this.$labelDropdown = this.form.find('.js-label-select');
diff --git a/app/assets/javascripts/issuable_index.js b/app/assets/javascripts/issuable_index.js
index 16f88cddce3..f3f8b6ec715 100644
--- a/app/assets/javascripts/issuable_index.js
+++ b/app/assets/javascripts/issuable_index.js
@@ -2,26 +2,13 @@ import $ from 'jquery';
import axios from './lib/utils/axios_utils';
import flash from './flash';
import { s__, __ } from './locale';
-import IssuableBulkUpdateSidebar from './issuable_bulk_update_sidebar';
-import IssuableBulkUpdateActions from './issuable_bulk_update_actions';
+import issuableInitBulkUpdateSidebar from './issuable_init_bulk_update_sidebar';
export default class IssuableIndex {
constructor(pagePrefix) {
- this.initBulkUpdate(pagePrefix);
+ issuableInitBulkUpdateSidebar.init(pagePrefix);
IssuableIndex.resetIncomingEmailToken();
}
- initBulkUpdate(pagePrefix) {
- const userCanBulkUpdate = $('.issues-bulk-update').length > 0;
- const alreadyInitialized = Boolean(this.bulkUpdateSidebar);
-
- if (userCanBulkUpdate && !alreadyInitialized) {
- IssuableBulkUpdateActions.init({
- prefixId: pagePrefix,
- });
-
- this.bulkUpdateSidebar = new IssuableBulkUpdateSidebar();
- }
- }
static resetIncomingEmailToken() {
const $resetToken = $('.incoming-email-token-reset');
diff --git a/app/assets/javascripts/issuable_init_bulk_update_sidebar.js b/app/assets/javascripts/issuable_init_bulk_update_sidebar.js
new file mode 100644
index 00000000000..da8969c80f3
--- /dev/null
+++ b/app/assets/javascripts/issuable_init_bulk_update_sidebar.js
@@ -0,0 +1,19 @@
+import IssuableBulkUpdateSidebar from './issuable_bulk_update_sidebar';
+import issuableBulkUpdateActions from './issuable_bulk_update_actions';
+
+export default {
+ bulkUpdateSidebar: null,
+
+ init(prefixId) {
+ const bulkUpdateEl = document.querySelector('.issues-bulk-update');
+ const alreadyInitialized = Boolean(this.bulkUpdateSidebar);
+
+ if (bulkUpdateEl && !alreadyInitialized) {
+ issuableBulkUpdateActions.init({ prefixId });
+
+ this.bulkUpdateSidebar = new IssuableBulkUpdateSidebar();
+ }
+
+ return this.bulkUpdateSidebar;
+ },
+};
diff --git a/app/assets/javascripts/labels_select.js b/app/assets/javascripts/labels_select.js
index 3f954b43ee3..bea43430edc 100644
--- a/app/assets/javascripts/labels_select.js
+++ b/app/assets/javascripts/labels_select.js
@@ -11,7 +11,7 @@ import CreateLabelDropdown from './create_label';
import flash from './flash';
import ModalStore from './boards/stores/modal_store';
import boardsStore from './boards/stores/boards_store';
-import { isEE, isScopedLabel } from '~/lib/utils/common_utils';
+import { isScopedLabel } from '~/lib/utils/common_utils';
export default class LabelsSelect {
constructor(els, options = {}) {
@@ -140,7 +140,7 @@ export default class LabelsSelect {
labelCount = data.labels.length;
// EE Specific
- if (isEE) {
+ if (IS_EE) {
/**
* For Scoped labels, the last label selected with the
* same key will be applied to the current issueable.
diff --git a/app/assets/javascripts/lib/utils/common_utils.js b/app/assets/javascripts/lib/utils/common_utils.js
index cc5e12aa467..5e90893b684 100644
--- a/app/assets/javascripts/lib/utils/common_utils.js
+++ b/app/assets/javascripts/lib/utils/common_utils.js
@@ -727,14 +727,6 @@ export const NavigationType = {
};
/**
- * Returns the value of `gon.ee`
- * Used to check if it's the EE codebase or the CE one.
- *
- * @returns Boolean
- */
-export const isEE = () => window.gon && window.gon.ee;
-
-/**
* Checks if the given Label has a special syntax `::` in
* it's title.
*
diff --git a/app/assets/javascripts/lib/utils/text_utility.js b/app/assets/javascripts/lib/utils/text_utility.js
index cc1d85fd97d..d38f59b5861 100644
--- a/app/assets/javascripts/lib/utils/text_utility.js
+++ b/app/assets/javascripts/lib/utils/text_utility.js
@@ -44,11 +44,18 @@ export const pluralize = (str, count) => str + (count > 1 || count === 0 ? 's' :
export const dasherize = str => str.replace(/[_\s]+/g, '-');
/**
- * Replaces whitespaces with hyphens and converts to lower case
+ * Replaces whitespaces with hyphens, convert to lower case and remove non-allowed special characters
* @param {String} str
* @returns {String}
*/
-export const slugifyWithHyphens = str => str.toLowerCase().replace(/\s+/g, '-');
+export const slugify = str => {
+ const slug = str
+ .trim()
+ .toLowerCase()
+ .replace(/[^a-zA-Z0-9_.-]+/g, '-');
+
+ return slug === '-' ? '' : slug;
+};
/**
* Replaces whitespaces with underscore and converts to lower case
diff --git a/app/assets/javascripts/main.js b/app/assets/javascripts/main.js
index 9f30a989295..9e97f345717 100644
--- a/app/assets/javascripts/main.js
+++ b/app/assets/javascripts/main.js
@@ -33,6 +33,8 @@ import GlFieldErrors from './gl_field_errors';
import initUserPopovers from './user_popovers';
import { __ } from './locale';
+import 'ee_else_ce/main_ee';
+
// expose jQuery as global (TODO: remove these)
window.jQuery = jQuery;
window.$ = jQuery;
@@ -119,11 +121,15 @@ function deferredInitialisation() {
.catch(() => {});
}
+ const glTooltipDelay = localStorage.getItem('gl-tooltip-delay');
+ const delay = glTooltipDelay ? JSON.parse(glTooltipDelay) : 0;
+
// Initialize tooltips
$body.tooltip({
selector: '.has-tooltip, [data-toggle="tooltip"]',
trigger: 'hover',
boundary: 'viewport',
+ delay,
});
// Initialize popovers
diff --git a/app/assets/javascripts/main_ee.js b/app/assets/javascripts/main_ee.js
new file mode 100644
index 00000000000..84d74775163
--- /dev/null
+++ b/app/assets/javascripts/main_ee.js
@@ -0,0 +1 @@
+// This is an empty file to satisfy ee_else_ce import for the EE main entry point
diff --git a/app/assets/javascripts/manual_ordering.js b/app/assets/javascripts/manual_ordering.js
index e16ddbfef7e..012d1e70410 100644
--- a/app/assets/javascripts/manual_ordering.js
+++ b/app/assets/javascripts/manual_ordering.js
@@ -21,7 +21,7 @@ const updateIssue = (url, issueList, { move_before_id, move_after_id }) =>
const initManualOrdering = () => {
const issueList = document.querySelector('.manual-ordering');
- if (!issueList || !(gon.features && gon.features.manualSorting)) {
+ if (!issueList || !(gon.features && gon.features.manualSorting) || !(gon.current_user_id > 0)) {
return;
}
diff --git a/app/assets/javascripts/monitoring/components/dashboard.vue b/app/assets/javascripts/monitoring/components/dashboard.vue
index 2cbda8ea05d..ba79a697df2 100644
--- a/app/assets/javascripts/monitoring/components/dashboard.vue
+++ b/app/assets/javascripts/monitoring/components/dashboard.vue
@@ -4,7 +4,6 @@ import _ from 'underscore';
import { mapActions, mapState } from 'vuex';
import { s__ } from '~/locale';
import Icon from '~/vue_shared/components/icon.vue';
-import '~/vue_shared/mixins/is_ee';
import { getParameterValues } from '~/lib/utils/url_utility';
import invalidUrl from '~/lib/utils/invalid_url';
import MonitorAreaChart from './charts/area.vue';
@@ -124,6 +123,11 @@ export default {
required: false,
default: '',
},
+ smallEmptyState: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
},
data() {
return {
@@ -155,6 +159,12 @@ export default {
selectedDashboardText() {
return this.currentDashboard || (this.allDashboards[0] && this.allDashboards[0].display_name);
},
+ addingMetricsAvailable() {
+ return IS_EE && this.canAddMetrics && !this.showEmptyState;
+ },
+ alertWidgetAvailable() {
+ return IS_EE && this.prometheusAlertsAvailable && this.alertsEndpoint;
+ },
},
created() {
this.setEndpoints({
@@ -308,7 +318,7 @@ export default {
</div>
</div>
<div class="d-flex">
- <div v-if="isEE && canAddMetrics && !showEmptyState">
+ <div v-if="addingMetricsAvailable">
<gl-button
v-gl-modal-directive="$options.addMetric.modalId"
class="js-add-metric-button text-success border-success"
@@ -367,7 +377,7 @@ export default {
group-id="monitor-area-chart"
>
<alert-widget
- v-if="isEE && prometheusAlertsAvailable && alertsEndpoint && graphData"
+ v-if="alertWidgetAvailable && graphData"
:alerts-endpoint="alertsEndpoint"
:relevant-queries="graphData.queries"
:alerts-to-manage="getGraphAlerts(graphData.queries)"
@@ -386,6 +396,7 @@ export default {
:empty-loading-svg-path="emptyLoadingSvgPath"
:empty-no-data-svg-path="emptyNoDataSvgPath"
:empty-unable-to-connect-svg-path="emptyUnableToConnectSvgPath"
+ :compact="smallEmptyState"
/>
</div>
</template>
diff --git a/app/assets/javascripts/monitoring/components/empty_state.vue b/app/assets/javascripts/monitoring/components/empty_state.vue
index a3c6de14aa4..1bb40447a3e 100644
--- a/app/assets/javascripts/monitoring/components/empty_state.vue
+++ b/app/assets/javascripts/monitoring/components/empty_state.vue
@@ -1,7 +1,11 @@
<script>
import { __ } from '~/locale';
+import { GlEmptyState } from '@gitlab/ui';
export default {
+ components: {
+ GlEmptyState,
+ },
props: {
documentationPath: {
type: String,
@@ -37,6 +41,11 @@ export default {
type: String,
required: true,
},
+ compact: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
},
data() {
return {
@@ -58,6 +67,8 @@ export default {
If this takes a long time, ensure that data is available.`),
buttonText: __('View documentation'),
buttonPath: this.documentationPath,
+ secondaryButtonText: '',
+ secondaryButtonPath: '',
},
noData: {
svgUrl: this.emptyNoDataSvgPath,
@@ -66,13 +77,19 @@ export default {
no data to display.`),
buttonText: __('Configure Prometheus'),
buttonPath: this.settingsPath,
+ secondaryButtonText: '',
+ secondaryButtonPath: '',
},
unableToConnect: {
svgUrl: this.emptyUnableToConnectSvgPath,
title: __('Unable to connect to Prometheus server'),
- description: 'Ensure connectivity is available from the GitLab server to the ',
+ description: __(
+ 'Ensure connectivity is available from the GitLab server to the Prometheus server',
+ ),
buttonText: __('View documentation'),
buttonPath: this.documentationPath,
+ secondaryButtonText: __('Configure Prometheus'),
+ secondaryButtonPath: this.settingsPath,
},
},
};
@@ -81,45 +98,19 @@ export default {
currentState() {
return this.states[this.selectedState];
},
- showButtonDescription() {
- if (this.selectedState === 'unableToConnect') return true;
- return false;
- },
},
};
</script>
<template>
- <div class="row empty-state js-empty-state">
- <div class="col-12">
- <div class="state-svg svg-content">
- <img :src="currentState.svgUrl" />
- </div>
- </div>
-
- <div class="col-12">
- <div class="text-content">
- <h4 class="state-title text-center">{{ currentState.title }}</h4>
- <p class="state-description">
- {{ currentState.description }}
- <a v-if="showButtonDescription" :href="settingsPath">{{ __('Prometheus server') }}</a>
- </p>
-
- <div class="text-center">
- <a
- v-if="currentState.buttonPath"
- :href="currentState.buttonPath"
- class="btn btn-success"
- >{{ currentState.buttonText }}</a
- >
- <a
- v-if="currentState.secondaryButtonPath"
- :href="currentState.secondaryButtonPath"
- class="btn"
- >{{ currentState.secondaryButtonText }}</a
- >
- </div>
- </div>
- </div>
- </div>
+ <gl-empty-state
+ :title="currentState.title"
+ :description="currentState.description"
+ :primary-button-text="currentState.buttonText"
+ :primary-button-link="currentState.buttonPath"
+ :secondary-button-text="currentState.secondaryButtonText"
+ :secondary-button-link="currentState.secondaryButtonPath"
+ :svg-path="currentState.svgUrl"
+ :compact="compact"
+ />
</template>
diff --git a/app/assets/javascripts/monitoring/stores/utils.js b/app/assets/javascripts/monitoring/stores/utils.js
index 84e1f1c4c20..721942f9d3b 100644
--- a/app/assets/javascripts/monitoring/stores/utils.js
+++ b/app/assets/javascripts/monitoring/stores/utils.js
@@ -36,15 +36,26 @@ function removeTimeSeriesNoData(queries) {
// { metricId: 2, ...query2Attrs }] },
// { title: 'new title', y_label: 'MB', queries: [{ metricId: 3, ...query3Attrs }]}
// ]
-function groupQueriesByChartInfo(metrics) {
+export function groupQueriesByChartInfo(metrics) {
const metricsByChart = metrics.reduce((accumulator, metric) => {
const { queries, ...chart } = metric;
- const metricId = chart.id ? chart.id.toString() : null;
const chartKey = `${chart.title}|${chart.y_label}`;
accumulator[chartKey] = accumulator[chartKey] || { ...chart, queries: [] };
- queries.forEach(queryAttrs => accumulator[chartKey].queries.push({ metricId, ...queryAttrs }));
+ queries.forEach(queryAttrs => {
+ let metricId;
+
+ if (chart.id) {
+ metricId = chart.id.toString();
+ } else if (queryAttrs.metric_id) {
+ metricId = queryAttrs.metric_id.toString();
+ } else {
+ metricId = null;
+ }
+
+ accumulator[chartKey].queries.push({ metricId, ...queryAttrs });
+ });
return accumulator;
}, {});
diff --git a/app/assets/javascripts/notes/components/comment_form.vue b/app/assets/javascripts/notes/components/comment_form.vue
index 075c28e8d07..fda494fec07 100644
--- a/app/assets/javascripts/notes/components/comment_form.vue
+++ b/app/assets/javascripts/notes/components/comment_form.vue
@@ -13,6 +13,7 @@ import {
splitCamelCase,
slugifyWithUnderscore,
} from '../../lib/utils/text_utility';
+import { refreshUserMergeRequestCounts } from '~/commons/nav/user_merge_requests';
import * as constants from '../constants';
import eventHub from '../event_hub';
import issueWarning from '../../vue_shared/components/issue/issue_warning.vue';
@@ -65,14 +66,12 @@ export default {
return this.getUserData.id;
},
commentButtonTitle() {
- return this.noteType === constants.COMMENT ? 'Comment' : 'Start discussion';
+ return this.noteType === constants.COMMENT ? __('Comment') : __('Start thread');
},
startDiscussionDescription() {
- let text = 'Discuss a specific suggestion or question';
- if (this.getNoteableData.noteableType === constants.MERGE_REQUEST_NOTEABLE_TYPE) {
- text += ' that needs to be resolved';
- }
- return `${text}.`;
+ return this.getNoteableData.noteableType === constants.MERGE_REQUEST_NOTEABLE_TYPE
+ ? __('Discuss a specific suggestion or question that needs to be resolved.')
+ : __('Discuss a specific suggestion or question.');
},
isOpen() {
return this.openState === constants.OPENED || this.openState === constants.REOPENED;
@@ -127,8 +126,8 @@ export default {
},
issuableTypeTitle() {
return this.noteableType === constants.MERGE_REQUEST_NOTEABLE_TYPE
- ? 'merge request'
- : 'issue';
+ ? __('merge request')
+ : __('issue');
},
trackingLabel() {
return slugifyWithUnderscore(`${this.commentButtonTitle} button`);
@@ -203,7 +202,7 @@ export default {
this.discard();
} else {
Flash(
- 'Something went wrong while adding your comment. Please try again.',
+ __('Something went wrong while adding your comment. Please try again.'),
'alert',
this.$refs.commentForm,
);
@@ -219,8 +218,9 @@ export default {
.catch(() => {
this.enableButton();
this.discard(false);
- const msg = `Your comment could not be submitted!
-Please check your network connection and try again.`;
+ const msg = __(
+ 'Your comment could not be submitted! Please check your network connection and try again.',
+ );
Flash(msg, 'alert', this.$el);
this.note = noteData.data.note.note; // Restore textarea content.
this.removePlaceholderNotes();
@@ -235,7 +235,10 @@ Please check your network connection and try again.`;
toggleIssueState() {
if (this.isOpen) {
this.closeIssue()
- .then(() => this.enableButton())
+ .then(() => {
+ this.enableButton();
+ refreshUserMergeRequestCounts();
+ })
.catch(() => {
this.enableButton();
this.toggleStateButtonLoading(false);
@@ -248,7 +251,10 @@ Please check your network connection and try again.`;
});
} else {
this.reopenIssue()
- .then(() => this.enableButton())
+ .then(() => {
+ this.enableButton();
+ refreshUserMergeRequestCounts();
+ })
.catch(({ data }) => {
this.enableButton();
this.toggleStateButtonLoading(false);
@@ -298,7 +304,7 @@ Please check your network connection and try again.`;
const noteableType = capitalizeFirstCharacter(convertToCamelCase(this.noteableType));
this.autosave = new Autosave($(this.$refs.textarea), [
- 'Note',
+ __('Note'),
noteableType,
this.getNoteableData.id,
]);
@@ -359,8 +365,8 @@ Please check your network connection and try again.`;
class="note-textarea js-vue-comment-form js-note-text
js-gfm-input js-autosize markdown-area js-vue-textarea qa-comment-input"
data-supports-quick-actions="true"
- aria-label="Description"
- placeholder="Write a comment or drag your files here…"
+ :aria-label="__('Description')"
+ :placeholder="__('Write a comment or drag your files here…')"
@keydown.up="editCurrentUserLastNote()"
@keydown.meta.enter="handleSave()"
@keydown.ctrl.enter="handleSave()"
@@ -381,7 +387,7 @@ append-right-10 comment-type-dropdown js-comment-type-dropdown droplab-dropdown"
data-track-event="click_button"
@click.prevent="handleSave()"
>
- {{ __(commentButtonTitle) }}
+ {{ commentButtonTitle }}
</button>
<button
:disabled="isSubmitButtonDisabled"
@@ -390,7 +396,7 @@ append-right-10 comment-type-dropdown js-comment-type-dropdown droplab-dropdown"
class="btn btn-success note-type-toggle js-note-new-discussion dropdown-toggle qa-note-dropdown"
data-display="static"
data-toggle="dropdown"
- aria-label="Open comment type dropdown"
+ :aria-label="__('Open comment type dropdown')"
>
<i aria-hidden="true" class="fa fa-caret-down toggle-icon"> </i>
</button>
@@ -404,8 +410,14 @@ append-right-10 comment-type-dropdown js-comment-type-dropdown droplab-dropdown"
>
<i aria-hidden="true" class="fa fa-check icon"> </i>
<div class="description">
- <strong>Comment</strong>
- <p>Add a general comment to this {{ noteableDisplayName }}.</p>
+ <strong>{{ __('Comment') }}</strong>
+ <p>
+ {{
+ sprintf(__('Add a general comment to this %{noteableDisplayName}.'), {
+ noteableDisplayName,
+ })
+ }}
+ </p>
</div>
</button>
</li>
@@ -418,7 +430,7 @@ append-right-10 comment-type-dropdown js-comment-type-dropdown droplab-dropdown"
>
<i aria-hidden="true" class="fa fa-check icon"> </i>
<div class="description">
- <strong>Start discussion</strong>
+ <strong>{{ __('Start thread') }}</strong>
<p>{{ startDiscussionDescription }}</p>
</div>
</button>
diff --git a/app/assets/javascripts/notes/components/diff_with_note.vue b/app/assets/javascripts/notes/components/diff_with_note.vue
index 54c242b2fda..164e79c6294 100644
--- a/app/assets/javascripts/notes/components/diff_with_note.vue
+++ b/app/assets/javascripts/notes/components/diff_with_note.vue
@@ -100,7 +100,7 @@ export default {
class="btn-link btn-link-retry btn-no-padding js-toggle-lazy-diff-retry-button"
@click="fetchDiff"
>
- Try again
+ {{ __('Try again') }}
</button>
</td>
<td v-else class="line_content js-success-lazy-load">
diff --git a/app/assets/javascripts/notes/components/discussion_actions.vue b/app/assets/javascripts/notes/components/discussion_actions.vue
index 1357a5268d6..f4570c1292c 100644
--- a/app/assets/javascripts/notes/components/discussion_actions.vue
+++ b/app/assets/javascripts/notes/components/discussion_actions.vue
@@ -39,15 +39,23 @@ export default {
</script>
<template>
- <div class="discussion-with-resolve-btn clearfix">
- <reply-placeholder class="qa-discussion-reply" @onClick="$emit('showReplyForm')" />
-
- <div class="btn-group discussion-actions" role="group">
- <resolve-discussion-button
- v-if="discussion.resolvable"
- :is-resolving="isResolving"
- :button-title="resolveButtonTitle"
- @onClick="$emit('resolve')"
+ <div class="discussion-with-resolve-btn">
+ <reply-placeholder
+ :button-text="s__('MergeRequests|Reply...')"
+ class="qa-discussion-reply"
+ @onClick="$emit('showReplyForm')"
+ />
+ <resolve-discussion-button
+ v-if="discussion.resolvable"
+ :is-resolving="isResolving"
+ :button-title="resolveButtonTitle"
+ @onClick="$emit('resolve')"
+ />
+ <div v-if="discussion.resolvable" class="btn-group discussion-actions ml-sm-2" role="group">
+ <resolve-with-issue-button v-if="resolveWithIssuePath" :url="resolveWithIssuePath" />
+ <jump-to-next-discussion-button
+ v-if="shouldShowJumpToNextDiscussion"
+ @onClick="$emit('jumpToNextDiscussion')"
/>
<resolve-with-issue-button
v-if="discussion.resolvable && resolveWithIssuePath"
diff --git a/app/assets/javascripts/notes/components/discussion_counter.vue b/app/assets/javascripts/notes/components/discussion_counter.vue
index efd84f5722c..d7ffa0abb79 100644
--- a/app/assets/javascripts/notes/components/discussion_counter.vue
+++ b/app/assets/javascripts/notes/components/discussion_counter.vue
@@ -61,7 +61,7 @@ export default {
</span>
<span class="line-resolve-text">
{{ resolvedDiscussionsCount }}/{{ resolvableDiscussionsCount }}
- {{ n__('discussion resolved', 'discussions resolved', resolvableDiscussionsCount) }}
+ {{ n__('thread resolved', 'threads resolved', resolvableDiscussionsCount) }}
</span>
</div>
<div
@@ -72,7 +72,7 @@ export default {
<a
v-gl-tooltip
:href="resolveAllDiscussionsIssuePath"
- :title="s__('Resolve all discussions in new issue')"
+ :title="s__('Resolve all threads in new issue')"
class="new-issue-for-discussion btn btn-default discussion-create-issue-btn"
>
<icon name="issue-new" />
@@ -81,7 +81,7 @@ export default {
<div v-if="isLoggedIn && !allResolved" class="btn-group btn-group-sm" role="group">
<button
v-gl-tooltip
- title="Jump to first unresolved discussion"
+ title="Jump to first unresolved thread"
class="btn btn-default discussion-next-btn"
@click="jumpToFirstUnresolvedDiscussion"
>
diff --git a/app/assets/javascripts/notes/components/discussion_notes.vue b/app/assets/javascripts/notes/components/discussion_notes.vue
index 30971ad5227..0b136549c14 100644
--- a/app/assets/javascripts/notes/components/discussion_notes.vue
+++ b/app/assets/javascripts/notes/components/discussion_notes.vue
@@ -1,19 +1,21 @@
<script>
-import { mapGetters } from 'vuex';
+import { mapGetters, mapActions } from 'vuex';
import { SYSTEM_NOTE } from '../constants';
import { __ } from '~/locale';
-import NoteableNote from './noteable_note.vue';
-import PlaceholderNote from '../../vue_shared/components/notes/placeholder_note.vue';
-import PlaceholderSystemNote from '../../vue_shared/components/notes/placeholder_system_note.vue';
+import PlaceholderNote from '~/vue_shared/components/notes/placeholder_note.vue';
+import PlaceholderSystemNote from '~/vue_shared/components/notes/placeholder_system_note.vue';
import SystemNote from '~/vue_shared/components/notes/system_note.vue';
+import NoteableNote from './noteable_note.vue';
import ToggleRepliesWidget from './toggle_replies_widget.vue';
import NoteEditedText from './note_edited_text.vue';
+import DiscussionNotesRepliesWrapper from './discussion_notes_replies_wrapper.vue';
export default {
name: 'DiscussionNotes',
components: {
ToggleRepliesWidget,
NoteEditedText,
+ DiscussionNotesRepliesWrapper,
},
props: {
discussion: {
@@ -72,6 +74,7 @@ export default {
},
},
methods: {
+ ...mapActions(['toggleDiscussion']),
componentName(note) {
if (note.isPlaceholderNote) {
if (note.placeholderType === SYSTEM_NOTE) {
@@ -101,7 +104,7 @@ export default {
<component
:is="componentName(firstNote)"
:note="componentData(firstNote)"
- :line="line"
+ :line="line || diffLine"
:commit="commit"
:help-page-path="helpPagePath"
:show-reply-button="userCanReply"
@@ -118,23 +121,27 @@ export default {
/>
<slot slot="avatar-badge" name="avatar-badge"></slot>
</component>
- <toggle-replies-widget
- v-if="hasReplies"
- :collapsed="!isExpanded"
- :replies="replies"
- @toggle="$emit('toggleDiscussion')"
- />
- <template v-if="isExpanded">
- <component
- :is="componentName(note)"
- v-for="note in replies"
- :key="note.id"
- :note="componentData(note)"
- :help-page-path="helpPagePath"
- :line="line"
- @handleDeleteNote="$emit('deleteNote')"
+ <discussion-notes-replies-wrapper :is-diff-discussion="discussion.diff_discussion">
+ <toggle-replies-widget
+ v-if="hasReplies"
+ :collapsed="!isExpanded"
+ :replies="replies"
+ :class="{ 'discussion-toggle-replies': discussion.diff_discussion }"
+ @toggle="toggleDiscussion({ discussionId: discussion.id })"
/>
- </template>
+ <template v-if="isExpanded">
+ <component
+ :is="componentName(note)"
+ v-for="note in replies"
+ :key="note.id"
+ :note="componentData(note)"
+ :help-page-path="helpPagePath"
+ :line="line"
+ @handleDeleteNote="$emit('deleteNote')"
+ />
+ </template>
+ <slot :show-replies="isExpanded || !hasReplies" name="footer"></slot>
+ </discussion-notes-replies-wrapper>
</template>
<template v-else>
<component
@@ -148,8 +155,8 @@ export default {
>
<slot v-if="index === 0" slot="avatar-badge" name="avatar-badge"></slot>
</component>
+ <slot :show-replies="isExpanded || !hasReplies" name="footer"></slot>
</template>
</ul>
- <slot :show-replies="isExpanded || !hasReplies" name="footer"></slot>
</div>
</template>
diff --git a/app/assets/javascripts/notes/components/discussion_notes_replies_wrapper.vue b/app/assets/javascripts/notes/components/discussion_notes_replies_wrapper.vue
new file mode 100644
index 00000000000..2ddca56ddd5
--- /dev/null
+++ b/app/assets/javascripts/notes/components/discussion_notes_replies_wrapper.vue
@@ -0,0 +1,27 @@
+<script>
+/**
+ * Wrapper for discussion notes replies section.
+ *
+ * This is a functional component using the render method because in some cases
+ * the wrapper is not needed and we want to simply render along the children.
+ */
+export default {
+ functional: true,
+ props: {
+ isDiffDiscussion: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ },
+ render(h, { props, children }) {
+ if (props.isDiffDiscussion) {
+ return h('li', { class: 'discussion-collapsible bordered-box clearfix' }, [
+ h('ul', { class: 'notes' }, children),
+ ]);
+ }
+
+ return children;
+ },
+};
+</script>
diff --git a/app/assets/javascripts/notes/components/discussion_reply_placeholder.vue b/app/assets/javascripts/notes/components/discussion_reply_placeholder.vue
index ea590905e3c..0204169214b 100644
--- a/app/assets/javascripts/notes/components/discussion_reply_placeholder.vue
+++ b/app/assets/javascripts/notes/components/discussion_reply_placeholder.vue
@@ -1,6 +1,12 @@
<script>
export default {
name: 'ReplyPlaceholder',
+ props: {
+ buttonText: {
+ type: String,
+ required: true,
+ },
+ },
};
</script>
@@ -12,6 +18,6 @@ export default {
:title="s__('MergeRequests|Add a reply')"
@click="$emit('onClick')"
>
- {{ s__('MergeRequests|Reply...') }}
+ {{ buttonText }}
</button>
</template>
diff --git a/app/assets/javascripts/notes/components/discussion_resolve_with_issue_button.vue b/app/assets/javascripts/notes/components/discussion_resolve_with_issue_button.vue
index e413398696a..f03e6fd73d7 100644
--- a/app/assets/javascripts/notes/components/discussion_resolve_with_issue_button.vue
+++ b/app/assets/javascripts/notes/components/discussion_resolve_with_issue_button.vue
@@ -25,7 +25,7 @@ export default {
<gl-button
v-gl-tooltip
:href="url"
- :title="s__('MergeRequests|Resolve this discussion in a new issue')"
+ :title="s__('MergeRequests|Resolve this thread in a new issue')"
class="new-issue-for-discussion discussion-create-issue-btn"
>
<icon name="issue-new" />
diff --git a/app/assets/javascripts/notes/components/note_awards_list.vue b/app/assets/javascripts/notes/components/note_awards_list.vue
index 941b6d5cab3..d4a57d5d58d 100644
--- a/app/assets/javascripts/notes/components/note_awards_list.vue
+++ b/app/assets/javascripts/notes/components/note_awards_list.vue
@@ -4,6 +4,7 @@ import tooltip from '~/vue_shared/directives/tooltip';
import Icon from '~/vue_shared/components/icon.vue';
import Flash from '../../flash';
import { glEmojiTag } from '../../emoji';
+import { __, sprintf } from '~/locale';
export default {
components: {
@@ -108,23 +109,26 @@ export default {
// Add myself to the beginning of the list so title will start with You.
if (hasReactionByCurrentUser) {
- namesToShow.unshift('You');
+ namesToShow.unshift(__('You'));
}
let title = '';
// We have 10+ awarded user, join them with comma and add `and x more`.
if (remainingAwardList.length) {
- title = `${namesToShow.join(', ')}, and ${remainingAwardList.length} more.`;
+ title = sprintf(__(`%{listToShow}, and %{awardsListLength} more.`), {
+ listToShow: namesToShow.join(', '),
+ awardsListLength: remainingAwardList.length,
+ });
} else if (namesToShow.length > 1) {
// Join all names with comma but not the last one, it will be added with and text.
title = namesToShow.slice(0, namesToShow.length - 1).join(', ');
// If we have more than 2 users we need an extra comma before and text.
title += namesToShow.length > 2 ? ',' : '';
- title += ` and ${namesToShow.slice(-1)}`; // Append and text
+ title += sprintf(__(` and %{sliced}`), { sliced: namesToShow.slice(-1) }); // Append and text
} else {
// We have only 2 users so join them with and.
- title = namesToShow.join(' and ');
+ title = namesToShow.join(__(' and '));
}
return title;
@@ -155,7 +159,7 @@ export default {
awardName: parsedName,
};
- this.toggleAwardRequest(data).catch(() => Flash('Something went wrong on our end.'));
+ this.toggleAwardRequest(data).catch(() => Flash(__('Something went wrong on our end.')));
},
},
};
@@ -184,7 +188,7 @@ export default {
:class="{ 'js-user-authored': isAuthoredByMe }"
class="award-control btn js-add-award"
title="Add reaction"
- aria-label="Add reaction"
+ :aria-label="__('Add reaction')"
data-boundary="viewport"
type="button"
>
diff --git a/app/assets/javascripts/notes/components/note_form.vue b/app/assets/javascripts/notes/components/note_form.vue
index 042ed196933..3823861c0b9 100644
--- a/app/assets/javascripts/notes/components/note_form.vue
+++ b/app/assets/javascripts/notes/components/note_form.vue
@@ -1,14 +1,14 @@
<script>
import { mergeUrlParams } from '~/lib/utils/url_utility';
import { mapGetters, mapActions } from 'vuex';
+import noteFormMixin from 'ee_else_ce/notes/mixins/note_form';
import eventHub from '../event_hub';
import issueWarning from '../../vue_shared/components/issue/issue_warning.vue';
import markdownField from '../../vue_shared/components/markdown/field.vue';
import issuableStateMixin from '../mixins/issuable_state';
import resolvable from '../mixins/resolvable';
-import { __ } from '~/locale';
+import { __, sprintf } from '~/locale';
import { getDraft, updateDraft } from '~/lib/utils/autosave';
-import noteFormMixin from 'ee_else_ce/notes/mixins/note_form';
export default {
name: 'NoteForm',
@@ -174,6 +174,18 @@ export default {
(this.line && this.line.can_receive_suggestion)
);
},
+ changedCommentText() {
+ return sprintf(
+ __(
+ 'This comment has changed since you started editing, please review the %{startTag}updated comment%{endTag} to ensure information is not lost.',
+ ),
+ {
+ startTag: `<a href="${this.noteHash}" target="_blank" rel="noopener noreferrer">`,
+ endTag: '</a>',
+ },
+ false,
+ );
+ },
},
watch: {
noteBody() {
@@ -228,11 +240,11 @@ export default {
<template>
<div ref="editNoteForm" class="note-edit-form current-note-edit-form js-discussion-note-form">
- <div v-if="conflictWhileEditing" class="js-conflict-edit-warning alert alert-danger">
- This comment has changed since you started editing, please review the
- <a :href="noteHash" target="_blank" rel="noopener noreferrer">updated comment</a> to ensure
- information is not lost.
- </div>
+ <div
+ v-if="conflictWhileEditing"
+ class="js-conflict-edit-warning alert alert-danger"
+ v-html="changedCommentText"
+ ></div>
<div class="flash-container timeline-content"></div>
<form :data-line-code="lineCode" class="edit-note common-note-form js-quick-submit gfm-form">
<issue-warning
@@ -264,8 +276,8 @@ export default {
name="note[note]"
class="note-textarea js-gfm-input js-note-text js-autosize markdown-area js-vue-issue-note-form js-vue-textarea qa-reply-input"
dir="auto"
- aria-label="Description"
- placeholder="Write a comment or drag your files here…"
+ :aria-label="__('Description')"
+ :placeholder="__('Write a comment or drag your files here…')"
@keydown.meta.enter="handleKeySubmit()"
@keydown.ctrl.enter="handleKeySubmit()"
@keydown.exact.up="editMyLastNote()"
@@ -283,11 +295,11 @@ export default {
type="checkbox"
class="qa-unresolve-review-discussion"
/>
- {{ __('Unresolve discussion') }}
+ {{ __('Unresolve thread') }}
</template>
<template v-else>
<input v-model="isResolving" type="checkbox" class="qa-resolve-review-discussion" />
- {{ __('Resolve discussion') }}
+ {{ __('Resolve thread') }}
</template>
</label>
</p>
@@ -339,7 +351,7 @@ export default {
type="button"
@click="cancelHandler()"
>
- Cancel
+ {{ __('Cancel') }}
</button>
</template>
</div>
diff --git a/app/assets/javascripts/notes/components/note_header.vue b/app/assets/javascripts/notes/components/note_header.vue
index fbf82fab9e9..3158e086f6c 100644
--- a/app/assets/javascripts/notes/components/note_header.vue
+++ b/app/assets/javascripts/notes/components/note_header.vue
@@ -70,7 +70,7 @@ export default {
@click="handleToggle"
>
<i :class="toggleChevronClass" class="fa" aria-hidden="true"></i>
- {{ __('Toggle discussion') }}
+ {{ __('Toggle thread') }}
</button>
</div>
<a
@@ -103,7 +103,7 @@ export default {
</template>
<i
class="fa fa-spinner fa-spin editing-spinner"
- aria-label="Comment is being updated"
+ :aria-label="__('Comment is being updated')"
aria-hidden="true"
></i>
</span>
diff --git a/app/assets/javascripts/notes/components/note_signed_out_widget.vue b/app/assets/javascripts/notes/components/note_signed_out_widget.vue
index e3eb92956b1..ccfe84ab098 100644
--- a/app/assets/javascripts/notes/components/note_signed_out_widget.vue
+++ b/app/assets/javascripts/notes/components/note_signed_out_widget.vue
@@ -1,5 +1,6 @@
<script>
import { mapGetters } from 'vuex';
+import { __, sprintf } from '~/locale';
export default {
computed: {
@@ -10,12 +11,24 @@ export default {
signInLink() {
return this.getNotesDataByProp('newSessionPath');
},
+ signedOutText() {
+ return sprintf(
+ __(
+ 'Please %{startTagRegister}register%{endRegisterTag} or %{startTagSignIn}sign in%{endSignInTag} to reply',
+ ),
+ {
+ startTagRegister: `<a href="${this.registerLink}">`,
+ startTagSignIn: `<a href="${this.signInLink}">`,
+ endRegisterTag: '</a>',
+ endSignInTag: '</a>',
+ },
+ false,
+ );
+ },
},
};
</script>
<template>
- <div class="disabled-comment text-center">
- Please <a :href="registerLink">register</a> or <a :href="signInLink">sign in</a> to reply
- </div>
+ <div class="disabled-comment text-center" v-html="signedOutText"></div>
</template>
diff --git a/app/assets/javascripts/notes/components/noteable_discussion.vue b/app/assets/javascripts/notes/components/noteable_discussion.vue
index b8eaff32cce..ac743d9f4b8 100644
--- a/app/assets/javascripts/notes/components/noteable_discussion.vue
+++ b/app/assets/javascripts/notes/components/noteable_discussion.vue
@@ -132,7 +132,7 @@ export default {
return this.discussion.diff_discussion && this.renderDiffFile;
},
shouldGroupReplies() {
- return !this.shouldRenderDiffs && !this.discussion.diff_discussion;
+ return !this.shouldRenderDiffs;
},
wrapperComponent() {
return this.shouldRenderDiffs ? diffWithNote : 'div';
@@ -144,15 +144,6 @@ export default {
return {};
},
- componentClassName() {
- if (this.shouldRenderDiffs) {
- if (!this.lastUpdatedAt && !this.discussion.resolved) {
- return 'unresolved';
- }
- }
-
- return '';
- },
isExpanded() {
return this.discussion.expanded || this.alwaysExpanded;
},
@@ -174,22 +165,20 @@ export default {
active: isActive,
} = this.discussion;
- let text = s__('MergeRequests|started a discussion');
+ let text = s__('MergeRequests|started a thread');
if (isForCommit) {
- text = s__(
- 'MergeRequests|started a discussion on commit %{linkStart}%{commitId}%{linkEnd}',
- );
+ text = s__('MergeRequests|started a thread on commit %{linkStart}%{commitId}%{linkEnd}');
} else if (isDiffDiscussion && commitId) {
text = isActive
- ? s__('MergeRequests|started a discussion on commit %{linkStart}%{commitId}%{linkEnd}')
+ ? s__('MergeRequests|started a thread on commit %{linkStart}%{commitId}%{linkEnd}')
: s__(
- 'MergeRequests|started a discussion on an outdated change in commit %{linkStart}%{commitId}%{linkEnd}',
+ 'MergeRequests|started a thread on an outdated change in commit %{linkStart}%{commitId}%{linkEnd}',
);
} else if (isDiffDiscussion) {
text = isActive
- ? s__('MergeRequests|started a discussion on %{linkStart}the diff%{linkEnd}')
+ ? s__('MergeRequests|started a thread on %{linkStart}the diff%{linkEnd}')
: s__(
- 'MergeRequests|started a discussion on %{linkStart}an old version of the diff%{linkEnd}',
+ 'MergeRequests|started a thread on %{linkStart}an old version of the diff%{linkEnd}',
);
}
@@ -250,6 +239,11 @@ export default {
clearDraft(this.autosaveKey);
},
saveReply(noteText, form, callback) {
+ if (!noteText) {
+ this.cancelReplyForm();
+ callback();
+ return;
+ }
const postData = {
in_reply_to_discussion_id: this.discussion.reply_id,
target_type: this.getNoteableData.targetType,
@@ -280,8 +274,9 @@ export default {
this.removePlaceholderNotes();
this.isReplying = true;
this.$nextTick(() => {
- const msg = `Your comment could not be submitted!
-Please check your network connection and try again.`;
+ const msg = __(
+ 'Your comment could not be submitted! Please check your network connection and try again.',
+ );
Flash(msg, 'alert', this.$el);
this.$refs.noteForm.note = noteText;
callback(err);
@@ -309,11 +304,11 @@ Please check your network connection and try again.`;
</script>
<template>
- <timeline-entry-item class="note note-discussion" :class="componentClassName">
+ <timeline-entry-item class="note note-discussion">
<div class="timeline-content">
<div :data-discussion-id="discussion.id" class="discussion js-discussion-container">
<div v-if="shouldRenderDiffs" class="discussion-header note-wrapper">
- <div v-once class="timeline-icon">
+ <div v-once class="timeline-icon align-self-start flex-shrink-0">
<user-avatar-link
v-if="author"
:link-href="author.path"
@@ -322,7 +317,7 @@ Please check your network connection and try again.`;
:img-size="40"
/>
</div>
- <div class="timeline-content">
+ <div class="timeline-content w-100">
<note-header
:author="author"
:created-at="firstNote.created_at"
@@ -363,7 +358,6 @@ Please check your network connection and try again.`;
:line="line"
:should-group-replies="shouldGroupReplies"
@startReplying="showReplyForm"
- @toggleDiscussion="toggleDiscussionHandler"
@deleteNote="deleteNoteHandler"
>
<slot slot="avatar-badge" name="avatar-badge"></slot>
@@ -376,7 +370,7 @@ Please check your network connection and try again.`;
<div
v-else-if="showReplies"
:class="{ 'is-replying': isReplying }"
- class="discussion-reply-holder"
+ class="discussion-reply-holder clearfix"
>
<user-avatar-link
v-if="!isReplying && userCanReply"
diff --git a/app/assets/javascripts/notes/components/noteable_note.vue b/app/assets/javascripts/notes/components/noteable_note.vue
index aa80e25a3e0..2f201839d45 100644
--- a/app/assets/javascripts/notes/components/noteable_note.vue
+++ b/app/assets/javascripts/notes/components/noteable_note.vue
@@ -5,7 +5,7 @@ import { escape } from 'underscore';
import { truncateSha } from '~/lib/utils/text_utility';
import TimelineEntryItem from '~/vue_shared/components/notes/timeline_entry_item.vue';
import draftMixin from 'ee_else_ce/notes/mixins/draft';
-import { s__, sprintf } from '../../locale';
+import { __, s__, sprintf } from '../../locale';
import Flash from '../../flash';
import userAvatarLink from '../../vue_shared/components/user_avatar/user_avatar_link.vue';
import noteHeader from './note_header.vue';
@@ -128,9 +128,13 @@ export default {
this.$emit('handleEdit');
},
deleteHandler() {
- const typeOfComment = this.note.isDraft ? 'pending comment' : 'comment';
- // eslint-disable-next-line no-alert
- if (window.confirm(`Are you sure you want to delete this ${typeOfComment}?`)) {
+ const typeOfComment = this.note.isDraft ? __('pending comment') : __('comment');
+ if (
+ // eslint-disable-next-line no-alert
+ window.confirm(
+ sprintf(__('Are you sure you want to delete this %{typeOfComment}?'), { typeOfComment }),
+ )
+ ) {
this.isDeleting = true;
this.$emit('handleDeleteNote', this.note);
@@ -141,7 +145,7 @@ export default {
this.isDeleting = false;
})
.catch(() => {
- Flash('Something went wrong while deleting your note. Please try again.');
+ Flash(__('Something went wrong while deleting your note. Please try again.'));
this.isDeleting = false;
});
}
@@ -185,7 +189,7 @@ export default {
this.isRequesting = false;
this.isEditing = true;
this.$nextTick(() => {
- const msg = 'Something went wrong while editing your comment. Please try again.';
+ const msg = __('Something went wrong while editing your comment. Please try again.');
Flash(msg, 'alert', this.$el);
this.recoverNoteContent(noteText);
callback();
@@ -195,7 +199,7 @@ export default {
formCancelHandler(shouldConfirm, isDirty) {
if (shouldConfirm && isDirty) {
// eslint-disable-next-line no-alert
- if (!window.confirm('Are you sure you want to cancel editing this comment?')) return;
+ if (!window.confirm(__('Are you sure you want to cancel editing this comment?'))) return;
}
this.$refs.noteBody.resetAutoSave();
if (this.oldContent) {
diff --git a/app/assets/javascripts/notes/components/notes_app.vue b/app/assets/javascripts/notes/components/notes_app.vue
index 4d00e957973..a0695f9e191 100644
--- a/app/assets/javascripts/notes/components/notes_app.vue
+++ b/app/assets/javascripts/notes/components/notes_app.vue
@@ -1,4 +1,5 @@
<script>
+import { __ } from '~/locale';
import { mapGetters, mapActions } from 'vuex';
import { getLocationHash } from '../../lib/utils/url_utility';
import Flash from '../../flash';
@@ -170,7 +171,7 @@ export default {
.catch(() => {
this.setLoadingState(false);
this.setNotesFetchedState(true);
- Flash('Something went wrong while fetching comments. Please try again.');
+ Flash(__('Something went wrong while fetching comments. Please try again.'));
});
},
initPolling() {
diff --git a/app/assets/javascripts/notes/index.js b/app/assets/javascripts/notes/index.js
index 57dd1c5cab2..c70c0e4095c 100644
--- a/app/assets/javascripts/notes/index.js
+++ b/app/assets/javascripts/notes/index.js
@@ -1,5 +1,4 @@
import Vue from 'vue';
-import { isEE } from '~/lib/utils/common_utils';
import initNoteStats from 'ee_else_ce/event_tracking/notes';
import notesApp from './components/notes_app.vue';
import initDiscussionFilters from './discussion_filters';
@@ -41,9 +40,7 @@ document.addEventListener('DOMContentLoaded', () => {
};
},
mounted() {
- if (isEE) {
- initNoteStats();
- }
+ initNoteStats();
},
render(createElement) {
return createElement('notes-app', {
diff --git a/app/assets/javascripts/notes/mixins/resolvable.js b/app/assets/javascripts/notes/mixins/resolvable.js
index 2329727bca2..16b7598ee09 100644
--- a/app/assets/javascripts/notes/mixins/resolvable.js
+++ b/app/assets/javascripts/notes/mixins/resolvable.js
@@ -20,13 +20,13 @@ export default {
resolveButtonTitle() {
if (this.updatedNoteBody) {
if (this.discussionResolved) {
- return __('Comment & unresolve discussion');
+ return __('Comment & unresolve thread');
}
- return __('Comment & resolve discussion');
+ return __('Comment & resolve thread');
}
- return this.discussionResolved ? __('Unresolve discussion') : __('Resolve discussion');
+ return this.discussionResolved ? __('Unresolve thread') : __('Resolve thread');
},
},
methods: {
diff --git a/app/assets/javascripts/notes/services/notes_service.js b/app/assets/javascripts/notes/services/notes_service.js
index 237e70c0a4c..47a6f07cce2 100644
--- a/app/assets/javascripts/notes/services/notes_service.js
+++ b/app/assets/javascripts/notes/services/notes_service.js
@@ -1,5 +1,4 @@
import Vue from 'vue';
-import Api from '~/api';
import VueResource from 'vue-resource';
import * as constants from '../constants';
@@ -45,7 +44,4 @@ export default {
toggleIssueState(endpoint, data) {
return Vue.http.put(endpoint, data);
},
- applySuggestion(id) {
- return Api.applySuggestion(id);
- },
};
diff --git a/app/assets/javascripts/notes/stores/actions.js b/app/assets/javascripts/notes/stores/actions.js
index 63658d49a05..fef962f008e 100644
--- a/app/assets/javascripts/notes/stores/actions.js
+++ b/app/assets/javascripts/notes/stores/actions.js
@@ -14,6 +14,7 @@ import sidebarTimeTrackingEventHub from '../../sidebar/event_hub';
import { isInViewport, scrollToElement, isInMRPage } from '../../lib/utils/common_utils';
import mrWidgetEventHub from '../../vue_merge_request_widget/event_hub';
import { __ } from '~/locale';
+import Api from '~/api';
let eTagPoll;
@@ -51,7 +52,7 @@ export const fetchDiscussions = ({ commit, dispatch }, { path, filter }) =>
.then(res => res.json())
.then(discussions => {
commit(types.SET_INITIAL_DISCUSSIONS, discussions);
- dispatch('updateResolvableDiscussonsCounts');
+ dispatch('updateResolvableDiscussionsCounts');
});
export const updateDiscussion = ({ commit, state }, discussion) => {
@@ -67,7 +68,7 @@ export const deleteNote = ({ commit, dispatch, state }, note) =>
commit(types.DELETE_NOTE, note);
dispatch('updateMergeRequestWidget');
- dispatch('updateResolvableDiscussonsCounts');
+ dispatch('updateResolvableDiscussionsCounts');
if (isInMRPage()) {
dispatch('diffs/removeDiscussionsFromDiff', discussion);
@@ -117,7 +118,7 @@ export const replyToDiscussion = ({ commit, state, getters, dispatch }, { endpoi
dispatch('updateMergeRequestWidget');
dispatch('startTaskList');
- dispatch('updateResolvableDiscussonsCounts');
+ dispatch('updateResolvableDiscussionsCounts');
} else {
commit(types.ADD_NEW_REPLY_TO_DISCUSSION, res);
}
@@ -135,7 +136,7 @@ export const createNewNote = ({ commit, dispatch }, { endpoint, data }) =>
dispatch('updateMergeRequestWidget');
dispatch('startTaskList');
- dispatch('updateResolvableDiscussonsCounts');
+ dispatch('updateResolvableDiscussionsCounts');
}
return res;
});
@@ -168,7 +169,7 @@ export const toggleResolveNote = ({ commit, dispatch }, { endpoint, isResolved,
commit(mutationType, res);
- dispatch('updateResolvableDiscussonsCounts');
+ dispatch('updateResolvableDiscussionsCounts');
dispatch('updateMergeRequestWidget');
});
@@ -442,15 +443,14 @@ export const startTaskList = ({ dispatch }) =>
}),
);
-export const updateResolvableDiscussonsCounts = ({ commit }) =>
+export const updateResolvableDiscussionsCounts = ({ commit }) =>
commit(types.UPDATE_RESOLVABLE_DISCUSSIONS_COUNTS);
export const submitSuggestion = (
{ commit, dispatch },
{ discussionId, noteId, suggestionId, flashContainer },
) =>
- service
- .applySuggestion(suggestionId)
+ Api.applySuggestion(suggestionId)
.then(() => commit(types.APPLY_SUGGESTION, { discussionId, noteId, suggestionId }))
.then(() => dispatch('resolveDiscussion', { discussionId }).catch(() => {}))
.catch(err => {
diff --git a/app/assets/javascripts/pages/dashboard/todos/index/todos.js b/app/assets/javascripts/pages/dashboard/todos/index/todos.js
index 1b56b97f751..d51d411f3c6 100644
--- a/app/assets/javascripts/pages/dashboard/todos/index/todos.js
+++ b/app/assets/javascripts/pages/dashboard/todos/index/todos.js
@@ -82,7 +82,7 @@ export default class Todos {
})
.catch(() => {
this.updateRowState(target, true);
- return flash(__('Error updating todo status.'));
+ return flash(__('Error updating status of to-do item.'));
});
}
@@ -124,7 +124,7 @@ export default class Todos {
this.updateAllState(target, data);
this.updateBadges(data);
})
- .catch(() => flash(__('Error updating status for all todos.')));
+ .catch(() => flash(__('Error updating status for all to-do items.')));
}
updateAllState(target, data) {
diff --git a/app/assets/javascripts/pages/groups/issues/index.js b/app/assets/javascripts/pages/groups/issues/index.js
index 23fb5656008..dcdee77a8ab 100644
--- a/app/assets/javascripts/pages/groups/issues/index.js
+++ b/app/assets/javascripts/pages/groups/issues/index.js
@@ -1,11 +1,15 @@
import projectSelect from '~/project_select';
import initFilteredSearch from '~/pages/search/init_filtered_search';
+import issuableInitBulkUpdateSidebar from '~/issuable_init_bulk_update_sidebar';
import { FILTERED_SEARCH } from '~/pages/constants';
import IssuableFilteredSearchTokenKeys from 'ee_else_ce/filtered_search/issuable_filtered_search_token_keys';
import initManualOrdering from '~/manual_ordering';
+const ISSUE_BULK_UPDATE_PREFIX = 'issue_';
+
document.addEventListener('DOMContentLoaded', () => {
IssuableFilteredSearchTokenKeys.addExtraTokensForIssues();
+ issuableInitBulkUpdateSidebar.init(ISSUE_BULK_UPDATE_PREFIX);
initFilteredSearch({
page: FILTERED_SEARCH.ISSUES,
diff --git a/app/assets/javascripts/pages/projects/branches/index/index.js b/app/assets/javascripts/pages/projects/branches/index/index.js
index 29de3b7806c..37e8c75f299 100644
--- a/app/assets/javascripts/pages/projects/branches/index/index.js
+++ b/app/assets/javascripts/pages/projects/branches/index/index.js
@@ -5,5 +5,5 @@ import initDiverganceGraph from '~/branches/divergence_graph';
document.addEventListener('DOMContentLoaded', () => {
AjaxLoadingSpinner.init();
new DeleteModal(); // eslint-disable-line no-new
- initDiverganceGraph();
+ initDiverganceGraph(document.querySelector('.js-branch-list').dataset.divergingCountsEndpoint);
});
diff --git a/app/assets/javascripts/pages/projects/issues/form.js b/app/assets/javascripts/pages/projects/issues/form.js
index 941c4552579..2205a7bafe3 100644
--- a/app/assets/javascripts/pages/projects/issues/form.js
+++ b/app/assets/javascripts/pages/projects/issues/form.js
@@ -17,7 +17,5 @@ export default () => {
new MilestoneSelect();
new IssuableTemplateSelectors();
- if (gon.features.graphql) {
- initSuggestions();
- }
+ initSuggestions();
};
diff --git a/app/assets/javascripts/pages/projects/shared/permissions/components/project_feature_setting.vue b/app/assets/javascripts/pages/projects/shared/permissions/components/project_feature_setting.vue
index ff6dadeff7d..533065b2d4d 100644
--- a/app/assets/javascripts/pages/projects/shared/permissions/components/project_feature_setting.vue
+++ b/app/assets/javascripts/pages/projects/shared/permissions/components/project_feature_setting.vue
@@ -1,5 +1,6 @@
<script>
-import projectFeatureToggle from '../../../../../vue_shared/components/toggle_button.vue';
+import projectFeatureToggle from '~/vue_shared/components/toggle_button.vue';
+import { featureAccessLevelNone } from '../constants';
export default {
components: {
@@ -43,7 +44,7 @@ export default {
if (this.featureEnabled) {
return this.options;
}
- return [[0, 'Enable feature to choose access level']];
+ return [featureAccessLevelNone];
},
displaySelectInput() {
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 0bcfb740469..b4d24f3aa36 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
@@ -1,11 +1,19 @@
<script>
import settingsMixin from 'ee_else_ce/pages/projects/shared/permissions/mixins/settings_pannel_mixin';
+import { __ } from '~/locale';
import projectFeatureSetting from './project_feature_setting.vue';
import projectFeatureToggle from '~/vue_shared/components/toggle_button.vue';
import projectSettingRow from './project_setting_row.vue';
-import { visibilityOptions, visibilityLevelDescriptions } from '../constants';
+import {
+ visibilityOptions,
+ visibilityLevelDescriptions,
+ featureAccessLevelMembers,
+ featureAccessLevelEveryone,
+} from '../constants';
import { toggleHiddenClassBySelector } from '../external';
+const PAGE_FEATURE_ACCESS_LEVEL = __('Everyone');
+
export default {
components: {
projectFeatureSetting,
@@ -102,9 +110,9 @@ export default {
computed: {
featureAccessLevelOptions() {
- const options = [[10, 'Only Project Members']];
+ const options = [featureAccessLevelMembers];
if (this.visibilityLevel !== visibilityOptions.PRIVATE) {
- options.push([20, 'Everyone With Access']);
+ options.push(featureAccessLevelEveryone);
}
return options;
},
@@ -117,7 +125,7 @@ export default {
pagesFeatureAccessLevelOptions() {
if (this.visibilityLevel !== visibilityOptions.PUBLIC) {
- return this.featureAccessLevelOptions.concat([[30, 'Everyone']]);
+ return this.featureAccessLevelOptions.concat([[30, PAGE_FEATURE_ACCESS_LEVEL]]);
}
return this.featureAccessLevelOptions;
},
@@ -200,17 +208,17 @@ export default {
<option
:value="visibilityOptions.PRIVATE"
:disabled="!visibilityAllowed(visibilityOptions.PRIVATE)"
- >Private</option
+ >{{ __('Private') }}</option
>
<option
:value="visibilityOptions.INTERNAL"
:disabled="!visibilityAllowed(visibilityOptions.INTERNAL)"
- >Internal</option
+ >{{ __('Internal') }}</option
>
<option
:value="visibilityOptions.PUBLIC"
:disabled="!visibilityAllowed(visibilityOptions.PUBLIC)"
- >Public</option
+ >{{ __('Public') }}</option
>
</select>
<i aria-hidden="true" data-hidden="true" class="fa fa-chevron-down"></i>
diff --git a/app/assets/javascripts/pages/projects/shared/permissions/constants.js b/app/assets/javascripts/pages/projects/shared/permissions/constants.js
index ac0dca31c37..73269c6f3ba 100644
--- a/app/assets/javascripts/pages/projects/shared/permissions/constants.js
+++ b/app/assets/javascripts/pages/projects/shared/permissions/constants.js
@@ -15,3 +15,30 @@ export const visibilityLevelDescriptions = {
'The project can be accessed by anyone, regardless of authentication.',
),
};
+
+const featureAccessLevel = {
+ NOT_ENABLED: 0,
+ PROJECT_MEMBERS: 10,
+ EVERYONE: 20,
+};
+
+const featureAccessLevelDescriptions = {
+ [featureAccessLevel.NOT_ENABLED]: __('Enable feature to choose access level'),
+ [featureAccessLevel.PROJECT_MEMBERS]: __('Only Project Members'),
+ [featureAccessLevel.EVERYONE]: __('Everyone With Access'),
+};
+
+export const featureAccessLevelNone = [
+ featureAccessLevel.NOT_ENABLED,
+ featureAccessLevelDescriptions[featureAccessLevel.NOT_ENABLED],
+];
+
+export const featureAccessLevelMembers = [
+ featureAccessLevel.PROJECT_MEMBERS,
+ featureAccessLevelDescriptions[featureAccessLevel.PROJECT_MEMBERS],
+];
+
+export const featureAccessLevelEveryone = [
+ featureAccessLevel.EVERYONE,
+ featureAccessLevelDescriptions[featureAccessLevel.EVERYONE],
+];
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 185003c306e..015c1527500 100644
--- a/app/assets/javascripts/performance_bar/components/performance_bar_app.vue
+++ b/app/assets/javascripts/performance_bar/components/performance_bar_app.vue
@@ -4,14 +4,12 @@ import { glEmojiTag } from '~/emoji';
import detailedMetric from './detailed_metric.vue';
import requestSelector from './request_selector.vue';
-import simpleMetric from './simple_metric.vue';
import { s__ } from '~/locale';
export default {
components: {
detailedMetric,
requestSelector,
- simpleMetric,
},
props: {
store: {
@@ -43,8 +41,13 @@ export default {
details: 'details',
keys: ['feature', 'request'],
},
+ {
+ metric: 'redis',
+ header: 'Redis calls',
+ details: 'details',
+ keys: ['cmd'],
+ },
],
- simpleMetrics: ['redis'],
data() {
return { currentRequestId: '' };
},
@@ -124,12 +127,6 @@ export default {
</button>
<a v-else :href="profileUrl">{{ s__('PerformanceBar|profile') }}</a>
</div>
- <simple-metric
- v-for="metric in $options.simpleMetrics"
- :key="metric"
- :current-request="currentRequest"
- :metric="metric"
- />
<div id="peek-view-gc" class="view">
<span v-if="currentRequest.details" class="bold">
<span title="Invoke Time">{{ currentRequest.details.gc.gc_time }}</span
diff --git a/app/assets/javascripts/performance_bar/components/simple_metric.vue b/app/assets/javascripts/performance_bar/components/simple_metric.vue
deleted file mode 100644
index 358a57d5bc5..00000000000
--- a/app/assets/javascripts/performance_bar/components/simple_metric.vue
+++ /dev/null
@@ -1,33 +0,0 @@
-<script>
-export default {
- props: {
- currentRequest: {
- type: Object,
- 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 :id="`peek-view-${metric}`" class="view">
- <span v-if="currentRequest.details" class="bold"> {{ duration }} / {{ calls }} </span>
- {{ metric }}
- </div>
-</template>
diff --git a/app/assets/javascripts/pipelines/components/header_component.vue b/app/assets/javascripts/pipelines/components/header_component.vue
index b2e365e5cde..39afa87afc3 100644
--- a/app/assets/javascripts/pipelines/components/header_component.vue
+++ b/app/assets/javascripts/pipelines/components/header_component.vue
@@ -2,6 +2,7 @@
import { GlLoadingIcon } from '@gitlab/ui';
import ciHeader from '../../vue_shared/components/header_ci_component.vue';
import eventHub from '../event_hub';
+import { __ } from '~/locale';
export default {
name: 'PipelineHeaderSection',
@@ -54,7 +55,7 @@ export default {
if (this.pipeline.retry_path) {
actions.push({
- label: 'Retry',
+ label: __('Retry'),
path: this.pipeline.retry_path,
cssClass: 'js-retry-button btn btn-inverted-secondary',
type: 'button',
@@ -64,7 +65,7 @@ export default {
if (this.pipeline.cancel_path) {
actions.push({
- label: 'Cancel running',
+ label: __('Cancel running'),
path: this.pipeline.cancel_path,
cssClass: 'js-btn-cancel-pipeline btn btn-danger',
type: 'button',
diff --git a/app/assets/javascripts/pipelines/components/pipeline_url.vue b/app/assets/javascripts/pipelines/components/pipeline_url.vue
index 65a2b61396c..3f021a26ec5 100644
--- a/app/assets/javascripts/pipelines/components/pipeline_url.vue
+++ b/app/assets/javascripts/pipelines/components/pipeline_url.vue
@@ -94,9 +94,8 @@ export default {
tabindex="0"
class="js-pipeline-url-autodevops badge badge-info autodevops-badge"
role="button"
+ >{{ __('Auto DevOps') }}</gl-link
>
- Auto DevOps
- </gl-link>
<span v-if="pipeline.flags.stuck" class="js-pipeline-url-stuck badge badge-warning">
{{ __('stuck') }}
</span>
diff --git a/app/assets/javascripts/pipelines/components/pipelines_table.vue b/app/assets/javascripts/pipelines/components/pipelines_table.vue
index 03d332cd430..d3ba0c97f6b 100644
--- a/app/assets/javascripts/pipelines/components/pipelines_table.vue
+++ b/app/assets/javascripts/pipelines/components/pipelines_table.vue
@@ -44,6 +44,11 @@ export default {
cancelingPipeline: null,
};
},
+ watch: {
+ pipelines() {
+ this.cancelingPipeline = null;
+ },
+ },
created() {
eventHub.$on('openConfirmationModal', this.setModalData);
},
diff --git a/app/assets/javascripts/pipelines/components/pipelines_table_row.vue b/app/assets/javascripts/pipelines/components/pipelines_table_row.vue
index e32e2f785bd..5275de3bc8b 100644
--- a/app/assets/javascripts/pipelines/components/pipelines_table_row.vue
+++ b/app/assets/javascripts/pipelines/components/pipelines_table_row.vue
@@ -241,7 +241,11 @@ export default {
return this.cancelingPipeline === this.pipeline.id;
},
},
-
+ watch: {
+ pipeline() {
+ this.isRetrying = false;
+ },
+ },
methods: {
handleCancelClick() {
eventHub.$emit('openConfirmationModal', {
diff --git a/app/assets/javascripts/pipelines/mixins/pipelines.js b/app/assets/javascripts/pipelines/mixins/pipelines.js
index 3cc9d0a3a4e..a6243366375 100644
--- a/app/assets/javascripts/pipelines/mixins/pipelines.js
+++ b/app/assets/javascripts/pipelines/mixins/pipelines.js
@@ -107,8 +107,8 @@ export default {
}
// Stop polling
this.poll.stop();
- // Update the table
- return this.getPipelines().then(() => this.poll.restart());
+ // Restarting the poll also makes an initial request
+ this.poll.restart();
},
fetchPipelines() {
if (!this.isMakingRequest) {
@@ -153,7 +153,7 @@ export default {
postAction(endpoint) {
this.service
.postAction(endpoint)
- .then(() => this.fetchPipelines())
+ .then(() => this.updateTable())
.catch(() => Flash(__('An error occurred while making the request.')));
},
},
diff --git a/app/assets/javascripts/projects/project_new.js b/app/assets/javascripts/projects/project_new.js
index ea82ff4e340..9066844f687 100644
--- a/app/assets/javascripts/projects/project_new.js
+++ b/app/assets/javascripts/projects/project_new.js
@@ -1,6 +1,6 @@
import $ from 'jquery';
import { addSelectOnFocusBehaviour } from '../lib/utils/common_utils';
-import { slugifyWithHyphens } from '../lib/utils/text_utility';
+import { slugify } from '../lib/utils/text_utility';
import { s__ } from '~/locale';
let hasUserDefinedProjectPath = false;
@@ -34,7 +34,7 @@ const deriveProjectPathFromUrl = $projectImportUrl => {
};
const onProjectNameChange = ($projectNameInput, $projectPathInput) => {
- const slug = slugifyWithHyphens($projectNameInput.val());
+ const slug = slugify($projectNameInput.val());
$projectPathInput.val(slug);
};
diff --git a/app/assets/javascripts/projects/tree/components/commit_pipeline_status_component.vue b/app/assets/javascripts/projects/tree/components/commit_pipeline_status_component.vue
index bfc55013a71..03281aa1317 100644
--- a/app/assets/javascripts/projects/tree/components/commit_pipeline_status_component.vue
+++ b/app/assets/javascripts/projects/tree/components/commit_pipeline_status_component.vue
@@ -3,7 +3,7 @@ import Visibility from 'visibilityjs';
import ciIcon from '~/vue_shared/components/ci_icon.vue';
import Poll from '~/lib/utils/poll';
import Flash from '~/flash';
-import { s__, sprintf } from '~/locale';
+import { __, s__, sprintf } from '~/locale';
import tooltip from '~/vue_shared/directives/tooltip';
import { GlLoadingIcon } from '@gitlab/ui';
import CommitPipelineService from '../services/commit_pipeline_service';
@@ -56,7 +56,7 @@ export default {
},
errorCallback() {
this.ciStatus = {
- text: 'not found',
+ text: __('not found'),
icon: 'status_notfound',
group: 'notfound',
};
diff --git a/app/assets/javascripts/registry/components/app.vue b/app/assets/javascripts/registry/components/app.vue
index ee973017387..7752723baac 100644
--- a/app/assets/javascripts/registry/components/app.vue
+++ b/app/assets/javascripts/registry/components/app.vue
@@ -3,22 +3,81 @@ import { mapGetters, mapActions } from 'vuex';
import { GlLoadingIcon } from '@gitlab/ui';
import store from '../stores';
import CollapsibleContainer from './collapsible_container.vue';
+import SvgMessage from './svg_message.vue';
+import { s__, sprintf } from '../../locale';
export default {
name: 'RegistryListApp',
components: {
CollapsibleContainer,
GlLoadingIcon,
+ SvgMessage,
},
props: {
endpoint: {
type: String,
required: true,
},
+ characterError: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ helpPagePath: {
+ type: String,
+ required: true,
+ },
+ noContainersImage: {
+ type: String,
+ required: true,
+ },
+ containersErrorImage: {
+ type: String,
+ required: true,
+ },
+ repositoryUrl: {
+ type: String,
+ required: true,
+ },
},
store,
computed: {
...mapGetters(['isLoading', 'repos']),
+ dockerConnectionErrorText() {
+ return sprintf(
+ s__(`ContainerRegistry|We are having trouble connecting to Docker, which could be due to an
+ issue with your project name or path. For more information, please review the
+ %{docLinkStart}Container Registry documentation%{docLinkEnd}.`),
+ {
+ docLinkStart: `<a href="${this.helpPagePath}#docker-connection-error">`,
+ docLinkEnd: '</a>',
+ },
+ false,
+ );
+ },
+ introText() {
+ return sprintf(
+ s__(`ContainerRegistry|With the Docker Container Registry integrated into GitLab, every
+ project can have its own space to store its Docker images. Learn more about the
+ %{docLinkStart}Container Registry%{docLinkEnd}.`),
+ {
+ docLinkStart: `<a href="${this.helpPagePath}">`,
+ docLinkEnd: '</a>',
+ },
+ false,
+ );
+ },
+ noContainerImagesText() {
+ return sprintf(
+ s__(`ContainerRegistry|With the Container Registry, every project can have its own space to
+ store its Docker images. Learn more about the %{docLinkStart}Container Registry%{docLinkEnd}.`),
+ {
+ docLinkStart: `<a href="${this.helpPagePath}">`,
+ docLinkEnd: '</a>',
+ },
+ false,
+ );
+ },
},
created() {
this.setMainEndpoint(this.endpoint);
@@ -33,20 +92,44 @@ export default {
</script>
<template>
<div>
- <gl-loading-icon v-if="isLoading" size="md" />
+ <svg-message v-if="characterError" id="invalid-characters" :svg-path="containersErrorImage">
+ <h4>
+ {{ s__('ContainerRegistry|Docker connection error') }}
+ </h4>
+ <p v-html="dockerConnectionErrorText"></p>
+ </svg-message>
+
+ <gl-loading-icon v-else-if="isLoading" size="md" class="prepend-top-16" />
+
+ <div v-else-if="!isLoading && !characterError && repos.length">
+ <h4>{{ s__('ContainerRegistry|Container Registry') }}</h4>
+ <p v-html="introText"></p>
+ <collapsible-container v-for="item in repos" :key="item.id" :repo="item" />
+ </div>
+
+ <svg-message
+ v-else-if="!isLoading && !characterError && !repos.length"
+ id="no-container-images"
+ :svg-path="noContainersImage"
+ >
+ <h4>
+ {{ s__('ContainerRegistry|There are no container images stored for this project') }}
+ </h4>
+ <p v-html="noContainerImagesText"></p>
- <collapsible-container
- v-for="item in repos"
- v-else-if="!isLoading && repos.length"
- :key="item.id"
- :repo="item"
- />
+ <h5>{{ s__('ContainerRegistry|Quick Start') }}</h5>
+ <p>
+ {{
+ s__(
+ 'ContainerRegistry|You can add an image to this registry with the following commands:',
+ )
+ }}
+ </p>
- <p v-else-if="!isLoading && !repos.length">
- {{
- __(`No container images stored for this project.
- Add one by following the instructions above.`)
- }}
- </p>
+ <pre>
+ docker build -t {{ repositoryUrl }} .
+ docker push {{ repositoryUrl }}
+ </pre>
+ </svg-message>
</div>
</template>
diff --git a/app/assets/javascripts/registry/components/svg_message.vue b/app/assets/javascripts/registry/components/svg_message.vue
new file mode 100644
index 00000000000..d0d44bf2d14
--- /dev/null
+++ b/app/assets/javascripts/registry/components/svg_message.vue
@@ -0,0 +1,24 @@
+<script>
+export default {
+ name: 'RegistrySvgMessage',
+ props: {
+ id: {
+ type: String,
+ required: true,
+ },
+ svgPath: {
+ type: String,
+ required: true,
+ },
+ },
+};
+</script>
+
+<template>
+ <div :id="id" class="empty-state container-message mw-70p">
+ <div class="svg-content">
+ <img :src="svgPath" class="flex-align-self-center" />
+ </div>
+ <slot></slot>
+ </div>
+</template>
diff --git a/app/assets/javascripts/registry/index.js b/app/assets/javascripts/registry/index.js
index 025afefe7f0..d8daec29fda 100644
--- a/app/assets/javascripts/registry/index.js
+++ b/app/assets/javascripts/registry/index.js
@@ -14,12 +14,22 @@ export default () =>
const { dataset } = document.querySelector(this.$options.el);
return {
endpoint: dataset.endpoint,
+ characterError: Boolean(dataset.characterError),
+ helpPagePath: dataset.helpPagePath,
+ noContainersImage: dataset.noContainersImage,
+ containersErrorImage: dataset.containersErrorImage,
+ repositoryUrl: dataset.repositoryUrl,
};
},
render(createElement) {
return createElement('registry-app', {
props: {
endpoint: this.endpoint,
+ characterError: this.characterError,
+ helpPagePath: this.helpPagePath,
+ noContainersImage: this.noContainersImage,
+ containersErrorImage: this.containersErrorImage,
+ repositoryUrl: this.repositoryUrl,
},
});
},
diff --git a/app/assets/javascripts/releases/components/release_block.vue b/app/assets/javascripts/releases/components/release_block.vue
index f510b905a2e..0031ba04d78 100644
--- a/app/assets/javascripts/releases/components/release_block.vue
+++ b/app/assets/javascripts/releases/components/release_block.vue
@@ -4,7 +4,7 @@ import { GlTooltipDirective, GlLink, GlBadge } from '@gitlab/ui';
import Icon from '~/vue_shared/components/icon.vue';
import UserAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link.vue';
import timeagoMixin from '~/vue_shared/mixins/timeago';
-import { sprintf } from '../../locale';
+import { __, sprintf } from '../../locale';
export default {
name: 'ReleaseBlock',
@@ -27,13 +27,13 @@ export default {
},
computed: {
releasedTimeAgo() {
- return sprintf('released %{time}', {
- time: this.timeFormated(this.release.created_at),
+ return sprintf(__('released %{time}'), {
+ time: this.timeFormated(this.release.released_at),
});
},
userImageAltDescription() {
return this.author && this.author.username
- ? sprintf("%{username}'s avatar", { username: this.author.username })
+ ? sprintf(__("%{username}'s avatar"), { username: this.author.username })
: null;
},
commit() {
@@ -56,8 +56,8 @@ export default {
<div class="card-body">
<h2 class="card-title mt-0">
{{ release.name }}
- <gl-badge v-if="release.pre_release" variant="warning" class="align-middle">{{
- __('Pre-release')
+ <gl-badge v-if="release.upcoming_release" variant="warning" class="align-middle">{{
+ __('Upcoming Release')
}}</gl-badge>
</h2>
@@ -74,7 +74,7 @@ export default {
<div class="append-right-4">
&bull;
- <span v-gl-tooltip.bottom :title="tooltipTitle(release.created_at)">
+ <span v-gl-tooltip.bottom :title="tooltipTitle(release.released_at)">
{{ releasedTimeAgo }}
</span>
</div>
diff --git a/app/assets/javascripts/repository/components/table/index.vue b/app/assets/javascripts/repository/components/table/index.vue
index 1e66ccbfa29..0d9e992e596 100644
--- a/app/assets/javascripts/repository/components/table/index.vue
+++ b/app/assets/javascripts/repository/components/table/index.vue
@@ -76,7 +76,7 @@ export default {
variables: {
projectPath: this.projectPath,
ref: this.ref,
- path: this.path,
+ path: this.path || '/',
nextPageCursor: this.nextPageCursor,
pageSize: PAGE_SIZE,
},
diff --git a/app/assets/javascripts/repository/components/table/row.vue b/app/assets/javascripts/repository/components/table/row.vue
index c31e7fa71a2..3e060e9ecb6 100644
--- a/app/assets/javascripts/repository/components/table/row.vue
+++ b/app/assets/javascripts/repository/components/table/row.vue
@@ -110,9 +110,7 @@ export default {
<component :is="linkComponent" :to="routerLinkTo" :href="url" class="str-truncated">
{{ fullPath }}
</component>
- <gl-badge v-if="lfsOid" variant="default" class="label-lfs ml-1">
- LFS
- </gl-badge>
+ <gl-badge v-if="lfsOid" variant="default" class="label-lfs ml-1">LFS</gl-badge>
<template v-if="isSubmodule">
@ <gl-link href="#" class="commit-sha">{{ shortSha }}</gl-link>
</template>
diff --git a/app/assets/javascripts/serverless/components/area.vue b/app/assets/javascripts/serverless/components/area.vue
index 32c9d6eccb8..a1a8cd3acbd 100644
--- a/app/assets/javascripts/serverless/components/area.vue
+++ b/app/assets/javascripts/serverless/components/area.vue
@@ -4,6 +4,7 @@ import { debounceByAnimationFrame } from '~/lib/utils/common_utils';
import dateFormat from 'dateformat';
import { X_INTERVAL } from '../constants';
import { validateGraphData } from '../utils';
+import { __ } from '~/locale';
let debouncedResize;
@@ -42,7 +43,7 @@ export default {
},
generateSeries() {
return {
- name: 'Invocations',
+ name: __('Invocations'),
type: 'line',
data: this.chartData.requests.map(data => [data.time, data.value]),
symbolSize: 0,
@@ -124,7 +125,9 @@ export default {
<div class="prometheus-graph">
<div class="prometheus-graph-header">
<h5 ref="graphTitle" class="prometheus-graph-title">{{ graphData.title }}</h5>
- <div ref="graphWidgets" class="prometheus-graph-widgets"><slot></slot></div>
+ <div ref="graphWidgets" class="prometheus-graph-widgets">
+ <slot></slot>
+ </div>
</div>
<gl-area-chart
ref="areaChart"
@@ -135,12 +138,8 @@ export default {
:width="width"
:include-legend-avg-max="false"
>
- <template slot="tooltipTitle">
- {{ tooltipPopoverTitle }}
- </template>
- <template slot="tooltipContent">
- {{ tooltipPopoverContent }}
- </template>
+ <template slot="tooltipTitle">{{ tooltipPopoverTitle }}</template>
+ <template slot="tooltipContent">{{ tooltipPopoverContent }}</template>
</gl-area-chart>
</div>
</template>
diff --git a/app/assets/javascripts/serverless/components/function_details.vue b/app/assets/javascripts/serverless/components/function_details.vue
index b8906cfca4e..d542dad8119 100644
--- a/app/assets/javascripts/serverless/components/function_details.vue
+++ b/app/assets/javascripts/serverless/components/function_details.vue
@@ -89,7 +89,9 @@ export default {
}}
</p>
</div>
- <div v-else><p>No pods loaded at this time.</p></div>
+ <div v-else>
+ <p>{{ s__('ServerlessDetails|No pods loaded at this time.') }}</p>
+ </div>
<area-chart v-if="hasPrometheusData" :graph-data="graphData" :container-width="elWidth" />
<missing-prometheus
diff --git a/app/assets/javascripts/serverless/components/functions.vue b/app/assets/javascripts/serverless/components/functions.vue
index 94341050b86..9e66869515c 100644
--- a/app/assets/javascripts/serverless/components/functions.vue
+++ b/app/assets/javascripts/serverless/components/functions.vue
@@ -1,4 +1,5 @@
<script>
+import { sprintf, s__ } from '~/locale';
import { mapState, mapActions, mapGetters } from 'vuex';
import { GlLoadingIcon } from '@gitlab/ui';
import FunctionRow from './function_row.vue';
@@ -37,6 +38,28 @@ export default {
isInstalled() {
return this.installed === true;
},
+ noServerlessConfigFile() {
+ return sprintf(
+ s__(
+ 'Serverless|Your repository does not have a corresponding %{startTag}serverless.yml%{endTag} file.',
+ ),
+ { startTag: '<code>', endTag: '</code>' },
+ );
+ },
+ noGitlabYamlConfigured() {
+ return sprintf(
+ s__('Serverless|Your %{startTag}.gitlab-ci.yml%{endTag} file is not properly configured.'),
+ { startTag: '<code>', endTag: '</code>' },
+ );
+ },
+ mismatchedServerlessFunctions() {
+ return sprintf(
+ s__(
+ "Serverless|The functions listed in the %{startTag}serverless.yml%{endTag} file don't match the namespace of your cluster.",
+ ),
+ { startTag: '<code>', endTag: '</code>' },
+ );
+ },
},
created() {
this.fetchFunctions({
@@ -82,25 +105,29 @@ export default {
<h4 class="state-title text-center">{{ s__('Serverless|No functions available') }}</h4>
<p class="state-description">
{{
- s__(`Serverless|There is currently no function data available from Knative.
- This could be for a variety of reasons including:`)
+ s__(
+ 'Serverless|There is currently no function data available from Knative. This could be for a variety of reasons including:',
+ )
}}
</p>
<ul>
- <li>Your repository does not have a corresponding <code>serverless.yml</code> file.</li>
- <li>Your <code>.gitlab-ci.yml</code> file is not properly configured.</li>
<li>
- The functions listed in the <code>serverless.yml</code> file don't match the namespace
- of your cluster.
+ {{ noServerlessConfigFile }}
+ </li>
+ <li>
+ {{ noGitlabYamlConfigured }}
+ </li>
+ <li>
+ {{ mismatchedServerlessFunctions }}
</li>
- <li>The deploy job has not finished.</li>
+ <li>{{ s__('Serverless|The deploy job has not finished.') }}</li>
</ul>
<p>
{{
- s__(`Serverless|If you believe none of these apply, please check
- back later as the function data may be in the process of becoming
- available.`)
+ s__(
+ 'Serverless|If you believe none of these apply, please check back later as the function data may be in the process of becoming available.',
+ )
}}
</p>
<div class="text-center">
diff --git a/app/assets/javascripts/sidebar/components/assignees/assignee_title.vue b/app/assets/javascripts/sidebar/components/assignees/assignee_title.vue
index 0ad2b3a73a2..fa6b6bfaef1 100644
--- a/app/assets/javascripts/sidebar/components/assignees/assignee_title.vue
+++ b/app/assets/javascripts/sidebar/components/assignees/assignee_title.vue
@@ -1,4 +1,6 @@
<script>
+import { n__ } from '~/locale';
+
export default {
name: 'AssigneeTitle',
props: {
@@ -24,7 +26,7 @@ export default {
computed: {
assigneeTitle() {
const assignees = this.numberOfAssignees;
- return assignees > 1 ? `${assignees} Assignees` : 'Assignee';
+ return n__('Assignee', `%d Assignees`, assignees);
},
},
};
@@ -32,18 +34,18 @@ export default {
<template>
<div class="title hide-collapsed">
{{ assigneeTitle }}
- <i v-if="loading" aria-hidden="true" class="fa fa-spinner fa-spin block-loading"> </i>
+ <i v-if="loading" aria-hidden="true" class="fa fa-spinner fa-spin block-loading"></i>
<a v-if="editable" class="js-sidebar-dropdown-toggle edit-link float-right" href="#">
{{ __('Edit') }}
</a>
<a
v-if="showToggle"
- aria-label="Toggle sidebar"
+ :aria-label="__('Toggle sidebar')"
class="gutter-toggle float-right js-sidebar-toggle"
href="#"
role="button"
>
- <i aria-hidden="true" data-hidden="true" class="fa fa-angle-double-right"> </i>
+ <i aria-hidden="true" data-hidden="true" class="fa fa-angle-double-right"></i>
</a>
</div>
</template>
diff --git a/app/assets/javascripts/sidebar/components/assignees/assignees.vue b/app/assets/javascripts/sidebar/components/assignees/assignees.vue
index 0074d7099dc..805c21d0965 100644
--- a/app/assets/javascripts/sidebar/components/assignees/assignees.vue
+++ b/app/assets/javascripts/sidebar/components/assignees/assignees.vue
@@ -1,5 +1,5 @@
<script>
-import { __ } from '~/locale';
+import { __, sprintf } from '~/locale';
import tooltip from '~/vue_shared/directives/tooltip';
export default {
@@ -62,7 +62,8 @@ export default {
return this.numberOfHiddenAssignees > 0;
},
hiddenAssigneesLabel() {
- return `+ ${this.numberOfHiddenAssignees} more`;
+ const { numberOfHiddenAssignees } = this;
+ return sprintf(__('+ %{numberOfHiddenAssignees} more'), { numberOfHiddenAssignees });
},
collapsedTooltipTitle() {
const maxRender = Math.min(this.defaultRenderCount, this.users.length);
@@ -103,12 +104,15 @@ export default {
// Everyone can merge
return null;
} else if (cannotMergeCount === assigneesCount && assigneesCount > 1) {
- return 'No one can merge';
+ return __('No one can merge');
} else if (assigneesCount === 1) {
- return 'Cannot merge';
+ return __('Cannot merge');
}
- return `${canMergeCount}/${assigneesCount} can merge`;
+ return sprintf(__('%{canMergeCount}/%{assigneesCount} can merge'), {
+ canMergeCount,
+ assigneesCount,
+ });
},
},
methods: {
@@ -128,7 +132,7 @@ export default {
return `${this.rootPath}${user.username}`;
},
assigneeAlt(user) {
- return `${user.name}'s avatar`;
+ return sprintf(__("%{userName}'s avatar"), { userName: user.name });
},
assigneeUsername(user) {
return `@${user.username}`;
@@ -153,7 +157,7 @@ export default {
data-placement="left"
data-boundary="viewport"
>
- <i v-if="hasNoUsers" aria-label="None" class="fa fa-user"> </i>
+ <i v-if="hasNoUsers" :aria-label="__('None')" class="fa fa-user"> </i>
<button
v-for="(user, index) in users"
v-if="shouldRenderCollapsedAssignee(index)"
@@ -185,9 +189,12 @@ export default {
</span>
<template v-if="hasNoUsers">
<span class="assign-yourself no-value qa-assign-yourself">
- None
+ {{ __('None') }}
<template v-if="editable">
- - <button type="button" class="btn-link" @click="assignSelf">assign yourself</button>
+ -
+ <button type="button" class="btn-link" @click="assignSelf">
+ {{ __('assign yourself') }}
+ </button>
</template>
</span>
</template>
@@ -232,9 +239,7 @@ export default {
<template v-if="showLess">
{{ hiddenAssigneesLabel }}
</template>
- <template v-else>
- - show less
- </template>
+ <template v-else>{{ __('- show less') }}</template>
</button>
</div>
</template>
diff --git a/app/assets/javascripts/sidebar/components/assignees/sidebar_assignees.vue b/app/assets/javascripts/sidebar/components/assignees/sidebar_assignees.vue
index cfa7029b388..be1e4811856 100644
--- a/app/assets/javascripts/sidebar/components/assignees/sidebar_assignees.vue
+++ b/app/assets/javascripts/sidebar/components/assignees/sidebar_assignees.vue
@@ -2,8 +2,10 @@
import Flash from '~/flash';
import eventHub from '~/sidebar/event_hub';
import Store from '~/sidebar/stores/sidebar_store';
+import { refreshUserMergeRequestCounts } from '~/commons/nav/user_merge_requests';
import AssigneeTitle from './assignee_title.vue';
import Assignees from './assignees.vue';
+import { __ } from '~/locale';
export default {
name: 'SidebarAssignees',
@@ -72,9 +74,12 @@ export default {
this.mediator
.saveAssignees(this.field)
.then(setLoadingFalse.bind(this))
+ .then(() => {
+ refreshUserMergeRequestCounts();
+ })
.catch(() => {
setLoadingFalse();
- return new Flash('Error occurred when saving assignees');
+ return new Flash(__('Error occurred when saving assignees'));
});
},
},
diff --git a/app/assets/javascripts/sidebar/components/confidential/edit_form_buttons.vue b/app/assets/javascripts/sidebar/components/confidential/edit_form_buttons.vue
index 4b9bb5c7b0e..5d0e39e8195 100644
--- a/app/assets/javascripts/sidebar/components/confidential/edit_form_buttons.vue
+++ b/app/assets/javascripts/sidebar/components/confidential/edit_form_buttons.vue
@@ -1,6 +1,7 @@
<script>
import $ from 'jquery';
import eventHub from '../../event_hub';
+import { __ } from '~/locale';
export default {
props: {
@@ -15,7 +16,7 @@ export default {
},
computed: {
toggleButtonText() {
- return this.isConfidential ? 'Turn Off' : 'Turn On';
+ return this.isConfidential ? __('Turn Off') : __('Turn On');
},
updateConfidentialBool() {
return !this.isConfidential;
diff --git a/app/assets/javascripts/sidebar/components/time_tracking/collapsed_state.vue b/app/assets/javascripts/sidebar/components/time_tracking/collapsed_state.vue
index 657ac837baf..24d5b14ded9 100644
--- a/app/assets/javascripts/sidebar/components/time_tracking/collapsed_state.vue
+++ b/app/assets/javascripts/sidebar/components/time_tracking/collapsed_state.vue
@@ -79,7 +79,7 @@ export default {
} else if (this.showSpentOnlyState) {
return `${this.timeSpent} / --`;
} else if (this.showNoTimeTrackingState) {
- return 'None';
+ return __('None');
}
return '';
diff --git a/app/assets/javascripts/sidebar/components/time_tracking/comparison_pane.vue b/app/assets/javascripts/sidebar/components/time_tracking/comparison_pane.vue
index bc263bc36e4..06aca547183 100644
--- a/app/assets/javascripts/sidebar/components/time_tracking/comparison_pane.vue
+++ b/app/assets/javascripts/sidebar/components/time_tracking/comparison_pane.vue
@@ -2,6 +2,7 @@
import { parseSeconds, stringifyTime } from '~/lib/utils/datetime_utility';
import tooltip from '../../../vue_shared/directives/tooltip';
import { GlProgressBar } from '@gitlab/ui';
+import { s__, sprintf } from '~/locale';
export default {
name: 'TimeTrackingComparisonPane',
@@ -43,8 +44,14 @@ export default {
return stringifyTime(this.parsedTimeRemaining);
},
timeRemainingTooltip() {
- const prefix = this.timeRemainingMinutes < 0 ? 'Over by' : 'Time remaining:';
- return `${prefix} ${this.timeRemainingHumanReadable}`;
+ const { timeRemainingHumanReadable, timeRemainingMinutes } = this;
+ return timeRemainingMinutes < 0
+ ? sprintf(s__('TimeTracking|Over by %{timeRemainingHumanReadable}'), {
+ timeRemainingHumanReadable,
+ })
+ : sprintf(s__('TimeTracking|Time remaining: %{timeRemainingHumanReadable}'), {
+ timeRemainingHumanReadable,
+ });
},
/* Diff values for comparison meter */
timeRemainingMinutes() {
@@ -74,12 +81,12 @@ export default {
<gl-progress-bar :value="timeRemainingPercent" :variant="progressBarVariant" />
<div class="compare-display-container">
<div class="compare-display float-left">
- <span class="compare-label"> {{ s__('TimeTracking|Spent') }} </span>
- <span class="compare-value spent"> {{ timeSpentHumanReadable }} </span>
+ <span class="compare-label">{{ s__('TimeTracking|Spent') }}</span>
+ <span class="compare-value spent">{{ timeSpentHumanReadable }}</span>
</div>
<div class="compare-display estimated float-right">
- <span class="compare-label"> {{ s__('TimeTrackingEstimated|Est') }} </span>
- <span class="compare-value"> {{ timeEstimateHumanReadable }} </span>
+ <span class="compare-label">{{ s__('TimeTrackingEstimated|Est') }}</span>
+ <span class="compare-value">{{ timeEstimateHumanReadable }}</span>
</div>
</div>
</div>
diff --git a/app/assets/javascripts/sidebar/components/time_tracking/spent_only_pane.vue b/app/assets/javascripts/sidebar/components/time_tracking/spent_only_pane.vue
index 7c7356e2afa..c2f30310e2e 100644
--- a/app/assets/javascripts/sidebar/components/time_tracking/spent_only_pane.vue
+++ b/app/assets/javascripts/sidebar/components/time_tracking/spent_only_pane.vue
@@ -1,4 +1,6 @@
<script>
+import { sprintf, s__ } from '~/locale';
+
export default {
name: 'TimeTrackingSpentOnlyPane',
props: {
@@ -7,11 +9,22 @@ export default {
required: true,
},
},
+ computed: {
+ timeSpent() {
+ return sprintf(
+ s__('TimeTracking|%{startTag}Spent: %{endTag}%{timeSpentHumanReadable}'),
+ {
+ startTag: '<span class="bold">',
+ endTag: '</span>',
+ timeSpentHumanReadable: this.timeSpentHumanReadable,
+ },
+ false,
+ );
+ },
+ },
};
</script>
<template>
- <div class="time-tracking-spend-only-pane">
- <span class="bold">Spent:</span> {{ timeSpentHumanReadable }}
- </div>
+ <div class="time-tracking-spend-only-pane" v-html="timeSpent"></div>
</template>
diff --git a/app/assets/javascripts/sidebar/components/todo_toggle/todo.vue b/app/assets/javascripts/sidebar/components/todo_toggle/todo.vue
index 57125c78cf6..e6f2fe2b5fc 100644
--- a/app/assets/javascripts/sidebar/components/todo_toggle/todo.vue
+++ b/app/assets/javascripts/sidebar/components/todo_toggle/todo.vue
@@ -5,8 +5,8 @@ import { GlLoadingIcon } from '@gitlab/ui';
import Icon from '~/vue_shared/components/icon.vue';
-const MARK_TEXT = __('Mark todo as done');
-const TODO_TEXT = __('Add todo');
+const MARK_TEXT = __('Mark as done');
+const TODO_TEXT = __('Add a To Do');
export default {
directives: {
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 34cdb70ce14..5c7859828d8 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/deployment.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/deployment.vue
@@ -125,7 +125,9 @@ export default {
this.isStopping = false;
})
.catch(() => {
- createFlash('Something went wrong while stopping this environment. Please try again.');
+ createFlash(
+ __('Something went wrong while stopping this environment. Please try again.'),
+ );
this.isStopping = false;
});
}
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 e20a16900d4..fb826be19f5 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
@@ -139,7 +139,7 @@ export default {
type="button"
class="btn dropdown-toggle qa-dropdown-toggle"
data-toggle="dropdown"
- aria-label="Download as"
+ :aria-label="__('Download as')"
aria-haspopup="true"
aria-expanded="false"
>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_auto_merge_enabled.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_auto_merge_enabled.vue
index 5958c2cf87e..8e8e67228ed 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_auto_merge_enabled.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_auto_merge_enabled.vue
@@ -6,6 +6,7 @@ import statusIcon from '../mr_widget_status_icon.vue';
import MrWidgetAuthor from '../../components/mr_widget_author.vue';
import eventHub from '../../event_hub';
import { AUTO_MERGE_STRATEGIES } from '../../constants';
+import { __ } from '~/locale';
export default {
name: 'MRWidgetAutoMergeEnabled',
@@ -55,7 +56,7 @@ export default {
})
.catch(() => {
this.isCancellingAutoMerge = false;
- Flash('Something went wrong. Please try again.');
+ Flash(__('Something went wrong. Please try again.'));
});
},
removeSourceBranch() {
@@ -76,7 +77,7 @@ export default {
})
.catch(() => {
this.isRemovingSourceBranch = false;
- Flash('Something went wrong. Please try again.');
+ Flash(__('Something went wrong. Please try again.'));
});
},
},
@@ -107,15 +108,15 @@ export default {
<section class="mr-info-list">
<p>
{{ s__('mrWidget|The changes will be merged into') }}
- <a :href="mr.targetBranchPath" class="label-branch"> {{ mr.targetBranch }} </a>
+ <a :href="mr.targetBranchPath" class="label-branch">{{ mr.targetBranch }}</a>
</p>
<p v-if="mr.shouldRemoveSourceBranch">
{{ s__('mrWidget|The source branch will be deleted') }}
</p>
<p v-else class="d-flex align-items-start">
- <span class="append-right-10">
- {{ s__('mrWidget|The source branch will not be deleted') }}
- </span>
+ <span class="append-right-10">{{
+ s__('mrWidget|The source branch will not be deleted')
+ }}</span>
<a
v-if="canRemoveSourceBranch"
:disabled="isRemovingSourceBranch"
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_rebase.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_rebase.vue
index 0bcccc50eb2..c7b064b8506 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_rebase.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_rebase.vue
@@ -4,6 +4,7 @@ import simplePoll from '../../../lib/utils/simple_poll';
import eventHub from '../../event_hub';
import statusIcon from '../mr_widget_status_icon.vue';
import Flash from '../../../flash';
+import { __, sprintf } from '~/locale';
export default {
name: 'MRWidgetRebase',
@@ -40,6 +41,17 @@ export default {
showDisabledButton() {
return ['failed', 'loading'].includes(this.status);
},
+ fastForwardMergeText() {
+ return sprintf(
+ __(
+ `Fast-forward merge is not possible. Rebase the source branch onto %{startTag}${this.mr.targetBranch}%{endTag} to allow this merge request to be merged.`,
+ ),
+ {
+ startTag: '<span class="label-branch">',
+ endTag: '</span>',
+ },
+ );
+ },
},
methods: {
rebase() {
@@ -54,7 +66,7 @@ export default {
.catch(error => {
this.rebasingError = error.merge_error;
this.isMakingRequest = false;
- Flash('Something went wrong. Please try again.');
+ Flash(__('Something went wrong. Please try again.'));
});
},
checkRebaseStatus(continuePolling, stopPolling) {
@@ -69,7 +81,7 @@ export default {
if (res.merge_error && res.merge_error.length) {
this.rebasingError = res.merge_error;
- Flash('Something went wrong. Please try again.');
+ Flash(__('Something went wrong. Please try again.'));
}
eventHub.$emit('MRWidgetRebaseSuccess');
@@ -78,7 +90,7 @@ export default {
})
.catch(() => {
this.isMakingRequest = false;
- Flash('Something went wrong. Please try again.');
+ Flash(__('Something went wrong. Please try again.'));
stopPolling();
});
},
@@ -91,19 +103,14 @@ export default {
<div class="rebase-state-find-class-convention media media-body space-children">
<template v-if="mr.rebaseInProgress || isMakingRequest">
- <span class="bold"> Rebase in progress </span>
+ <span class="bold">{{ __('Rebase in progress') }}</span>
</template>
<template v-if="!mr.rebaseInProgress && !mr.canPushToSourceBranch">
- <span class="bold">
- Fast-forward merge is not possible. Rebase the source branch onto
- <span class="label-branch">{{ mr.targetBranch }}</span> to allow this merge request to be
- merged.
- </span>
+ <span class="bold" v-html="fastForwardMergeText"></span>
</template>
<template v-if="!mr.rebaseInProgress && mr.canPushToSourceBranch && !isMakingRequest">
<div
- class="accept-merge-holder clearfix
-js-toggle-container accept-action media space-children"
+ class="accept-merge-holder clearfix js-toggle-container accept-action media space-children"
>
<button
:disabled="isMakingRequest"
@@ -111,14 +118,14 @@ js-toggle-container accept-action media space-children"
class="btn btn-sm btn-reopen btn-success qa-mr-rebase-button"
@click="rebase"
>
- <gl-loading-icon v-if="isMakingRequest" />
- Rebase
+ <gl-loading-icon v-if="isMakingRequest" />{{ __('Rebase') }}
</button>
- <span v-if="!rebasingError" class="bold">
- Fast-forward merge is not possible. Rebase the source branch onto the target branch or
- merge target branch into source branch to allow this merge request to be merged.
- </span>
- <span v-else class="bold danger"> {{ rebasingError }} </span>
+ <span v-if="!rebasingError" class="bold">{{
+ __(
+ 'Fast-forward merge is not possible. Rebase the source branch onto the target branch or merge target branch into source branch to allow this merge request to be merged.',
+ )
+ }}</span>
+ <span v-else class="bold danger">{{ rebasingError }}</span>
</div>
</template>
</div>
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 a38495bb4cc..7312b31c01c 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
@@ -22,19 +22,29 @@ export default {
<span v-html="emptyStateSVG"></span>
</div>
<div class="text col-md-7 order-md-first col-12">
- <span>
- Merge requests are a place to propose changes you have made to a project and discuss those
- changes with others.
- </span>
- <p>Interested parties can even contribute by pushing commits if they want to.</p>
+ <span>{{
+ s__(
+ 'mrWidgetNothingToMerge|Merge requests are a place to propose changes you have made to a project and discuss those changes with others.',
+ )
+ }}</span>
<p>
- Currently there are no changes in this merge request's source branch. Please push new
- commits or use a different branch.
+ {{
+ s__(
+ 'mrWidgetNothingToMerge|Interested parties can even contribute by pushing commits if they want to.',
+ )
+ }}
+ </p>
+ <p>
+ {{
+ s__(
+ "mrWidgetNothingToMerge|Currently there are no changes in this merge request's source branch. Please push new commits or use a different branch.",
+ )
+ }}
</p>
<div>
- <a v-if="mr.newBlobPath" :href="mr.newBlobPath" class="btn btn-inverted btn-success">
- Create file
- </a>
+ <a v-if="mr.newBlobPath" :href="mr.newBlobPath" class="btn btn-inverted btn-success">{{
+ __('Create file')
+ }}</a>
</div>
</div>
</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 ca1b4a57717..d4514767912 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,6 +6,7 @@ import simplePoll from '~/lib/utils/simple_poll';
import { __ } from '~/locale';
import readyToMergeMixin from 'ee_else_ce/vue_merge_request_widget/mixins/ready_to_merge';
import MergeRequest from '../../../merge_request';
+import { refreshUserMergeRequestCounts } from '~/commons/nav/user_merge_requests';
import Flash from '../../../flash';
import statusIcon from '../mr_widget_status_icon.vue';
import eventHub from '../../event_hub';
@@ -174,6 +175,8 @@ export default {
MergeRequest.decreaseCounter();
stopPolling();
+ refreshUserMergeRequestCounts();
+
// If user checked remove source branch and we didn't remove the branch yet
// we should start another polling for source branch remove process
if (this.removeSourceBranch && data.source_branch_exists) {
@@ -248,7 +251,7 @@ export default {
type="button"
class="btn btn-sm btn-info dropdown-toggle js-merge-moment"
data-toggle="dropdown"
- aria-label="Select merge moment"
+ :aria-label="__('Select merge moment')"
>
<i class="fa fa-chevron-down qa-merge-moment-dropdown" aria-hidden="true"></i>
</button>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/unresolved_discussions.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/unresolved_discussions.vue
index a9fb40a4949..d4a5fdb4b97 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/unresolved_discussions.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/unresolved_discussions.vue
@@ -20,7 +20,7 @@ export default {
<status-icon :show-disabled-button="true" status="warning" />
<div class="media-body space-children">
<span class="bold">
- {{ s__('mrWidget|There are unresolved discussions. Please resolve these discussions') }}
+ {{ s__('mrWidget|There are unresolved threads. Please resolve these threads') }}
</span>
<a
v-if="mr.createIssueToResolveDiscussionsPath"
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/work_in_progress.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/work_in_progress.vue
index 7c322388d30..91c0b40a0b5 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/work_in_progress.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/work_in_progress.vue
@@ -46,14 +46,20 @@ export default {
<status-icon :show-disabled-button="Boolean(mr.removeWIPPath)" status="warning" />
<div class="media-body space-children">
<span class="bold">
- This is a Work in Progress
+ {{ __('This is a Work in Progress') }}
<i
v-tooltip
class="fa fa-question-circle"
- title="When this merge request is ready,
- remove the WIP: prefix from the title to allow it to be merged"
- aria-label="When this merge request is ready,
- remove the WIP: prefix from the title to allow it to be merged"
+ :title="
+ s__(
+ 'mrWidget|When this merge request is ready, remove the WIP: prefix from the title to allow it to be merged',
+ )
+ "
+ :aria-label="
+ s__(
+ 'mrWidget|When this merge request is ready, remove the WIP: prefix from the title to allow it to be merged',
+ )
+ "
>
</i>
</span>
@@ -64,8 +70,8 @@ export default {
class="btn btn-default btn-sm js-remove-wip"
@click="removeWIP"
>
- <i v-if="isMakingRequest" class="fa fa-spinner fa-spin" aria-hidden="true"> </i> Resolve WIP
- status
+ <i v-if="isMakingRequest" class="fa fa-spinner fa-spin" aria-hidden="true"> </i>
+ {{ s__('mrWidget|Resolve WIP status') }}
</button>
</div>
</div>
diff --git a/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue b/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue
index a79da476890..8d415c1bbea 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
@@ -263,8 +263,11 @@ export default {
if (!data.pipeline) return;
const { label } = data.pipeline.details.status;
- const title = `Pipeline ${label}`;
- const message = `Pipeline ${label} for "${data.title}"`;
+ const title = sprintf(__('Pipeline %{label}'), { label });
+ const message = sprintf(__('Pipeline %{label} for "%{dataTitle}"'), {
+ dataTitle: data.title,
+ label,
+ });
notify.notifyMe(title, message, this.mr.gitlabLogo);
},
diff --git a/app/assets/javascripts/vue_shared/components/changed_file_icon.vue b/app/assets/javascripts/vue_shared/components/changed_file_icon.vue
index e9ab6f5ba7a..15cb0bd9792 100644
--- a/app/assets/javascripts/vue_shared/components/changed_file_icon.vue
+++ b/app/assets/javascripts/vue_shared/components/changed_file_icon.vue
@@ -1,7 +1,6 @@
<script>
import { GlTooltipDirective } from '@gitlab/ui';
import Icon from '~/vue_shared/components/icon.vue';
-import { pluralize } from '~/lib/utils/text_utility';
import { __, sprintf } from '~/locale';
import { getCommitIconMap } from '~/ide/utils';
@@ -69,7 +68,7 @@ export default {
});
} else if (this.file.changed && this.file.staged) {
return sprintf(__('Unstaged and staged %{type}'), {
- type: pluralize(type),
+ type,
});
}
diff --git a/app/assets/javascripts/vue_shared/components/commit.vue b/app/assets/javascripts/vue_shared/components/commit.vue
index a1168fa0f1e..ae9b013d980 100644
--- a/app/assets/javascripts/vue_shared/components/commit.vue
+++ b/app/assets/javascripts/vue_shared/components/commit.vue
@@ -1,6 +1,7 @@
<script>
import _ from 'underscore';
import { GlTooltipDirective, GlLink } from '@gitlab/ui';
+import { __, sprintf } from '~/locale';
import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate.vue';
import UserAvatarLink from './user_avatar/user_avatar_link.vue';
import Icon from '../../vue_shared/components/icon.vue';
@@ -129,7 +130,9 @@ export default {
* @returns {String}
*/
userImageAltDescription() {
- return this.author && this.author.username ? `${this.author.username}'s avatar` : null;
+ return this.author && this.author.username
+ ? sprintf(__("%{username}'s avatar"), { username: this.author.username })
+ : null;
},
},
};
@@ -180,7 +183,7 @@ export default {
{{ title }}
</gl-link>
</tooltip-on-truncate>
- <span v-else> Can't find HEAD commit for this branch </span>
+ <span v-else>{{ __("Can't find HEAD commit for this branch") }}</span>
</div>
</div>
</template>
diff --git a/app/assets/javascripts/vue_shared/components/content_viewer/lib/viewer_utils.js b/app/assets/javascripts/vue_shared/components/content_viewer/lib/viewer_utils.js
index ba63683f5c0..da0b45110e2 100644
--- a/app/assets/javascripts/vue_shared/components/content_viewer/lib/viewer_utils.js
+++ b/app/assets/javascripts/vue_shared/components/content_viewer/lib/viewer_utils.js
@@ -3,6 +3,7 @@ import { __ } from '~/locale';
const viewers = {
image: {
id: 'image',
+ binary: true,
},
markdown: {
id: 'markdown',
diff --git a/app/assets/javascripts/vue_shared/components/content_viewer/viewers/image_viewer.vue b/app/assets/javascripts/vue_shared/components/content_viewer/viewers/image_viewer.vue
index 2ca933a37d2..fc6a45b957e 100644
--- a/app/assets/javascripts/vue_shared/components/content_viewer/viewers/image_viewer.vue
+++ b/app/assets/javascripts/vue_shared/components/content_viewer/viewers/image_viewer.vue
@@ -91,7 +91,9 @@ export default {
|
</template>
<template v-if="hasDimensions">
- <strong>W</strong>: {{ width }} | <strong>H</strong>: {{ height }}
+ <strong>{{ s__('ImageViewerDimensions|W') }}</strong
+ >: {{ width }} | <strong>{{ s__('ImageViewerDimensions|H') }}</strong
+ >: {{ height }}
</template>
</p>
</div>
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 5fdc915fffb..655f0054887 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
@@ -40,7 +40,7 @@ export default {
this.fetchMarkdownPreview();
},
destroyed() {
- if (this.isLoading) axiosSource.cancel('Cancelling Preview');
+ if (this.isLoading) axiosSource.cancel(__('Cancelling Preview'));
},
methods: {
fetchMarkdownPreview() {
diff --git a/app/assets/javascripts/vue_shared/components/deprecated_modal.vue b/app/assets/javascripts/vue_shared/components/deprecated_modal.vue
index 36b3ee05456..d5558d93219 100644
--- a/app/assets/javascripts/vue_shared/components/deprecated_modal.vue
+++ b/app/assets/javascripts/vue_shared/components/deprecated_modal.vue
@@ -1,5 +1,7 @@
<script>
/* eslint-disable vue/require-default-prop */
+import { __ } from '~/locale';
+
export default {
name: 'DeprecatedModal', // use GlModal instead
@@ -39,7 +41,7 @@ export default {
closeButtonLabel: {
type: String,
required: false,
- default: 'Cancel',
+ default: __('Cancel'),
},
primaryButtonLabel: {
type: String,
@@ -94,7 +96,7 @@ export default {
type="button"
class="close float-right"
data-dismiss="modal"
- aria-label="Close"
+ :aria-label="__('Close')"
@click="emitCancel($event)"
>
<span aria-hidden="true">&times;</span>
diff --git a/app/assets/javascripts/vue_shared/components/droplab_dropdown_button.vue b/app/assets/javascripts/vue_shared/components/droplab_dropdown_button.vue
index 7d49c87271d..c35fee84771 100644
--- a/app/assets/javascripts/vue_shared/components/droplab_dropdown_button.vue
+++ b/app/assets/javascripts/vue_shared/components/droplab_dropdown_button.vue
@@ -69,7 +69,7 @@ export default {
data-display="static"
data-toggle="dropdown"
>
- <icon name="arrow-down" aria-label="toggle dropdown" />
+ <icon name="arrow-down" :aria-label="__('toggle dropdown')" />
</button>
<ul :class="dropdownClass" class="dropdown-menu dropdown-open-top">
<template v-for="(action, index) in actions">
diff --git a/app/assets/javascripts/vue_shared/components/file_row.vue b/app/assets/javascripts/vue_shared/components/file_row.vue
index 1bfa91500cb..fe5289ff371 100644
--- a/app/assets/javascripts/vue_shared/components/file_row.vue
+++ b/app/assets/javascripts/vue_shared/components/file_row.vue
@@ -131,7 +131,7 @@ export default {
</script>
<template>
- <div>
+ <div v-if="!file.moved">
<file-header v-if="file.isHeader" :path="file.path" />
<div
v-else
diff --git a/app/assets/javascripts/vue_shared/components/filtered_search_dropdown.vue b/app/assets/javascripts/vue_shared/components/filtered_search_dropdown.vue
index 4e5dfbf3bf8..20bcceeb477 100644
--- a/app/assets/javascripts/vue_shared/components/filtered_search_dropdown.vue
+++ b/app/assets/javascripts/vue_shared/components/filtered_search_dropdown.vue
@@ -115,7 +115,7 @@ export default {
data-toggle="dropdown"
aria-haspopup="true"
aria-expanded="false"
- aria-label="Expand dropdown"
+ :aria-label="__('Expand dropdown')"
>
<icon name="angle-down" :size="12" />
</button>
@@ -125,7 +125,7 @@ export default {
ref="searchInput"
v-model="filter"
type="search"
- placeholder="Filter"
+ :placeholder="__('Filter')"
class="js-filtered-dropdown-input dropdown-input-field"
/>
<icon class="dropdown-input-search" name="search" />
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 3f45dc7853b..c652a684d7c 100644
--- a/app/assets/javascripts/vue_shared/components/header_ci_component.vue
+++ b/app/assets/javascripts/vue_shared/components/header_ci_component.vue
@@ -1,5 +1,6 @@
<script>
import { GlTooltipDirective, GlLink, GlButton } from '@gitlab/ui';
+import { __, sprintf } from '~/locale';
import CiIconBadge from './ci_badge_link.vue';
import TimeagoTooltip from './time_ago_tooltip.vue';
import UserAvatarImage from './user_avatar/user_avatar_image.vue';
@@ -65,7 +66,7 @@ export default {
computed: {
userAvatarAltText() {
- return `${this.user.name}'s avatar`;
+ return sprintf(__(`%{username}'s avatar`), { username: this.user.name });
},
},
@@ -87,16 +88,12 @@ export default {
<strong> {{ itemName }} #{{ itemId }} </strong>
- <template v-if="shouldRenderTriggeredLabel">
- triggered
- </template>
- <template v-else>
- created
- </template>
+ <template v-if="shouldRenderTriggeredLabel">{{ __('triggered') }}</template>
+ <template v-else>{{ __('created') }}</template>
<timeago-tooltip :time="time" />
- by
+ {{ __('by') }}
<template v-if="user">
<gl-link
diff --git a/app/assets/javascripts/vue_shared/components/issue/issue_warning.vue b/app/assets/javascripts/vue_shared/components/issue/issue_warning.vue
index e438ff16a41..47f0851f650 100644
--- a/app/assets/javascripts/vue_shared/components/issue/issue_warning.vue
+++ b/app/assets/javascripts/vue_shared/components/issue/issue_warning.vue
@@ -1,7 +1,7 @@
<script>
import { GlLink } from '@gitlab/ui';
import _ from 'underscore';
-import { sprintf } from '~/locale';
+import { __, sprintf } from '~/locale';
import icon from '../../../vue_shared/components/icon.vue';
function buildDocsLinkStart(path) {
@@ -47,7 +47,9 @@ export default {
},
confidentialAndLockedDiscussionText() {
return sprintf(
- 'This issue is %{confidentialLinkStart}confidential%{linkEnd} and %{lockedLinkStart}locked%{linkEnd}.',
+ __(
+ 'This issue is %{confidentialLinkStart}confidential%{linkEnd} and %{lockedLinkStart}locked%{linkEnd}.',
+ ),
{
confidentialLinkStart: buildDocsLinkStart(this.confidentialIssueDocsPath),
lockedLinkStart: buildDocsLinkStart(this.lockedIssueDocsPath),
@@ -66,7 +68,7 @@ export default {
<span v-if="isLockedAndConfidential">
<span v-html="confidentialAndLockedDiscussionText"></span>
{{
- __(`People without permission will never get a notification and won't be able to comment.`)
+ __("People without permission will never get a notification and won't be able to comment.")
}}
</span>
diff --git a/app/assets/javascripts/vue_shared/components/issue/related_issuable_item.vue b/app/assets/javascripts/vue_shared/components/issue/related_issuable_item.vue
index eb0f666422f..b76679960ca 100644
--- a/app/assets/javascripts/vue_shared/components/issue/related_issuable_item.vue
+++ b/app/assets/javascripts/vue_shared/components/issue/related_issuable_item.vue
@@ -160,8 +160,8 @@ export default {
:disabled="removeDisabled"
type="button"
class="btn btn-default btn-svg btn-item-remove js-issue-item-remove-button qa-remove-issue-button mr-xl-0 align-self-xl-center"
- title="Remove"
- aria-label="Remove"
+ :title="__('Remove')"
+ :aria-label="__('Remove')"
@click="onRemoveRequest"
>
<icon :size="16" class="btn-item-remove-icon" name="close" />
diff --git a/app/assets/javascripts/vue_shared/components/markdown/field.vue b/app/assets/javascripts/vue_shared/components/markdown/field.vue
index 3bdc0bb8ebd..b520d302407 100644
--- a/app/assets/javascripts/vue_shared/components/markdown/field.vue
+++ b/app/assets/javascripts/vue_shared/components/markdown/field.vue
@@ -1,7 +1,7 @@
<script>
import $ from 'jquery';
import _ from 'underscore';
-import { __ } from '~/locale';
+import { __, sprintf } from '~/locale';
import { stripHtml } from '~/lib/utils/text_utility';
import Flash from '../../../flash';
import GLForm from '../../../gl_form';
@@ -118,6 +118,18 @@ export default {
lineType() {
return this.line ? this.line.type : '';
},
+ addMultipleToDiscussionWarning() {
+ return sprintf(
+ __(
+ '%{icon}You are about to add %{usersTag} people to the discussion. Proceed with caution.',
+ ),
+ {
+ icon: '<i class="fa fa-exclamation-triangle" aria-hidden="true"></i>',
+ usersTag: `<strong><span class="js-referenced-users-count">${this.referencedUsers.length}</span></strong>`,
+ },
+ false,
+ );
+ },
},
mounted() {
/*
@@ -172,7 +184,7 @@ export default {
renderMarkdown(data = {}) {
this.markdownPreviewLoading = false;
- this.markdownPreview = data.body || 'Nothing to preview.';
+ this.markdownPreview = data.body || __('Nothing to preview.');
if (data.references) {
this.referencedCommands = data.references.commands;
@@ -207,7 +219,11 @@ export default {
<div v-show="!previewMarkdown" class="md-write-holder">
<div class="zen-backdrop">
<slot name="textarea"></slot>
- <a class="zen-control zen-control-leave js-zen-leave" href="#" aria-label="Enter zen mode">
+ <a
+ class="zen-control zen-control-leave js-zen-leave"
+ href="#"
+ :aria-label="__('Enter zen mode')"
+ >
<icon :size="32" name="screen-normal" />
</a>
<markdown-toolbar
@@ -246,13 +262,7 @@ export default {
<template v-if="previewMarkdown && !markdownPreviewLoading">
<div v-if="referencedCommands" class="referenced-commands" v-html="referencedCommands"></div>
<div v-if="shouldShowReferencedUsers" class="referenced-users">
- <span>
- <i class="fa fa-exclamation-triangle" aria-hidden="true"></i> You are about to add
- <strong>
- <span class="js-referenced-users-count">{{ referencedUsers.length }}</span>
- </strong>
- people to the discussion. Proceed with caution.
- </span>
+ <span v-html="addMultipleToDiscussionWarning"></span>
</div>
</template>
</div>
diff --git a/app/assets/javascripts/vue_shared/components/markdown/suggestions.vue b/app/assets/javascripts/vue_shared/components/markdown/suggestions.vue
index 8d3705e1e4a..7f0fcfac071 100644
--- a/app/assets/javascripts/vue_shared/components/markdown/suggestions.vue
+++ b/app/assets/javascripts/vue_shared/components/markdown/suggestions.vue
@@ -1,5 +1,6 @@
<script>
import Vue from 'vue';
+import { __ } from '~/locale';
import SuggestionDiff from './suggestion_diff.vue';
import Flash from '~/flash';
@@ -56,7 +57,7 @@ export default {
const suggestionElements = container.querySelectorAll('.js-render-suggestion');
if (this.lineType === 'old') {
- Flash('Unable to apply suggestions to a deleted line.', 'alert', this.$el);
+ Flash(__('Unable to apply suggestions to a deleted line.'), 'alert', this.$el);
}
suggestionElements.forEach((suggestionEl, i) => {
diff --git a/app/assets/javascripts/vue_shared/components/markdown/toolbar.vue b/app/assets/javascripts/vue_shared/components/markdown/toolbar.vue
index d6c398c8946..8ce5b615795 100644
--- a/app/assets/javascripts/vue_shared/components/markdown/toolbar.vue
+++ b/app/assets/javascripts/vue_shared/components/markdown/toolbar.vue
@@ -33,13 +33,18 @@ export default {
<div class="comment-toolbar clearfix">
<div class="toolbar-text">
<template v-if="!hasQuickActionsDocsPath && markdownDocsPath">
- <gl-link :href="markdownDocsPath" target="_blank" tabindex="-1"
- >Markdown is supported</gl-link
- >
+ <gl-link :href="markdownDocsPath" target="_blank" tabindex="-1">{{
+ __('Markdown is supported')
+ }}</gl-link>
</template>
<template v-if="hasQuickActionsDocsPath && markdownDocsPath">
- <gl-link :href="markdownDocsPath" target="_blank" tabindex="-1">Markdown</gl-link> and
- <gl-link :href="quickActionsDocsPath" target="_blank" tabindex="-1">quick actions</gl-link>
+ <gl-link :href="markdownDocsPath" target="_blank" tabindex="-1">{{
+ __('Markdown')
+ }}</gl-link>
+ and
+ <gl-link :href="quickActionsDocsPath" target="_blank" tabindex="-1">{{
+ __('quick actions')
+ }}</gl-link>
are supported
</template>
</div>
@@ -57,15 +62,17 @@ export default {
<i class="fa fa-file-image-o toolbar-button-icon" aria-hidden="true"></i>
</span>
<span class="uploading-error-message"></span>
- <button class="retry-uploading-link" type="button">Try again</button> or
- <button class="attach-new-file markdown-selector" type="button">attach a new file</button>
+ <button class="retry-uploading-link" type="button">{{ __('Try again') }}</button> or
+ <button class="attach-new-file markdown-selector" type="button">
+ {{ __('attach a new file') }}
+ </button>
</span>
<button class="markdown-selector button-attach-file btn-link" tabindex="-1" type="button">
<i class="fa fa-file-image-o toolbar-button-icon" aria-hidden="true"></i
- ><span class="text-attach-file">Attach a file</span>
+ ><span class="text-attach-file">{{ __('Attach a file') }}</span>
</button>
<button class="btn btn-default btn-sm hide button-cancel-uploading-files" type="button">
- Cancel
+ {{ __('Cancel') }}
</button>
</span>
</div>
diff --git a/app/assets/javascripts/vue_shared/components/memory_graph.vue b/app/assets/javascripts/vue_shared/components/memory_graph.vue
index 16f4ff068f6..26d7d8e8866 100644
--- a/app/assets/javascripts/vue_shared/components/memory_graph.vue
+++ b/app/assets/javascripts/vue_shared/components/memory_graph.vue
@@ -1,4 +1,5 @@
<script>
+import { __, sprintf } from '~/locale';
import { getTimeago } from '../../lib/utils/datetime_utility';
export default {
@@ -20,7 +21,7 @@ export default {
computed: {
getFormattedMedian() {
const deployedSince = getTimeago().format(this.deploymentTime * 1000);
- return `Deployed ${deployedSince}`;
+ return sprintf(__('Deployed %{deployedSince}'), { deployedSince });
},
},
mounted() {
diff --git a/app/assets/javascripts/vue_shared/components/notes/placeholder_note.vue b/app/assets/javascripts/vue_shared/components/notes/placeholder_note.vue
index baed26a157c..af02b8969ee 100644
--- a/app/assets/javascripts/vue_shared/components/notes/placeholder_note.vue
+++ b/app/assets/javascripts/vue_shared/components/notes/placeholder_note.vue
@@ -39,7 +39,7 @@ export default {
</script>
<template>
- <timeline-entry-item class="note being-posted fade-in-half">
+ <timeline-entry-item class="note note-wrapper being-posted fade-in-half">
<div class="timeline-icon">
<user-avatar-link
:link-href="getUserData.path"
diff --git a/app/assets/javascripts/vue_shared/components/notes/system_note.vue b/app/assets/javascripts/vue_shared/components/notes/system_note.vue
index 3c86b7e4c61..d6dfe9eded8 100644
--- a/app/assets/javascripts/vue_shared/components/notes/system_note.vue
+++ b/app/assets/javascripts/vue_shared/components/notes/system_note.vue
@@ -103,7 +103,7 @@ export default {
<div v-if="hasMoreCommits" class="flex-list">
<div class="system-note-commit-list-toggler flex-row" @click="expanded = !expanded">
<icon :name="toggleIcon" :size="8" class="append-right-5" />
- <span>Toggle commit list</span>
+ <span>{{ __('Toggle commit list') }}</span>
</div>
</div>
</div>
diff --git a/app/assets/javascripts/vue_shared/components/project_avatar/image.vue b/app/assets/javascripts/vue_shared/components/project_avatar/image.vue
index b9311d65360..43bbb756805 100644
--- a/app/assets/javascripts/vue_shared/components/project_avatar/image.vue
+++ b/app/assets/javascripts/vue_shared/components/project_avatar/image.vue
@@ -14,7 +14,7 @@
/>
*/
-
+import { __ } from '~/locale';
import defaultAvatarUrl from 'images/no_avatar.png';
import { placeholderImage } from '../../../lazy_loader';
@@ -39,7 +39,7 @@ export default {
imgAlt: {
type: String,
required: false,
- default: 'project avatar',
+ default: __('project avatar'),
},
size: {
type: Number,
diff --git a/app/assets/javascripts/vue_shared/components/sidebar/collapsed_grouped_date_picker.vue b/app/assets/javascripts/vue_shared/components/sidebar/collapsed_grouped_date_picker.vue
index b5e43da401e..4dcc121496c 100644
--- a/app/assets/javascripts/vue_shared/components/sidebar/collapsed_grouped_date_picker.vue
+++ b/app/assets/javascripts/vue_shared/components/sidebar/collapsed_grouped_date_picker.vue
@@ -85,7 +85,7 @@ export default {
@click="toggleSidebar"
>
<span class="sidebar-collapsed-value">
- <span v-if="showFromText">From</span> <span>{{ dateText('min') }}</span>
+ <span v-if="showFromText">{{ __('From') }}</span> <span>{{ dateText('min') }}</span>
</span>
</collapsed-calendar-icon>
<div v-if="hasMinAndMaxDates" class="text-center sidebar-collapsed-divider">-</div>
@@ -96,7 +96,7 @@ export default {
@click="toggleSidebar"
>
<span class="sidebar-collapsed-value">
- <span v-if="!minDate">Until</span> <span>{{ dateText('max') }}</span>
+ <span v-if="!minDate">{{ __('Until') }}</span> <span>{{ dateText('max') }}</span>
</span>
</collapsed-calendar-icon>
</div>
diff --git a/app/assets/javascripts/vue_shared/components/sidebar/date_picker.vue b/app/assets/javascripts/vue_shared/components/sidebar/date_picker.vue
index 45f01a6fced..6caf8bc92c2 100644
--- a/app/assets/javascripts/vue_shared/components/sidebar/date_picker.vue
+++ b/app/assets/javascripts/vue_shared/components/sidebar/date_picker.vue
@@ -74,7 +74,7 @@ export default {
return dateInWords(this.selectedDate, true);
},
collapsedText() {
- return this.selectedDateWords ? this.selectedDateWords : 'None';
+ return this.selectedDateWords ? this.selectedDateWords : __('None');
},
},
methods: {
@@ -112,7 +112,7 @@ export default {
class="btn-blank btn-link btn-primary-hover-link btn-sidebar-action"
@click="toggleDatePicker"
>
- Edit
+ {{ __('Edit') }}
</button>
<toggle-sidebar v-if="showToggleSidebar" :collapsed="collapsed" @toggle="toggleSidebar" />
</div>
@@ -137,11 +137,11 @@ export default {
class="btn-blank btn-link btn-secondary-hover-link"
@click="newDateSelected(null)"
>
- remove
+ {{ __('remove') }}
</button>
</span>
</template>
- <span v-else class="no-value"> None </span>
+ <span v-else class="no-value">{{ __('None') }}</span>
</span>
</div>
</div>
diff --git a/app/assets/javascripts/vue_shared/components/sidebar/toggle_sidebar.vue b/app/assets/javascripts/vue_shared/components/sidebar/toggle_sidebar.vue
index 3b5ce0e9910..913c971a512 100644
--- a/app/assets/javascripts/vue_shared/components/sidebar/toggle_sidebar.vue
+++ b/app/assets/javascripts/vue_shared/components/sidebar/toggle_sidebar.vue
@@ -48,7 +48,7 @@ export default {
'fa-angle-double-right': !collapsed,
'fa-angle-double-left': collapsed,
}"
- aria-label="toggle collapse"
+ :aria-label="__('toggle collapse')"
class="fa"
>
</i>
diff --git a/app/assets/javascripts/vue_shared/components/user_avatar/user_avatar_image.vue b/app/assets/javascripts/vue_shared/components/user_avatar/user_avatar_image.vue
index a6c1737dcab..ea483416c46 100644
--- a/app/assets/javascripts/vue_shared/components/user_avatar/user_avatar_image.vue
+++ b/app/assets/javascripts/vue_shared/components/user_avatar/user_avatar_image.vue
@@ -17,6 +17,7 @@
import { GlTooltip } from '@gitlab/ui';
import defaultAvatarUrl from 'images/no_avatar.png';
+import { __ } from '~/locale';
import { placeholderImage } from '../../../lazy_loader';
export default {
@@ -43,7 +44,7 @@ export default {
imgAlt: {
type: String,
required: false,
- default: 'user avatar',
+ default: __('user avatar'),
},
size: {
type: Number,
diff --git a/app/assets/javascripts/vue_shared/mixins/is_ee.js b/app/assets/javascripts/vue_shared/mixins/is_ee.js
deleted file mode 100644
index 8e00d93ef18..00000000000
--- a/app/assets/javascripts/vue_shared/mixins/is_ee.js
+++ /dev/null
@@ -1,10 +0,0 @@
-import Vue from 'vue';
-import { isEE } from '~/lib/utils/common_utils';
-
-Vue.mixin({
- computed: {
- isEE() {
- return isEE();
- },
- },
-});
diff --git a/app/assets/stylesheets/framework/dropdowns.scss b/app/assets/stylesheets/framework/dropdowns.scss
index cd951f67293..e75c1379dfb 100644
--- a/app/assets/stylesheets/framework/dropdowns.scss
+++ b/app/assets/stylesheets/framework/dropdowns.scss
@@ -288,7 +288,7 @@
padding: 0 1px;
a,
- button,
+ button:not(.dropdown-toggle,.ci-action-icon-container),
.menu-item {
@include dropdown-link;
}
diff --git a/app/assets/stylesheets/framework/modal.scss b/app/assets/stylesheets/framework/modal.scss
index f75e5b55506..975dca168d5 100644
--- a/app/assets/stylesheets/framework/modal.scss
+++ b/app/assets/stylesheets/framework/modal.scss
@@ -35,7 +35,8 @@
background-color: $modal-body-bg;
line-height: $line-height-base;
position: relative;
- padding: #{3 * $grid-size} #{2 * $grid-size};
+ min-height: $modal-body-height;
+ padding: #{2 * $grid-size} #{6 * $grid-size} #{2 * $grid-size} #{2 * $grid-size};
text-align: left;
white-space: normal;
@@ -85,9 +86,9 @@ body.modal-open {
.modal {
background-color: $black-transparent;
- @include media-breakpoint-up(md) {
+ @include media-breakpoint-up(sm) {
.modal-dialog {
- margin: 30px auto;
+ margin: 64px auto;
}
}
}
diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss
index b6a24247d40..406bcda418e 100644
--- a/app/assets/stylesheets/framework/variables.scss
+++ b/app/assets/stylesheets/framework/variables.scss
@@ -805,7 +805,7 @@ $border-color-settings: #e1e1e1;
/*
Modals
*/
-$modal-body-height: 134px;
+$modal-body-height: 80px;
$modal-border-color: #e9ecef;
$priority-label-empty-state-width: 114px;
diff --git a/app/assets/stylesheets/pages/container_registry.scss b/app/assets/stylesheets/pages/container_registry.scss
index dfff3e15556..cca5214a508 100644
--- a/app/assets/stylesheets/pages/container_registry.scss
+++ b/app/assets/stylesheets/pages/container_registry.scss
@@ -2,6 +2,12 @@
* Container Registry
*/
+.container-message {
+ pre {
+ white-space: pre-line;
+ }
+}
+
.container-image {
border-bottom: 1px solid $white-normal;
}
diff --git a/app/assets/stylesheets/pages/diff.scss b/app/assets/stylesheets/pages/diff.scss
index d2d35d91e0b..3ffe8ae304d 100644
--- a/app/assets/stylesheets/pages/diff.scss
+++ b/app/assets/stylesheets/pages/diff.scss
@@ -1093,6 +1093,21 @@ table.code {
line-height: 0;
}
+.discussion-collapsible {
+ margin: 0 $gl-padding $gl-padding 71px;
+
+ .notes {
+ border-radius: $border-radius-default;
+ }
+}
+
+.parallel {
+ .discussion-collapsible {
+ margin: $gl-padding;
+ margin-top: 0;
+ }
+}
+
@media (max-width: map-get($grid-breakpoints, md)-1) {
.diffs .files {
@include fixed-width-container;
@@ -1110,6 +1125,11 @@ table.code {
padding-right: 0;
}
}
+
+ .discussion-collapsible {
+ margin: $gl-padding;
+ margin-top: 0;
+ }
}
.image-diff-overlay,
diff --git a/app/assets/stylesheets/pages/notes.scss b/app/assets/stylesheets/pages/notes.scss
index e880b941d67..b9b8eabf909 100644
--- a/app/assets/stylesheets/pages/notes.scss
+++ b/app/assets/stylesheets/pages/notes.scss
@@ -134,6 +134,15 @@ $note-form-margin-left: 72px;
}
}
+ .discussion-toggle-replies {
+ border-top: 0;
+ border-radius: 4px 4px 0 0;
+
+ &.collapsed {
+ border-radius: 4px;
+ }
+ }
+
.note-created-ago,
.note-updated-at {
white-space: normal;
@@ -396,7 +405,7 @@ $note-form-margin-left: 72px;
border-radius: 0;
@media (min-width: map-get($grid-breakpoints, md)) {
- top: 91px;
+ top: $mr-tabs-height + $header-height;
.with-performance-bar & {
top: 126px;
@@ -462,6 +471,14 @@ $note-form-margin-left: 72px;
position: relative;
}
+ .notes-content .discussion-notes.diff-discussions {
+ border-bottom: 1px solid $border-color;
+
+ &:nth-last-child(1) {
+ border-bottom: 0;
+ }
+ }
+
.notes_holder {
font-family: $regular-font;
@@ -517,6 +534,17 @@ $note-form-margin-left: 72px;
.discussion-reply-holder {
border-radius: 0 0 $border-radius-default $border-radius-default;
position: relative;
+
+ .discussion-form {
+ width: 100%;
+ background-color: $gray-light;
+ padding: 0;
+ }
+
+ .disabled-comment {
+ padding: $gl-vert-padding 0;
+ width: 100%;
+ }
}
}
@@ -569,7 +597,8 @@ $note-form-margin-left: 72px;
}
.discussion-header {
- min-height: 74px;
+ min-height: $line-height-base * 2em;
+ box-sizing: content-box;
.note-header-info {
padding-bottom: 0;
@@ -579,13 +608,10 @@ $note-form-margin-left: 72px;
overflow-x: auto;
overflow-y: hidden;
}
-}
-.unresolved {
- .discussion-header {
- .note-header-info {
- margin-top: $gl-padding-8;
- }
+ &.note-wrapper {
+ display: flex;
+ align-items: center;
}
}
diff --git a/app/assets/stylesheets/pages/wiki.scss b/app/assets/stylesheets/pages/wiki.scss
index 10120a472d3..60400f10ca5 100644
--- a/app/assets/stylesheets/pages/wiki.scss
+++ b/app/assets/stylesheets/pages/wiki.scss
@@ -168,6 +168,10 @@
}
ul.wiki-pages-list.content-list {
+ a {
+ color: $blue-600;
+ }
+
ul {
list-style: none;
margin-left: 0;
diff --git a/app/controllers/admin/application_settings_controller.rb b/app/controllers/admin/application_settings_controller.rb
index 42634bf611e..a570da61d54 100644
--- a/app/controllers/admin/application_settings_controller.rb
+++ b/app/controllers/admin/application_settings_controller.rb
@@ -64,7 +64,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
private
def set_application_setting
- @application_setting = Gitlab::CurrentSettings.current_application_settings
+ @application_setting = ApplicationSetting.current_without_cache
end
def whitelist_query_limiting
diff --git a/app/controllers/concerns/issuable_actions.rb b/app/controllers/concerns/issuable_actions.rb
index 065d2d3a4ec..6fa2f75be33 100644
--- a/app/controllers/concerns/issuable_actions.rb
+++ b/app/controllers/concerns/issuable_actions.rb
@@ -92,7 +92,7 @@ module IssuableActions
end
def bulk_update
- result = Issuable::BulkUpdateService.new(project, current_user, bulk_update_params).execute(resource_name)
+ result = Issuable::BulkUpdateService.new(current_user, bulk_update_params).execute(resource_name)
quantity = result[:count]
render json: { notice: "#{quantity} #{resource_name.pluralize(quantity)} updated" }
@@ -181,7 +181,7 @@ module IssuableActions
end
def authorize_admin_issuable!
- unless can?(current_user, :"admin_#{resource_name}", @project) # rubocop:disable Gitlab/ModuleWithInstanceVariables
+ unless can?(current_user, :"admin_#{resource_name}", parent)
return access_denied!
end
end
diff --git a/app/controllers/concerns/issuable_collections.rb b/app/controllers/concerns/issuable_collections.rb
index 88a0690938a..21b3949e361 100644
--- a/app/controllers/concerns/issuable_collections.rb
+++ b/app/controllers/concerns/issuable_collections.rb
@@ -42,7 +42,7 @@ module IssuableCollections
@issuables = @issuables.page(params[:page])
@issuables = per_page_for_relative_position if params[:sort] == 'relative_position'
- @issuable_meta_data = issuable_meta_data(@issuables, collection_type)
+ @issuable_meta_data = issuable_meta_data(@issuables, collection_type, current_user)
@total_pages = issuable_page_count
end
# rubocop:enable Gitlab/ModuleWithInstanceVariables
diff --git a/app/controllers/concerns/issuable_collections_action.rb b/app/controllers/concerns/issuable_collections_action.rb
index 18ed4027eac..4ad287c4a13 100644
--- a/app/controllers/concerns/issuable_collections_action.rb
+++ b/app/controllers/concerns/issuable_collections_action.rb
@@ -11,7 +11,7 @@ module IssuableCollectionsAction
.non_archived
.page(params[:page])
- @issuable_meta_data = issuable_meta_data(@issues, collection_type)
+ @issuable_meta_data = issuable_meta_data(@issues, collection_type, current_user)
respond_to do |format|
format.html
@@ -22,7 +22,7 @@ module IssuableCollectionsAction
def merge_requests
@merge_requests = issuables_collection.page(params[:page])
- @issuable_meta_data = issuable_meta_data(@merge_requests, collection_type)
+ @issuable_meta_data = issuable_meta_data(@merge_requests, collection_type, current_user)
end
# rubocop:enable Gitlab/ModuleWithInstanceVariables
diff --git a/app/controllers/concerns/notes_actions.rb b/app/controllers/concerns/notes_actions.rb
index f96d1821095..0098c4cdf4c 100644
--- a/app/controllers/concerns/notes_actions.rb
+++ b/app/controllers/concerns/notes_actions.rb
@@ -203,17 +203,17 @@ module NotesActions
# These params are also sent by the client but we need to set these based on
# target_type and target_id because we're checking permissions based on that
- create_params[:noteable_type] = params[:target_type].classify
+ create_params[:noteable_type] = noteable.class.name
- case params[:target_type]
- when 'commit'
- create_params[:commit_id] = params[:target_id]
- when 'merge_request'
- create_params[:noteable_id] = params[:target_id]
+ case noteable
+ when Commit
+ create_params[:commit_id] = noteable.id
+ when MergeRequest
+ create_params[:noteable_id] = noteable.id
# Notes on MergeRequest can have an extra `commit_id` context
create_params[:commit_id] = params.dig(:note, :commit_id)
else
- create_params[:noteable_id] = params[:target_id]
+ create_params[:noteable_id] = noteable.id
end
end
end
diff --git a/app/controllers/dashboard/projects_controller.rb b/app/controllers/dashboard/projects_controller.rb
index 65d14781d92..daeb8fda417 100644
--- a/app/controllers/dashboard/projects_controller.rb
+++ b/app/controllers/dashboard/projects_controller.rb
@@ -3,11 +3,12 @@
class Dashboard::ProjectsController < Dashboard::ApplicationController
include ParamsBackwardCompatibility
include RendersMemberAccess
+ include OnboardingExperimentHelper
prepend_before_action(only: [:index]) { authenticate_sessionless_user!(:rss) }
before_action :set_non_archived_param
- before_action :projects, only: [:index]
before_action :default_sorting
+ before_action :projects, only: [:index]
skip_cross_project_access_check :index, :starred
def index
diff --git a/app/controllers/dashboard/todos_controller.rb b/app/controllers/dashboard/todos_controller.rb
index 27980466a42..8f6fcb362d2 100644
--- a/app/controllers/dashboard/todos_controller.rb
+++ b/app/controllers/dashboard/todos_controller.rb
@@ -22,7 +22,7 @@ class Dashboard::TodosController < Dashboard::ApplicationController
format.html do
redirect_to dashboard_todos_path,
status: 302,
- notice: _('Todo was successfully marked as done.')
+ notice: _('To-do item successfully marked as done.')
end
format.js { head :ok }
format.json { render json: todos_counts }
@@ -33,7 +33,7 @@ class Dashboard::TodosController < Dashboard::ApplicationController
updated_ids = TodoService.new.mark_todos_as_done(@todos, current_user)
respond_to do |format|
- format.html { redirect_to dashboard_todos_path, status: 302, notice: _('All todos were marked as done.') }
+ format.html { redirect_to dashboard_todos_path, status: 302, notice: _('Everything on your to-do list is marked as done.') }
format.js { head :ok }
format.json { render json: todos_counts.merge(updated_ids: updated_ids) }
end
diff --git a/app/controllers/graphql_controller.rb b/app/controllers/graphql_controller.rb
index 1ce0afac83b..9fbbe373b0d 100644
--- a/app/controllers/graphql_controller.rb
+++ b/app/controllers/graphql_controller.rb
@@ -11,7 +11,6 @@ class GraphqlController < ApplicationController
# around in GraphiQL.
protect_from_forgery with: :null_session, only: :execute
- before_action :check_graphql_feature_flag!
before_action :authorize_access_api!
before_action(only: [:execute]) { authenticate_sessionless_user!(:api) }
@@ -86,8 +85,4 @@ class GraphqlController < ApplicationController
render json: error, status: status
end
-
- def check_graphql_feature_flag!
- render_404 unless Gitlab::Graphql.enabled?
- end
end
diff --git a/app/controllers/groups_controller.rb b/app/controllers/groups_controller.rb
index 316da8f129d..797833e3f91 100644
--- a/app/controllers/groups_controller.rb
+++ b/app/controllers/groups_controller.rb
@@ -201,8 +201,7 @@ class GroupsController < Groups::ApplicationController
params[:sort] ||= 'latest_activity_desc'
options = {}
- options[:only_owned] = true if params[:shared] == '0'
- options[:only_shared] = true if params[:shared] == '1'
+ options[:include_subgroups] = true
@projects = GroupProjectsFinder.new(params: params, group: group, options: options, current_user: current_user)
.execute
diff --git a/app/controllers/projects/application_controller.rb b/app/controllers/projects/application_controller.rb
index 90396c15375..b1f285f76d7 100644
--- a/app/controllers/projects/application_controller.rb
+++ b/app/controllers/projects/application_controller.rb
@@ -12,6 +12,11 @@ class Projects::ApplicationController < ApplicationController
helper_method :repository, :can_collaborate_with_project?, :user_access
+ rescue_from Gitlab::Template::Finders::RepoTemplateFinder::FileNotFoundError do |exception|
+ log_exception(exception)
+ render_404
+ end
+
private
def project
diff --git a/app/controllers/projects/branches_controller.rb b/app/controllers/projects/branches_controller.rb
index da5efe4f21c..141a7dfb923 100644
--- a/app/controllers/projects/branches_controller.rb
+++ b/app/controllers/projects/branches_controller.rb
@@ -68,8 +68,9 @@ class Projects::BranchesController < Projects::ApplicationController
success = (result[:status] == :success)
if params[:issue_iid] && success
- issue = IssuesFinder.new(current_user, project_id: @project.id).find_by(iid: params[:issue_iid])
- SystemNoteService.new_issue_branch(issue, @project, current_user, branch_name) if issue
+ target_project = confidential_issue_project || @project
+ issue = IssuesFinder.new(current_user, project_id: target_project.id).find_by(iid: params[:issue_iid])
+ SystemNoteService.new_issue_branch(issue, target_project, current_user, branch_name, branch_project: @project) if issue
end
respond_to do |format|
@@ -166,4 +167,15 @@ class Projects::BranchesController < Projects::ApplicationController
@branches = Kaminari.paginate_array(@branches).page(params[:page])
end
end
+
+ def confidential_issue_project
+ return unless helpers.create_confidential_merge_request_enabled?
+ return if params[:confidential_issue_project_id].blank?
+
+ confidential_issue_project = Project.find(params[:confidential_issue_project_id])
+
+ return unless can?(current_user, :update_issue, confidential_issue_project)
+
+ confidential_issue_project
+ end
end
diff --git a/app/controllers/projects/deployments_controller.rb b/app/controllers/projects/deployments_controller.rb
index 0a009477d61..32111b07a0b 100644
--- a/app/controllers/projects/deployments_controller.rb
+++ b/app/controllers/projects/deployments_controller.rb
@@ -15,24 +15,22 @@ class Projects::DeploymentsController < Projects::ApplicationController
# rubocop: enable CodeReuse/ActiveRecord
def metrics
- return render_404 unless deployment.has_metrics?
+ return render_404 unless deployment_metrics.has_metrics?
- @metrics = deployment.metrics
+ @metrics = deployment_metrics.metrics
if @metrics&.any?
render json: @metrics, status: :ok
else
head :no_content
end
- rescue NotImplementedError
- render_404
end
def additional_metrics
- return render_404 unless deployment.has_metrics?
+ return render_404 unless deployment_metrics.has_metrics?
respond_to do |format|
format.json do
- metrics = deployment.additional_metrics
+ metrics = deployment_metrics.additional_metrics
if metrics.any?
render json: metrics
@@ -45,6 +43,10 @@ class Projects::DeploymentsController < Projects::ApplicationController
private
+ def deployment_metrics
+ @deployment_metrics ||= DeploymentMetrics.new(deployment.project, deployment)
+ end
+
# rubocop: disable CodeReuse/ActiveRecord
def deployment
@deployment ||= environment.deployments.find_by(iid: params[:id])
diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb
index f221f0363d3..228de8bc6f3 100644
--- a/app/controllers/projects/issues_controller.rb
+++ b/app/controllers/projects/issues_controller.rb
@@ -45,8 +45,6 @@ class Projects::IssuesController < Projects::ApplicationController
before_action :authorize_import_issues!, only: [:import_csv]
before_action :authorize_download_code!, only: [:related_branches]
- before_action :set_suggested_issues_feature_flags, only: [:new]
-
respond_to :html
def index
@@ -172,6 +170,7 @@ class Projects::IssuesController < Projects::ApplicationController
def create_merge_request
create_params = params.slice(:branch_name, :ref).merge(issue_iid: issue.iid)
+ create_params[:target_project_id] = params[:target_project_id] if helpers.create_confidential_merge_request_enabled?
result = ::MergeRequests::CreateFromIssueService.new(project, current_user, create_params).execute
if result[:status] == :success
@@ -284,8 +283,4 @@ class Projects::IssuesController < Projects::ApplicationController
# 3. https://gitlab.com/gitlab-org/gitlab-ce/issues/42426
Gitlab::QueryLimiting.whitelist('https://gitlab.com/gitlab-org/gitlab-ce/issues/42422')
end
-
- def set_suggested_issues_feature_flags
- push_frontend_feature_flag(:graphql, default_enabled: true)
- end
end
diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb
index 7ee8e0ea8f8..2aa2508be16 100644
--- a/app/controllers/projects/merge_requests_controller.rb
+++ b/app/controllers/projects/merge_requests_controller.rb
@@ -201,7 +201,7 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
end
def rebase
- RebaseWorker.perform_async(@merge_request.id, current_user.id)
+ @merge_request.rebase_async(current_user.id)
head :ok
end
diff --git a/app/controllers/projects/registry/repositories_controller.rb b/app/controllers/projects/registry/repositories_controller.rb
index 6d60117c37d..e205e2fd4f8 100644
--- a/app/controllers/projects/registry/repositories_controller.rb
+++ b/app/controllers/projects/registry/repositories_controller.rb
@@ -46,6 +46,8 @@ module Projects
repository.save! if repository.has_tags?
end
end
+ rescue ContainerRegistry::Path::InvalidRegistryPathError
+ @character_error = true
end
end
end
diff --git a/app/controllers/projects/settings/repository_controller.rb b/app/controllers/projects/settings/repository_controller.rb
index ac3004d069f..bc2ce15286f 100644
--- a/app/controllers/projects/settings/repository_controller.rb
+++ b/app/controllers/projects/settings/repository_controller.rb
@@ -99,7 +99,7 @@ module Projects
end
def deploy_token_params
- params.require(:deploy_token).permit(:name, :expires_at, :read_repository, :read_registry)
+ params.require(:deploy_token).permit(:name, :expires_at, :read_repository, :read_registry, :username)
end
end
end
diff --git a/app/controllers/projects/templates_controller.rb b/app/controllers/projects/templates_controller.rb
index 7ceea4e5b96..f987033a26c 100644
--- a/app/controllers/projects/templates_controller.rb
+++ b/app/controllers/projects/templates_controller.rb
@@ -1,7 +1,9 @@
# frozen_string_literal: true
class Projects::TemplatesController < Projects::ApplicationController
- before_action :authenticate_user!, :get_template_class
+ before_action :authenticate_user!
+ before_action :authorize_can_read_issuable!
+ before_action :get_template_class
def show
template = @template_type.find(params[:key], project)
@@ -13,9 +15,20 @@ class Projects::TemplatesController < Projects::ApplicationController
private
+ # User must have:
+ # - `read_merge_request` to see merge request templates, or
+ # - `read_issue` to see issue templates
+ #
+ # Note params[:template_type] has a route constraint to limit it to
+ # `merge_request` or `issue`
+ def authorize_can_read_issuable!
+ action = [:read_, params[:template_type]].join
+
+ authorize_action!(action)
+ end
+
def get_template_class
template_types = { issue: Gitlab::Template::IssueTemplate, merge_request: Gitlab::Template::MergeRequestTemplate }.with_indifferent_access
@template_type = template_types[params[:template_type]]
- render json: [], status: :not_found unless @template_type
end
end
diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb
index 12db493978b..feefc7f8137 100644
--- a/app/controllers/projects_controller.rb
+++ b/app/controllers/projects_controller.rb
@@ -182,7 +182,7 @@ class ProjectsController < Projects::ApplicationController
end
def housekeeping
- ::Projects::HousekeepingService.new(@project).execute
+ ::Projects::HousekeepingService.new(@project, :gc).execute
redirect_to(
project_path(@project),
@@ -298,7 +298,7 @@ class ProjectsController < Projects::ApplicationController
elsif @project.feature_available?(:issues, current_user)
@issues = issuables_collection.page(params[:page])
@collection_type = 'Issue'
- @issuable_meta_data = issuable_meta_data(@issues, @collection_type)
+ @issuable_meta_data = issuable_meta_data(@issues, @collection_type, current_user)
end
render :show
diff --git a/app/controllers/snippets/notes_controller.rb b/app/controllers/snippets/notes_controller.rb
index eee14b0faf4..612897f27e6 100644
--- a/app/controllers/snippets/notes_controller.rb
+++ b/app/controllers/snippets/notes_controller.rb
@@ -5,8 +5,8 @@ class Snippets::NotesController < ApplicationController
include ToggleAwardEmoji
skip_before_action :authenticate_user!, only: [:index]
- before_action :snippet
- before_action :authorize_read_snippet!, only: [:show, :index, :create]
+ before_action :authorize_read_snippet!, only: [:show, :index]
+ before_action :authorize_create_note!, only: [:create]
private
@@ -33,4 +33,8 @@ class Snippets::NotesController < ApplicationController
def authorize_read_snippet!
return render_404 unless can?(current_user, :read_personal_snippet, snippet)
end
+
+ def authorize_create_note!
+ access_denied! unless can?(current_user, :create_note, noteable)
+ end
end
diff --git a/app/controllers/snippets_controller.rb b/app/controllers/snippets_controller.rb
index 8ea5450b4e8..fad036b8df8 100644
--- a/app/controllers/snippets_controller.rb
+++ b/app/controllers/snippets_controller.rb
@@ -137,7 +137,7 @@ class SnippetsController < ApplicationController
def move_temporary_files
params[:files].each do |file|
- FileMover.new(file, @snippet).execute
+ FileMover.new(file, from_model: current_user, to_model: @snippet).execute
end
end
end
diff --git a/app/controllers/uploads_controller.rb b/app/controllers/uploads_controller.rb
index 5d28635232b..94bd18f70d4 100644
--- a/app/controllers/uploads_controller.rb
+++ b/app/controllers/uploads_controller.rb
@@ -41,7 +41,11 @@ class UploadsController < ApplicationController
when Note
can?(current_user, :read_project, model.project)
when User
- true
+ # We validate the current user has enough (writing)
+ # access to itself when a secret is given.
+ # For instance, user avatars are readable by anyone,
+ # while temporary, user snippet uploads are not.
+ !secret? || can?(current_user, :update_user, model)
when Appearance
true
else
@@ -56,9 +60,13 @@ class UploadsController < ApplicationController
def authorize_create_access!
return unless model
- # for now we support only personal snippets comments. Only personal_snippet
- # is allowed as a model to #create through routing.
- authorized = can?(current_user, :create_note, model)
+ authorized =
+ case model
+ when User
+ can?(current_user, :update_user, model)
+ else
+ can?(current_user, :create_note, model)
+ end
render_unauthorized unless authorized
end
@@ -75,6 +83,10 @@ class UploadsController < ApplicationController
User === model || Appearance === model
end
+ def secret?
+ params[:secret].present?
+ end
+
def upload_model_class
MODEL_CLASSES[params[:model]] || raise(UnknownUploadModelError)
end
diff --git a/app/finders/issuable_finder.rb b/app/finders/issuable_finder.rb
index 3592505a977..f4fbeacfaba 100644
--- a/app/finders/issuable_finder.rb
+++ b/app/finders/issuable_finder.rb
@@ -429,7 +429,7 @@ class IssuableFinder
items = klass.with(cte.to_arel).from(klass.table_name)
end
- items.full_search(search, matched_columns: params[:in])
+ items.full_search(search, matched_columns: params[:in], use_minimum_char_limit: !use_cte_for_search?)
end
# rubocop: enable CodeReuse/ActiveRecord
diff --git a/app/finders/runner_jobs_finder.rb b/app/finders/runner_jobs_finder.rb
index 4fca4ec94f3..ef90817416a 100644
--- a/app/finders/runner_jobs_finder.rb
+++ b/app/finders/runner_jobs_finder.rb
@@ -3,6 +3,8 @@
class RunnerJobsFinder
attr_reader :runner, :params
+ ALLOWED_INDEXED_COLUMNS = %w[id].freeze
+
def initialize(runner, params = {})
@runner = runner
@params = params
@@ -11,7 +13,7 @@ class RunnerJobsFinder
def execute
items = @runner.builds
items = by_status(items)
- items
+ sort_items(items)
end
private
@@ -23,4 +25,19 @@ class RunnerJobsFinder
items.where(status: params[:status])
end
# rubocop: enable CodeReuse/ActiveRecord
+
+ # rubocop: disable CodeReuse/ActiveRecord
+ def sort_items(items)
+ return items unless ALLOWED_INDEXED_COLUMNS.include?(params[:order_by])
+
+ order_by = params[:order_by]
+ sort = if /\A(ASC|DESC)\z/i.match?(params[:sort])
+ params[:sort]
+ else
+ :desc
+ end
+
+ items.order(order_by => sort)
+ end
+ # rubocop: enable CodeReuse/ActiveRecord
end
diff --git a/app/graphql/gitlab_schema.rb b/app/graphql/gitlab_schema.rb
index 5615909c4ec..152ebb930e2 100644
--- a/app/graphql/gitlab_schema.rb
+++ b/app/graphql/gitlab_schema.rb
@@ -13,6 +13,7 @@ class GitlabSchema < GraphQL::Schema
use BatchLoader::GraphQL
use Gitlab::Graphql::Authorize
use Gitlab::Graphql::Present
+ use Gitlab::Graphql::CallsGitaly
use Gitlab::Graphql::Connections
use Gitlab::Graphql::GenericTracing
diff --git a/app/graphql/types/base_field.rb b/app/graphql/types/base_field.rb
index dd0d9105df6..efeee4a7a4d 100644
--- a/app/graphql/types/base_field.rb
+++ b/app/graphql/types/base_field.rb
@@ -7,18 +7,34 @@ module Types
DEFAULT_COMPLEXITY = 1
def initialize(*args, **kwargs, &block)
+ @calls_gitaly = !!kwargs.delete(:calls_gitaly)
+ @constant_complexity = !!kwargs[:complexity]
kwargs[:complexity] ||= field_complexity(kwargs[:resolver_class])
super(*args, **kwargs, &block)
end
+ def base_complexity
+ complexity = DEFAULT_COMPLEXITY
+ complexity += 1 if calls_gitaly?
+ complexity
+ end
+
+ def calls_gitaly?
+ @calls_gitaly
+ end
+
+ def constant_complexity?
+ @constant_complexity
+ end
+
private
def field_complexity(resolver_class)
if resolver_class
field_resolver_complexity
else
- DEFAULT_COMPLEXITY
+ base_complexity
end
end
@@ -31,6 +47,7 @@ module Types
proc do |ctx, args, child_complexity|
# Resolvers may add extra complexity depending on used arguments
complexity = child_complexity + self.resolver&.try(:resolver_complexity, args, child_complexity: child_complexity).to_i
+ complexity += 1 if calls_gitaly?
field_defn = to_graphql
diff --git a/app/graphql/types/ci/detailed_status_type.rb b/app/graphql/types/ci/detailed_status_type.rb
index 2987354b556..5f7d7a934ce 100644
--- a/app/graphql/types/ci/detailed_status_type.rb
+++ b/app/graphql/types/ci/detailed_status_type.rb
@@ -1,6 +1,8 @@
# frozen_string_literal: true
module Types
module Ci
+ # rubocop: disable Graphql/AuthorizeTypes
+ # This is presented through `PipelineType` that has its own authorization
class DetailedStatusType < BaseObject
graphql_name 'DetailedStatus'
@@ -13,5 +15,6 @@ module Types
field :text, GraphQL::STRING_TYPE, null: false
field :tooltip, GraphQL::STRING_TYPE, null: false, method: :status_tooltip
end
+ # rubocop: enable Graphql/AuthorizeTypes
end
end
diff --git a/app/graphql/types/issue_state_enum.rb b/app/graphql/types/issue_state_enum.rb
index 6521407fc9d..70c34fbe491 100644
--- a/app/graphql/types/issue_state_enum.rb
+++ b/app/graphql/types/issue_state_enum.rb
@@ -1,8 +1,11 @@
# frozen_string_literal: true
module Types
+ # rubocop: disable Graphql/AuthorizeTypes
+ # This is a BaseEnum through IssuableEnum, so it does not need authorization
class IssueStateEnum < IssuableStateEnum
graphql_name 'IssueState'
description 'State of a GitLab issue'
end
+ # rubocop: enable Graphql/AuthorizeTypes
end
diff --git a/app/graphql/types/label_type.rb b/app/graphql/types/label_type.rb
index 50eb1b89c61..3aeda2e7953 100644
--- a/app/graphql/types/label_type.rb
+++ b/app/graphql/types/label_type.rb
@@ -4,6 +4,8 @@ module Types
class LabelType < BaseObject
graphql_name 'Label'
+ authorize :read_label
+
field :description, GraphQL::STRING_TYPE, null: true
markdown_field :description_html, null: true
field :title, GraphQL::STRING_TYPE, null: false
diff --git a/app/graphql/types/merge_request_state_enum.rb b/app/graphql/types/merge_request_state_enum.rb
index 92f52726ab3..37c890a3c8d 100644
--- a/app/graphql/types/merge_request_state_enum.rb
+++ b/app/graphql/types/merge_request_state_enum.rb
@@ -1,10 +1,13 @@
# frozen_string_literal: true
module Types
+ # rubocop: disable Graphql/AuthorizeTypes
+ # This is a BaseEnum through IssuableEnum, so it does not need authorization
class MergeRequestStateEnum < IssuableStateEnum
graphql_name 'MergeRequestState'
description 'State of a GitLab merge request'
value 'merged'
end
+ # rubocop: enable Graphql/AuthorizeTypes
end
diff --git a/app/graphql/types/merge_request_type.rb b/app/graphql/types/merge_request_type.rb
index 577ccd48ef8..6734d4761c2 100644
--- a/app/graphql/types/merge_request_type.rb
+++ b/app/graphql/types/merge_request_type.rb
@@ -43,7 +43,7 @@ module Types
field :allow_collaboration, GraphQL::BOOLEAN_TYPE, null: true
field :should_be_rebased, GraphQL::BOOLEAN_TYPE, method: :should_be_rebased?, null: false
field :rebase_commit_sha, GraphQL::STRING_TYPE, null: true
- field :rebase_in_progress, GraphQL::BOOLEAN_TYPE, method: :rebase_in_progress?, null: false
+ field :rebase_in_progress, GraphQL::BOOLEAN_TYPE, method: :rebase_in_progress?, null: false, calls_gitaly: true
field :merge_commit_message, GraphQL::STRING_TYPE, method: :default_merge_commit_message, null: true, deprecation_reason: "Renamed to defaultMergeCommitMessage"
field :default_merge_commit_message, GraphQL::STRING_TYPE, null: true
field :merge_ongoing, GraphQL::BOOLEAN_TYPE, method: :merge_ongoing?, null: false
diff --git a/app/graphql/types/metadata_type.rb b/app/graphql/types/metadata_type.rb
index 2d8bad0614b..7d7813a7652 100644
--- a/app/graphql/types/metadata_type.rb
+++ b/app/graphql/types/metadata_type.rb
@@ -4,6 +4,8 @@ module Types
class MetadataType < ::Types::BaseObject
graphql_name 'Metadata'
+ authorize :read_instance_metadata
+
field :version, GraphQL::STRING_TYPE, null: false
field :revision, GraphQL::STRING_TYPE, null: false
end
diff --git a/app/graphql/types/mutation_type.rb b/app/graphql/types/mutation_type.rb
index 6ef1d816b7c..bc5fb709522 100644
--- a/app/graphql/types/mutation_type.rb
+++ b/app/graphql/types/mutation_type.rb
@@ -9,6 +9,6 @@ module Types
mount_mutation Mutations::AwardEmojis::Add
mount_mutation Mutations::AwardEmojis::Remove
mount_mutation Mutations::AwardEmojis::Toggle
- mount_mutation Mutations::MergeRequests::SetWip
+ mount_mutation Mutations::MergeRequests::SetWip, calls_gitaly: true
end
end
diff --git a/app/graphql/types/namespace_type.rb b/app/graphql/types/namespace_type.rb
index 62feccaa660..f105e9e6e28 100644
--- a/app/graphql/types/namespace_type.rb
+++ b/app/graphql/types/namespace_type.rb
@@ -4,6 +4,8 @@ module Types
class NamespaceType < BaseObject
graphql_name 'Namespace'
+ authorize :read_namespace
+
field :id, GraphQL::ID_TYPE, null: false
field :name, GraphQL::STRING_TYPE, null: false
diff --git a/app/graphql/types/notes/diff_position_type.rb b/app/graphql/types/notes/diff_position_type.rb
index 104ccb79bbb..ebc24451715 100644
--- a/app/graphql/types/notes/diff_position_type.rb
+++ b/app/graphql/types/notes/diff_position_type.rb
@@ -2,6 +2,8 @@
module Types
module Notes
+ # rubocop: disable Graphql/AuthorizeTypes
+ # This is presented through `NoteType` that has its own authorization
class DiffPositionType < BaseObject
graphql_name 'DiffPosition'
@@ -42,5 +44,6 @@ module Types
description: "The total height of the image",
resolve: -> (position, _args, _ctx) { position.height if position.on_image? }
end
+ # rubocop: enable Graphql/AuthorizeTypes
end
end
diff --git a/app/graphql/types/permission_types/merge_request.rb b/app/graphql/types/permission_types/merge_request.rb
index 13995d3ea8f..d877fc177d2 100644
--- a/app/graphql/types/permission_types/merge_request.rb
+++ b/app/graphql/types/permission_types/merge_request.rb
@@ -10,8 +10,8 @@ module Types
abilities :read_merge_request, :admin_merge_request,
:update_merge_request, :create_note
- permission_field :push_to_source_branch, method: :can_push_to_source_branch?
- permission_field :remove_source_branch, method: :can_remove_source_branch?
+ permission_field :push_to_source_branch, method: :can_push_to_source_branch?, calls_gitaly: true
+ permission_field :remove_source_branch, method: :can_remove_source_branch?, calls_gitaly: true
permission_field :cherry_pick_on_current_merge_request, method: :can_cherry_pick_on_current_merge_request?
permission_field :revert_on_current_merge_request, method: :can_revert_on_current_merge_request?
end
diff --git a/app/graphql/types/project_type.rb b/app/graphql/types/project_type.rb
index ac957eafafc..13be71c26ee 100644
--- a/app/graphql/types/project_type.rb
+++ b/app/graphql/types/project_type.rb
@@ -26,7 +26,7 @@ module Types
field :web_url, GraphQL::STRING_TYPE, null: true
field :star_count, GraphQL::INT_TYPE, null: false
- field :forks_count, GraphQL::INT_TYPE, null: false
+ field :forks_count, GraphQL::INT_TYPE, null: false, calls_gitaly: true # 4 times
field :created_at, Types::TimeType, null: true
field :last_activity_at, Types::TimeType, null: true
@@ -40,7 +40,7 @@ module Types
field :lfs_enabled, GraphQL::BOOLEAN_TYPE, null: true
field :merge_requests_ff_only_enabled, GraphQL::BOOLEAN_TYPE, null: true
- field :avatar_url, GraphQL::STRING_TYPE, null: true, resolve: -> (project, args, ctx) do
+ field :avatar_url, GraphQL::STRING_TYPE, null: true, calls_gitaly: true, resolve: -> (project, args, ctx) do
project.avatar_url(only_path: false)
end
@@ -67,14 +67,14 @@ module Types
field :only_allow_merge_if_all_discussions_are_resolved, GraphQL::BOOLEAN_TYPE, null: true
field :printing_merge_request_link_enabled, GraphQL::BOOLEAN_TYPE, null: true
- field :namespace, Types::NamespaceType, null: false
+ field :namespace, Types::NamespaceType, null: true
field :group, Types::GroupType, null: true
field :statistics, Types::ProjectStatisticsType,
null: true,
resolve: -> (obj, _args, _ctx) { Gitlab::Graphql::Loaders::BatchProjectStatisticsLoader.new(obj.id).find }
- field :repository, Types::RepositoryType, null: false
+ field :repository, Types::RepositoryType, null: true
field :merge_requests,
Types::MergeRequestType.connection_type,
diff --git a/app/graphql/types/query_type.rb b/app/graphql/types/query_type.rb
index 536bdb077ad..53d36b43576 100644
--- a/app/graphql/types/query_type.rb
+++ b/app/graphql/types/query_type.rb
@@ -22,10 +22,7 @@ module Types
field :metadata, Types::MetadataType,
null: true,
resolver: Resolvers::MetadataResolver,
- description: 'Metadata about GitLab' do |*args|
-
- authorize :read_instance_metadata
- end
+ description: 'Metadata about GitLab'
field :echo, GraphQL::STRING_TYPE, null: false, function: Functions::Echo.new
end
diff --git a/app/graphql/types/repository_type.rb b/app/graphql/types/repository_type.rb
index 5987467e1ea..b024eca61fc 100644
--- a/app/graphql/types/repository_type.rb
+++ b/app/graphql/types/repository_type.rb
@@ -6,9 +6,9 @@ module Types
authorize :download_code
- field :root_ref, GraphQL::STRING_TYPE, null: true
- field :empty, GraphQL::BOOLEAN_TYPE, null: false, method: :empty?
+ field :root_ref, GraphQL::STRING_TYPE, null: true, calls_gitaly: true
+ field :empty, GraphQL::BOOLEAN_TYPE, null: false, method: :empty?, calls_gitaly: true
field :exists, GraphQL::BOOLEAN_TYPE, null: false, method: :exists?
- field :tree, Types::Tree::TreeType, null: true, resolver: Resolvers::TreeResolver
+ field :tree, Types::Tree::TreeType, null: true, resolver: Resolvers::TreeResolver, calls_gitaly: true
end
end
diff --git a/app/graphql/types/task_completion_status.rb b/app/graphql/types/task_completion_status.rb
index c289802509d..ac128481ac4 100644
--- a/app/graphql/types/task_completion_status.rb
+++ b/app/graphql/types/task_completion_status.rb
@@ -1,6 +1,9 @@
# frozen_string_literal: true
module Types
+ # rubocop: disable Graphql/AuthorizeTypes
+ # This is used in `IssueType` and `MergeRequestType` both of which have their
+ # own authorization
class TaskCompletionStatus < BaseObject
graphql_name 'TaskCompletionStatus'
description 'Completion status of tasks'
@@ -8,4 +11,5 @@ module Types
field :count, GraphQL::INT_TYPE, null: false
field :completed_count, GraphQL::INT_TYPE, null: false
end
+ # rubocop: enable Graphql/AuthorizeTypes
end
diff --git a/app/graphql/types/tree/blob_type.rb b/app/graphql/types/tree/blob_type.rb
index 760781f3612..9497e378dc0 100644
--- a/app/graphql/types/tree/blob_type.rb
+++ b/app/graphql/types/tree/blob_type.rb
@@ -1,6 +1,8 @@
# frozen_string_literal: true
module Types
module Tree
+ # rubocop: disable Graphql/AuthorizeTypes
+ # This is presented through `Repository` that has its own authorization
class BlobType < BaseObject
implements Types::Tree::EntryType
@@ -12,6 +14,7 @@ module Types
field :lfs_oid, GraphQL::STRING_TYPE, null: true, resolve: -> (blob, args, ctx) do
Gitlab::Graphql::Loaders::BatchLfsOidLoader.new(blob.repository, blob.id).find
end
+ # rubocop: enable Graphql/AuthorizeTypes
end
end
end
diff --git a/app/graphql/types/tree/submodule_type.rb b/app/graphql/types/tree/submodule_type.rb
index cea76dbfd2a..8cb1e04f5ba 100644
--- a/app/graphql/types/tree/submodule_type.rb
+++ b/app/graphql/types/tree/submodule_type.rb
@@ -1,10 +1,13 @@
# frozen_string_literal: true
module Types
module Tree
+ # rubocop: disable Graphql/AuthorizeTypes
+ # This is presented through `Repository` that has its own authorization
class SubmoduleType < BaseObject
implements Types::Tree::EntryType
graphql_name 'Submodule'
end
+ # rubocop: enable Graphql/AuthorizeTypes
end
end
diff --git a/app/graphql/types/tree/tree_entry_type.rb b/app/graphql/types/tree/tree_entry_type.rb
index 23ec2ef0ec2..d7faa633706 100644
--- a/app/graphql/types/tree/tree_entry_type.rb
+++ b/app/graphql/types/tree/tree_entry_type.rb
@@ -1,6 +1,8 @@
# frozen_string_literal: true
module Types
module Tree
+ # rubocop: disable Graphql/AuthorizeTypes
+ # This is presented through `Repository` that has its own authorization
class TreeEntryType < BaseObject
implements Types::Tree::EntryType
@@ -11,5 +13,6 @@ module Types
field :web_url, GraphQL::STRING_TYPE, null: true
end
+ # rubocop: enable Graphql/AuthorizeTypes
end
end
diff --git a/app/graphql/types/tree/tree_type.rb b/app/graphql/types/tree/tree_type.rb
index cbc448a0695..fbdc1597461 100644
--- a/app/graphql/types/tree/tree_type.rb
+++ b/app/graphql/types/tree/tree_type.rb
@@ -1,11 +1,13 @@
# frozen_string_literal: true
module Types
module Tree
+ # rubocop: disable Graphql/AuthorizeTypes
+ # This is presented through `Repository` that has its own authorization
class TreeType < BaseObject
graphql_name 'Tree'
# Complexity 10 as it triggers a Gitaly call on each render
- field :last_commit, Types::CommitType, null: true, complexity: 10, resolve: -> (tree, args, ctx) do
+ field :last_commit, Types::CommitType, null: true, complexity: 10, calls_gitaly: true, resolve: -> (tree, args, ctx) do
tree.repository.last_commit_for_path(tree.sha, tree.path)
end
@@ -13,11 +15,12 @@ module Types
Gitlab::Graphql::Representation::TreeEntry.decorate(obj.trees, obj.repository)
end
- field :submodules, Types::Tree::SubmoduleType.connection_type, null: false
+ field :submodules, Types::Tree::SubmoduleType.connection_type, null: false, calls_gitaly: true
- field :blobs, Types::Tree::BlobType.connection_type, null: false, resolve: -> (obj, args, ctx) do
+ field :blobs, Types::Tree::BlobType.connection_type, null: false, calls_gitaly: true, resolve: -> (obj, args, ctx) do
Gitlab::Graphql::Representation::TreeEntry.decorate(obj.blobs, obj.repository)
end
+ # rubocop: enable Graphql/AuthorizeTypes
end
end
end
diff --git a/app/helpers/application_settings_helper.rb b/app/helpers/application_settings_helper.rb
index aaaa954047f..4bf9b708401 100644
--- a/app/helpers/application_settings_helper.rb
+++ b/app/helpers/application_settings_helper.rb
@@ -69,7 +69,7 @@ module ApplicationSettingsHelper
# toggle button effect.
def import_sources_checkboxes(help_block_id, options = {})
Gitlab::ImportSources.options.map do |name, source|
- checked = Gitlab::CurrentSettings.import_sources.include?(source)
+ checked = @application_setting.import_sources.include?(source)
css_class = checked ? 'active' : ''
checkbox_name = 'application_setting[import_sources][]'
@@ -85,7 +85,7 @@ module ApplicationSettingsHelper
def oauth_providers_checkboxes
button_based_providers.map do |source|
- disabled = Gitlab::CurrentSettings.disabled_oauth_sign_in_sources.include?(source.to_s)
+ disabled = @application_setting.disabled_oauth_sign_in_sources.include?(source.to_s)
css_class = ['btn']
css_class << 'active' unless disabled
checkbox_name = 'application_setting[enabled_oauth_sign_in_sources][]'
@@ -187,6 +187,8 @@ module ApplicationSettingsHelper
:gitaly_timeout_default,
:gitaly_timeout_medium,
:gitaly_timeout_fast,
+ :grafana_enabled,
+ :grafana_url,
:gravatar_enabled,
:hashed_storage_enabled,
:help_page_hide_commercial_content,
diff --git a/app/helpers/auth_helper.rb b/app/helpers/auth_helper.rb
index 076976175a9..31c4b27273b 100644
--- a/app/helpers/auth_helper.rb
+++ b/app/helpers/auth_helper.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module AuthHelper
- PROVIDERS_WITH_ICONS = %w(twitter github gitlab bitbucket google_oauth2 facebook azure_oauth2 authentiq).freeze
+ PROVIDERS_WITH_ICONS = %w(twitter github gitlab bitbucket google_oauth2 facebook azure_oauth2 authentiq salesforce).freeze
LDAP_PROVIDER = /\Aldap/.freeze
def ldap_enabled?
diff --git a/app/helpers/branches_helper.rb b/app/helpers/branches_helper.rb
index eadf48205fc..c759882d7f8 100644
--- a/app/helpers/branches_helper.rb
+++ b/app/helpers/branches_helper.rb
@@ -8,12 +8,4 @@ module BranchesHelper
def protected_branch?(project, branch)
ProtectedBranch.protected?(project, branch.name)
end
-
- def diverging_count_label(count)
- if count >= Repository::MAX_DIVERGING_COUNT
- "#{Repository::MAX_DIVERGING_COUNT - 1}+"
- else
- count.to_s
- end
- end
end
diff --git a/app/helpers/issuables_helper.rb b/app/helpers/issuables_helper.rb
index 045de105b77..67685ba4e1d 100644
--- a/app/helpers/issuables_helper.rb
+++ b/app/helpers/issuables_helper.rb
@@ -280,7 +280,7 @@ module IssuablesHelper
initialTaskStatus: issuable.task_status
}
- data[:hasClosingMergeRequest] = issuable.merge_requests_count != 0 if issuable.is_a?(Issue)
+ data[:hasClosingMergeRequest] = issuable.merge_requests_count(current_user) != 0 if issuable.is_a?(Issue)
if parent.is_a?(Group)
data[:groupPath] = parent.path
@@ -390,8 +390,8 @@ module IssuablesHelper
def issuable_todo_button_data(issuable, is_collapsed)
{
- todo_text: _('Add todo'),
- mark_text: _('Mark todo as done'),
+ todo_text: _('Add a To Do'),
+ mark_text: _('Mark as done'),
todo_icon: sprite_icon('todo-add'),
mark_icon: sprite_icon('todo-done', css_class: 'todo-undone'),
issuable_id: issuable[:id],
diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb
index dfadcfc33b2..5476a7cdff6 100644
--- a/app/helpers/issues_helper.rb
+++ b/app/helpers/issues_helper.rb
@@ -137,7 +137,7 @@ module IssuesHelper
end
def create_confidential_merge_request_enabled?
- Feature.enabled?(:create_confidential_merge_request, @project)
+ Feature.enabled?(:create_confidential_merge_request, @project, default_enabled: true)
end
def show_new_branch_button?
diff --git a/app/helpers/onboarding_experiment_helper.rb b/app/helpers/onboarding_experiment_helper.rb
new file mode 100644
index 00000000000..ad49d333d7a
--- /dev/null
+++ b/app/helpers/onboarding_experiment_helper.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+module OnboardingExperimentHelper
+ def allow_access_to_onboarding?
+ ::Gitlab.com? && Feature.enabled?(:user_onboarding)
+ end
+end
diff --git a/app/helpers/preferences_helper.rb b/app/helpers/preferences_helper.rb
index 766508b6609..3672d8b1b03 100644
--- a/app/helpers/preferences_helper.rb
+++ b/app/helpers/preferences_helper.rb
@@ -16,7 +16,7 @@ module PreferencesHelper
project_activity: _("Your Projects' Activity"),
starred_project_activity: _("Starred Projects' Activity"),
groups: _("Your Groups"),
- todos: _("Your Todos"),
+ todos: _("Your To-Do List"),
issues: _("Assigned Issues"),
merge_requests: _("Assigned Merge Requests"),
operations: _("Operations Dashboard")
diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb
index 8dee842a22d..8d0079a4dd3 100644
--- a/app/helpers/projects_helper.rb
+++ b/app/helpers/projects_helper.rb
@@ -662,6 +662,6 @@ module ProjectsHelper
end
def vue_file_list_enabled?
- Gitlab::Graphql.enabled? && Feature.enabled?(:vue_file_list, @project)
+ Feature.enabled?(:vue_file_list, @project)
end
end
diff --git a/app/helpers/snippets_helper.rb b/app/helpers/snippets_helper.rb
index ecb2b2d707b..6ccc1fb2ed1 100644
--- a/app/helpers/snippets_helper.rb
+++ b/app/helpers/snippets_helper.rb
@@ -1,6 +1,16 @@
# frozen_string_literal: true
module SnippetsHelper
+ def snippets_upload_path(snippet, user)
+ return unless user
+
+ if snippet&.persisted?
+ upload_path('personal_snippet', id: snippet.id)
+ else
+ upload_path('user', id: user.id)
+ end
+ end
+
def reliable_snippet_path(snippet, opts = nil)
if snippet.project_id?
project_snippet_path(snippet.project, snippet, opts)
diff --git a/app/helpers/storage_helper.rb b/app/helpers/storage_helper.rb
index ecf37bae6b3..ce810433a3a 100644
--- a/app/helpers/storage_helper.rb
+++ b/app/helpers/storage_helper.rb
@@ -17,6 +17,6 @@ module StorageHelper
counter_lfs_objects: storage_counter(statistics.lfs_objects_size)
}
- _("%{counter_repositories} repositories, %{counter_wikis} wikis, %{counter_build_artifacts} build artifacts, %{counter_lfs_objects} LFS") % counters
+ _("Repository: %{counter_repositories} / Wikis: %{counter_wikis} / Build Artifacts: %{counter_build_artifacts} / LFS: %{counter_lfs_objects}") % counters
end
end
diff --git a/app/mailers/emails/notes.rb b/app/mailers/emails/notes.rb
index 506c8d251b7..04db1980b99 100644
--- a/app/mailers/emails/notes.rb
+++ b/app/mailers/emails/notes.rb
@@ -51,7 +51,7 @@ module Emails
def note_thread_options(recipient_id)
{
from: sender(@note.author_id),
- to: recipient(recipient_id, @group),
+ to: recipient(recipient_id, @project&.group || @group),
subject: subject("#{@note.noteable.title} (#{@note.noteable.reference_link_text})")
}
end
@@ -60,7 +60,7 @@ module Emails
# `note_id` is a `Note` when originating in `NotifyPreview`
@note = note_id.is_a?(Note) ? note_id : Note.find(note_id)
@project = @note.project
- @group = @project.try(:group) || @note.noteable.try(:group)
+ @group = @note.noteable.try(:group)
if (@project || @group) && @note.persisted?
@sent_notification = SentNotification.record_note(@note, recipient_id, reply_key)
diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb
index cd645850af3..8e558487c1c 100644
--- a/app/models/application_setting.rb
+++ b/app/models/application_setting.rb
@@ -23,11 +23,6 @@ class ApplicationSetting < ApplicationRecord
serialize :domain_blacklist, Array # rubocop:disable Cop/ActiveRecordSerialize
serialize :repository_storages # rubocop:disable Cop/ActiveRecordSerialize
- ignore_column :circuitbreaker_failure_count_threshold
- ignore_column :circuitbreaker_failure_reset_time
- ignore_column :circuitbreaker_storage_timeout
- ignore_column :circuitbreaker_access_retries
- ignore_column :circuitbreaker_check_interval
ignore_column :koding_url
ignore_column :koding_enabled
ignore_column :sentry_enabled
@@ -277,4 +272,12 @@ class ApplicationSetting < ApplicationRecord
# We already have an ApplicationSetting record, so just return it.
current_without_cache
end
+
+ # By default, the backend is Rails.cache, which uses
+ # ActiveSupport::Cache::RedisStore. Since loading ApplicationSetting
+ # can cause a significant amount of load on Redis, let's cache it in
+ # memory.
+ def self.cache_backend
+ Gitlab::ThreadMemoryCache.cache_backend
+ end
end
diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb
index fd5aa216174..20ca4a9ab24 100644
--- a/app/models/ci/pipeline.rb
+++ b/app/models/ci/pipeline.rb
@@ -790,6 +790,10 @@ module Ci
stages.find_by!(name: name)
end
+ def error_messages
+ errors ? errors.full_messages.to_sentence : ""
+ end
+
private
def ci_yaml_from_repo
diff --git a/app/models/clusters/applications/ingress.rb b/app/models/clusters/applications/ingress.rb
index a1023f44049..1430b82c2f2 100644
--- a/app/models/clusters/applications/ingress.rb
+++ b/app/models/clusters/applications/ingress.rb
@@ -35,11 +35,8 @@ module Clusters
'stable/nginx-ingress'
end
- # We will implement this in future MRs.
- # Basically we need to check all dependent applications are not installed
- # first.
def allowed_to_uninstall?
- false
+ external_ip_or_hostname? && application_jupyter_nil_or_installable?
end
def install_command
@@ -52,6 +49,10 @@ module Clusters
)
end
+ def external_ip_or_hostname?
+ external_ip.present? || external_hostname.present?
+ end
+
def schedule_status_update
return unless installed?
return if external_ip
@@ -63,6 +64,12 @@ module Clusters
def ingress_service
cluster.kubeclient.get_service('ingress-nginx-ingress-controller', Gitlab::Kubernetes::Helm::NAMESPACE)
end
+
+ private
+
+ def application_jupyter_nil_or_installable?
+ cluster.application_jupyter.nil? || cluster.application_jupyter&.installable?
+ end
end
end
end
diff --git a/app/models/clusters/applications/jupyter.rb b/app/models/clusters/applications/jupyter.rb
index 4aaa1f941e5..9ede0615fa3 100644
--- a/app/models/clusters/applications/jupyter.rb
+++ b/app/models/clusters/applications/jupyter.rb
@@ -23,9 +23,7 @@ module Clusters
return unless cluster&.application_ingress_available?
ingress = cluster.application_ingress
- if ingress.external_ip || ingress.external_hostname
- self.status = 'installable'
- end
+ self.status = 'installable' if ingress.external_ip_or_hostname?
end
def chart
@@ -40,12 +38,6 @@ module Clusters
content_values.to_yaml
end
- # Will be addressed in future MRs
- # We need to investigate and document what will be permanently deleted.
- def allowed_to_uninstall?
- false
- end
-
def install_command
Gitlab::Kubernetes::Helm::InstallCommand.new(
name: name,
diff --git a/app/models/clusters/applications/prometheus.rb b/app/models/clusters/applications/prometheus.rb
index a6b7617b830..805c8a73f8c 100644
--- a/app/models/clusters/applications/prometheus.rb
+++ b/app/models/clusters/applications/prometheus.rb
@@ -49,14 +49,6 @@ module Clusters
)
end
- def uninstall_command
- Gitlab::Kubernetes::Helm::DeleteCommand.new(
- name: name,
- rbac: cluster.platform_kubernetes_rbac?,
- files: files
- )
- end
-
def upgrade_command(values)
::Gitlab::Kubernetes::Helm::InstallCommand.new(
name: name,
diff --git a/app/models/clusters/clusters_hierarchy.rb b/app/models/clusters/clusters_hierarchy.rb
new file mode 100644
index 00000000000..dab034b7234
--- /dev/null
+++ b/app/models/clusters/clusters_hierarchy.rb
@@ -0,0 +1,104 @@
+# frozen_string_literal: true
+
+module Clusters
+ class ClustersHierarchy
+ DEPTH_COLUMN = :depth
+
+ def initialize(clusterable)
+ @clusterable = clusterable
+ end
+
+ # Returns clusters in order from deepest to highest group
+ def base_and_ancestors
+ cte = recursive_cte
+ cte_alias = cte.table.alias(model.table_name)
+
+ model
+ .unscoped
+ .where('clusters.id IS NOT NULL')
+ .with
+ .recursive(cte.to_arel)
+ .from(cte_alias)
+ .order(DEPTH_COLUMN => :asc)
+ end
+
+ private
+
+ attr_reader :clusterable
+
+ def recursive_cte
+ cte = Gitlab::SQL::RecursiveCTE.new(:clusters_cte)
+
+ base_query = case clusterable
+ when ::Group
+ group_clusters_base_query
+ when ::Project
+ project_clusters_base_query
+ else
+ raise ArgumentError, "unknown type for #{clusterable}"
+ end
+
+ cte << base_query
+ cte << parent_query(cte)
+
+ cte
+ end
+
+ def group_clusters_base_query
+ group_parent_id_alias = alias_as_column(groups[:parent_id], 'group_parent_id')
+ join_sources = ::Group.left_joins(:clusters).join_sources
+
+ model
+ .unscoped
+ .select([clusters_star, group_parent_id_alias, "1 AS #{DEPTH_COLUMN}"])
+ .where(groups[:id].eq(clusterable.id))
+ .from(groups)
+ .joins(join_sources)
+ end
+
+ def project_clusters_base_query
+ projects = ::Project.arel_table
+ project_parent_id_alias = alias_as_column(projects[:namespace_id], 'group_parent_id')
+ join_sources = ::Project.left_joins(:clusters).join_sources
+
+ model
+ .unscoped
+ .select([clusters_star, project_parent_id_alias, "1 AS #{DEPTH_COLUMN}"])
+ .where(projects[:id].eq(clusterable.id))
+ .from(projects)
+ .joins(join_sources)
+ end
+
+ def parent_query(cte)
+ group_parent_id_alias = alias_as_column(groups[:parent_id], 'group_parent_id')
+
+ model
+ .unscoped
+ .select([clusters_star, group_parent_id_alias, cte.table[DEPTH_COLUMN] + 1])
+ .from([cte.table, groups])
+ .joins('LEFT OUTER JOIN cluster_groups ON cluster_groups.group_id = namespaces.id')
+ .joins('LEFT OUTER JOIN clusters ON cluster_groups.cluster_id = clusters.id')
+ .where(groups[:id].eq(cte.table[:group_parent_id]))
+ end
+
+ def model
+ Clusters::Cluster
+ end
+
+ def clusters
+ @clusters ||= model.arel_table
+ end
+
+ def groups
+ @groups ||= ::Group.arel_table
+ end
+
+ def clusters_star
+ @clusters_star ||= clusters[Arel.star]
+ end
+
+ def alias_as_column(value, alias_to)
+ Arel::Nodes::As.new(value, Arel::Nodes::SqlLiteral.new(alias_to))
+ end
+ end
+end
diff --git a/app/models/concerns/cacheable_attributes.rb b/app/models/concerns/cacheable_attributes.rb
index 3d60f6924c1..8cbf4bcfaf7 100644
--- a/app/models/concerns/cacheable_attributes.rb
+++ b/app/models/concerns/cacheable_attributes.rb
@@ -36,7 +36,7 @@ module CacheableAttributes
end
def retrieve_from_cache
- record = Rails.cache.read(cache_key)
+ record = cache_backend.read(cache_key)
ensure_cache_setup if record.present?
record
@@ -58,7 +58,7 @@ module CacheableAttributes
end
def expire
- Rails.cache.delete(cache_key)
+ cache_backend.delete(cache_key)
rescue
# Gracefully handle when Redis is not available. For example,
# omnibus may fail here during gitlab:assets:compile.
@@ -69,9 +69,13 @@ module CacheableAttributes
# to be loaded when read from cache: https://github.com/rails/rails/issues/27348
define_attribute_methods
end
+
+ def cache_backend
+ Rails.cache
+ end
end
def cache!
- Rails.cache.write(self.class.cache_key, self, expires_in: 1.minute)
+ self.class.cache_backend.write(self.class.cache_key, self, expires_in: 1.minute)
end
end
diff --git a/app/models/concerns/deployment_platform.rb b/app/models/concerns/deployment_platform.rb
index 5a358ae2ef6..8f28c897eb6 100644
--- a/app/models/concerns/deployment_platform.rb
+++ b/app/models/concerns/deployment_platform.rb
@@ -12,11 +12,26 @@ module DeploymentPlatform
private
def find_deployment_platform(environment)
- find_cluster_platform_kubernetes(environment: environment) ||
- find_group_cluster_platform_kubernetes(environment: environment) ||
+ find_platform_kubernetes(environment) ||
find_instance_cluster_platform_kubernetes(environment: environment)
end
+ def find_platform_kubernetes(environment)
+ if Feature.enabled?(:clusters_cte)
+ find_platform_kubernetes_with_cte(environment)
+ else
+ find_cluster_platform_kubernetes(environment: environment) ||
+ find_group_cluster_platform_kubernetes(environment: environment)
+ end
+ end
+
+ # EE would override this and utilize environment argument
+ def find_platform_kubernetes_with_cte(_environment)
+ Clusters::ClustersHierarchy.new(self).base_and_ancestors
+ .enabled.default_environment
+ .first&.platform_kubernetes
+ end
+
# EE would override this and utilize environment argument
def find_cluster_platform_kubernetes(environment: nil)
clusters.enabled.default_environment
diff --git a/app/models/concerns/issuable.rb b/app/models/concerns/issuable.rb
index 127430cc68f..952de92cae1 100644
--- a/app/models/concerns/issuable.rb
+++ b/app/models/concerns/issuable.rb
@@ -29,7 +29,11 @@ module Issuable
# This object is used to gather issuable meta data for displaying
# upvotes, downvotes, notes and closing merge requests count for issues and merge requests
# lists avoiding n+1 queries and improving performance.
- IssuableMeta = Struct.new(:upvotes, :downvotes, :user_notes_count, :merge_requests_count)
+ IssuableMeta = Struct.new(:upvotes, :downvotes, :user_notes_count, :mrs_count) do
+ def merge_requests_count(user = nil)
+ mrs_count
+ end
+ end
included do
cache_markdown_field :title, pipeline: :single_line
@@ -164,7 +168,7 @@ module Issuable
# matched_columns - Modify the scope of the query. 'title', 'description' or joining them with a comma.
#
# Returns an ActiveRecord::Relation.
- def full_search(query, matched_columns: 'title,description')
+ def full_search(query, matched_columns: 'title,description', use_minimum_char_limit: true)
allowed_columns = [:title, :description]
matched_columns = matched_columns.to_s.split(',').map(&:to_sym)
matched_columns &= allowed_columns
@@ -172,7 +176,7 @@ module Issuable
# Matching title or description if the matched_columns did not contain any allowed columns.
matched_columns = [:title, :description] if matched_columns.empty?
- fuzzy_search(query, matched_columns)
+ fuzzy_search(query, matched_columns, use_minimum_char_limit: use_minimum_char_limit)
end
def simple_sorts
diff --git a/app/models/concerns/reactive_caching.rb b/app/models/concerns/reactive_caching.rb
index 6c3962b4c4f..d91be73d6f0 100644
--- a/app/models/concerns/reactive_caching.rb
+++ b/app/models/concerns/reactive_caching.rb
@@ -173,12 +173,16 @@ module ReactiveCaching
end
def within_reactive_cache_lifetime?(*args)
- !!Rails.cache.read(alive_reactive_cache_key(*args))
+ if Feature.enabled?(:reactive_caching_check_key_exists, default_enabled: true)
+ Rails.cache.exist?(alive_reactive_cache_key(*args))
+ else
+ !!Rails.cache.read(alive_reactive_cache_key(*args))
+ end
end
def enqueuing_update(*args)
yield
- ensure
+
ReactiveCachingWorker.perform_in(self.class.reactive_cache_refresh_interval, self.class, id, *args)
end
end
diff --git a/app/models/concerns/update_project_statistics.rb b/app/models/concerns/update_project_statistics.rb
index 1f881249322..570a735973f 100644
--- a/app/models/concerns/update_project_statistics.rb
+++ b/app/models/concerns/update_project_statistics.rb
@@ -19,9 +19,9 @@
#
# - `statistic_attribute` must be an ActiveRecord attribute
# - The model must implement `project` and `project_id`. i.e. direct Project relationship or delegation
-#
module UpdateProjectStatistics
extend ActiveSupport::Concern
+ include AfterCommitQueue
class_methods do
attr_reader :project_statistics_name, :statistic_attribute
@@ -31,7 +31,6 @@ module UpdateProjectStatistics
#
# - project_statistics_name: A column of `ProjectStatistics` to update
# - statistic_attribute: An attribute of the current model, default to `size`
- #
def update_project_statistics(project_statistics_name:, statistic_attribute: :size)
@project_statistics_name = project_statistics_name
@statistic_attribute = statistic_attribute
@@ -51,6 +50,7 @@ module UpdateProjectStatistics
delta = read_attribute(attr).to_i - attribute_before_last_save(attr).to_i
update_project_statistics(delta)
+ schedule_namespace_aggregation_worker
end
def update_project_statistics_attribute_changed?
@@ -59,6 +59,8 @@ module UpdateProjectStatistics
def update_project_statistics_after_destroy
update_project_statistics(-read_attribute(self.class.statistic_attribute).to_i)
+
+ schedule_namespace_aggregation_worker
end
def project_destroyed?
@@ -68,5 +70,18 @@ module UpdateProjectStatistics
def update_project_statistics(delta)
ProjectStatistics.increment_statistic(project_id, self.class.project_statistics_name, delta)
end
+
+ def schedule_namespace_aggregation_worker
+ run_after_commit do
+ next unless schedule_aggregation_worker?
+
+ Namespaces::ScheduleAggregationWorker.perform_async(project.namespace_id)
+ end
+ end
+
+ def schedule_aggregation_worker?
+ !project.nil? &&
+ Feature.enabled?(:update_statistics_namespace, project.root_ancestor)
+ end
end
end
diff --git a/app/models/deploy_token.rb b/app/models/deploy_token.rb
index b0e570f52ba..33f0be91632 100644
--- a/app/models/deploy_token.rb
+++ b/app/models/deploy_token.rb
@@ -16,6 +16,14 @@ class DeployToken < ApplicationRecord
has_many :projects, through: :project_deploy_tokens
validate :ensure_at_least_one_scope
+ validates :username,
+ length: { maximum: 255 },
+ allow_nil: true,
+ format: {
+ with: /\A[a-zA-Z0-9\.\+_-]+\z/,
+ message: "can contain only letters, digits, '_', '-', '+', and '.'"
+ }
+
before_save :ensure_token
accepts_nested_attributes_for :project_deploy_tokens
@@ -39,7 +47,7 @@ class DeployToken < ApplicationRecord
end
def username
- "gitlab+deploy-token-#{id}"
+ super || default_username
end
def has_access_to?(requested_project)
@@ -75,4 +83,8 @@ class DeployToken < ApplicationRecord
def ensure_at_least_one_scope
errors.add(:base, "Scopes can't be blank") unless read_repository || read_registry
end
+
+ def default_username
+ "gitlab+deploy-token-#{id}" if persisted?
+ end
end
diff --git a/app/models/deployment.rb b/app/models/deployment.rb
index a8f5642f726..b69cda4f2f9 100644
--- a/app/models/deployment.rb
+++ b/app/models/deployment.rb
@@ -85,11 +85,6 @@ class Deployment < ApplicationRecord
Commit.truncate_sha(sha)
end
- # Deprecated - will be replaced by a persisted cluster_id
- def deployment_platform_cluster
- environment.deployment_platform&.cluster
- end
-
def execute_hooks
deployment_data = Gitlab::DataBuilder::Deployment.build(self)
project.execute_services(deployment_data, :deployment_hooks)
@@ -176,45 +171,8 @@ class Deployment < ApplicationRecord
deployed_at&.to_time&.in_time_zone&.to_s(:medium)
end
- def has_metrics?
- success? && prometheus_adapter&.can_query?
- end
-
- def metrics
- return {} unless has_metrics?
-
- metrics = prometheus_adapter.query(:deployment, self)
- metrics&.merge(deployment_time: finished_at.to_i) || {}
- end
-
- def additional_metrics
- return {} unless has_metrics?
-
- metrics = prometheus_adapter.query(:additional_metrics_deployment, self)
- metrics&.merge(deployment_time: finished_at.to_i) || {}
- end
-
private
- def prometheus_adapter
- service = project.find_or_initialize_service('prometheus')
-
- if service.can_query?
- service
- else
- cluster_prometheus
- end
- end
-
- # TODO remove fallback case to deployment_platform_cluster.
- # Otherwise we will continue to pay the performance penalty described in
- # https://gitlab.com/gitlab-org/gitlab-ce/issues/63475
- def cluster_prometheus
- cluster_with_fallback = cluster || deployment_platform_cluster
-
- cluster_with_fallback.application_prometheus if cluster_with_fallback&.application_prometheus_available?
- end
-
def ref_path
File.join(environment.ref_path, 'deployments', iid.to_s)
end
diff --git a/app/models/deployment_metrics.rb b/app/models/deployment_metrics.rb
new file mode 100644
index 00000000000..cfe762ca25e
--- /dev/null
+++ b/app/models/deployment_metrics.rb
@@ -0,0 +1,61 @@
+# frozen_string_literal: true
+
+class DeploymentMetrics
+ include Gitlab::Utils::StrongMemoize
+
+ attr_reader :project, :deployment
+
+ delegate :cluster, to: :deployment
+
+ def initialize(project, deployment)
+ @project = project
+ @deployment = deployment
+ end
+
+ def has_metrics?
+ deployment.success? && prometheus_adapter&.can_query?
+ end
+
+ def metrics
+ return {} unless has_metrics?
+
+ metrics = prometheus_adapter.query(:deployment, deployment)
+ metrics&.merge(deployment_time: deployment.finished_at.to_i) || {}
+ end
+
+ def additional_metrics
+ return {} unless has_metrics?
+
+ metrics = prometheus_adapter.query(:additional_metrics_deployment, deployment)
+ metrics&.merge(deployment_time: deployment.finished_at.to_i) || {}
+ end
+
+ private
+
+ def prometheus_adapter
+ strong_memoize(:prometheus_adapter) do
+ service = project.find_or_initialize_service('prometheus')
+
+ if service.can_query?
+ service
+ else
+ cluster_prometheus
+ end
+ end
+ end
+
+ # TODO remove fallback case to deployment_platform_cluster.
+ # Otherwise we will continue to pay the performance penalty described in
+ # https://gitlab.com/gitlab-org/gitlab-ce/issues/63475
+ #
+ # Removal issue: https://gitlab.com/gitlab-org/gitlab-ce/issues/64105
+ def cluster_prometheus
+ cluster_with_fallback = cluster || deployment_platform_cluster
+
+ cluster_with_fallback.application_prometheus if cluster_with_fallback&.application_prometheus_available?
+ end
+
+ def deployment_platform_cluster
+ deployment.environment.deployment_platform&.cluster
+ end
+end
diff --git a/app/models/environment_status.rb b/app/models/environment_status.rb
index 2fb6cadc8cd..465a42759df 100644
--- a/app/models/environment_status.rb
+++ b/app/models/environment_status.rb
@@ -3,11 +3,10 @@
class EnvironmentStatus
include Gitlab::Utils::StrongMemoize
- attr_reader :environment, :merge_request, :sha
+ attr_reader :project, :environment, :merge_request, :sha
delegate :id, to: :environment
delegate :name, to: :environment
- delegate :project, to: :environment
delegate :status, to: :deployment, allow_nil: true
delegate :deployed_at, to: :deployment, allow_nil: true
@@ -21,7 +20,8 @@ class EnvironmentStatus
build_environments_status(mr, user, mr.merge_pipeline)
end
- def initialize(environment, merge_request, sha)
+ def initialize(project, environment, merge_request, sha)
+ @project = project
@environment = environment
@merge_request = merge_request
@sha = sha
@@ -33,6 +33,12 @@ class EnvironmentStatus
end
end
+ def has_metrics?
+ strong_memoize(:has_metrics) do
+ deployment_metrics.has_metrics?
+ end
+ end
+
def changes
return [] if project.route_map_for(sha).nil?
@@ -48,6 +54,10 @@ class EnvironmentStatus
PAGE_EXTENSIONS = /\A\.(s?html?|php|asp|cgi|pl)\z/i.freeze
+ def deployment_metrics
+ @deployment_metrics ||= DeploymentMetrics.new(project, deployment)
+ end
+
def build_change(file)
public_path = project.public_path_for_source_path(file.new_path, sha)
return if public_path.nil?
@@ -67,7 +77,7 @@ class EnvironmentStatus
pipeline.environments.available.map do |environment|
next unless Ability.allowed?(user, :read_environment, environment)
- EnvironmentStatus.new(environment, mr, pipeline.sha)
+ EnvironmentStatus.new(pipeline.project, environment, mr, pipeline.sha)
end.compact
end
private_class_method :build_environments_status
diff --git a/app/models/group.rb b/app/models/group.rb
index 8e89c7ecfb1..9520db1bc0a 100644
--- a/app/models/group.rb
+++ b/app/models/group.rb
@@ -63,6 +63,8 @@ class Group < Namespace
after_save :update_two_factor_requirement
after_update :path_changed_hook, if: :saved_change_to_path?
+ scope :with_users, -> { includes(:users) }
+
class << self
def sort_by_attribute(method)
if method == 'storage_size_desc'
diff --git a/app/models/issue.rb b/app/models/issue.rb
index 30e29911758..982a94315bd 100644
--- a/app/models/issue.rb
+++ b/app/models/issue.rb
@@ -250,8 +250,8 @@ class Issue < ApplicationRecord
end
# rubocop: enable CodeReuse/ServiceClass
- def merge_requests_count
- merge_requests_closing_issues.count
+ def merge_requests_count(user = nil)
+ ::MergeRequestsClosingIssues.count_for_issue(self.id, user)
end
def labels_hook_attrs
diff --git a/app/models/label_note.rb b/app/models/label_note.rb
index d6814f4a948..ba5f1f82a81 100644
--- a/app/models/label_note.rb
+++ b/app/models/label_note.rb
@@ -62,19 +62,27 @@ class LabelNote < Note
end
def note_text(html: false)
- added = labels_str('added', label_refs_by_action('add', html))
- removed = labels_str('removed', label_refs_by_action('remove', html))
+ added = labels_str(label_refs_by_action('add', html), prefix: 'added', suffix: added_suffix)
+ removed = labels_str(label_refs_by_action('remove', html), prefix: removed_prefix)
[added, removed].compact.join(' and ')
end
+ def removed_prefix
+ 'removed'
+ end
+
+ def added_suffix
+ ''
+ end
+
# returns string containing added/removed labels including
# count of deleted labels:
#
# added ~1 ~2 + 1 deleted label
# added 3 deleted labels
# added ~1 ~2 labels
- def labels_str(prefix, label_refs)
+ def labels_str(label_refs, prefix: '', suffix: '')
existing_refs = label_refs.select { |ref| ref.present? }.sort
refs_str = existing_refs.empty? ? nil : existing_refs.join(' ')
@@ -84,9 +92,9 @@ class LabelNote < Note
return unless refs_str || deleted_str
label_list_str = [refs_str, deleted_str].compact.join(' + ')
- suffix = 'label'.pluralize(deleted > 0 ? deleted : existing_refs.count)
+ suffix += ' label'.pluralize(deleted > 0 ? deleted : existing_refs.count)
- "#{prefix} #{label_list_str} #{suffix}"
+ "#{prefix} #{label_list_str} #{suffix.squish}"
end
def label_refs_by_action(action, html)
diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb
index 82034f5946b..53977748c30 100644
--- a/app/models/merge_request.rb
+++ b/app/models/merge_request.rb
@@ -223,7 +223,13 @@ class MergeRequest < ApplicationRecord
end
def rebase_in_progress?
- strong_memoize(:rebase_in_progress) do
+ (rebase_jid.present? && Gitlab::SidekiqStatus.running?(rebase_jid)) ||
+ gitaly_rebase_in_progress?
+ end
+
+ # TODO: remove the Gitaly lookup after v12.1, when rebase_jid will be reliable
+ def gitaly_rebase_in_progress?
+ strong_memoize(:gitaly_rebase_in_progress) do
# The source project can be deleted
next false unless source_project
@@ -389,6 +395,26 @@ class MergeRequest < ApplicationRecord
update_column(:merge_jid, jid)
end
+ # Set off a rebase asynchronously, atomically updating the `rebase_jid` of
+ # the MR so that the status of the operation can be tracked.
+ def rebase_async(user_id)
+ transaction do
+ lock!
+
+ raise ActiveRecord::StaleObjectError if !open? || rebase_in_progress?
+
+ # Although there is a race between setting rebase_jid here and clearing it
+ # in the RebaseWorker, it can't do any harm since we check both that the
+ # attribute is set *and* that the sidekiq job is still running. So a JID
+ # for a completed RebaseWorker is equivalent to a nil JID.
+ jid = Sidekiq::Worker.skipping_transaction_check do
+ RebaseWorker.perform_async(id, user_id)
+ end
+
+ update_column(:rebase_jid, jid)
+ end
+ end
+
def merge_participants
participants = [author]
@@ -1101,6 +1127,19 @@ class MergeRequest < ApplicationRecord
"refs/#{Repository::REF_MERGE_REQUEST}/#{iid}/merge"
end
+ def train_ref_path
+ "refs/#{Repository::REF_MERGE_REQUEST}/#{iid}/train"
+ end
+
+ def cleanup_refs(only: :all)
+ target_refs = []
+ target_refs << ref_path if %i[all head].include?(only)
+ target_refs << merge_ref_path if %i[all merge].include?(only)
+ target_refs << train_ref_path if %i[all train].include?(only)
+
+ project.repository.delete_refs(*target_refs)
+ end
+
def self.merge_request_ref?(ref)
ref.start_with?("refs/#{Repository::REF_MERGE_REQUEST}/")
end
@@ -1353,6 +1392,7 @@ class MergeRequest < ApplicationRecord
end
# TODO: remove once production database rename completes
+ # https://gitlab.com/gitlab-org/gitlab-ce/issues/47592
alias_attribute :allow_collaboration, :allow_maintainer_to_push
def allow_collaboration
diff --git a/app/models/merge_requests_closing_issues.rb b/app/models/merge_requests_closing_issues.rb
index 61af50841ee..22cedf57b86 100644
--- a/app/models/merge_requests_closing_issues.rb
+++ b/app/models/merge_requests_closing_issues.rb
@@ -7,11 +7,38 @@ class MergeRequestsClosingIssues < ApplicationRecord
validates :merge_request_id, uniqueness: { scope: :issue_id }, presence: true
validates :issue_id, presence: true
+ scope :with_issues, ->(ids) { where(issue_id: ids) }
+ scope :with_merge_requests_enabled, -> do
+ joins(:merge_request)
+ .joins('INNER JOIN project_features ON merge_requests.target_project_id = project_features.project_id')
+ .where('project_features.merge_requests_access_level >= :access', access: ProjectFeature::ENABLED)
+ end
+
+ scope :accessible_by, ->(user) do
+ joins(:merge_request)
+ .joins('INNER JOIN project_features ON merge_requests.target_project_id = project_features.project_id')
+ .where('project_features.merge_requests_access_level >= :access OR EXISTS(:authorizations)',
+ access: ProjectFeature::ENABLED,
+ authorizations: user.authorizations_for_projects(min_access_level: Gitlab::Access::REPORTER, related_project_column: "merge_requests.target_project_id")
+ )
+ end
+
class << self
- def count_for_collection(ids)
- group(:issue_id)
- .where(issue_id: ids)
- .pluck('issue_id', 'COUNT(*) as count')
+ def count_for_collection(ids, current_user)
+ closing_merge_requests(ids, current_user).group(:issue_id).pluck('issue_id', 'COUNT(*) as count')
+ end
+
+ def count_for_issue(id, current_user)
+ closing_merge_requests(id, current_user).count
+ end
+
+ private
+
+ def closing_merge_requests(ids, current_user)
+ return with_issues(ids) if current_user&.admin?
+ return with_issues(ids).with_merge_requests_enabled if current_user.blank?
+
+ with_issues(ids).accessible_by(current_user)
end
end
end
diff --git a/app/models/namespace.rb b/app/models/namespace.rb
index f9b53b2b70a..af50293a179 100644
--- a/app/models/namespace.rb
+++ b/app/models/namespace.rb
@@ -250,7 +250,9 @@ class Namespace < ApplicationRecord
end
def root_ancestor
- self_and_ancestors.reorder(nil).find_by(parent_id: nil)
+ strong_memoize(:root_ancestor) do
+ self_and_ancestors.reorder(nil).find_by(parent_id: nil)
+ end
end
def subgroup?
@@ -291,6 +293,10 @@ class Namespace < ApplicationRecord
end
end
+ def aggregation_scheduled?
+ aggregation_schedule.present?
+ end
+
private
def parent_changed?
diff --git a/app/models/namespace/aggregation_schedule.rb b/app/models/namespace/aggregation_schedule.rb
index 43afd0b954c..0bef352cf24 100644
--- a/app/models/namespace/aggregation_schedule.rb
+++ b/app/models/namespace/aggregation_schedule.rb
@@ -1,7 +1,55 @@
# frozen_string_literal: true
class Namespace::AggregationSchedule < ApplicationRecord
+ include AfterCommitQueue
+ include ExclusiveLeaseGuard
+
self.primary_key = :namespace_id
+ DEFAULT_LEASE_TIMEOUT = 3.hours
+ REDIS_SHARED_KEY = 'gitlab:update_namespace_statistics_delay'.freeze
+
belongs_to :namespace
+
+ after_create :schedule_root_storage_statistics
+
+ def self.delay_timeout
+ redis_timeout = Gitlab::Redis::SharedState.with do |redis|
+ redis.get(REDIS_SHARED_KEY)
+ end
+
+ redis_timeout.nil? ? DEFAULT_LEASE_TIMEOUT : redis_timeout.to_i
+ end
+
+ def schedule_root_storage_statistics
+ run_after_commit_or_now do
+ try_obtain_lease do
+ Namespaces::RootStatisticsWorker
+ .perform_async(namespace_id)
+
+ Namespaces::RootStatisticsWorker
+ .perform_in(self.class.delay_timeout, namespace_id)
+ end
+ end
+ end
+
+ private
+
+ # Used by ExclusiveLeaseGuard
+ def lease_timeout
+ self.class.delay_timeout
+ end
+
+ # Used by ExclusiveLeaseGuard
+ def lease_key
+ "namespace:namespaces_root_statistics:#{namespace_id}"
+ end
+
+ # Used by ExclusiveLeaseGuard
+ # Overriding value as we never release the lease
+ # before the timeout in order to prevent multiple
+ # RootStatisticsWorker to start in a short span of time
+ def lease_release?
+ false
+ end
end
diff --git a/app/models/namespace/root_storage_statistics.rb b/app/models/namespace/root_storage_statistics.rb
index de28eb6b37f..56c430013ee 100644
--- a/app/models/namespace/root_storage_statistics.rb
+++ b/app/models/namespace/root_storage_statistics.rb
@@ -1,10 +1,38 @@
# frozen_string_literal: true
class Namespace::RootStorageStatistics < ApplicationRecord
+ STATISTICS_ATTRIBUTES = %w(storage_size repository_size wiki_size lfs_objects_size build_artifacts_size packages_size).freeze
+
self.primary_key = :namespace_id
belongs_to :namespace
has_one :route, through: :namespace
delegate :all_projects, to: :namespace
+
+ def recalculate!
+ update!(attributes_from_project_statistics)
+ end
+
+ private
+
+ def attributes_from_project_statistics
+ from_project_statistics
+ .take
+ .attributes
+ .slice(*STATISTICS_ATTRIBUTES)
+ end
+
+ def from_project_statistics
+ all_projects
+ .joins('INNER JOIN project_statistics ps ON ps.project_id = projects.id')
+ .select(
+ 'COALESCE(SUM(ps.storage_size), 0) AS storage_size',
+ 'COALESCE(SUM(ps.repository_size), 0) AS repository_size',
+ 'COALESCE(SUM(ps.wiki_size), 0) AS wiki_size',
+ 'COALESCE(SUM(ps.lfs_objects_size), 0) AS lfs_objects_size',
+ 'COALESCE(SUM(ps.build_artifacts_size), 0) AS build_artifacts_size',
+ 'COALESCE(SUM(ps.packages_size), 0) AS packages_size'
+ )
+ end
end
diff --git a/app/models/project.rb b/app/models/project.rb
index 0f4fba5d0b6..075f7882d72 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -2144,7 +2144,7 @@ class Project < ApplicationRecord
public? &&
repository_exists? &&
Gitlab::CurrentSettings.hashed_storage_enabled &&
- Feature.enabled?(:object_pools, self)
+ Feature.enabled?(:object_pools, self, default_enabled: true)
end
def leave_pool_repository
diff --git a/app/models/project_services/bugzilla_service.rb b/app/models/project_services/bugzilla_service.rb
index 1a2bb6a171b..8b79b5e9f0c 100644
--- a/app/models/project_services/bugzilla_service.rb
+++ b/app/models/project_services/bugzilla_service.rb
@@ -3,22 +3,14 @@
class BugzillaService < IssueTrackerService
validates :project_url, :issues_url, :new_issue_url, presence: true, public_url: true, if: :activated?
- prop_accessor :title, :description, :project_url, :issues_url, :new_issue_url
+ prop_accessor :project_url, :issues_url, :new_issue_url
- def title
- if self.properties && self.properties['title'].present?
- self.properties['title']
- else
- 'Bugzilla'
- end
+ def default_title
+ 'Bugzilla'
end
- def description
- if self.properties && self.properties['description'].present?
- self.properties['description']
- else
- 'Bugzilla issue tracker'
- end
+ def default_description
+ s_('IssueTracker|Bugzilla issue tracker')
end
def self.to_param
diff --git a/app/models/project_services/custom_issue_tracker_service.rb b/app/models/project_services/custom_issue_tracker_service.rb
index b8f8072869c..535fcf6b94e 100644
--- a/app/models/project_services/custom_issue_tracker_service.rb
+++ b/app/models/project_services/custom_issue_tracker_service.rb
@@ -5,24 +5,12 @@ class CustomIssueTrackerService < IssueTrackerService
prop_accessor :title, :description, :project_url, :issues_url, :new_issue_url
- def title
- if self.properties && self.properties['title'].present?
- self.properties['title']
- else
- 'Custom Issue Tracker'
- end
+ def default_title
+ 'Custom Issue Tracker'
end
- def title=(value)
- self.properties['title'] = value if self.properties
- end
-
- def description
- if self.properties && self.properties['description'].present?
- self.properties['description']
- else
- 'Custom issue tracker'
- end
+ def default_description
+ s_('IssueTracker|Custom issue tracker')
end
def self.to_param
diff --git a/app/models/project_services/drone_ci_service.rb b/app/models/project_services/drone_ci_service.rb
index dbdc8345c93..d2660051343 100644
--- a/app/models/project_services/drone_ci_service.rb
+++ b/app/models/project_services/drone_ci_service.rb
@@ -46,7 +46,7 @@ class DroneCiService < CiService
end
def commit_status(sha, ref)
- with_reactive_cache(sha, ref) {|cached| cached[:commit_status] }
+ with_reactive_cache(sha, ref) { |cached| cached[:commit_status] }
end
def calculate_reactive_cache(sha, ref)
@@ -68,7 +68,7 @@ class DroneCiService < CiService
end
{ commit_status: status }
- rescue Errno::ECONNREFUSED
+ rescue *Gitlab::HTTP::HTTP_ERRORS
{ commit_status: :error }
end
diff --git a/app/models/project_services/gitlab_issue_tracker_service.rb b/app/models/project_services/gitlab_issue_tracker_service.rb
index fa9abf58e62..51032932eab 100644
--- a/app/models/project_services/gitlab_issue_tracker_service.rb
+++ b/app/models/project_services/gitlab_issue_tracker_service.rb
@@ -5,10 +5,18 @@ class GitlabIssueTrackerService < IssueTrackerService
validates :project_url, :issues_url, :new_issue_url, presence: true, public_url: true, if: :activated?
- prop_accessor :title, :description, :project_url, :issues_url, :new_issue_url
+ prop_accessor :project_url, :issues_url, :new_issue_url
default_value_for :default, true
+ def default_title
+ 'GitLab'
+ end
+
+ def default_description
+ s_('IssueTracker|GitLab issue tracker')
+ end
+
def self.to_param
'gitlab'
end
diff --git a/app/models/project_services/issue_tracker_service.rb b/app/models/project_services/issue_tracker_service.rb
index f54497fc6d8..3a1130ffc15 100644
--- a/app/models/project_services/issue_tracker_service.rb
+++ b/app/models/project_services/issue_tracker_service.rb
@@ -5,6 +5,8 @@ class IssueTrackerService < Service
default_value_for :category, 'issue_tracker'
+ before_save :handle_properties
+
# Pattern used to extract links from comments
# Override this method on services that uses different patterns
# This pattern does not support cross-project references
@@ -18,6 +20,37 @@ class IssueTrackerService < Service
end
end
+ # this will be removed as part of https://gitlab.com/gitlab-org/gitlab-ce/issues/63084
+ def title
+ if title_attribute = read_attribute(:title)
+ title_attribute
+ elsif self.properties && self.properties['title'].present?
+ self.properties['title']
+ else
+ default_title
+ end
+ end
+
+ # this will be removed as part of https://gitlab.com/gitlab-org/gitlab-ce/issues/63084
+ def description
+ if description_attribute = read_attribute(:description)
+ description_attribute
+ elsif self.properties && self.properties['description'].present?
+ self.properties['description']
+ else
+ default_description
+ end
+ end
+
+ def handle_properties
+ properties.slice('title', 'description').each do |key, _|
+ current_value = self.properties.delete(key)
+ value = attribute_changed?(key) ? attribute_change(key).last : current_value
+
+ write_attribute(key, value)
+ end
+ end
+
def default?
default
end
diff --git a/app/models/project_services/jira_service.rb b/app/models/project_services/jira_service.rb
index f31eb7fd19a..a3b89b2543a 100644
--- a/app/models/project_services/jira_service.rb
+++ b/app/models/project_services/jira_service.rb
@@ -17,7 +17,7 @@ class JiraService < IssueTrackerService
# Jira Cloud version is deprecating authentication via username and password.
# We should use username/password for Jira Server and email/api_token for Jira Cloud,
# for more information check: https://gitlab.com/gitlab-org/gitlab-ce/issues/49936.
- prop_accessor :username, :password, :url, :api_url, :jira_issue_transition_id, :title, :description
+ prop_accessor :username, :password, :url, :api_url, :jira_issue_transition_id
before_update :reset_password
@@ -37,7 +37,6 @@ class JiraService < IssueTrackerService
def initialize_properties
super do
self.properties = {
- title: issues_tracker['title'],
url: issues_tracker['url'],
api_url: issues_tracker['api_url']
}
@@ -74,20 +73,12 @@ class JiraService < IssueTrackerService
[Jira service documentation](#{help_page_url('user/project/integrations/jira')})."
end
- def title
- if self.properties && self.properties['title'].present?
- self.properties['title']
- else
- 'Jira'
- end
+ def default_title
+ 'Jira'
end
- def description
- if self.properties && self.properties['description'].present?
- self.properties['description']
- else
- s_('JiraService|Jira issue tracker')
- end
+ def default_description
+ s_('JiraService|Jira issue tracker')
end
def self.to_param
diff --git a/app/models/project_services/kubernetes_service.rb b/app/models/project_services/kubernetes_service.rb
index 27b7827d55e..9f5c226f4c9 100644
--- a/app/models/project_services/kubernetes_service.rb
+++ b/app/models/project_services/kubernetes_service.rb
@@ -1,18 +1,8 @@
# frozen_string_literal: true
-##
-# NOTE:
-# We'll move this class to Clusters::Platforms::Kubernetes, which contains exactly the same logic.
-# After we've migrated data, we'll remove KubernetesService. This would happen in a few months.
-# If you're modyfiyng this class, please note that you should update the same change in Clusters::Platforms::Kubernetes.
class KubernetesService < Service
- include Gitlab::Kubernetes
- include ReactiveCaching
-
default_value_for :category, 'deployment'
- self.reactive_cache_key = ->(service) { [service.class.model_name.singular, service.project_id] }
-
# Namespace defaults to the project path, but can be overridden in case that
# is an invalid or inappropriate name
prop_accessor :namespace
@@ -47,8 +37,6 @@ class KubernetesService < Service
message: Gitlab::Regex.kubernetes_namespace_regex_message
}
- after_save :clear_reactive_cache!
-
def self.supported_events
%w()
end
@@ -94,72 +82,6 @@ class KubernetesService < Service
]
end
- def kubernetes_namespace_for(project)
- if namespace.present?
- namespace
- else
- default_namespace
- end
- end
-
- # Check we can connect to the Kubernetes API
- def test(*args)
- kubeclient = build_kube_client!
-
- kubeclient.core_client.discover
- { success: kubeclient.core_client.discovered, result: "Checked API discovery endpoint" }
- rescue => err
- { success: false, result: err }
- end
-
- # Project param was added on
- # https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/22011,
- # as a way to keep this service compatible with
- # Clusters::Platforms::Kubernetes, it won't be used on this method
- # as it's only needed for Clusters::Cluster.
- def predefined_variables(project:)
- Gitlab::Ci::Variables::Collection.new.tap do |variables|
- variables
- .append(key: 'KUBE_URL', value: api_url)
- .append(key: 'KUBE_TOKEN', value: token, public: false, masked: true)
- .append(key: 'KUBE_NAMESPACE', value: kubernetes_namespace_for(project))
- .append(key: 'KUBECONFIG', value: kubeconfig, public: false, file: true)
-
- if ca_pem.present?
- variables
- .append(key: 'KUBE_CA_PEM', value: ca_pem)
- .append(key: 'KUBE_CA_PEM_FILE', value: ca_pem, file: true)
- end
- end
- end
-
- # Constructs a list of terminals from the reactive cache
- #
- # Returns nil if the cache is empty, in which case you should try again a
- # short time later
- def terminals(environment)
- with_reactive_cache do |data|
- project = environment.project
-
- pods = filter_by_project_environment(data[:pods], project.full_path_slug, environment.slug)
- terminals = pods.flat_map { |pod| terminals_for_pod(api_url, kubernetes_namespace_for(project), pod) }.compact
- terminals.each { |terminal| add_terminal_auth(terminal, terminal_auth) }
- end
- end
-
- # Caches resources in the namespace so other calls don't need to block on
- # network access
- def calculate_reactive_cache
- return unless active? && project && !project.pending_delete?
-
- # We may want to cache extra things in the future
- { pods: read_pods }
- end
-
- def kubeclient
- @kubeclient ||= build_kube_client!
- end
-
def deprecated?
true
end
@@ -186,14 +108,6 @@ class KubernetesService < Service
private
- def kubeconfig
- to_kubeconfig(
- url: api_url,
- namespace: kubernetes_namespace_for(project),
- token: token,
- ca_pem: ca_pem)
- end
-
def namespace_placeholder
default_namespace || TEMPLATE_PLACEHOLDER
end
@@ -205,49 +119,6 @@ class KubernetesService < Service
slug.gsub(/[^-a-z0-9]/, '-').gsub(/^-+/, '')
end
- def build_kube_client!
- raise "Incomplete settings" unless api_url && kubernetes_namespace_for(project) && token
-
- Gitlab::Kubernetes::KubeClient.new(
- api_url,
- auth_options: kubeclient_auth_options,
- ssl_options: kubeclient_ssl_options,
- http_proxy_uri: ENV['http_proxy']
- )
- end
-
- # Returns a hash of all pods in the namespace
- def read_pods
- kubeclient = build_kube_client!
-
- kubeclient.get_pods(namespace: kubernetes_namespace_for(project)).as_json
- rescue Kubeclient::ResourceNotFoundError
- []
- 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
-
- def kubeclient_auth_options
- { bearer_token: token }
- end
-
- def terminal_auth
- {
- token: token,
- ca_pem: ca_pem,
- max_session_time: Gitlab::CurrentSettings.terminal_max_session_time
- }
- end
-
def enforce_namespace_to_lower_case
self.namespace = self.namespace&.downcase
end
diff --git a/app/models/project_services/redmine_service.rb b/app/models/project_services/redmine_service.rb
index a80be4b06da..5ca057ca833 100644
--- a/app/models/project_services/redmine_service.rb
+++ b/app/models/project_services/redmine_service.rb
@@ -3,22 +3,14 @@
class RedmineService < IssueTrackerService
validates :project_url, :issues_url, :new_issue_url, presence: true, public_url: true, if: :activated?
- prop_accessor :title, :description, :project_url, :issues_url, :new_issue_url
+ prop_accessor :project_url, :issues_url, :new_issue_url
- def title
- if self.properties && self.properties['title'].present?
- self.properties['title']
- else
- 'Redmine'
- end
+ def default_title
+ 'Redmine'
end
- def description
- if self.properties && self.properties['description'].present?
- self.properties['description']
- else
- 'Redmine issue tracker'
- end
+ def default_description
+ s_('IssueTracker|Redmine issue tracker')
end
def self.to_param
diff --git a/app/models/project_services/youtrack_service.rb b/app/models/project_services/youtrack_service.rb
index 175c2ebf197..f9de1f7dc49 100644
--- a/app/models/project_services/youtrack_service.rb
+++ b/app/models/project_services/youtrack_service.rb
@@ -3,7 +3,7 @@
class YoutrackService < IssueTrackerService
validates :project_url, :issues_url, presence: true, public_url: true, if: :activated?
- prop_accessor :description, :project_url, :issues_url
+ prop_accessor :project_url, :issues_url
# {PROJECT-KEY}-{NUMBER} Examples: YT-1, PRJ-1, gl-030
def self.reference_pattern(only_long: false)
@@ -14,16 +14,12 @@ class YoutrackService < IssueTrackerService
end
end
- def title
+ def default_title
'YouTrack'
end
- def description
- if self.properties && self.properties['description'].present?
- self.properties['description']
- else
- 'YouTrack issue tracker'
- end
+ def default_description
+ s_('IssueTracker|YouTrack issue tracker')
end
def self.to_param
diff --git a/app/models/project_statistics.rb b/app/models/project_statistics.rb
index 8a179b4d56d..3802d258664 100644
--- a/app/models/project_statistics.rb
+++ b/app/models/project_statistics.rb
@@ -1,6 +1,8 @@
# frozen_string_literal: true
class ProjectStatistics < ApplicationRecord
+ include AfterCommitQueue
+
belongs_to :project
belongs_to :namespace
@@ -15,6 +17,7 @@ class ProjectStatistics < ApplicationRecord
COLUMNS_TO_REFRESH = [:repository_size, :wiki_size, :lfs_objects_size, :commit_count].freeze
INCREMENTABLE_COLUMNS = { build_artifacts_size: %i[storage_size], packages_size: %i[storage_size] }.freeze
+ NAMESPACE_RELATABLE_COLUMNS = [:repository_size, :wiki_size, :lfs_objects_size].freeze
scope :for_project_ids, ->(project_ids) { where(project_id: project_ids) }
@@ -22,13 +25,17 @@ class ProjectStatistics < ApplicationRecord
repository_size + lfs_objects_size
end
- def refresh!(only: nil)
+ def refresh!(only: [])
COLUMNS_TO_REFRESH.each do |column, generator|
- if only.blank? || only.include?(column)
+ if only.empty? || only.include?(column)
public_send("update_#{column}") # rubocop:disable GitlabSecurity/PublicSend
end
end
+ if only.empty? || only.any? { |column| NAMESPACE_RELATABLE_COLUMNS.include?(column) }
+ schedule_namespace_aggregation_worker
+ end
+
save!
end
@@ -81,4 +88,18 @@ class ProjectStatistics < ApplicationRecord
update_all(updates.join(', '))
end
+
+ private
+
+ def schedule_namespace_aggregation_worker
+ run_after_commit do
+ next unless schedule_aggregation_worker?
+
+ Namespaces::ScheduleAggregationWorker.perform_async(project.namespace_id)
+ end
+ end
+
+ def schedule_aggregation_worker?
+ Feature.enabled?(:update_statistics_namespace, project&.root_ancestor)
+ end
end
diff --git a/app/models/release.rb b/app/models/release.rb
index 7bbeb3c9976..459a7c29ad0 100644
--- a/app/models/release.rb
+++ b/app/models/release.rb
@@ -12,12 +12,16 @@ class Release < ApplicationRecord
has_many :links, class_name: 'Releases::Link'
+ default_value_for :released_at, allows_nil: false do
+ Time.zone.now
+ end
+
accepts_nested_attributes_for :links, allow_destroy: true
validates :description, :project, :tag, presence: true
validates :name, presence: true, on: :create
- scope :sorted, -> { order(created_at: :desc) }
+ scope :sorted, -> { order(released_at: :desc) }
delegate :repository, to: :project
@@ -44,6 +48,10 @@ class Release < ApplicationRecord
end
end
+ def upcoming_release?
+ released_at.present? && released_at > Time.zone.now
+ end
+
private
def actual_sha
diff --git a/app/models/repository.rb b/app/models/repository.rb
index 992ed7485e5..a25d5abfa64 100644
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -6,7 +6,6 @@ class Repository
REF_MERGE_REQUEST = 'merge-requests'.freeze
REF_KEEP_AROUND = 'keep-around'.freeze
REF_ENVIRONMENTS = 'environments'.freeze
- MAX_DIVERGING_COUNT = 1000
RESERVED_REFS_NAMES = %W[
heads
@@ -840,10 +839,14 @@ class Repository
end
end
- def merge_to_ref(user, source_sha, merge_request, target_ref, message)
+ def merge_to_ref(user, source_sha, merge_request, target_ref, message, first_parent_ref)
branch = merge_request.target_branch
- raw.merge_to_ref(user, source_sha, branch, target_ref, message)
+ raw.merge_to_ref(user, source_sha, branch, target_ref, message, first_parent_ref)
+ end
+
+ def delete_refs(*ref_names)
+ raw.delete_refs(*ref_names)
end
def ff_merge(user, source, target_branch, merge_request: nil)
diff --git a/app/models/resource_label_event.rb b/app/models/resource_label_event.rb
index f2c7cb6a65d..ad08f4763ae 100644
--- a/app/models/resource_label_event.rb
+++ b/app/models/resource_label_event.rb
@@ -36,10 +36,9 @@ class ResourceLabelEvent < ApplicationRecord
issue || merge_request
end
- # create same discussion id for all actions with the same user and time
def discussion_id(resource = nil)
strong_memoize(:discussion_id) do
- Digest::SHA1.hexdigest([self.class.name, created_at, user_id].join("-"))
+ Digest::SHA1.hexdigest(discussion_id_key.join("-"))
end
end
@@ -121,4 +120,8 @@ class ResourceLabelEvent < ApplicationRecord
def resource_parent
issuable.project || issuable.group
end
+
+ def discussion_id_key
+ [self.class.name, created_at, user_id]
+ end
end
diff --git a/app/models/service.rb b/app/models/service.rb
index 40033003f3b..752467622f2 100644
--- a/app/models/service.rb
+++ b/app/models/service.rb
@@ -129,7 +129,7 @@ class Service < ApplicationRecord
def api_field_names
fields.map { |field| field[:name] }
- .reject { |field_name| field_name =~ /(password|token|key)/ }
+ .reject { |field_name| field_name =~ /(password|token|key|title|description)/ }
end
def global_fields
diff --git a/app/models/user.rb b/app/models/user.rb
index 38cb4d1a6e8..26be197209a 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -1460,7 +1460,7 @@ class User < ApplicationRecord
end
def requires_usage_stats_consent?
- !consented_usage_stats? && 7.days.ago > self.created_at && !has_current_license? && User.single_user?
+ self.admin? && 7.days.ago > self.created_at && !has_current_license? && User.single_user? && !consented_usage_stats?
end
# Avoid migrations only building user preference object when needed.
@@ -1495,7 +1495,14 @@ class User < ApplicationRecord
end
def consented_usage_stats?
- Gitlab::CurrentSettings.usage_stats_set_by_user_id == self.id
+ # Bypass the cache here because it's possible the admin enabled the
+ # usage ping, and we don't want to annoy the user again if they
+ # already set the value. This is a bit of hack, but the alternative
+ # would be to put in a more complex cache invalidation step. Since
+ # this call only gets called in the uncommon situation where the
+ # user is an admin and the only user in the instance, this shouldn't
+ # cause too much load on the system.
+ ApplicationSetting.current_without_cache&.usage_stats_set_by_user_id == self.id
end
# Added according to https://github.com/plataformatec/devise/blob/7df57d5081f9884849ca15e4fde179ef164a575f/README.md#activejob-integration
diff --git a/app/policies/repository_policy.rb b/app/policies/repository_policy.rb
new file mode 100644
index 00000000000..32340749858
--- /dev/null
+++ b/app/policies/repository_policy.rb
@@ -0,0 +1,5 @@
+# frozen_string_literal: true
+
+class RepositoryPolicy < BasePolicy
+ delegate { @subject.project }
+end
diff --git a/app/serializers/environment_status_entity.rb b/app/serializers/environment_status_entity.rb
index f6321b9e520..811cc2ad5af 100644
--- a/app/serializers/environment_status_entity.rb
+++ b/app/serializers/environment_status_entity.rb
@@ -11,7 +11,7 @@ class EnvironmentStatusEntity < Grape::Entity
project_environment_path(es.project, es.environment)
end
- expose :metrics_url, if: ->(*) { can_read_environment? && deployment.has_metrics? } do |es|
+ expose :metrics_url, if: ->(*) { can_read_environment? && has_metrics? } do |es|
metrics_project_environment_deployment_path(es.project, es.environment, es.deployment)
end
@@ -45,8 +45,8 @@ class EnvironmentStatusEntity < Grape::Entity
object.environment
end
- def deployment
- object.deployment
+ def has_metrics?
+ object.has_metrics?
end
def project
diff --git a/app/serializers/test_suite_comparer_entity.rb b/app/serializers/test_suite_comparer_entity.rb
index 9fa3a897ebe..d402a4d5718 100644
--- a/app/serializers/test_suite_comparer_entity.rb
+++ b/app/serializers/test_suite_comparer_entity.rb
@@ -1,6 +1,9 @@
# frozen_string_literal: true
class TestSuiteComparerEntity < Grape::Entity
+ DEFAULT_MAX_TESTS = 100
+ DEFAULT_MIN_TESTS = 10
+
expose :name
expose :total_status, as: :status
@@ -10,7 +13,27 @@ class TestSuiteComparerEntity < Grape::Entity
expose :failed_count, as: :failed
end
- expose :new_failures, using: TestCaseEntity
- expose :resolved_failures, using: TestCaseEntity
- expose :existing_failures, using: TestCaseEntity
+ # rubocop: disable CodeReuse/ActiveRecord
+ expose :new_failures, using: TestCaseEntity do |suite|
+ suite.new_failures.take(max_tests)
+ end
+
+ expose :existing_failures, using: TestCaseEntity do |suite|
+ suite.existing_failures.take(
+ max_tests(suite.new_failures))
+ end
+
+ expose :resolved_failures, using: TestCaseEntity do |suite|
+ suite.resolved_failures.take(
+ max_tests(suite.new_failures, suite.existing_failures))
+ end
+
+ private
+
+ def max_tests(*used)
+ return Integer::MAX unless Feature.enabled?(:ci_limit_test_reports_size, default_enabled: true)
+
+ [DEFAULT_MAX_TESTS - used.map(&:count).sum, DEFAULT_MIN_TESTS].max
+ end
+ # rubocop: enable CodeReuse/ActiveRecord
end
diff --git a/app/services/auto_merge/base_service.rb b/app/services/auto_merge/base_service.rb
index d726085b89a..e06659a39cd 100644
--- a/app/services/auto_merge/base_service.rb
+++ b/app/services/auto_merge/base_service.rb
@@ -29,7 +29,7 @@ module AutoMerge
end
def cancel(merge_request)
- if cancel_auto_merge(merge_request)
+ if clear_auto_merge_parameters(merge_request)
yield if block_given?
success
@@ -38,6 +38,16 @@ module AutoMerge
end
end
+ def abort(merge_request, reason)
+ if clear_auto_merge_parameters(merge_request)
+ yield if block_given?
+
+ success
+ else
+ error("Can't abort the automatic merge", 406)
+ end
+ end
+
private
def strategy
@@ -46,7 +56,7 @@ module AutoMerge
end
end
- def cancel_auto_merge(merge_request)
+ def clear_auto_merge_parameters(merge_request)
merge_request.auto_merge_enabled = false
merge_request.merge_user = nil
diff --git a/app/services/auto_merge/merge_when_pipeline_succeeds_service.rb b/app/services/auto_merge/merge_when_pipeline_succeeds_service.rb
index c41073a73e9..6a33ec071db 100644
--- a/app/services/auto_merge/merge_when_pipeline_succeeds_service.rb
+++ b/app/services/auto_merge/merge_when_pipeline_succeeds_service.rb
@@ -5,7 +5,7 @@ module AutoMerge
def execute(merge_request)
super do
if merge_request.saved_change_to_auto_merge_enabled?
- SystemNoteService.merge_when_pipeline_succeeds(merge_request, project, current_user, merge_request.diff_head_commit)
+ SystemNoteService.merge_when_pipeline_succeeds(merge_request, project, current_user, merge_request.actual_head_pipeline.sha)
end
end
end
@@ -19,7 +19,13 @@ module AutoMerge
def cancel(merge_request)
super do
- SystemNoteService.cancel_merge_when_pipeline_succeeds(merge_request, @project, @current_user)
+ SystemNoteService.cancel_merge_when_pipeline_succeeds(merge_request, project, current_user)
+ end
+ end
+
+ def abort(merge_request, reason)
+ super do
+ SystemNoteService.abort_merge_when_pipeline_succeeds(merge_request, project, current_user, reason)
end
end
diff --git a/app/services/auto_merge_service.rb b/app/services/auto_merge_service.rb
index 926d2f5fc66..95bf2db2018 100644
--- a/app/services/auto_merge_service.rb
+++ b/app/services/auto_merge_service.rb
@@ -42,6 +42,12 @@ class AutoMergeService < BaseService
get_service_instance(merge_request.auto_merge_strategy).cancel(merge_request)
end
+ def abort(merge_request, reason)
+ return error("Can't abort the automatic merge", 406) unless merge_request.auto_merge_enabled?
+
+ get_service_instance(merge_request.auto_merge_strategy).abort(merge_request, reason)
+ end
+
def available_strategies(merge_request)
self.class.all_strategies.select do |strategy|
get_service_instance(strategy).available_for?(merge_request)
diff --git a/app/services/branches/diverging_commit_counts_service.rb b/app/services/branches/diverging_commit_counts_service.rb
index f947cec1663..a3404caf2d7 100644
--- a/app/services/branches/diverging_commit_counts_service.rb
+++ b/app/services/branches/diverging_commit_counts_service.rb
@@ -8,11 +8,7 @@ module Branches
end
def call(branch)
- if Feature.enabled?('gitaly_count_diverging_commits_no_max')
- diverging_commit_counts_without_max(branch)
- else
- diverging_commit_counts(branch)
- end
+ diverging_commit_counts(branch)
end
private
@@ -22,27 +18,9 @@ module Branches
delegate :raw_repository, to: :repository
def diverging_commit_counts(branch)
- ## TODO: deprecate the below code after 12.0
@root_ref_hash ||= raw_repository.commit(repository.root_ref).id
cache.fetch(:"diverging_commit_counts_#{branch.name}") do
number_commits_behind, number_commits_ahead =
- repository.raw_repository.diverging_commit_count(
- @root_ref_hash,
- branch.dereferenced_target.sha,
- max_count: Repository::MAX_DIVERGING_COUNT)
-
- if number_commits_behind + number_commits_ahead >= Repository::MAX_DIVERGING_COUNT
- { distance: Repository::MAX_DIVERGING_COUNT }
- else
- { behind: number_commits_behind, ahead: number_commits_ahead }
- end
- end
- end
-
- def diverging_commit_counts_without_max(branch)
- @root_ref_hash ||= raw_repository.commit(repository.root_ref).id
- cache.fetch(:"diverging_commit_counts_without_max_#{branch.name}") do
- number_commits_behind, number_commits_ahead =
raw_repository.diverging_commit_count(
@root_ref_hash,
branch.dereferenced_target.sha)
diff --git a/app/services/ci/compare_reports_base_service.rb b/app/services/ci/compare_reports_base_service.rb
index d5625857599..6c2d80d8f45 100644
--- a/app/services/ci/compare_reports_base_service.rb
+++ b/app/services/ci/compare_reports_base_service.rb
@@ -8,7 +8,7 @@ module Ci
status: :parsed,
key: key(base_pipeline, head_pipeline),
data: serializer_class
- .new(project: project)
+ .new(**serializer_params)
.represent(comparer).as_json
}
rescue Gitlab::Ci::Parsers::ParserError => e
@@ -40,6 +40,10 @@ module Ci
raise NotImplementedError
end
+ def serializer_params
+ { project: project }
+ end
+
def get_report(pipeline)
raise NotImplementedError
end
diff --git a/app/services/ci/create_pipeline_service.rb b/app/services/ci/create_pipeline_service.rb
index c17712355af..cdcc4b15bea 100644
--- a/app/services/ci/create_pipeline_service.rb
+++ b/app/services/ci/create_pipeline_service.rb
@@ -65,7 +65,7 @@ module Ci
def execute!(*args, &block)
execute(*args, &block).tap do |pipeline|
unless pipeline.persisted?
- raise CreateError, pipeline.errors.full_messages.join(',')
+ raise CreateError, pipeline.error_messages
end
end
end
diff --git a/app/services/deploy_tokens/create_service.rb b/app/services/deploy_tokens/create_service.rb
index dc0122002e9..327a1dbf408 100644
--- a/app/services/deploy_tokens/create_service.rb
+++ b/app/services/deploy_tokens/create_service.rb
@@ -3,7 +3,9 @@
module DeployTokens
class CreateService < BaseService
def execute
- @project.deploy_tokens.create(params)
+ @project.deploy_tokens.create(params) do |deploy_token|
+ deploy_token.username = params[:username].presence
+ end
end
end
end
diff --git a/app/services/discussions/update_diff_position_service.rb b/app/services/discussions/update_diff_position_service.rb
index c61437fb2e3..7bdf7711155 100644
--- a/app/services/discussions/update_diff_position_service.rb
+++ b/app/services/discussions/update_diff_position_service.rb
@@ -3,7 +3,8 @@
module Discussions
class UpdateDiffPositionService < BaseService
def execute(discussion)
- result = tracer.trace(discussion.position)
+ old_position = discussion.position
+ result = tracer.trace(old_position)
return unless result
position = result[:position]
diff --git a/app/services/issuable/bulk_update_service.rb b/app/services/issuable/bulk_update_service.rb
index c4beddf2294..6d215d7a3b9 100644
--- a/app/services/issuable/bulk_update_service.rb
+++ b/app/services/issuable/bulk_update_service.rb
@@ -1,7 +1,15 @@
# frozen_string_literal: true
module Issuable
- class BulkUpdateService < IssuableBaseService
+ class BulkUpdateService
+ include Gitlab::Allowable
+
+ attr_accessor :current_user, :params
+
+ def initialize(user = nil, params = {})
+ @current_user, @params = user, params.dup
+ end
+
# rubocop: disable CodeReuse/ActiveRecord
def execute(type)
model_class = type.classify.constantize
diff --git a/app/services/issuable_base_service.rb b/app/services/issuable_base_service.rb
index 02de080e0ba..db673cace81 100644
--- a/app/services/issuable_base_service.rb
+++ b/app/services/issuable_base_service.rb
@@ -182,7 +182,7 @@ class IssuableBaseService < BaseService
# To be overridden by subclasses
end
- def before_update(issuable)
+ def before_update(issuable, skip_spam_check: false)
# To be overridden by subclasses
end
@@ -257,7 +257,7 @@ class IssuableBaseService < BaseService
last_edited_at: Time.now,
last_edited_by: current_user))
- before_update(issuable)
+ before_update(issuable, skip_spam_check: true)
if issuable.with_transaction_returning_status { issuable.save }
# We do not touch as it will affect a update on updated_at field
diff --git a/app/services/issues/update_service.rb b/app/services/issues/update_service.rb
index 6b9f23f24cd..7cd825aa967 100644
--- a/app/services/issues/update_service.rb
+++ b/app/services/issues/update_service.rb
@@ -17,8 +17,8 @@ module Issues
super
end
- def before_update(issue)
- spam_check(issue, current_user)
+ def before_update(issue, skip_spam_check: false)
+ spam_check(issue, current_user) unless skip_spam_check
end
def handle_changes(issue, options)
diff --git a/app/services/merge_requests/base_service.rb b/app/services/merge_requests/base_service.rb
index c34fbeb2adb..067510a8a0a 100644
--- a/app/services/merge_requests/base_service.rb
+++ b/app/services/merge_requests/base_service.rb
@@ -68,8 +68,8 @@ module MergeRequests
!merge_request.for_fork?
end
- def cancel_auto_merge(merge_request)
- AutoMergeService.new(project, current_user).cancel(merge_request)
+ def abort_auto_merge(merge_request, reason)
+ AutoMergeService.new(project, current_user).abort(merge_request, reason)
end
# Returns all origin and fork merge requests from `@project` satisfying passed arguments.
diff --git a/app/services/merge_requests/close_service.rb b/app/services/merge_requests/close_service.rb
index b81a4dd81d2..c2174d2a130 100644
--- a/app/services/merge_requests/close_service.rb
+++ b/app/services/merge_requests/close_service.rb
@@ -18,7 +18,7 @@ module MergeRequests
invalidate_cache_counts(merge_request, users: merge_request.assignees)
merge_request.update_project_counter_caches
cleanup_environments(merge_request)
- cancel_auto_merge(merge_request)
+ abort_auto_merge(merge_request, 'merge request was closed')
end
merge_request
diff --git a/app/services/merge_requests/create_from_issue_service.rb b/app/services/merge_requests/create_from_issue_service.rb
index e69791872cc..2a217a6f689 100644
--- a/app/services/merge_requests/create_from_issue_service.rb
+++ b/app/services/merge_requests/create_from_issue_service.rb
@@ -6,17 +6,20 @@ module MergeRequests
# branch - the name of new branch
# ref - the source of new branch.
- @branch_name = params[:branch_name]
- @issue_iid = params[:issue_iid]
- @ref = params[:ref]
+ @branch_name = params[:branch_name]
+ @issue_iid = params[:issue_iid]
+ @ref = params[:ref]
+ @target_project_id = params[:target_project_id]
super(project, user)
end
def execute
+ return error('Project not found') if target_project.blank?
+ return error('Not allowed to create merge request') unless can_create_merge_request?
return error('Invalid issue iid') unless @issue_iid.present? && issue.present?
- result = CreateBranchService.new(project, current_user).execute(branch_name, ref)
+ result = CreateBranchService.new(target_project, current_user).execute(branch_name, ref)
return result if result[:status] == :error
new_merge_request = create(merge_request)
@@ -26,7 +29,7 @@ module MergeRequests
success(new_merge_request)
else
- SystemNoteService.new_issue_branch(issue, project, current_user, branch_name)
+ SystemNoteService.new_issue_branch(issue, project, current_user, branch_name, branch_project: target_project)
error(new_merge_request.errors)
end
@@ -34,6 +37,10 @@ module MergeRequests
private
+ def can_create_merge_request?
+ can?(current_user, :create_merge_request_from, target_project)
+ end
+
# rubocop: disable CodeReuse/ActiveRecord
def issue
@issue ||= IssuesFinder.new(current_user, project_id: project.id).find_by(iid: @issue_iid)
@@ -45,21 +52,21 @@ module MergeRequests
end
def ref
- return @ref if project.repository.branch_exists?(@ref)
+ return @ref if target_project.repository.branch_exists?(@ref)
- project.default_branch || 'master'
+ target_project.default_branch || 'master'
end
def merge_request
- MergeRequests::BuildService.new(project, current_user, merge_request_params).execute
+ MergeRequests::BuildService.new(target_project, current_user, merge_request_params).execute
end
def merge_request_params
{
issue_iid: @issue_iid,
- source_project_id: project.id,
+ source_project_id: target_project.id,
source_branch: branch_name,
- target_project_id: project.id,
+ target_project_id: target_project.id,
target_branch: ref
}
end
@@ -67,5 +74,14 @@ module MergeRequests
def success(merge_request)
super().merge(merge_request: merge_request)
end
+
+ def target_project
+ @target_project ||=
+ if @target_project_id.present?
+ project.forks.find_by_id(@target_project_id)
+ else
+ project
+ end
+ end
end
end
diff --git a/app/services/merge_requests/merge_to_ref_service.rb b/app/services/merge_requests/merge_to_ref_service.rb
index efe4dcd6255..0ea50a5dbf5 100644
--- a/app/services/merge_requests/merge_to_ref_service.rb
+++ b/app/services/merge_requests/merge_to_ref_service.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module MergeRequests
- # Performs the merge between source SHA and the target branch. Instead
+ # Performs the merge between source SHA and the target branch or the specified first parent ref. Instead
# of writing the result to the MR target branch, it targets the `target_ref`.
#
# Ideally this should leave the `target_ref` state with the same state the
@@ -56,12 +56,22 @@ module MergeRequests
raise_error(error) if error
end
+ ##
+ # The parameter `target_ref` is where the merge result will be written.
+ # Default is the merge ref i.e. `refs/merge-requests/:iid/merge`.
def target_ref
- merge_request.merge_ref_path
+ params[:target_ref] || merge_request.merge_ref_path
+ end
+
+ ##
+ # The parameter `first_parent_ref` is the main line of the merge commit.
+ # Default is the target branch ref of the merge request.
+ def first_parent_ref
+ params[:first_parent_ref] || merge_request.target_branch_ref
end
def commit
- repository.merge_to_ref(current_user, source, merge_request, target_ref, commit_message)
+ repository.merge_to_ref(current_user, source, merge_request, target_ref, commit_message, first_parent_ref)
rescue Gitlab::Git::PreReceiveError => error
raise MergeError, error.message
end
diff --git a/app/services/merge_requests/rebase_service.rb b/app/services/merge_requests/rebase_service.rb
index 4b9921c28ba..8d3b9b05819 100644
--- a/app/services/merge_requests/rebase_service.rb
+++ b/app/services/merge_requests/rebase_service.rb
@@ -15,7 +15,7 @@ module MergeRequests
end
def rebase
- if merge_request.rebase_in_progress?
+ if merge_request.gitaly_rebase_in_progress?
log_error('Rebase task canceled: Another rebase is already in progress', save_message_on_model: true)
return false
end
@@ -27,6 +27,8 @@ module MergeRequests
log_error(REBASE_ERROR, save_message_on_model: true)
log_error(e.message)
false
+ ensure
+ merge_request.update_column(:rebase_jid, nil)
end
end
end
diff --git a/app/services/merge_requests/refresh_service.rb b/app/services/merge_requests/refresh_service.rb
index 4b199bd8fa8..8961d2e1023 100644
--- a/app/services/merge_requests/refresh_service.rb
+++ b/app/services/merge_requests/refresh_service.rb
@@ -24,7 +24,7 @@ module MergeRequests
reload_merge_requests
outdate_suggestions
refresh_pipelines_on_merge_requests
- cancel_auto_merges
+ abort_auto_merges
mark_pending_todos_done
cache_merge_requests_closing_issues
@@ -142,9 +142,9 @@ module MergeRequests
end
end
- def cancel_auto_merges
+ def abort_auto_merges
merge_requests_for_source_branch.each do |merge_request|
- cancel_auto_merge(merge_request)
+ abort_auto_merge(merge_request, 'source branch was updated')
end
end
diff --git a/app/services/merge_requests/update_service.rb b/app/services/merge_requests/update_service.rb
index 0066cd0491f..d361e96babf 100644
--- a/app/services/merge_requests/update_service.rb
+++ b/app/services/merge_requests/update_service.rb
@@ -44,7 +44,7 @@ module MergeRequests
merge_request.previous_changes['target_branch'].first,
merge_request.target_branch)
- cancel_auto_merge(merge_request)
+ abort_auto_merge(merge_request, 'target branch was changed')
end
if merge_request.assignees != old_assignees
diff --git a/app/services/namespaces/statistics_refresher_service.rb b/app/services/namespaces/statistics_refresher_service.rb
new file mode 100644
index 00000000000..c07b302839b
--- /dev/null
+++ b/app/services/namespaces/statistics_refresher_service.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+module Namespaces
+ class StatisticsRefresherService
+ RefresherError = Class.new(StandardError)
+
+ def execute(root_namespace)
+ root_storage_statistics = find_or_create_root_storage_statistics(root_namespace.id)
+
+ root_storage_statistics.recalculate!
+ rescue ActiveRecord::ActiveRecordError => e
+ raise RefresherError.new(e.message)
+ end
+
+ private
+
+ def find_or_create_root_storage_statistics(root_namespace_id)
+ Namespace::RootStorageStatistics
+ .safe_find_or_create_by!(namespace_id: root_namespace_id)
+ end
+ end
+end
diff --git a/app/services/prometheus/adapter_service.rb b/app/services/prometheus/adapter_service.rb
index 3be958e1613..399f4c35d66 100644
--- a/app/services/prometheus/adapter_service.rb
+++ b/app/services/prometheus/adapter_service.rb
@@ -27,12 +27,9 @@ module Prometheus
end
def cluster_prometheus_adapter
- return unless deployment_platform.respond_to?(:cluster)
+ application = deployment_platform&.cluster&.application_prometheus
- cluster = deployment_platform.cluster
- return unless cluster.application_prometheus&.available?
-
- cluster.application_prometheus
+ application if application&.available?
end
end
end
diff --git a/app/services/releases/concerns.rb b/app/services/releases/concerns.rb
index ff6b696ca96..618d96717b8 100644
--- a/app/services/releases/concerns.rb
+++ b/app/services/releases/concerns.rb
@@ -22,6 +22,10 @@ module Releases
params[:description]
end
+ def released_at
+ params[:released_at]
+ end
+
def release
strong_memoize(:release) do
project.releases.find_by_tag(tag_name)
diff --git a/app/services/releases/create_service.rb b/app/services/releases/create_service.rb
index a271a7e5e49..5b13ac631ba 100644
--- a/app/services/releases/create_service.rb
+++ b/app/services/releases/create_service.rb
@@ -58,6 +58,7 @@ module Releases
author: current_user,
tag: tag.name,
sha: tag.dereferenced_target.sha,
+ released_at: released_at,
links_attributes: params.dig(:assets, 'links') || []
)
end
diff --git a/app/services/system_note_service.rb b/app/services/system_note_service.rb
index 1390f7cdf46..e4564bc9b00 100644
--- a/app/services/system_note_service.rb
+++ b/app/services/system_note_service.rb
@@ -221,8 +221,8 @@ module SystemNoteService
end
# Called when 'merge when pipeline succeeds' is executed
- def merge_when_pipeline_succeeds(noteable, project, author, last_commit)
- body = "enabled an automatic merge when the pipeline for #{last_commit.to_reference(project)} succeeds"
+ def merge_when_pipeline_succeeds(noteable, project, author, sha)
+ body = "enabled an automatic merge when the pipeline for #{sha} succeeds"
create_note(NoteSummary.new(noteable, project, author, body, action: 'merge'))
end
@@ -234,6 +234,16 @@ module SystemNoteService
create_note(NoteSummary.new(noteable, project, author, body, action: 'merge'))
end
+ # Called when 'merge when pipeline succeeds' is aborted
+ def abort_merge_when_pipeline_succeeds(noteable, project, author, reason)
+ body = "aborted the automatic merge because #{reason}"
+
+ ##
+ # TODO: Abort message should be sent by the system, not a particular user.
+ # See https://gitlab.com/gitlab-org/gitlab-ce/issues/63187.
+ create_note(NoteSummary.new(noteable, project, author, body, action: 'merge'))
+ end
+
def handle_merge_request_wip(noteable, project, author)
prefix = noteable.work_in_progress? ? "marked" : "unmarked"
@@ -249,7 +259,7 @@ module SystemNoteService
end
def resolve_all_discussions(merge_request, project, author)
- body = "resolved all discussions"
+ body = "resolved all threads"
create_note(NoteSummary.new(merge_request, project, author, body, action: 'discussion'))
end
@@ -268,11 +278,13 @@ module SystemNoteService
merge_request = discussion.noteable
diff_refs = change_position.diff_refs
version_index = merge_request.merge_request_diffs.viewable.count
+ position_on_text = change_position.on_text?
+ text_parts = ["changed this #{position_on_text ? 'line' : 'file'} in"]
- text_parts = ["changed this line in"]
if version_params = merge_request.version_params_for(diff_refs)
- line_code = change_position.line_code(project.repository)
- url = url_helpers.diffs_project_merge_request_path(project, merge_request, version_params.merge(anchor: line_code))
+ repository = project.repository
+ anchor = position_on_text ? change_position.line_code(repository) : change_position.file_hash
+ url = url_helpers.diffs_project_merge_request_path(project, merge_request, version_params.merge(anchor: anchor))
text_parts << "[version #{version_index} of the diff](#{url})"
else
@@ -404,8 +416,9 @@ module SystemNoteService
# Example note text:
#
# "created branch `201-issue-branch-button`"
- def new_issue_branch(issue, project, author, branch)
- link = url_helpers.project_compare_path(project, from: project.default_branch, to: branch)
+ def new_issue_branch(issue, project, author, branch, branch_project: nil)
+ branch_project ||= project
+ link = url_helpers.project_compare_path(branch_project, from: branch_project.default_branch, to: branch)
body = "created branch [`#{branch}`](#{link}) to address this issue"
@@ -413,7 +426,7 @@ module SystemNoteService
end
def new_merge_request(issue, project, author, merge_request)
- body = "created merge request #{merge_request.to_reference} to address this issue"
+ body = "created merge request #{merge_request.to_reference(project)} to address this issue"
create_note(NoteSummary.new(issue, project, author, body, action: 'merge'))
end
diff --git a/app/uploaders/file_mover.rb b/app/uploaders/file_mover.rb
index 236b7ed2b3d..12be1e2bb22 100644
--- a/app/uploaders/file_mover.rb
+++ b/app/uploaders/file_mover.rb
@@ -1,22 +1,29 @@
# frozen_string_literal: true
class FileMover
- attr_reader :secret, :file_name, :model, :update_field
+ include Gitlab::Utils::StrongMemoize
- def initialize(file_path, model, update_field = :description)
+ attr_reader :secret, :file_name, :from_model, :to_model, :update_field
+
+ def initialize(file_path, update_field = :description, from_model:, to_model:)
@secret = File.split(File.dirname(file_path)).last
@file_name = File.basename(file_path)
- @model = model
+ @from_model = from_model
+ @to_model = to_model
@update_field = update_field
end
def execute
+ temp_file_uploader.retrieve_from_store!(file_name)
+
return unless valid?
+ uploader.retrieve_from_store!(file_name)
+
move
if update_markdown
- uploader.record_upload
+ update_upload_model
uploader.schedule_background_upload
end
end
@@ -24,52 +31,77 @@ class FileMover
private
def valid?
- Pathname.new(temp_file_path).realpath.to_path.start_with?(
- (Pathname(temp_file_uploader.root) + temp_file_uploader.base_dir).to_path
- )
+ if temp_file_uploader.file_storage?
+ Pathname.new(temp_file_path).realpath.to_path.start_with?(
+ (Pathname(temp_file_uploader.root) + temp_file_uploader.base_dir).to_path
+ )
+ else
+ temp_file_uploader.exists?
+ end
end
def move
- FileUtils.mkdir_p(File.dirname(file_path))
- FileUtils.move(temp_file_path, file_path)
+ if temp_file_uploader.file_storage?
+ FileUtils.mkdir_p(File.dirname(file_path))
+ FileUtils.move(temp_file_path, file_path)
+ else
+ uploader.copy_file(temp_file_uploader.file)
+ temp_file_uploader.upload.destroy!
+ end
end
def update_markdown
- updated_text = model.read_attribute(update_field)
- .gsub(temp_file_uploader.markdown_link, uploader.markdown_link)
- model.update_attribute(update_field, updated_text)
+ updated_text = to_model.read_attribute(update_field)
+ .gsub(temp_file_uploader.markdown_link, uploader.markdown_link)
+ to_model.update_attribute(update_field, updated_text)
rescue
revert
false
end
- def temp_file_path
- return @temp_file_path if @temp_file_path
+ def update_upload_model
+ return unless upload = temp_file_uploader.upload
+ return if upload.destroyed?
- temp_file_uploader.retrieve_from_store!(file_name)
+ upload.update!(model: to_model)
+ end
- @temp_file_path = temp_file_uploader.file.path
+ def temp_file_path
+ strong_memoize(:temp_file_path) do
+ temp_file_uploader.file.path
+ end
end
def file_path
- return @file_path if @file_path
-
- uploader.retrieve_from_store!(file_name)
-
- @file_path = uploader.file.path
+ strong_memoize(:file_path) do
+ uploader.file.path
+ end
end
def uploader
- @uploader ||= PersonalFileUploader.new(model, secret: secret)
+ @uploader ||=
+ begin
+ uploader = PersonalFileUploader.new(to_model, secret: secret)
+
+ # Enforcing a REMOTE object storage given FileUploader#retrieve_from_store! won't do it
+ # (there's no upload at the target yet).
+ if uploader.class.object_store_enabled?
+ uploader.object_store = ::ObjectStorage::Store::REMOTE
+ end
+
+ uploader
+ end
end
def temp_file_uploader
- @temp_file_uploader ||= PersonalFileUploader.new(nil, secret: secret)
+ @temp_file_uploader ||= PersonalFileUploader.new(from_model, secret: secret)
end
def revert
- Rails.logger.warn("Markdown not updated, file move reverted for #{model}")
+ Rails.logger.warn("Markdown not updated, file move reverted for #{to_model}")
- FileUtils.move(file_path, temp_file_path)
+ if temp_file_uploader.file_storage?
+ FileUtils.move(file_path, temp_file_path)
+ end
end
end
diff --git a/app/uploaders/file_uploader.rb b/app/uploaders/file_uploader.rb
index 1c7582533ad..b326b266017 100644
--- a/app/uploaders/file_uploader.rb
+++ b/app/uploaders/file_uploader.rb
@@ -203,6 +203,6 @@ class FileUploader < GitlabUploader
end
def secure_url
- File.join('/uploads', @secret, file.filename)
+ File.join('/uploads', @secret, filename)
end
end
diff --git a/app/uploaders/personal_file_uploader.rb b/app/uploaders/personal_file_uploader.rb
index b43162f0935..1ac69601d18 100644
--- a/app/uploaders/personal_file_uploader.rb
+++ b/app/uploaders/personal_file_uploader.rb
@@ -93,6 +93,6 @@ class PersonalFileUploader < FileUploader
end
def secure_url
- File.join('/', base_dir, secret, file.filename)
+ File.join('/', base_dir, secret, filename)
end
end
diff --git a/app/validators/color_validator.rb b/app/validators/color_validator.rb
index 1932d042e83..974dfbbf394 100644
--- a/app/validators/color_validator.rb
+++ b/app/validators/color_validator.rb
@@ -12,7 +12,7 @@
# end
#
class ColorValidator < ActiveModel::EachValidator
- PATTERN = /\A\#[0-9A-Fa-f]{3}{1,2}+\Z/.freeze
+ PATTERN = /\A\#(?:[0-9A-Fa-f]{3}){1,2}\Z/.freeze
def validate_each(record, attribute, value)
unless value =~ PATTERN
diff --git a/app/views/admin/application_settings/_grafana.html.haml b/app/views/admin/application_settings/_grafana.html.haml
new file mode 100644
index 00000000000..b6e02bde895
--- /dev/null
+++ b/app/views/admin/application_settings/_grafana.html.haml
@@ -0,0 +1,17 @@
+= form_for @application_setting, url: admin_application_settings_path(anchor: 'js-grafana-settings'), html: { class: 'fieldset-form' } do |f|
+ = form_errors(@application_setting)
+
+ %fieldset
+ %p
+ = _("Add a Grafana button in the admin sidebar, monitoring section, to access a variety of statistics on the health and performance of GitLab.")
+ = link_to icon('question-circle'), help_page_path('administration/monitoring/performance/grafana_configuration.md')
+ .form-group
+ .form-check
+ = f.check_box :grafana_enabled, class: 'form-check-input'
+ = f.label :grafana_enabled, class: 'form-check-label' do
+ = _('Enable access to Grafana')
+ .form-group
+ = f.label :grafana_url, _('Grafana URL'), class: 'label-bold'
+ = f.text_field :grafana_url, class: 'form-control', placeholder: '/-/grafana'
+
+ = f.submit _('Save changes'), class: "btn btn-success"
diff --git a/app/views/admin/application_settings/metrics_and_profiling.html.haml b/app/views/admin/application_settings/metrics_and_profiling.html.haml
index 01d61beaf53..55a48da8342 100644
--- a/app/views/admin/application_settings/metrics_and_profiling.html.haml
+++ b/app/views/admin/application_settings/metrics_and_profiling.html.haml
@@ -24,6 +24,17 @@
.settings-content
= render 'prometheus'
+%section.settings.as-grafana.no-animate#js-grafana-settings{ class: ('expanded' if expanded_by_default?) }
+ .settings-header
+ %h4
+ = _('Metrics - Grafana')
+ %button.btn.btn-default.js-settings-toggle{ type: 'button' }
+ = expanded_by_default? ? _('Collapse') : _('Expand')
+ %p
+ = _('Enable and configure Grafana.')
+ .settings-content
+ = render 'grafana'
+
%section.settings.qa-performance-bar-settings.as-performance-bar.no-animate#js-performance-bar-settings{ class: ('expanded' if expanded_by_default?) }
.settings-header
%h4
diff --git a/app/views/admin/groups/show.html.haml b/app/views/admin/groups/show.html.haml
index f524d35d79e..98230684d56 100644
--- a/app/views/admin/groups/show.html.haml
+++ b/app/views/admin/groups/show.html.haml
@@ -43,11 +43,7 @@
= render_if_exists 'admin/namespace_plan_info', namespace: @group
%li
- %span.light= _('Storage:')
- %strong= storage_counter(@group.storage_size)
- (
- = storage_counters_details(@group)
- )
+ = render 'shared/storage_counter_statistics', storage_size: @group.storage_size, storage_details: @group
%li
%span.light= _('Group Git LFS status:')
diff --git a/app/views/admin/projects/show.html.haml b/app/views/admin/projects/show.html.haml
index e23accc1ea9..0fae8060b32 100644
--- a/app/views/admin/projects/show.html.haml
+++ b/app/views/admin/projects/show.html.haml
@@ -73,11 +73,7 @@
= @project.repository.relative_path
%li
- %span.light= _('Storage:')
- %strong= storage_counter(@project.statistics&.storage_size)
- - if @project.statistics
- = surround '(', ')' do
- = storage_counters_details(@project.statistics)
+ = render 'shared/storage_counter_statistics', storage_size: @project.statistics&.storage_size, storage_details: @project.statistics
%li
%span.light last commit:
diff --git a/app/views/admin/services/_form.html.haml b/app/views/admin/services/_form.html.haml
index 97373a3c350..ab08d5c4906 100644
--- a/app/views/admin/services/_form.html.haml
+++ b/app/views/admin/services/_form.html.haml
@@ -1,7 +1,7 @@
%h3.page-title
= @service.title
-%p #{@service.description} template
+%p #{@service.description} template.
= form_for :service, url: admin_application_settings_service_path, method: :put, html: { class: 'fieldset-form' } do |form|
= render 'shared/service_settings', form: form, subject: @service
diff --git a/app/views/admin/users/show.html.haml b/app/views/admin/users/show.html.haml
index 5c6131db37d..a988f746ced 100644
--- a/app/views/admin/users/show.html.haml
+++ b/app/views/admin/users/show.html.haml
@@ -139,7 +139,7 @@
%strong
= link_to @user.created_by.name, [:admin, @user.created_by]
- = render_if_exists partial: "namespaces/shared_runner_status", locals: { namespace: @user.namespace }
+ = render_if_exists 'namespaces/shared_runner_status', namespace: @user.namespace
.col-md-6
- unless @user == current_user
diff --git a/app/views/clusters/clusters/_form.html.haml b/app/views/clusters/clusters/_form.html.haml
index 455322b2089..3d0266a2d5b 100644
--- a/app/views/clusters/clusters/_form.html.haml
+++ b/app/views/clusters/clusters/_form.html.haml
@@ -1,4 +1,4 @@
-= form_for @cluster, url: clusterable.cluster_path(@cluster), as: :cluster do |field|
+= form_for @cluster, url: clusterable.cluster_path(@cluster), as: :cluster, html: { class: 'cluster_integration_form' } do |field|
= form_errors(@cluster)
.form-group
%h5= s_('ClusterIntegration|Integration status')
diff --git a/app/views/dashboard/todos/_todo.html.haml b/app/views/dashboard/todos/_todo.html.haml
index db6e40a6fd0..8cdfc7369a0 100644
--- a/app/views/dashboard/todos/_todo.html.haml
+++ b/app/views/dashboard/todos/_todo.html.haml
@@ -49,5 +49,5 @@
- else
.todo-actions
= link_to restore_dashboard_todo_path(todo), method: :patch, class: 'btn btn-loading js-add-todo', data: { href: restore_dashboard_todo_path(todo) } do
- Add todo
+ Add a To Do
= icon('spinner spin')
diff --git a/app/views/dashboard/todos/index.html.haml b/app/views/dashboard/todos/index.html.haml
index 8212fb8bb33..731e763f2be 100644
--- a/app/views/dashboard/todos/index.html.haml
+++ b/app/views/dashboard/todos/index.html.haml
@@ -1,11 +1,11 @@
- @hide_top_links = true
-- page_title "Todos"
-- header_title "Todos", dashboard_todos_path
+- page_title "To-Do List"
+- header_title "To-Do List", dashboard_todos_path
= render_dashboard_gold_trial(current_user)
.page-title-holder.d-flex.align-items-center
- %h1.page-title= _('Todos')
+ %h1.page-title= _('To-Do List')
- if current_user.todos.any?
.top-area
@@ -13,7 +13,7 @@
%li.todos-pending{ class: active_when(params[:state].blank? || params[:state] == 'pending') }>
= link_to todos_filter_path(state: 'pending') do
%span
- Todos
+ To Do
%span.badge.badge-pill
= number_with_delimiter(todos_pending_count)
%li.todos-done{ class: active_when(params[:state] == 'done') }>
@@ -102,24 +102,24 @@
%p
Are you looking for things to do? Take a look at
= succeed "," do
- = link_to "the opened issues", issues_dashboard_path
+ = link_to "open issues", issues_dashboard_path
contribute to
- = link_to "merge requests", merge_requests_dashboard_path
- or mention someone in a comment to assign a new todo automatically.
+ = link_to "a merge request\,", merge_requests_dashboard_path
+ or mention someone in a comment to automatically assign them a new to-do item.
- else
%h4.text-center
- There are no todos to show.
+ Nothing is on your to-do list. Nice work!
- else
.todos-empty
.todos-empty-hero.svg-content
= image_tag 'illustrations/todos_empty.svg'
.todos-empty-content
%h4
- Todos let you see what you should do next
+ Your To-Do List shows what to work on next
%p
- When an issue or merge request is assigned to you, or when you
+ When an issue or merge request is assigned to you, or when you receive a
%strong
@mention
- in a comment, this will trigger a new item in your todo list, automatically.
+ in a comment, this automatically triggers a new item in your To-Do List.
%p
- You will always know what to work on next.
+ It's how you always know what to work on next.
diff --git a/app/views/discussions/_discussion.html.haml b/app/views/discussions/_discussion.html.haml
index 10187129a33..9659d416a38 100644
--- a/app/views/discussions/_discussion.html.haml
+++ b/app/views/discussions/_discussion.html.haml
@@ -13,12 +13,12 @@
= icon("chevron-up")
- else
= icon("chevron-down")
- = _('Toggle discussion')
+ = _('Toggle thread')
= link_to_member(@project, discussion.author, avatar: false)
.inline.discussion-headline-light
= discussion.author.to_reference
- started a discussion
+ started a thread
- url = discussion_path(discussion)
- if discussion.for_commit? && @noteable != discussion.noteable
diff --git a/app/views/discussions/_new_issue_for_discussion.html.haml b/app/views/discussions/_new_issue_for_discussion.html.haml
index 2bfe118c608..49d5378d62e 100644
--- a/app/views/discussions/_new_issue_for_discussion.html.haml
+++ b/app/views/discussions/_new_issue_for_discussion.html.haml
@@ -4,7 +4,7 @@
.btn-group{ role: "group", "v-if" => "showButton" }
= link_to custom_icon('icon_mr_issue'),
new_project_issue_path(@project, merge_request_to_resolve_discussions_of: merge_request.iid, discussion_to_resolve: discussion.id),
- title: 'Resolve this discussion in a new issue',
- aria: { label: 'Resolve this discussion in a new issue' },
+ title: 'Resolve this thread in a new issue',
+ aria: { label: 'Resolve this thread in a new issue' },
data: { container: 'body' },
class: 'new-issue-for-discussion btn btn-default discussion-create-issue-btn has-tooltip'
diff --git a/app/views/groups/issues.html.haml b/app/views/groups/issues.html.haml
index 91d17cfd745..f05e269553a 100644
--- a/app/views/groups/issues.html.haml
+++ b/app/views/groups/issues.html.haml
@@ -1,3 +1,5 @@
+- @can_bulk_update = can?(current_user, :admin_issue, @group)
+
- page_title "Issues"
= content_for :meta_tags do
= auto_discovery_link_tag(:atom, safe_params.merge(rss_url_options).to_h, title: "#{@group.name} issues")
@@ -9,8 +11,15 @@
= render 'shared/issuable/nav', type: :issues
.nav-controls
= render 'shared/issuable/feed_buttons'
+
+ - if @can_bulk_update
+ = render_if_exists 'shared/issuable/bulk_update_button'
+
= render 'shared/new_project_item_select', path: 'issues/new', label: "New issue", type: :issues, with_feature_enabled: 'issues', with_shared: false, include_projects_in_subgroups: true
= render 'shared/issuable/search_bar', type: :issues
+ - if @can_bulk_update
+ = render_if_exists 'shared/issuable/group_bulk_update_sidebar', group: @group, type: :issues
+
= render 'shared/issues'
diff --git a/app/views/groups/settings/_general.html.haml b/app/views/groups/settings/_general.html.haml
index e12748666c8..db1849ebb45 100644
--- a/app/views/groups/settings/_general.html.haml
+++ b/app/views/groups/settings/_general.html.haml
@@ -13,7 +13,7 @@
= f.text_field :id, class: 'form-control w-auto', readonly: true
.row.prepend-top-8
- .form-group.col-md-9.append-bottom-0
+ .form-group.col-md-9
= f.label :description, _('Group description (optional)'), class: 'label-bold'
= f.text_area :description, class: 'form-control', rows: 3, maxlength: 250
diff --git a/app/views/layouts/_search.html.haml b/app/views/layouts/_search.html.haml
index 496ec3c78b0..a5f57f5893c 100644
--- a/app/views/layouts/_search.html.haml
+++ b/app/views/layouts/_search.html.haml
@@ -1,5 +1,5 @@
- if @group && @group.persisted? && @group.path
- - group_data_attrs = { group_path: j(@group.path), name: @group.name, issues_path: issues_group_path(j(@group.path)), mr_path: merge_requests_group_path(j(@group.path)) }
+ - group_data_attrs = { group_path: j(@group.path), name: j(@group.name), issues_path: issues_group_path(@group), mr_path: merge_requests_group_path(@group) }
- if @project && @project.persisted?
- project_data_attrs = { project_path: j(@project.path), name: j(@project.name), issues_path: project_issues_path(@project), mr_path: project_merge_requests_path(@project), issues_disabled: !@project.issues_enabled? }
.search.search-form{ data: { track_label: "navbar_search", track_event: "activate_form_input" } }
diff --git a/app/views/layouts/fullscreen.html.haml b/app/views/layouts/fullscreen.html.haml
index fa04b5be9f2..91a7777514c 100644
--- a/app/views/layouts/fullscreen.html.haml
+++ b/app/views/layouts/fullscreen.html.haml
@@ -3,6 +3,7 @@
= render "layouts/head"
%body{ class: "#{user_application_theme} #{@body_class} fullscreen-layout", data: { page: body_data_page } }
= render 'peek/bar'
+ = header_message
= render partial: "layouts/header/default", locals: { project: @project, group: @group }
= render 'shared/outdated_browser'
.mobile-overlay
@@ -12,3 +13,4 @@
= render "layouts/flash"
.content-wrapper{ id: "content-body", class: "d-flex flex-column align-items-stretch mt-0" }
= yield
+ = footer_message
diff --git a/app/views/layouts/header/_default.html.haml b/app/views/layouts/header/_default.html.haml
index f8b7d0c530a..f9ee6f42e23 100644
--- a/app/views/layouts/header/_default.html.haml
+++ b/app/views/layouts/header/_default.html.haml
@@ -53,7 +53,7 @@
= number_with_delimiter(merge_requests_count)
- if header_link?(:todos)
= nav_link(controller: 'dashboard/todos', html_options: { class: "user-counter" }) do
- = link_to dashboard_todos_path, title: _('Todos'), aria: { label: _('Todos') }, class: 'shortcuts-todos', data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do
+ = link_to dashboard_todos_path, title: _('To-Do List'), aria: { label: _('To-Do List') }, class: 'shortcuts-todos', data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do
= sprite_icon('todo-done', size: 16)
%span.badge.badge-pill.todos-count{ class: ('hidden' if todos_pending_count.zero?) }
= todos_count_format(todos_pending_count)
diff --git a/app/views/layouts/nav/sidebar/_admin.html.haml b/app/views/layouts/nav/sidebar/_admin.html.haml
index 83fe871285a..87133c7ba22 100644
--- a/app/views/layouts/nav/sidebar/_admin.html.haml
+++ b/app/views/layouts/nav/sidebar/_admin.html.haml
@@ -81,6 +81,11 @@
= link_to admin_requests_profiles_path, title: _('Requests Profiles') do
%span
= _('Requests Profiles')
+ - if Gitlab::CurrentSettings.current_application_settings.grafana_enabled?
+ = nav_link do
+ = link_to Gitlab::CurrentSettings.current_application_settings.grafana_url, target: '_blank', title: _('Metrics Dashboard') do
+ %span
+ = _('Metrics Dashboard')
= render_if_exists 'layouts/nav/ee/admin/new_monitoring_sidebar'
= nav_link(controller: :broadcast_messages) do
diff --git a/app/views/layouts/nav/sidebar/_project.html.haml b/app/views/layouts/nav/sidebar/_project.html.haml
index e401488ecff..a9af5ba5008 100644
--- a/app/views/layouts/nav/sidebar/_project.html.haml
+++ b/app/views/layouts/nav/sidebar/_project.html.haml
@@ -347,7 +347,7 @@
= _('Settings')
%li.divider.fly-out-top-item
= nav_link(path: %w[projects#edit]) do
- = link_to edit_project_path(@project), title: _('General') do
+ = link_to edit_project_path(@project), title: _('General'), class: 'qa-general-settings-link' do
%span
= _('General')
= nav_link(controller: :project_members) do
diff --git a/app/views/layouts/snippets.html.haml b/app/views/layouts/snippets.html.haml
index 5f986c81ff4..841b2a5e79c 100644
--- a/app/views/layouts/snippets.html.haml
+++ b/app/views/layouts/snippets.html.haml
@@ -1,9 +1,10 @@
- header_title _("Snippets"), snippets_path
+- snippets_upload_path = snippets_upload_path(@snippet, current_user)
- content_for :page_specific_javascripts do
- - if @snippet && current_user
+ - if snippets_upload_path
-# haml-lint:disable InlineJavaScript
:javascript
- window.uploads_path = "#{upload_path('personal_snippet', id: @snippet.id)}";
+ window.uploads_path = "#{snippets_upload_path}";
= render template: "layouts/application"
diff --git a/app/views/notify/new_merge_request_email.text.erb b/app/views/notify/new_merge_request_email.text.erb
index c3f2902c78a..6c0d7b1e60b 100644
--- a/app/views/notify/new_merge_request_email.text.erb
+++ b/app/views/notify/new_merge_request_email.text.erb
@@ -1,7 +1,7 @@
<%= @merge_request.author_name %> <%= 'created a merge request:' %> <%= url_for(project_merge_request_url(@merge_request.target_project, @merge_request)) %>
<%= merge_path_description(@merge_request, 'to') %>
-<%= 'Author' %>: <%= @merge_request.author_name %>
+<%= 'Author:' %> <%= @merge_request.author_name %>
<%= assignees_label(@merge_request) %>
<%= render_if_exists 'notify/merge_request_approvers', presenter: @mr_presenter %>
diff --git a/app/views/profiles/preferences/show.html.haml b/app/views/profiles/preferences/show.html.haml
index 4ebfaff0860..d16e2dddbe0 100644
--- a/app/views/profiles/preferences/show.html.haml
+++ b/app/views/profiles/preferences/show.html.haml
@@ -92,21 +92,21 @@
.col-lg-8
.form-group
%h5= s_('Preferences|Time format')
- .checkbox-icon-inline-wrapper.form-check
+ .checkbox-icon-inline-wrapper
- time_format_label = capture do
= s_('Preferences|Display time in 24-hour format')
- = f.check_box :time_format_in_24h, class: 'form-check-input'
+ = f.check_box :time_format_in_24h
= f.label :time_format_in_24h do
= time_format_label
%h5= s_('Preferences|Time display')
- .checkbox-icon-inline-wrapper.form-check
+ .checkbox-icon-inline-wrapper
- time_display_label = capture do
= s_('Preferences|Use relative times')
- = f.check_box :time_display_relative, class: 'form-check-input'
+ = f.check_box :time_display_relative
= f.label :time_display_relative do
= time_display_label
- .text-muted
- = s_('Preferences|For example: 30 mins ago.')
+ .form-text.text-muted
+ = s_('Preferences|For example: 30 mins ago.')
.col-lg-4.profile-settings-sidebar
.col-lg-8
.form-group
diff --git a/app/views/projects/_commit_button.html.haml b/app/views/projects/_commit_button.html.haml
index 1e27c71d20d..b6689f4b57a 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-success'
+ = button_tag 'Commit changes', class: 'btn commit-btn js-commit-button btn-success qa-commit-button'
= link_to 'Cancel', cancel_path,
class: 'btn btn-cancel', data: {confirm: leave_edit_message}
diff --git a/app/views/projects/_flash_messages.html.haml b/app/views/projects/_flash_messages.html.haml
index b2dab0b5348..d95045c9cce 100644
--- a/app/views/projects/_flash_messages.html.haml
+++ b/app/views/projects/_flash_messages.html.haml
@@ -5,6 +5,7 @@
- if current_user && can?(current_user, :download_code, project)
= render 'shared/no_ssh'
= render 'shared/no_password'
+ = render_if_exists 'shared/shared_runners_minutes_limit', project: project
- unless project.empty_repo?
= render 'shared/auto_devops_implicitly_enabled_banner', project: project
= render_if_exists 'projects/above_size_limit_warning', project: project
diff --git a/app/views/projects/blob/_editor.html.haml b/app/views/projects/blob/_editor.html.haml
index a54460f1196..283b845e40d 100644
--- a/app/views/projects/blob/_editor.html.haml
+++ b/app/views/projects/blob/_editor.html.haml
@@ -32,7 +32,7 @@
= select_tag :encoding, options_for_select([ "base64", "text" ], "text"), class: 'select2', tabindex: '-1'
.file-editor.code
- %pre.js-edit-mode-pane#editor= params[:content] || local_assigns[:blob_data]
+ %pre.js-edit-mode-pane.qa-editor#editor= params[:content] || local_assigns[:blob_data]
- if local_assigns[:path]
.js-edit-mode-pane#preview.hide
.center
diff --git a/app/views/projects/branches/_branch.html.haml b/app/views/projects/branches/_branch.html.haml
index f97b259f8f2..dbff2115f50 100644
--- a/app/views/projects/branches/_branch.html.haml
+++ b/app/views/projects/branches/_branch.html.haml
@@ -1,11 +1,7 @@
- merged = local_assigns.fetch(:merged, false)
- commit = @repository.commit(branch.dereferenced_target)
-- diverging_commit_counts = Branches::DivergingCommitCountsService.new(@repository).call(branch)
-- number_commits_distance = diverging_commit_counts[:distance]
-- number_commits_behind = diverging_commit_counts[:behind]
-- number_commits_ahead = diverging_commit_counts[:ahead]
- merge_project = merge_request_source_project_for_project(@project)
-%li{ class: "branch-item js-branch-#{branch.name}" }
+%li{ class: "branch-item js-branch-item js-branch-#{branch.name}", data: { name: branch.name } }
.branch-info
.branch-title
= sprite_icon('fork', size: 12)
@@ -30,7 +26,7 @@
= s_('Branches|Cant find HEAD commit for this branch')
- if branch.name != @repository.root_ref
- .js-branch-divergence-graph{ data: { distance: number_commits_distance, ahead_count: number_commits_ahead, behind_count: number_commits_behind, default_branch: @repository.root_ref, max_commits: @max_commits } }
+ .js-branch-divergence-graph
.controls.d-none.d-md-block<
- if merge_project && create_mr_button?(@repository.root_ref, branch.name)
diff --git a/app/views/projects/branches/index.html.haml b/app/views/projects/branches/index.html.haml
index d270e461ac8..11340d12423 100644
--- a/app/views/projects/branches/index.html.haml
+++ b/app/views/projects/branches/index.html.haml
@@ -47,6 +47,7 @@
= render_if_exists 'projects/commits/mirror_status'
+ .js-branch-list{ data: { diverging_counts_endpoint: diverging_commit_counts_namespace_project_branches_path(@project.namespace, @project, format: :json) } }
- if can?(current_user, :admin_project, @project)
- project_settings_link = link_to s_('Branches|project settings'), project_protected_branches_path(@project)
.row-content-block
diff --git a/app/views/projects/deploy_tokens/_form.html.haml b/app/views/projects/deploy_tokens/_form.html.haml
index 5412fcbc9d8..f846dbd3763 100644
--- a/app/views/projects/deploy_tokens/_form.html.haml
+++ b/app/views/projects/deploy_tokens/_form.html.haml
@@ -13,6 +13,11 @@
= f.text_field :expires_at, class: 'datepicker form-control qa-deploy-token-expires-at', value: f.object.expires_at
.form-group
+ = f.label :username, class: 'label-bold'
+ = f.text_field :username, class: 'form-control qa-deploy-token-username'
+ .text-secondary= s_('DeployTokens|Default format is "gitlab+deploy-token-{n}". Enter custom username if you want to change it.')
+
+ .form-group
= f.label :scopes, class: 'label-bold'
%fieldset.form-group.form-check
= f.check_box :read_repository, class: 'form-check-input qa-deploy-token-read-repository'
diff --git a/app/views/projects/edit.html.haml b/app/views/projects/edit.html.haml
index 29b7c45201c..3403564992e 100644
--- a/app/views/projects/edit.html.haml
+++ b/app/views/projects/edit.html.haml
@@ -121,7 +121,7 @@
%li= _('You can only transfer the project to namespaces you manage.')
%li= _('You will need to update your local repositories to point to the new location.')
%li= _('Project visibility level will be changed to match namespace rules when transferring to a group.')
- = f.submit 'Transfer project', class: "btn btn-remove js-confirm-danger", data: { "confirm-danger-message" => transfer_project_message(@project) }
+ = f.submit 'Transfer project', class: "btn btn-remove js-confirm-danger qa-transfer-button", data: { "confirm-danger-message" => transfer_project_message(@project) }
- if @project.forked? && can?(current_user, :remove_fork_project, @project)
.sub-section
diff --git a/app/views/projects/issues/_new_branch.html.haml b/app/views/projects/issues/_new_branch.html.haml
index 52bb797b5b3..8d3e54dc455 100644
--- a/app/views/projects/issues/_new_branch.html.haml
+++ b/app/views/projects/issues/_new_branch.html.haml
@@ -3,13 +3,14 @@
- data_action = can_create_merge_request ? 'create-mr' : 'create-branch'
- value = can_create_merge_request ? 'Create merge request' : 'Create branch'
- value = can_create_confidential_merge_request? ? _('Create confidential merge request') : value
+ - create_mr_text = can_create_confidential_merge_request? ? _('Create confidential merge request') : _('Create merge request')
- can_create_path = can_create_branch_project_issue_path(@project, @issue)
- create_mr_path = create_merge_request_project_issue_path(@project, @issue, branch_name: @issue.to_branch_name, ref: @project.default_branch)
- create_branch_path = project_branches_path(@project, branch_name: @issue.to_branch_name, ref: @project.default_branch, issue_iid: @issue.iid)
- refs_path = refs_namespace_project_path(@project.namespace, @project, search: '')
- .create-mr-dropdown-wrap.d-inline-block.full-width-mobile{ data: { can_create_path: can_create_path, create_mr_path: create_mr_path, create_branch_path: create_branch_path, refs_path: refs_path } }
+ .create-mr-dropdown-wrap.d-inline-block.full-width-mobile.js-create-mr{ data: { project_path: @project.full_path, project_id: @project.id, can_create_path: can_create_path, create_mr_path: create_mr_path, create_branch_path: create_branch_path, refs_path: refs_path, is_confidential: can_create_confidential_merge_request?.to_s } }
.btn-group.btn-group-sm.unavailable
%button.btn.btn-grouped{ type: 'button', disabled: 'disabled' }
= icon('spinner', class: 'fa-spin')
@@ -26,7 +27,7 @@
.droplab-dropdown
%ul#create-merge-request-dropdown.create-merge-request-dropdown-menu.dropdown-menu.dropdown-menu-right.gl-show-field-errors{ class: ("create-confidential-merge-request-dropdown-menu" if can_create_confidential_merge_request?), data: { dropdown: true } }
- if can_create_merge_request
- %li.droplab-item-selected{ role: 'button', data: { value: 'create-mr', text: _('Create merge request') } }
+ %li.droplab-item-selected{ role: 'button', data: { value: 'create-mr', text: create_mr_text } }
.menu-item
= icon('check', class: 'icon')
- if can_create_confidential_merge_request?
@@ -41,6 +42,8 @@
%li.divider.droplab-item-ignore
%li.droplab-item-ignore.prepend-left-8.append-right-8.prepend-top-16
+ - if can_create_confidential_merge_request?
+ #js-forked-project{ data: { namespace_path: @project.namespace.full_path, project_path: @project.full_path, new_fork_path: new_project_fork_path(@project), help_page_path: help_page_path('user/project/merge_requests') } }
.form-group
%label{ for: 'new-branch-name' }
= _('Branch name')
@@ -55,4 +58,8 @@
.form-group
%button.btn.btn-success.js-create-target{ type: 'button', data: { action: 'create-mr' } }
- = _('Create merge request')
+ = create_mr_text
+
+ - if can_create_confidential_merge_request?
+ %p.text-warning.js-exposed-info-warning.hidden
+ = _('This may expose confidential information as the selected fork is in another namespace that can have other members.')
diff --git a/app/views/projects/registry/repositories/index.html.haml b/app/views/projects/registry/repositories/index.html.haml
index db1f15f96b8..e34973f1f43 100644
--- a/app/views/projects/registry/repositories/index.html.haml
+++ b/app/views/projects/registry/repositories/index.html.haml
@@ -1,49 +1,9 @@
-- page_title "Container Registry"
-
%section
- .settings-header
- %h4
- = page_title
- %p
- = s_('ContainerRegistry|With the Docker Container Registry integrated into GitLab, every project can have its own space to store its Docker images.')
- %p.append-bottom-0
- = succeed '.' do
- = s_('ContainerRegistry|Learn more about')
- = link_to _('Container Registry'), help_page_path('user/project/container_registry'), target: '_blank'
.row.registry-placeholder.prepend-bottom-10
- .col-lg-12
- #js-vue-registry-images{ data: { endpoint: project_container_registry_index_path(@project, format: :json) } }
-
- .row.prepend-top-10
- .col-lg-12
- .card
- .card-header
- = s_('ContainerRegistry|How to use the Container Registry')
- .card-body
- %p
- - link_token = link_to(_('personal access token'), help_page_path('user/profile/account/two_factor_authentication', anchor: 'personal-access-tokens'), target: '_blank')
- - link_2fa = link_to(_('2FA enabled'), help_page_path('user/profile/account/two_factor_authentication'), target: '_blank')
- = s_('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}:').html_safe % { link_2fa: link_2fa, link_token: link_token }
- %pre
- docker login #{Gitlab.config.registry.host_port}
- %br
- %p
- - deploy_token = link_to(_('deploy token'), help_page_path('user/project/deploy_tokens/index', anchor: 'read-container-registry-images'), target: '_blank')
- = s_('ContainerRegistry|You can also use a %{deploy_token} for read-only access to the registry images.').html_safe % { deploy_token: deploy_token }
- %br
- %p
- = s_('ContainerRegistry|Once you log in, you&rsquo;re free to create and upload a container image using the common %{build} and %{push} commands').html_safe % { build: "<code>build</code>".html_safe, push: "<code>push</code>".html_safe }
- %pre
- :plain
- docker build -t #{escape_once(@project.container_registry_url)} .
- docker push #{escape_once(@project.container_registry_url)}
- %hr
- %h5.prepend-top-default
- = s_('ContainerRegistry|Use different image names')
- %p.light
- = s_('ContainerRegistry|GitLab supports up to 3 levels of image names. The following examples of images are valid for your project:')
- %pre
- :plain
- #{escape_once(@project.container_registry_url)}:tag
- #{escape_once(@project.container_registry_url)}/optional-image-name:tag
- #{escape_once(@project.container_registry_url)}/optional-name/optional-image-name:tag
+ .col-12
+ #js-vue-registry-images{ data: { endpoint: project_container_registry_index_path(@project, format: :json),
+ "help_page_path" => help_page_path('user/project/container_registry'),
+ "no_containers_image" => image_path('illustrations/docker-empty-state.svg'),
+ "containers_error_image" => image_path('illustrations/docker-error-state.svg'),
+ "repository_url" => escape_once(@project.container_registry_url),
+ character_error: @character_error.to_s } }
diff --git a/app/views/shared/_confirm_modal.html.haml b/app/views/shared/_confirm_modal.html.haml
index 3967c8148d2..8e3b482e27d 100644
--- a/app/views/shared/_confirm_modal.html.haml
+++ b/app/views/shared/_confirm_modal.html.haml
@@ -1,4 +1,4 @@
-#modal-confirm-danger.modal{ tabindex: -1 }
+#modal-confirm-danger.modal.qa-confirm-modal{ tabindex: -1 }
.modal-dialog
.modal-content
.modal-header
@@ -17,6 +17,6 @@
to proceed or close this modal to cancel.
.form-group
- = text_field_tag 'confirm_name_input', '', class: 'form-control js-confirm-danger-input'
+ = text_field_tag 'confirm_name_input', '', class: 'form-control js-confirm-danger-input qa-confirm-input'
.form-actions
- = submit_tag _('Confirm'), class: "btn btn-danger js-confirm-danger-submit"
+ = submit_tag _('Confirm'), class: "btn btn-danger js-confirm-danger-submit qa-confirm-button"
diff --git a/app/views/shared/_issuable_meta_data.html.haml b/app/views/shared/_issuable_meta_data.html.haml
index 31a5370a5f8..71b13a5d741 100644
--- a/app/views/shared/_issuable_meta_data.html.haml
+++ b/app/views/shared/_issuable_meta_data.html.haml
@@ -2,7 +2,7 @@
- issue_votes = @issuable_meta_data[issuable.id]
- upvotes, downvotes = issue_votes.upvotes, issue_votes.downvotes
- issuable_url = @collection_type == "Issue" ? issue_path(issuable, anchor: 'notes') : merge_request_path(issuable, anchor: 'notes')
-- issuable_mr = @issuable_meta_data[issuable.id].merge_requests_count
+- issuable_mr = @issuable_meta_data[issuable.id].merge_requests_count(current_user)
- if issuable_mr > 0
%li.issuable-mr.d-none.d-sm-block.has-tooltip{ title: _('Related merge requests') }
diff --git a/app/views/shared/_storage_counter_statistics.html.haml b/app/views/shared/_storage_counter_statistics.html.haml
new file mode 100644
index 00000000000..99b2323ca82
--- /dev/null
+++ b/app/views/shared/_storage_counter_statistics.html.haml
@@ -0,0 +1,4 @@
+%span.light= _('Storage:')
+%strong= storage_counter(storage_size)
+- if storage_details
+ (#{storage_counters_details(storage_details)})
diff --git a/app/views/shared/boards/components/_board.html.haml b/app/views/shared/boards/components/_board.html.haml
index fdb2a0a1843..6c0613605eb 100644
--- a/app/views/shared/boards/components/_board.html.haml
+++ b/app/views/shared/boards/components/_board.html.haml
@@ -19,8 +19,10 @@
%img.avatar.s20.has-tooltip{ height: "20", width: "20", ":src": "list.assignee.avatar", ":alt": "list.assignee.name" }
.board-title-text
- %span.board-title-main-text.has-tooltip.block-truncated{ "v-if": "list.type !== \"label\"",
- ":title" => '((list.label && list.label.description) || list.title || "")', data: { container: "body" } }
+ %span.board-title-main-text.block-truncated{ "v-if": "list.type !== \"label\"",
+ ":title" => '((list.label && list.label.description) || list.title || "")',
+ data: { container: "body" },
+ ":class": "{ 'has-tooltip': !['backlog', 'closed'].includes(list.type) }" }
{{ list.title }}
%span.board-title-sub-text.prepend-left-5.has-tooltip{ "v-if": "list.type === \"assignee\"",
diff --git a/app/views/shared/issuable/_form.html.haml b/app/views/shared/issuable/_form.html.haml
index c6a391ae563..214e87052da 100644
--- a/app/views/shared/issuable/_form.html.haml
+++ b/app/views/shared/issuable/_form.html.haml
@@ -17,8 +17,7 @@
= render 'shared/issuable/form/template_selector', issuable: issuable
= render 'shared/issuable/form/title', issuable: issuable, form: form, has_wip_commits: commits && commits.detect(&:work_in_progress?)
-- if Gitlab::Graphql.enabled?
- #js-suggestions{ data: { project_path: @project.full_path } }
+#js-suggestions{ data: { project_path: @project.full_path } }
= render 'shared/form_elements/description', model: issuable, form: form, project: project
@@ -48,13 +47,13 @@
= hidden_field_tag 'merge_request_to_resolve_discussions_of', @merge_request_to_resolve_discussions_of.iid
- if @discussion_to_resolve
= hidden_field_tag 'discussion_to_resolve', @discussion_to_resolve.id
- Creating this issue will resolve the discussion in
+ Creating this issue will resolve the thread in
- else
- Creating this issue will resolve all discussions in
+ Creating this issue will resolve all threads in
= link_to_discussions_to_resolve(@merge_request_to_resolve_discussions_of, @discussion_to_resolve)
- else
The
- = @discussion_to_resolve ? 'discussion' : 'discussions'
+ = @discussion_to_resolve ? 'thread' : 'threads'
at
= link_to_discussions_to_resolve(@merge_request_to_resolve_discussions_of, @discussion_to_resolve)
will stay unresolved. Ask someone with permission to resolve
diff --git a/app/views/shared/issuable/_sidebar.html.haml b/app/views/shared/issuable/_sidebar.html.haml
index e87e560266f..b4f8377c008 100644
--- a/app/views/shared/issuable/_sidebar.html.haml
+++ b/app/views/shared/issuable/_sidebar.html.haml
@@ -10,7 +10,7 @@
.block.issuable-sidebar-header
- if signed_in
%span.issuable-header-text.hide-collapsed.float-left
- = _('Todo')
+ = _('To Do')
%a.gutter-toggle.float-right.js-sidebar-toggle.has-tooltip{ role: "button", href: "#", "aria-label" => "Toggle sidebar", title: sidebar_gutter_tooltip_text, data: { container: 'body', placement: 'left', boundary: 'viewport' } }
= sidebar_gutter_toggle_icon
- if signed_in
diff --git a/app/views/shared/notes/_comment_button.html.haml b/app/views/shared/notes/_comment_button.html.haml
index c3f5eeb0da6..8d74eacc7dc 100644
--- a/app/views/shared/notes/_comment_button.html.haml
+++ b/app/views/shared/notes/_comment_button.html.haml
@@ -18,11 +18,11 @@
%li.divider.droplab-item-ignore
- %li#discussion{ data: { value: 'DiscussionNote', 'submit-text' => _('Start discussion'), 'close-text' => _("Start discussion & close %{noteable_name}") % { noteable_name: noteable_name }, 'reopen-text' => _("Start discussion & reopen %{noteable_name}") % { noteable_name: noteable_name } } }
+ %li#discussion{ data: { value: 'DiscussionNote', 'submit-text' => _('Start thread'), 'close-text' => _("Start thread & close %{noteable_name}") % { noteable_name: noteable_name }, 'reopen-text' => _("Start thread & reopen %{noteable_name}") % { noteable_name: noteable_name } } }
%button.btn.btn-transparent
= icon('check', class: 'icon')
.description
- %strong= _("Start discussion")
+ %strong= _("Start thread")
%p
= succeed '.' do
- if @note.noteable.supports_resolvable_notes?
diff --git a/app/workers/all_queues.yml b/app/workers/all_queues.yml
index e55962b629e..3d34bfc05c7 100644
--- a/app/workers/all_queues.yml
+++ b/app/workers/all_queues.yml
@@ -26,6 +26,7 @@
- cronjob:issue_due_scheduler
- cronjob:prune_web_hook_logs
- cronjob:schedule_migrate_external_diffs
+- cronjob:namespaces_prune_aggregation_schedules
- gcp_cluster:cluster_install_app
- gcp_cluster:cluster_patch_app
@@ -101,6 +102,9 @@
- todos_destroyer:todos_destroyer_project_private
- todos_destroyer:todos_destroyer_private_features
+- update_namespace_statistics:namespaces_schedule_aggregation
+- update_namespace_statistics:namespaces_root_statistics
+
- object_pool:object_pool_create
- object_pool:object_pool_schedule_join
- object_pool:object_pool_join
diff --git a/app/workers/concerns/application_worker.rb b/app/workers/concerns/application_worker.rb
index 25c3a945077..2b36ccb8304 100644
--- a/app/workers/concerns/application_worker.rb
+++ b/app/workers/concerns/application_worker.rb
@@ -1,5 +1,7 @@
# frozen_string_literal: true
+require 'sidekiq/api'
+
Sidekiq::Worker.extend ActiveSupport::Concern
module ApplicationWorker
@@ -44,6 +46,10 @@ module ApplicationWorker
get_sidekiq_options['queue'].to_s
end
+ def queue_size
+ Sidekiq::Queue.new(queue).size
+ end
+
def bulk_perform_async(args_list)
Sidekiq::Client.push_bulk('class' => self, 'args' => args_list)
end
diff --git a/app/workers/namespaces/prune_aggregation_schedules_worker.rb b/app/workers/namespaces/prune_aggregation_schedules_worker.rb
new file mode 100644
index 00000000000..4e40feee702
--- /dev/null
+++ b/app/workers/namespaces/prune_aggregation_schedules_worker.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+module Namespaces
+ class PruneAggregationSchedulesWorker
+ include ApplicationWorker
+ include CronjobQueue
+
+ # Worker to prune pending rows on Namespace::AggregationSchedule
+ # It's scheduled to run once a day at 1:05am.
+ def perform
+ aggregation_schedules.find_each do |aggregation_schedule|
+ aggregation_schedule.schedule_root_storage_statistics
+ end
+ end
+
+ private
+
+ def aggregation_schedules
+ Namespace::AggregationSchedule.all
+ end
+ end
+end
diff --git a/app/workers/namespaces/root_statistics_worker.rb b/app/workers/namespaces/root_statistics_worker.rb
new file mode 100644
index 00000000000..48876825564
--- /dev/null
+++ b/app/workers/namespaces/root_statistics_worker.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+module Namespaces
+ class RootStatisticsWorker
+ include ApplicationWorker
+
+ queue_namespace :update_namespace_statistics
+
+ def perform(namespace_id)
+ namespace = Namespace.find(namespace_id)
+
+ return unless update_statistics_enabled_for?(namespace) && namespace.aggregation_scheduled?
+
+ Namespaces::StatisticsRefresherService.new.execute(namespace)
+
+ namespace.aggregation_schedule.destroy
+ rescue ::Namespaces::StatisticsRefresherService::RefresherError, ActiveRecord::RecordNotFound => ex
+ log_error(namespace.full_path, ex.message) if namespace
+ end
+
+ private
+
+ def log_error(namespace_path, error_message)
+ Gitlab::SidekiqLogger.error("Namespace statistics can't be updated for #{namespace_path}: #{error_message}")
+ end
+
+ def update_statistics_enabled_for?(namespace)
+ Feature.enabled?(:update_statistics_namespace, namespace)
+ end
+ end
+end
diff --git a/app/workers/namespaces/schedule_aggregation_worker.rb b/app/workers/namespaces/schedule_aggregation_worker.rb
new file mode 100644
index 00000000000..a4594b84b13
--- /dev/null
+++ b/app/workers/namespaces/schedule_aggregation_worker.rb
@@ -0,0 +1,45 @@
+# frozen_string_literal: true
+
+module Namespaces
+ class ScheduleAggregationWorker
+ include ApplicationWorker
+
+ queue_namespace :update_namespace_statistics
+
+ def perform(namespace_id)
+ return unless aggregation_schedules_table_exists?
+
+ namespace = Namespace.find(namespace_id)
+ root_ancestor = namespace.root_ancestor
+
+ return unless update_statistics_enabled_for?(root_ancestor) && !root_ancestor.aggregation_scheduled?
+
+ Namespace::AggregationSchedule.safe_find_or_create_by!(namespace_id: root_ancestor.id)
+ rescue ActiveRecord::RecordNotFound
+ log_error(namespace_id)
+ end
+
+ private
+
+ # On db/post_migrate/20180529152628_schedule_to_archive_legacy_traces.rb
+ # traces are archived through build.trace.archive, which in consequence
+ # calls UpdateProjectStatistics#schedule_namespace_statistics_worker.
+ #
+ # The migration and specs fails since NamespaceAggregationSchedule table
+ # does not exist at that point.
+ # https://gitlab.com/gitlab-org/gitlab-ce/issues/50712
+ def aggregation_schedules_table_exists?
+ return true unless Rails.env.test?
+
+ Namespace::AggregationSchedule.table_exists?
+ end
+
+ def log_error(root_ancestor_id)
+ Gitlab::SidekiqLogger.error("Namespace can't be scheduled for aggregation: #{root_ancestor_id} does not exist")
+ end
+
+ def update_statistics_enabled_for?(root_ancestor)
+ Feature.enabled?(:update_statistics_namespace, root_ancestor)
+ end
+ end
+end
diff --git a/app/workers/rebase_worker.rb b/app/workers/rebase_worker.rb
index a6baebc1443..8d06adcd993 100644
--- a/app/workers/rebase_worker.rb
+++ b/app/workers/rebase_worker.rb
@@ -1,5 +1,7 @@
# frozen_string_literal: true
+# The RebaseWorker must be wrapped in important concurrency code, so should only
+# be scheduled via MergeRequest#rebase_async
class RebaseWorker
include ApplicationWorker
diff --git a/changelogs/unreleased/12533-shared-runners-warning.yml b/changelogs/unreleased/12533-shared-runners-warning.yml
new file mode 100644
index 00000000000..b2b526cc2e4
--- /dev/null
+++ b/changelogs/unreleased/12533-shared-runners-warning.yml
@@ -0,0 +1,5 @@
+---
+title: Removes EE differences for app/views/admin/users/show.html.haml
+merge_request:
+author:
+type: other
diff --git a/changelogs/unreleased/12550-fullscrean.yml b/changelogs/unreleased/12550-fullscrean.yml
new file mode 100644
index 00000000000..f20b191f411
--- /dev/null
+++ b/changelogs/unreleased/12550-fullscrean.yml
@@ -0,0 +1,5 @@
+---
+title: Removes EE differences for app/views/layouts/fullscreen.html.haml
+merge_request:
+author:
+type: other
diff --git a/changelogs/unreleased/12553-preferences.yml b/changelogs/unreleased/12553-preferences.yml
new file mode 100644
index 00000000000..c41a8c98e4e
--- /dev/null
+++ b/changelogs/unreleased/12553-preferences.yml
@@ -0,0 +1,5 @@
+---
+title: Removes EE diff for app/views/profiles/preferences/show.html.haml
+merge_request:
+author:
+type: other
diff --git a/changelogs/unreleased/32452-multiple-discussions.yml b/changelogs/unreleased/32452-multiple-discussions.yml
new file mode 100644
index 00000000000..5552340ee66
--- /dev/null
+++ b/changelogs/unreleased/32452-multiple-discussions.yml
@@ -0,0 +1,5 @@
+---
+title: Resolve Multiple discussions per line in merge request diffs
+merge_request: 28748
+author:
+type: added
diff --git a/changelogs/unreleased/40379-CJK-search-min-chars.yml b/changelogs/unreleased/40379-CJK-search-min-chars.yml
new file mode 100644
index 00000000000..6f6c4df464f
--- /dev/null
+++ b/changelogs/unreleased/40379-CJK-search-min-chars.yml
@@ -0,0 +1,5 @@
+---
+title: Remove minimum character limits for fuzzy searches when using a CTE
+merge_request: 29810
+author:
+type: fixed
diff --git a/changelogs/unreleased/44106-include-subgroups-in-group-activity.yml b/changelogs/unreleased/44106-include-subgroups-in-group-activity.yml
new file mode 100644
index 00000000000..6e78d61ebc4
--- /dev/null
+++ b/changelogs/unreleased/44106-include-subgroups-in-group-activity.yml
@@ -0,0 +1,5 @@
+---
+title: Include events from subgroups in group's activity
+merge_request: 29953
+author: Fabian Schneider @fabsrc
+type: changed
diff --git a/changelogs/unreleased/45104-special-characters-in-project-name-path-prevent-users-from-using-the-container-registry.yml b/changelogs/unreleased/45104-special-characters-in-project-name-path-prevent-users-from-using-the-container-registry.yml
new file mode 100644
index 00000000000..ddde0cc9c39
--- /dev/null
+++ b/changelogs/unreleased/45104-special-characters-in-project-name-path-prevent-users-from-using-the-container-registry.yml
@@ -0,0 +1,5 @@
+---
+title: Updated container registry to display error message when special characters in path. Documentation has also been updated.
+merge_request: 29616
+author:
+type: changed
diff --git a/changelogs/unreleased/50228-deploy-tokens-custom-username.yml b/changelogs/unreleased/50228-deploy-tokens-custom-username.yml
new file mode 100644
index 00000000000..fdafa7b1113
--- /dev/null
+++ b/changelogs/unreleased/50228-deploy-tokens-custom-username.yml
@@ -0,0 +1,5 @@
+---
+title: Allow custom username for deploy tokens
+merge_request: 29639
+author:
+type: added
diff --git a/changelogs/unreleased/51794-add-ordering-to-runner-jobs-api.yml b/changelogs/unreleased/51794-add-ordering-to-runner-jobs-api.yml
new file mode 100644
index 00000000000..908a132688c
--- /dev/null
+++ b/changelogs/unreleased/51794-add-ordering-to-runner-jobs-api.yml
@@ -0,0 +1,5 @@
+---
+title: Add order_by and sort params to list runner jobs api
+merge_request: 29629
+author: Sujay Patel
+type: added
diff --git a/changelogs/unreleased/53357-fix-plus-in-upload-file-names.yml b/changelogs/unreleased/53357-fix-plus-in-upload-file-names.yml
new file mode 100644
index 00000000000..c11d74bd4fe
--- /dev/null
+++ b/changelogs/unreleased/53357-fix-plus-in-upload-file-names.yml
@@ -0,0 +1,5 @@
+---
+title: Fix broken URLs for uploads with a plus in the filename
+merge_request: 29915
+author:
+type: fixed
diff --git a/changelogs/unreleased/54117-transactional-rebase.yml b/changelogs/unreleased/54117-transactional-rebase.yml
new file mode 100644
index 00000000000..d0c93114c49
--- /dev/null
+++ b/changelogs/unreleased/54117-transactional-rebase.yml
@@ -0,0 +1,5 @@
+---
+title: Allow asynchronous rebase operations to be monitored
+merge_request: 29940
+author:
+type: fixed
diff --git a/changelogs/unreleased/55487-enable-group-terminals-button.yml b/changelogs/unreleased/55487-enable-group-terminals-button.yml
new file mode 100644
index 00000000000..6bf16eaadd1
--- /dev/null
+++ b/changelogs/unreleased/55487-enable-group-terminals-button.yml
@@ -0,0 +1,5 @@
+---
+title: Enable terminals button for group clusters
+merge_request: 30255
+author:
+type: added
diff --git a/changelogs/unreleased/55953-renamed-discussion-to-thread.yml b/changelogs/unreleased/55953-renamed-discussion-to-thread.yml
new file mode 100644
index 00000000000..a5203ecf2e0
--- /dev/null
+++ b/changelogs/unreleased/55953-renamed-discussion-to-thread.yml
@@ -0,0 +1,5 @@
+---
+title: "renamed discussion to thread in merge-request and issue timeline"
+merge_request: 29553
+author: Michel Engelen
+type: changed
diff --git a/changelogs/unreleased/57793-fix-line-age.yml b/changelogs/unreleased/57793-fix-line-age.yml
new file mode 100644
index 00000000000..cf4e328e54a
--- /dev/null
+++ b/changelogs/unreleased/57793-fix-line-age.yml
@@ -0,0 +1,5 @@
+---
+title: Support note position tracing on an image
+merge_request: 30158
+author:
+type: fixed
diff --git a/changelogs/unreleased/58808-fix-image-diff-on-text.yml b/changelogs/unreleased/58808-fix-image-diff-on-text.yml
new file mode 100644
index 00000000000..78955c24186
--- /dev/null
+++ b/changelogs/unreleased/58808-fix-image-diff-on-text.yml
@@ -0,0 +1,5 @@
+---
+title: Don't show image diff note on text file
+merge_request: 30221
+author:
+type: fixed
diff --git a/changelogs/unreleased/60856-deleting-binary-file.yml b/changelogs/unreleased/60856-deleting-binary-file.yml
new file mode 100644
index 00000000000..9b587ed591b
--- /dev/null
+++ b/changelogs/unreleased/60856-deleting-binary-file.yml
@@ -0,0 +1,5 @@
+---
+title: Removing an image should not output binary data
+merge_request: 30314
+author:
+type: fixed
diff --git a/changelogs/unreleased/60859-upload-after-delete.yml b/changelogs/unreleased/60859-upload-after-delete.yml
new file mode 100644
index 00000000000..c36dfb84bfe
--- /dev/null
+++ b/changelogs/unreleased/60859-upload-after-delete.yml
@@ -0,0 +1,5 @@
+---
+title: In WebIDE allow adding new entries of the same name as deleted entry
+merge_request: 30239
+author:
+type: fixed
diff --git a/changelogs/unreleased/61005-grafanaInAdminSettingsMonitoringMenu.yml b/changelogs/unreleased/61005-grafanaInAdminSettingsMonitoringMenu.yml
new file mode 100644
index 00000000000..3ee512f3448
--- /dev/null
+++ b/changelogs/unreleased/61005-grafanaInAdminSettingsMonitoringMenu.yml
@@ -0,0 +1,5 @@
+---
+title: Adds link to Grafana in Admin > Monitoring settings when grafana is enabled in config
+merge_request: 28937
+author: Romain Maneschi
+type: added
diff --git a/changelogs/unreleased/61284-frontend-follow-up-from-add-packages_size-to-projectstatistics.yml b/changelogs/unreleased/61284-frontend-follow-up-from-add-packages_size-to-projectstatistics.yml
new file mode 100644
index 00000000000..3445057f7fb
--- /dev/null
+++ b/changelogs/unreleased/61284-frontend-follow-up-from-add-packages_size-to-projectstatistics.yml
@@ -0,0 +1,5 @@
+---
+title: Improved readability of storage statistics in group / project admin area
+merge_request: 30406
+author:
+type: other
diff --git a/changelogs/unreleased/62124-new-threaded-discussion-design.yml b/changelogs/unreleased/62124-new-threaded-discussion-design.yml
new file mode 100644
index 00000000000..6614e05be74
--- /dev/null
+++ b/changelogs/unreleased/62124-new-threaded-discussion-design.yml
@@ -0,0 +1,5 @@
+---
+title: Implement borderless discussion design with new reply field
+merge_request: 28580
+author:
+type: added
diff --git a/changelogs/unreleased/63475-fix-n-1.yml b/changelogs/unreleased/63475-fix-n-1.yml
new file mode 100644
index 00000000000..3ed825290fd
--- /dev/null
+++ b/changelogs/unreleased/63475-fix-n-1.yml
@@ -0,0 +1,5 @@
+---
+title: Improve performance of MergeRequestsController#ci_environment_status endpoint
+merge_request: 30224
+author:
+type: performance
diff --git a/changelogs/unreleased/63590-pipeline-actions-cause-full-refresh.yml b/changelogs/unreleased/63590-pipeline-actions-cause-full-refresh.yml
new file mode 100644
index 00000000000..a1e7d4679d8
--- /dev/null
+++ b/changelogs/unreleased/63590-pipeline-actions-cause-full-refresh.yml
@@ -0,0 +1,5 @@
+---
+title: Fix pipelines table to update without refreshing after action
+merge_request: 30190
+author:
+type: fixed
diff --git a/changelogs/unreleased/63873-process-start-time.yml b/changelogs/unreleased/63873-process-start-time.yml
new file mode 100644
index 00000000000..b11a66ca106
--- /dev/null
+++ b/changelogs/unreleased/63873-process-start-time.yml
@@ -0,0 +1,6 @@
+---
+title: Change ruby_process_start_time_seconds metric to unix timestamp instead of
+ seconds from boot.
+merge_request: 30195
+author:
+type: fixed
diff --git a/changelogs/unreleased/63971-remove-istanbul.yml b/changelogs/unreleased/63971-remove-istanbul.yml
new file mode 100644
index 00000000000..674df82db35
--- /dev/null
+++ b/changelogs/unreleased/63971-remove-istanbul.yml
@@ -0,0 +1,5 @@
+---
+title: Remove istanbul JavaScript package
+merge_request: 30232
+author: Takuya Noguchi
+type: other
diff --git a/changelogs/unreleased/64176-fix-error-handling.yml b/changelogs/unreleased/64176-fix-error-handling.yml
new file mode 100644
index 00000000000..e7a9a5897ae
--- /dev/null
+++ b/changelogs/unreleased/64176-fix-error-handling.yml
@@ -0,0 +1,5 @@
+---
+title: Fix invalid SSL certificate errors on Drone CI service
+merge_request: 30422
+author:
+type: fixed
diff --git a/changelogs/unreleased/Remove-unresolved-class-in-discussion-header.yml b/changelogs/unreleased/Remove-unresolved-class-in-discussion-header.yml
new file mode 100644
index 00000000000..3695f3063f3
--- /dev/null
+++ b/changelogs/unreleased/Remove-unresolved-class-in-discussion-header.yml
@@ -0,0 +1,5 @@
+---
+title: Remove unresolved class and fixed height in discussion header
+merge_request: 28440
+author: David Palubin
+type: other
diff --git a/changelogs/unreleased/add-salesforce-logo.yml b/changelogs/unreleased/add-salesforce-logo.yml
new file mode 100644
index 00000000000..13766821b88
--- /dev/null
+++ b/changelogs/unreleased/add-salesforce-logo.yml
@@ -0,0 +1,5 @@
+---
+title: Add salesforce logo for salesforce SSO
+merge_request: 28857
+author:
+type: changed
diff --git a/changelogs/unreleased/add-strategies-column-to-scopes-table.yml b/changelogs/unreleased/add-strategies-column-to-scopes-table.yml
new file mode 100644
index 00000000000..0bb87fca014
--- /dev/null
+++ b/changelogs/unreleased/add-strategies-column-to-scopes-table.yml
@@ -0,0 +1,5 @@
+---
+title: Add strategies column to operations_feature_flag_scopes table
+merge_request: 29808
+author:
+type: other
diff --git a/changelogs/unreleased/allow-reactive-caching-of-nil.yml b/changelogs/unreleased/allow-reactive-caching-of-nil.yml
new file mode 100644
index 00000000000..abd88c09d74
--- /dev/null
+++ b/changelogs/unreleased/allow-reactive-caching-of-nil.yml
@@ -0,0 +1,5 @@
+---
+title: Allow ReactiveCaching to support nil value
+merge_request: 30456
+author:
+type: performance
diff --git a/changelogs/unreleased/api-doc-negative-commit-message-push-rule.yml b/changelogs/unreleased/api-doc-negative-commit-message-push-rule.yml
new file mode 100644
index 00000000000..0500978a2e1
--- /dev/null
+++ b/changelogs/unreleased/api-doc-negative-commit-message-push-rule.yml
@@ -0,0 +1,5 @@
+---
+title: "Document the negative commit message push rule for the API."
+merge_request: 14004
+author: Maikel Vlasman
+type: added
diff --git a/changelogs/unreleased/asciidoc-enable-syntax-highlighting.yml b/changelogs/unreleased/asciidoc-enable-syntax-highlighting.yml
new file mode 100644
index 00000000000..558ee7b6224
--- /dev/null
+++ b/changelogs/unreleased/asciidoc-enable-syntax-highlighting.yml
@@ -0,0 +1,5 @@
+---
+title: "Enable syntax highlighting for AsciiDoc"
+merge_request: 29835
+author: Guillaume Grossetie
+type: added \ No newline at end of file
diff --git a/changelogs/unreleased/centralize-markdownlint-config.yml b/changelogs/unreleased/centralize-markdownlint-config.yml
new file mode 100644
index 00000000000..9ca36078cf1
--- /dev/null
+++ b/changelogs/unreleased/centralize-markdownlint-config.yml
@@ -0,0 +1,5 @@
+---
+title: Centralize markdownlint configuration
+merge_request: 30263
+author:
+type: other
diff --git a/changelogs/unreleased/clusters-group-cte.yml b/changelogs/unreleased/clusters-group-cte.yml
new file mode 100644
index 00000000000..4b51249062d
--- /dev/null
+++ b/changelogs/unreleased/clusters-group-cte.yml
@@ -0,0 +1,5 @@
+---
+title: Use CTE to fetch clusters hierarchy in single query
+merge_request: 30063
+author:
+type: performance
diff --git a/changelogs/unreleased/create-merge-train-ref-ce.yml b/changelogs/unreleased/create-merge-train-ref-ce.yml
new file mode 100644
index 00000000000..b0b95275f58
--- /dev/null
+++ b/changelogs/unreleased/create-merge-train-ref-ce.yml
@@ -0,0 +1,5 @@
+---
+title: Extend `MergeToRefService` to create merge ref from an arbitrary ref
+merge_request: 30361
+author:
+type: added
diff --git a/changelogs/unreleased/feature-uninstall_cluster_ingress.yml b/changelogs/unreleased/feature-uninstall_cluster_ingress.yml
new file mode 100644
index 00000000000..c3f8464c4b4
--- /dev/null
+++ b/changelogs/unreleased/feature-uninstall_cluster_ingress.yml
@@ -0,0 +1,5 @@
+---
+title: Allow Ingress to be uninstalled from the UI
+merge_request: 29977
+author:
+type: added
diff --git a/changelogs/unreleased/feature-uninstall_jupyter_hub_app.yml b/changelogs/unreleased/feature-uninstall_jupyter_hub_app.yml
new file mode 100644
index 00000000000..28753aa719c
--- /dev/null
+++ b/changelogs/unreleased/feature-uninstall_jupyter_hub_app.yml
@@ -0,0 +1,5 @@
+---
+title: Allow JupyterHub to be uninstalled from the UI
+merge_request: 30097
+author:
+type: added
diff --git a/changelogs/unreleased/fix-median-counting-for-cycle-analytics.yml b/changelogs/unreleased/fix-median-counting-for-cycle-analytics.yml
new file mode 100644
index 00000000000..6ae6db08ba1
--- /dev/null
+++ b/changelogs/unreleased/fix-median-counting-for-cycle-analytics.yml
@@ -0,0 +1,5 @@
+---
+title: Fix median counting for cycle analytics
+merge_request: 30229
+author:
+type: fixed
diff --git a/changelogs/unreleased/fix-sidekiq-transaction-check-race.yml b/changelogs/unreleased/fix-sidekiq-transaction-check-race.yml
new file mode 100644
index 00000000000..89ae4abfe11
--- /dev/null
+++ b/changelogs/unreleased/fix-sidekiq-transaction-check-race.yml
@@ -0,0 +1,5 @@
+---
+title: Fix race in forbid_sidekiq_in_transactions.rb
+merge_request: 30359
+author:
+type: fixed
diff --git a/changelogs/unreleased/fj-fix-subgroup-search-url.yml b/changelogs/unreleased/fj-fix-subgroup-search-url.yml
new file mode 100644
index 00000000000..bee6e97fb6f
--- /dev/null
+++ b/changelogs/unreleased/fj-fix-subgroup-search-url.yml
@@ -0,0 +1,5 @@
+---
+title: Fix subgroup url in search drop down
+merge_request: 30457
+author:
+type: fixed
diff --git a/changelogs/unreleased/gitaly-version-v1.51.0.yml b/changelogs/unreleased/gitaly-version-v1.51.0.yml
new file mode 100644
index 00000000000..00d52a190f3
--- /dev/null
+++ b/changelogs/unreleased/gitaly-version-v1.51.0.yml
@@ -0,0 +1,5 @@
+---
+title: Upgrade to Gitaly v1.51.0
+merge_request: 30353
+author:
+type: changed
diff --git a/changelogs/unreleased/issue-63222.yml b/changelogs/unreleased/issue-63222.yml
new file mode 100644
index 00000000000..bc6520b9fc5
--- /dev/null
+++ b/changelogs/unreleased/issue-63222.yml
@@ -0,0 +1,5 @@
+---
+title: Set default sort method for dashboard projects list
+merge_request: 29830
+author: David Palubin
+type: fixed
diff --git a/changelogs/unreleased/issue_64021.yml b/changelogs/unreleased/issue_64021.yml
new file mode 100644
index 00000000000..088d9348619
--- /dev/null
+++ b/changelogs/unreleased/issue_64021.yml
@@ -0,0 +1,5 @@
+---
+title: Skip spam check for task list updates
+merge_request: 30279
+author:
+type: fixed
diff --git a/changelogs/unreleased/jc-detect-nfs-for-rugged.yml b/changelogs/unreleased/jc-detect-nfs-for-rugged.yml
new file mode 100644
index 00000000000..ca738181a55
--- /dev/null
+++ b/changelogs/unreleased/jc-detect-nfs-for-rugged.yml
@@ -0,0 +1,5 @@
+---
+title: Use Rugged if we detect storage is NFS and we can access the disk
+merge_request: 29725
+author:
+type: performance
diff --git a/changelogs/unreleased/jramsay-enable-object-dedupe-by-default.yml b/changelogs/unreleased/jramsay-enable-object-dedupe-by-default.yml
new file mode 100644
index 00000000000..b953d7c0fc8
--- /dev/null
+++ b/changelogs/unreleased/jramsay-enable-object-dedupe-by-default.yml
@@ -0,0 +1,5 @@
+---
+title: Enable Git object pools
+merge_request: 29595
+author: jramsay
+type: changed
diff --git a/changelogs/unreleased/limit-amount-of-tests-returned.yml b/changelogs/unreleased/limit-amount-of-tests-returned.yml
new file mode 100644
index 00000000000..0e80a64b6b7
--- /dev/null
+++ b/changelogs/unreleased/limit-amount-of-tests-returned.yml
@@ -0,0 +1,5 @@
+---
+title: Limit amount of JUnit tests returned
+merge_request: 30274
+author:
+type: performance
diff --git a/changelogs/unreleased/mh-board-tooltips.yml b/changelogs/unreleased/mh-board-tooltips.yml
new file mode 100644
index 00000000000..06fc64c52a7
--- /dev/null
+++ b/changelogs/unreleased/mh-board-tooltips.yml
@@ -0,0 +1,5 @@
+---
+title: "'Open' and 'Closed' issue board lists no longer display a redundant tooltip"
+merge_request: 30187
+author:
+type: fixed
diff --git a/changelogs/unreleased/osw-persist-tmp-snippet-uploads.yml b/changelogs/unreleased/osw-persist-tmp-snippet-uploads.yml
new file mode 100644
index 00000000000..9348626c41d
--- /dev/null
+++ b/changelogs/unreleased/osw-persist-tmp-snippet-uploads.yml
@@ -0,0 +1,5 @@
+---
+title: Persist tmp snippet uploads at users
+merge_request:
+author:
+type: security
diff --git a/changelogs/unreleased/patch-29.yml b/changelogs/unreleased/patch-29.yml
new file mode 100644
index 00000000000..674c06e1259
--- /dev/null
+++ b/changelogs/unreleased/patch-29.yml
@@ -0,0 +1,5 @@
+---
+title: Updates PHP template to php:latest to ensure always targeting latest stable
+merge_request: 30319
+author: Paul Giberson
+type: changed
diff --git a/changelogs/unreleased/pre-releases-38105a.yml b/changelogs/unreleased/pre-releases-38105a.yml
new file mode 100644
index 00000000000..8b7cf6065d4
--- /dev/null
+++ b/changelogs/unreleased/pre-releases-38105a.yml
@@ -0,0 +1,5 @@
+---
+title: Show an Upcoming Status for Releases
+merge_request: 29577
+author:
+type: added
diff --git a/changelogs/unreleased/rj-fix-manual-order.yml b/changelogs/unreleased/rj-fix-manual-order.yml
new file mode 100644
index 00000000000..ecc39b78b06
--- /dev/null
+++ b/changelogs/unreleased/rj-fix-manual-order.yml
@@ -0,0 +1,5 @@
+---
+title: Don't let logged out user do manual order
+merge_request: 30264
+author:
+type: fixed
diff --git a/changelogs/unreleased/security-2858-fix-color-validation.yml b/changelogs/unreleased/security-2858-fix-color-validation.yml
new file mode 100644
index 00000000000..3430207a2b6
--- /dev/null
+++ b/changelogs/unreleased/security-2858-fix-color-validation.yml
@@ -0,0 +1,5 @@
+---
+title: Fix DoS vulnerability in color validation regex
+merge_request:
+author:
+type: security
diff --git a/changelogs/unreleased/security-59581-related-merge-requests-count.yml b/changelogs/unreleased/security-59581-related-merge-requests-count.yml
new file mode 100644
index 00000000000..83faa2f7c13
--- /dev/null
+++ b/changelogs/unreleased/security-59581-related-merge-requests-count.yml
@@ -0,0 +1,5 @@
+---
+title: Expose merge requests count based on user access
+merge_request:
+author:
+type: security
diff --git a/changelogs/unreleased/security-DOS_issue_comments_banzai.yml b/changelogs/unreleased/security-DOS_issue_comments_banzai.yml
new file mode 100644
index 00000000000..2405b1a4f5f
--- /dev/null
+++ b/changelogs/unreleased/security-DOS_issue_comments_banzai.yml
@@ -0,0 +1,5 @@
+---
+title: Fix Denial of Service for comments when rendering issues/MR comments
+merge_request:
+author:
+type: security
diff --git a/changelogs/unreleased/security-bvl-enforce-graphql-type-authorization.yml b/changelogs/unreleased/security-bvl-enforce-graphql-type-authorization.yml
new file mode 100644
index 00000000000..7dedb9f6230
--- /dev/null
+++ b/changelogs/unreleased/security-bvl-enforce-graphql-type-authorization.yml
@@ -0,0 +1,5 @@
+---
+title: Add missing authorizations in GraphQL
+merge_request:
+author:
+type: security
diff --git a/changelogs/unreleased/security-fp-prevent-billion-laughs-attack.yml b/changelogs/unreleased/security-fp-prevent-billion-laughs-attack.yml
new file mode 100644
index 00000000000..4e0cf848931
--- /dev/null
+++ b/changelogs/unreleased/security-fp-prevent-billion-laughs-attack.yml
@@ -0,0 +1,5 @@
+---
+title: Prevent Billion Laughs attack
+merge_request:
+author:
+type: security
diff --git a/changelogs/unreleased/security-mr-head-pipeline-leak.yml b/changelogs/unreleased/security-mr-head-pipeline-leak.yml
new file mode 100644
index 00000000000..fe8c4dfb3c8
--- /dev/null
+++ b/changelogs/unreleased/security-mr-head-pipeline-leak.yml
@@ -0,0 +1,5 @@
+---
+title: Gate MR head_pipeline behind read_pipeline ability.
+merge_request:
+author:
+type: security
diff --git a/changelogs/unreleased/security-notes-in-private-snippets.yml b/changelogs/unreleased/security-notes-in-private-snippets.yml
new file mode 100644
index 00000000000..907d98cb16d
--- /dev/null
+++ b/changelogs/unreleased/security-notes-in-private-snippets.yml
@@ -0,0 +1,5 @@
+---
+title: Correctly check permissions when creating snippet notes
+merge_request:
+author:
+type: security
diff --git a/changelogs/unreleased/security-prevent-detection-of-merge-request-template-name.yml b/changelogs/unreleased/security-prevent-detection-of-merge-request-template-name.yml
new file mode 100644
index 00000000000..d7bb884cb4b
--- /dev/null
+++ b/changelogs/unreleased/security-prevent-detection-of-merge-request-template-name.yml
@@ -0,0 +1,5 @@
+---
+title: Prevent the detection of merge request templates by unauthorized users
+merge_request:
+author:
+type: security
diff --git a/changelogs/unreleased/sh-add-thread-memory-cache.yml b/changelogs/unreleased/sh-add-thread-memory-cache.yml
new file mode 100644
index 00000000000..025ad6d9f14
--- /dev/null
+++ b/changelogs/unreleased/sh-add-thread-memory-cache.yml
@@ -0,0 +1,5 @@
+---
+title: Add a memory cache local to the thread to reduce Redis load
+merge_request: 30233
+author:
+type: performance
diff --git a/changelogs/unreleased/sh-cache-flipper-checks-in-memory.yml b/changelogs/unreleased/sh-cache-flipper-checks-in-memory.yml
new file mode 100644
index 00000000000..125b6244d80
--- /dev/null
+++ b/changelogs/unreleased/sh-cache-flipper-checks-in-memory.yml
@@ -0,0 +1,5 @@
+---
+title: Cache Flipper feature flags in L1 and L2 caches
+merge_request: 30276
+author:
+type: performance
diff --git a/changelogs/unreleased/sh-cache-flipper-names-memory-cache.yml b/changelogs/unreleased/sh-cache-flipper-names-memory-cache.yml
new file mode 100644
index 00000000000..00443e81244
--- /dev/null
+++ b/changelogs/unreleased/sh-cache-flipper-names-memory-cache.yml
@@ -0,0 +1,5 @@
+---
+title: Cache Flipper persisted names directly to local memory storage
+merge_request: 30265
+author:
+type: performance
diff --git a/changelogs/unreleased/sh-disable-reactive-caching-automatic-retries.yml b/changelogs/unreleased/sh-disable-reactive-caching-automatic-retries.yml
new file mode 100644
index 00000000000..a0db68adb78
--- /dev/null
+++ b/changelogs/unreleased/sh-disable-reactive-caching-automatic-retries.yml
@@ -0,0 +1,5 @@
+---
+title: Prevent amplification of ReactiveCachingWorker jobs upon failures
+merge_request: 30432
+author:
+type: performance
diff --git a/changelogs/unreleased/sh-fix-issue-63349.yml b/changelogs/unreleased/sh-fix-issue-63349.yml
new file mode 100644
index 00000000000..0e51a6b7b20
--- /dev/null
+++ b/changelogs/unreleased/sh-fix-issue-63349.yml
@@ -0,0 +1,5 @@
+---
+title: Make Housekeeping button do a full garbage collection
+merge_request: 30289
+author:
+type: fixed
diff --git a/changelogs/unreleased/sh-fix-issue-63910.yml b/changelogs/unreleased/sh-fix-issue-63910.yml
new file mode 100644
index 00000000000..50312558c57
--- /dev/null
+++ b/changelogs/unreleased/sh-fix-issue-63910.yml
@@ -0,0 +1,5 @@
+---
+title: Fix attachments using the wrong URLs in e-mails
+merge_request: 30197
+author:
+type: fixed
diff --git a/changelogs/unreleased/sh-improve-redis-peek.yml b/changelogs/unreleased/sh-improve-redis-peek.yml
new file mode 100644
index 00000000000..940be103ab7
--- /dev/null
+++ b/changelogs/unreleased/sh-improve-redis-peek.yml
@@ -0,0 +1,5 @@
+---
+title: Add Redis call details in Peek performance bar
+merge_request: 30191
+author:
+type: changed
diff --git a/changelogs/unreleased/sh-upgrade-rouge-3-5-1.yml b/changelogs/unreleased/sh-upgrade-rouge-3-5-1.yml
new file mode 100644
index 00000000000..b408019c736
--- /dev/null
+++ b/changelogs/unreleased/sh-upgrade-rouge-3-5-1.yml
@@ -0,0 +1,5 @@
+---
+title: Upgrade Rouge to 3.5.1
+merge_request: 30431
+author:
+type: changed
diff --git a/changelogs/unreleased/slugify.yml b/changelogs/unreleased/slugify.yml
new file mode 100644
index 00000000000..853e90b8bed
--- /dev/null
+++ b/changelogs/unreleased/slugify.yml
@@ -0,0 +1,5 @@
+---
+title: Replace slugifyWithHyphens with improved slugify function
+merge_request: 30172
+author: Luke Ward
+type: fixed
diff --git a/changelogs/unreleased/tz-update-mr-count-over-tabs.yml b/changelogs/unreleased/tz-update-mr-count-over-tabs.yml
new file mode 100644
index 00000000000..61a49dd8ecc
--- /dev/null
+++ b/changelogs/unreleased/tz-update-mr-count-over-tabs.yml
@@ -0,0 +1,6 @@
+---
+title: New API for User Counts, updates on success of an MR the count on top and in
+ other tabs
+merge_request: 29441
+author:
+type: added
diff --git a/changelogs/unreleased/unicorn-sampler-fix.yml b/changelogs/unreleased/unicorn-sampler-fix.yml
new file mode 100644
index 00000000000..3f0e509f15f
--- /dev/null
+++ b/changelogs/unreleased/unicorn-sampler-fix.yml
@@ -0,0 +1,5 @@
+---
+title: Make sure UnicornSampler is started only in master process.
+merge_request: 30215
+author:
+type: fixed
diff --git a/changelogs/unreleased/update-todo-in-ui.yml b/changelogs/unreleased/update-todo-in-ui.yml
new file mode 100644
index 00000000000..dddcf0f3983
--- /dev/null
+++ b/changelogs/unreleased/update-todo-in-ui.yml
@@ -0,0 +1,5 @@
+---
+title: Changes "Todo" to "To Do" in the UI for clarity
+merge_request: 28844
+author:
+type: other
diff --git a/changelogs/unreleased/use-pg-9-6-11-on-ci.yml b/changelogs/unreleased/use-pg-9-6-11-on-ci.yml
new file mode 100644
index 00000000000..785eb352895
--- /dev/null
+++ b/changelogs/unreleased/use-pg-9-6-11-on-ci.yml
@@ -0,0 +1,5 @@
+---
+title: Use PostgreSQL 9.6.11 in CI tests
+merge_request: 30270
+author: Takuya Noguchi
+type: other
diff --git a/changelogs/unreleased/winh-jest-markdown-header.yml b/changelogs/unreleased/winh-jest-markdown-header.yml
new file mode 100644
index 00000000000..6bf9d75cc93
--- /dev/null
+++ b/changelogs/unreleased/winh-jest-markdown-header.yml
@@ -0,0 +1,5 @@
+---
+title: Migrate markdown header_spec.js to Jest
+merge_request: 30228
+author: Martin Hobert
+type: other
diff --git a/changelogs/unreleased/winh-notes-service-applySuggestion.yml b/changelogs/unreleased/winh-notes-service-applySuggestion.yml
new file mode 100644
index 00000000000..30e540237b6
--- /dev/null
+++ b/changelogs/unreleased/winh-notes-service-applySuggestion.yml
@@ -0,0 +1,5 @@
+---
+title: Remove applySuggestion from notes service
+merge_request: 30399
+author: Frank van Rest
+type: other
diff --git a/changelogs/unreleased/winh-updateResolvableDiscussionsCounts-typo.yml b/changelogs/unreleased/winh-updateResolvableDiscussionsCounts-typo.yml
new file mode 100644
index 00000000000..24b10bb3edc
--- /dev/null
+++ b/changelogs/unreleased/winh-updateResolvableDiscussionsCounts-typo.yml
@@ -0,0 +1,5 @@
+---
+title: Fix typo in updateResolvableDiscussionsCounts action
+merge_request: 30278
+author: Frank van Rest
+type: other
diff --git a/config/README.md b/config/README.md
index 2778d0d4f02..9226f71a374 100644
--- a/config/README.md
+++ b/config/README.md
@@ -39,7 +39,7 @@ If desired, the routing URL provided by these settings can be used with:
1. `host name` or IP for each Redis instance desired
2. TCP port number for each Redis instance desired
3. `database number` for each Redis instance desired
-
+
## Example URL attribute formats for GitLab Redis `.yml` configuration files
* Unix Socket, default Redis database (0)
* `url: unix:/path/to/redis.sock`
@@ -147,4 +147,3 @@ searched):
3. the configuration file pointed to by the
`GITLAB_REDIS_CONFIG_FILE` environment variable
4. the configuration file `resque.yml`
-
diff --git a/config/application.rb b/config/application.rb
index c5ef6a2c60d..edf8b3e87f9 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -6,6 +6,7 @@ Bundler.require(:default, Rails.env)
module Gitlab
class Application < Rails::Application
+ require_dependency Rails.root.join('lib/gitlab')
require_dependency Rails.root.join('lib/gitlab/redis/wrapper')
require_dependency Rails.root.join('lib/gitlab/redis/cache')
require_dependency Rails.root.join('lib/gitlab/redis/queues')
diff --git a/config/boot.rb b/config/boot.rb
index 2811f0e6188..b76b26a5e75 100644
--- a/config/boot.rb
+++ b/config/boot.rb
@@ -3,7 +3,7 @@ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)
# Set up gems listed in the Gemfile.
require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])
begin
- require 'bootsnap/setup'
+ require 'bootsnap/setup' unless ENV['DISABLE_BOOTSNAP']
rescue LoadError
# bootsnap is an optional dependency, so if we don't have it, it's fine
end
diff --git a/config/initializers/0_license.rb b/config/initializers/0_license.rb
new file mode 100644
index 00000000000..f750022dfdf
--- /dev/null
+++ b/config/initializers/0_license.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+Gitlab.ee do
+ begin
+ public_key_file = File.read(Rails.root.join(".license_encryption_key.pub"))
+ public_key = OpenSSL::PKey::RSA.new(public_key_file)
+ Gitlab::License.encryption_key = public_key
+ rescue
+ warn "WARNING: No valid license encryption key provided."
+ end
+
+ # Needed to run migration
+ if ActiveRecord::Base.connected? && ActiveRecord::Base.connection.data_source_exists?('licenses')
+ message = LicenseHelper.license_message(signed_in: true, is_admin: true, in_html: false)
+ if ::License.block_changes? && message.present?
+ warn "WARNING: #{message}"
+ end
+ end
+end
diff --git a/config/initializers/0_thread_cache.rb b/config/initializers/0_thread_cache.rb
new file mode 100644
index 00000000000..feb8057132e
--- /dev/null
+++ b/config/initializers/0_thread_cache.rb
@@ -0,0 +1,3 @@
+# frozen_string_literal: true
+
+Gitlab::ThreadMemoryCache.cache_backend
diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb
index c803e4615b4..0b8a6607250 100644
--- a/config/initializers/1_settings.rb
+++ b/config/initializers/1_settings.rb
@@ -76,6 +76,7 @@ Gitlab.ee do
Settings['smartcard'] ||= Settingslogic.new({})
Settings.smartcard['enabled'] = false if Settings.smartcard['enabled'].nil?
Settings.smartcard['client_certificate_required_port'] = 3444 if Settings.smartcard['client_certificate_required_port'].nil?
+ Settings.smartcard['required_for_git_access'] = false if Settings.smartcard['required_for_git_access'].nil?
end
Settings['omniauth'] ||= Settingslogic.new({})
@@ -441,6 +442,9 @@ Settings.cron_jobs['prune_web_hook_logs_worker']['job_class'] = 'PruneWebHookLog
Settings.cron_jobs['schedule_migrate_external_diffs_worker'] ||= Settingslogic.new({})
Settings.cron_jobs['schedule_migrate_external_diffs_worker']['cron'] ||= '15 * * * *'
Settings.cron_jobs['schedule_migrate_external_diffs_worker']['job_class'] = 'ScheduleMigrateExternalDiffsWorker'
+Settings.cron_jobs['namespaces_prune_aggregation_schedules_worker'] ||= Settingslogic.new({})
+Settings.cron_jobs['namespaces_prune_aggregation_schedules_worker']['cron'] ||= '5 1 * * *'
+Settings.cron_jobs['namespaces_prune_aggregation_schedules_worker']['job_class'] = 'Namespaces::PruneAggregationSchedulesWorker'
Gitlab.ee do
Settings.cron_jobs['clear_shared_runners_minutes_worker'] ||= Settingslogic.new({})
diff --git a/config/initializers/6_validations.rb b/config/initializers/6_validations.rb
index bf9e5a50382..827b15e5c8d 100644
--- a/config/initializers/6_validations.rb
+++ b/config/initializers/6_validations.rb
@@ -1,24 +1,15 @@
-def storage_name_valid?(name)
- !!(name =~ /\A[a-zA-Z0-9\-_]+\z/)
-end
-
def storage_validation_error(message)
raise "#{message}. Please fix this in your gitlab.yml before starting GitLab."
end
def validate_storages_config
- storage_validation_error('No repository storage path defined') if Gitlab.config.repositories.storages.empty?
-
- Gitlab.config.repositories.storages.each do |name, repository_storage|
- storage_validation_error("\"#{name}\" is not a valid storage name") unless storage_name_valid?(name)
-
- %w(failure_count_threshold failure_reset_time storage_timeout).each do |setting|
- # Falling back to the defaults is fine!
- next if repository_storage[setting].nil?
+ if Gitlab.config.repositories.storages.empty?
+ storage_validation_error('No repository storage path defined')
+ end
- unless repository_storage[setting].to_f > 0
- storage_validation_error("`#{setting}` for storage `#{name}` needs to be greater than 0")
- end
+ Gitlab.config.repositories.storages.keys.each do |name|
+ unless /\A[a-zA-Z0-9\-_]+\z/.match?(name)
+ storage_validation_error("\"#{name}\" is not a valid storage name")
end
end
end
diff --git a/config/initializers/7_prometheus_metrics.rb b/config/initializers/7_prometheus_metrics.rb
index 68f8487d377..741c8ef1ca0 100644
--- a/config/initializers/7_prometheus_metrics.rb
+++ b/config/initializers/7_prometheus_metrics.rb
@@ -1,15 +1,27 @@
require 'prometheus/client'
require 'prometheus/client/support/unicorn'
+# Keep separate directories for separate processes
+def prometheus_default_multiproc_dir
+ return unless Rails.env.development? || Rails.env.test?
+
+ if Sidekiq.server?
+ Rails.root.join('tmp/prometheus_multiproc_dir/sidekiq')
+ elsif defined?(Unicorn::Worker)
+ Rails.root.join('tmp/prometheus_multiproc_dir/unicorn')
+ elsif defined?(::Puma)
+ Rails.root.join('tmp/prometheus_multiproc_dir/puma')
+ else
+ Rails.root.join('tmp/prometheus_multiproc_dir')
+ end
+end
+
Prometheus::Client.configure do |config|
config.logger = Rails.logger
config.initial_mmap_file_size = 4 * 1024
- config.multiprocess_files_dir = ENV['prometheus_multiproc_dir']
- if Rails.env.development? || Rails.env.test?
- config.multiprocess_files_dir ||= Rails.root.join('tmp/prometheus_multiproc_dir')
- end
+ config.multiprocess_files_dir = ENV['prometheus_multiproc_dir'] || prometheus_default_multiproc_dir
config.pid_provider = Prometheus::Client::Support::Unicorn.method(:worker_pid_provider)
end
@@ -29,28 +41,33 @@ if !Rails.env.test? && Gitlab::Metrics.prometheus_metrics_enabled?
Gitlab::Cluster::LifecycleEvents.on_worker_start do
defined?(::Prometheus::Client.reinitialize_on_pid_change) && Prometheus::Client.reinitialize_on_pid_change
- if defined?(::Unicorn)
- Gitlab::Metrics::Samplers::UnicornSampler.initialize_instance(Settings.monitoring.unicorn_sampler_interval).start
- end
-
Gitlab::Metrics::Samplers::RubySampler.initialize_instance(Settings.monitoring.ruby_sampler_interval).start
end
- if defined?(::Puma)
- Gitlab::Cluster::LifecycleEvents.on_master_start do
+ Gitlab::Cluster::LifecycleEvents.on_master_start do
+ if defined?(::Unicorn)
+ Gitlab::Metrics::Samplers::UnicornSampler.initialize_instance(Settings.monitoring.unicorn_sampler_interval).start
+ elsif defined?(::Puma)
Gitlab::Metrics::Samplers::PumaSampler.initialize_instance(Settings.monitoring.puma_sampler_interval).start
end
end
end
-Gitlab::Cluster::LifecycleEvents.on_master_restart do
+def cleanup_prometheus_multiproc_dir
# The following is necessary to ensure stale Prometheus metrics don't
# accumulate over time. It needs to be done in this hook as opposed to
# inside an init script to ensure metrics files aren't deleted after new
# unicorn workers start after a SIGUSR2 is received.
- prometheus_multiproc_dir = ENV['prometheus_multiproc_dir']
- if prometheus_multiproc_dir
- old_metrics = Dir[File.join(prometheus_multiproc_dir, '*.db')]
+ if dir = ::Prometheus::Client.configuration.multiprocess_files_dir
+ old_metrics = Dir[File.join(dir, '*.db')]
FileUtils.rm_rf(old_metrics)
end
end
+
+Gitlab::Cluster::LifecycleEvents.on_master_start do
+ cleanup_prometheus_multiproc_dir
+end
+
+Gitlab::Cluster::LifecycleEvents.on_master_restart do
+ cleanup_prometheus_multiproc_dir
+end
diff --git a/config/initializers/console_message.rb b/config/initializers/console_message.rb
index 05eb395028d..04c109aa844 100644
--- a/config/initializers/console_message.rb
+++ b/config/initializers/console_message.rb
@@ -2,9 +2,18 @@
if defined?(Rails::Console)
# note that this will not print out when using `spring`
justify = 15
- puts "-------------------------------------------------------------------------------------"
+
+ puts '-' * 80
puts " GitLab:".ljust(justify) + "#{Gitlab::VERSION} (#{Gitlab.revision})"
puts " GitLab Shell:".ljust(justify) + "#{Gitlab::VersionInfo.parse(Gitlab::Shell.new.version)}"
puts " #{Gitlab::Database.human_adapter_name}:".ljust(justify) + Gitlab::Database.version
- puts "-------------------------------------------------------------------------------------"
+
+ Gitlab.ee do
+ if Gitlab::Geo.enabled?
+ puts " Geo enabled:".ljust(justify) + 'yes'
+ puts " Geo server:".ljust(justify) + EE::GeoHelper.current_node_human_status
+ end
+ end
+
+ puts '-' * 80
end
diff --git a/config/initializers/elastic_client_setup.rb b/config/initializers/elastic_client_setup.rb
new file mode 100644
index 00000000000..2ecb7956007
--- /dev/null
+++ b/config/initializers/elastic_client_setup.rb
@@ -0,0 +1,50 @@
+# frozen_string_literal: true
+
+# Be sure to restart your server when you modify this file.
+
+require 'gitlab/current_settings'
+
+Gitlab.ee do
+ Elasticsearch::Model::Response::Records.prepend GemExtensions::Elasticsearch::Model::Response::Records
+ Elasticsearch::Model::Adapter::Multiple::Records.prepend GemExtensions::Elasticsearch::Model::Adapter::Multiple::Records
+ Elasticsearch::Model::Indexing::InstanceMethods.prepend GemExtensions::Elasticsearch::Model::Indexing::InstanceMethods
+
+ module Elasticsearch
+ module Model
+ module Client
+ # This mutex is only used to synchronize *creation* of a new client, so
+ # all including classes can share the same client instance
+ CLIENT_MUTEX = Mutex.new
+
+ cattr_accessor :cached_client
+ cattr_accessor :cached_config
+
+ module ClassMethods
+ # Override the default ::Elasticsearch::Model::Client implementation to
+ # return a client configured from application settings. All including
+ # classes will use the same instance, which is refreshed automatically
+ # if the settings change.
+ #
+ # _client is present to match the arity of the overridden method, where
+ # it is also not used.
+ #
+ # @return [Elasticsearch::Transport::Client]
+ def client(_client = nil)
+ store = ::Elasticsearch::Model::Client
+
+ store::CLIENT_MUTEX.synchronize do
+ config = Gitlab::CurrentSettings.elasticsearch_config
+
+ if store.cached_client.nil? || config != store.cached_config
+ store.cached_client = ::Gitlab::Elastic::Client.build(config)
+ store.cached_config = config
+ end
+ end
+
+ store.cached_client
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/config/initializers/forbid_sidekiq_in_transactions.rb b/config/initializers/forbid_sidekiq_in_transactions.rb
index a69f1ba090e..bb190af60b5 100644
--- a/config/initializers/forbid_sidekiq_in_transactions.rb
+++ b/config/initializers/forbid_sidekiq_in_transactions.rb
@@ -2,15 +2,16 @@ module Sidekiq
module Worker
EnqueueFromTransactionError = Class.new(StandardError)
- mattr_accessor :skip_transaction_check
- self.skip_transaction_check = false
-
def self.skipping_transaction_check(&block)
- skip_transaction_check = self.skip_transaction_check
- self.skip_transaction_check = true
+ previous_skip_transaction_check = self.skip_transaction_check
+ Thread.current[:sidekiq_worker_skip_transaction_check] = true
yield
ensure
- self.skip_transaction_check = skip_transaction_check
+ Thread.current[:sidekiq_worker_skip_transaction_check] = previous_skip_transaction_check
+ end
+
+ def self.skip_transaction_check
+ Thread.current[:sidekiq_worker_skip_transaction_check]
end
module ClassMethods
diff --git a/config/initializers/geo.rb b/config/initializers/geo.rb
new file mode 100644
index 00000000000..4cc9fbf49b2
--- /dev/null
+++ b/config/initializers/geo.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+Gitlab.ee do
+ if File.exist?(Rails.root.join('config/database_geo.yml'))
+ Rails.application.configure do
+ config.geo_database = config_for(:database_geo)
+ end
+ end
+
+ begin
+ if Gitlab::Geo.connected? && Gitlab::Geo.primary?
+ Gitlab::Geo.current_node&.update_clone_url!
+ end
+ rescue => e
+ warn "WARNING: Unable to check/update clone_url_prefix for Geo: #{e}"
+ end
+end
diff --git a/config/initializers/health_check.rb b/config/initializers/health_check.rb
index 959daa93f78..9f466dc39de 100644
--- a/config/initializers/health_check.rb
+++ b/config/initializers/health_check.rb
@@ -1,4 +1,10 @@
HealthCheck.setup do |config|
config.standard_checks = %w(database migrations cache)
config.full_checks = %w(database migrations cache)
+
+ Gitlab.ee do
+ config.add_custom_check('geo') do
+ Gitlab::Geo::HealthCheck.new.perform_checks
+ end
+ end
end
diff --git a/config/initializers/load_balancing.rb b/config/initializers/load_balancing.rb
new file mode 100644
index 00000000000..029c0ff4277
--- /dev/null
+++ b/config/initializers/load_balancing.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+# We need to run this initializer after migrations are done so it doesn't fail on CI
+
+Gitlab.ee do
+ if ActiveRecord::Base.connected? && ActiveRecord::Base.connection.data_source_exists?('licenses')
+ if Gitlab::Database::LoadBalancing.enable?
+ Gitlab::Database.disable_prepared_statements
+
+ Gitlab::Application.configure do |config|
+ config.middleware.use(Gitlab::Database::LoadBalancing::RackMiddleware)
+ end
+
+ Gitlab::Database::LoadBalancing.configure_proxy
+
+ # This needs to be executed after fork of clustered processes
+ Gitlab::Cluster::LifecycleEvents.on_worker_start do
+ # Service discovery must be started after configuring the proxy, as service
+ # discovery depends on this.
+ Gitlab::Database::LoadBalancing.start_service_discovery
+ end
+
+ end
+ end
+end
diff --git a/config/initializers/peek.rb b/config/initializers/peek.rb
index cb108416b10..d492b60705d 100644
--- a/config/initializers/peek.rb
+++ b/config/initializers/peek.rb
@@ -42,3 +42,6 @@ class PEEK_DB_CLIENT
end
PEEK_DB_VIEW.prepend ::Gitlab::PerformanceBar::PeekQueryTracker
+
+require 'peek/adapters/redis'
+Peek::Adapters::Redis.prepend ::Gitlab::PerformanceBar::RedisAdapterWhenPeekEnabled
diff --git a/config/initializers/rack_attack_logging.rb b/config/initializers/rack_attack_logging.rb
index 2a3fdc8de5f..7eb34bd69e5 100644
--- a/config/initializers/rack_attack_logging.rb
+++ b/config/initializers/rack_attack_logging.rb
@@ -4,12 +4,22 @@
ActiveSupport::Notifications.subscribe('rack.attack') do |name, start, finish, request_id, req|
if [:throttle, :blacklist].include? req.env['rack.attack.match_type']
- Gitlab::AuthLogger.error(
+ rack_attack_info = {
message: 'Rack_Attack',
env: req.env['rack.attack.match_type'],
ip: req.ip,
request_method: req.request_method,
fullpath: req.fullpath
- )
+ }
+
+ if %w(throttle_authenticated_api throttle_authenticated_web).include? req.env['rack.attack.matched']
+ user_id = req.env['rack.attack.match_discriminator']
+ user = User.find_by(id: user_id)
+
+ rack_attack_info[:user_id] = user_id
+ rack_attack_info[:username] = user.username unless user.nil?
+ end
+
+ Gitlab::AuthLogger.error(rack_attack_info)
end
end
diff --git a/config/initializers/sidekiq.rb b/config/initializers/sidekiq.rb
index 7b69cf11288..f9ef5d66bfa 100644
--- a/config/initializers/sidekiq.rb
+++ b/config/initializers/sidekiq.rb
@@ -85,6 +85,19 @@ Sidekiq.configure_server do |config|
ActiveRecord::Base.establish_connection(db_config)
Rails.logger.debug("Connection Pool size for Sidekiq Server is now: #{ActiveRecord::Base.connection.pool.instance_variable_get('@size')}")
+ Gitlab.ee do
+ Gitlab::Mirror.configure_cron_job!
+
+ Gitlab::Geo.configure_cron_jobs!
+
+ if Gitlab::Geo.geo_database_configured?
+ Rails.configuration.geo_database['pool'] = Sidekiq.options[:concurrency]
+ Geo::TrackingBase.establish_connection(Rails.configuration.geo_database)
+
+ Rails.logger.debug("Connection Pool size for Sidekiq Server is now: #{Geo::TrackingBase.connection_pool.size} (Geo tracking database)")
+ end
+ end
+
# Avoid autoload issue such as 'Mail::Parsers::AddressStruct'
# https://github.com/mikel/mail/issues/912#issuecomment-214850355
Mail.eager_autoload!
diff --git a/config/initializers/sidekiq_cluster.rb b/config/initializers/sidekiq_cluster.rb
new file mode 100644
index 00000000000..baa7495aa29
--- /dev/null
+++ b/config/initializers/sidekiq_cluster.rb
@@ -0,0 +1,20 @@
+# frozen_string_literal: true
+
+if ENV['ENABLE_SIDEKIQ_CLUSTER'] && Gitlab.ee?
+ Thread.new do
+ Thread.current.abort_on_exception = true
+
+ parent = Process.ppid
+
+ loop do
+ sleep(5)
+
+ # In cluster mode it's possible that the master process is SIGKILL'd. In
+ # this case the parent PID changes and we need to terminate ourselves.
+ if Process.ppid != parent
+ Process.kill(:TERM, Process.pid)
+ break
+ end
+ end
+ end
+end
diff --git a/config/no_todos_messages.yml b/config/no_todos_messages.yml
index da721a9b6e6..d2076f235fd 100644
--- a/config/no_todos_messages.yml
+++ b/config/no_todos_messages.yml
@@ -4,8 +4,8 @@
# If you come up with a fun one, please feel free to contribute it to GitLab!
# https://about.gitlab.com/contributing/
---
-- Good job! Looks like you don't have any todos left
-- Isn't an empty todo list beautiful?
+- Good job! Looks like you don't have anything left on your To-Do List
+- Isn't an empty To-Do List beautiful?
- Give yourself a pat on the back!
-- Nothing left to do, high five!
-- Henceforth you shall be known as "Todo Destroyer"
+- Nothing left to do. High five!
+- Henceforth, you shall be known as "To-Do Destroyer"
diff --git a/config/routes/api.rb b/config/routes/api.rb
index 3ba9176d943..c6c17b5708e 100644
--- a/config/routes/api.rb
+++ b/config/routes/api.rb
@@ -1,7 +1,5 @@
-constraints(::Constraints::FeatureConstrainer.new(:graphql, default_enabled: true)) do
- post '/api/graphql', to: 'graphql#execute'
- mount GraphiQL::Rails::Engine, at: '/-/graphql-explorer', graphql_path: '/api/graphql'
-end
+post '/api/graphql', to: 'graphql#execute'
+mount GraphiQL::Rails::Engine, at: '/-/graphql-explorer', graphql_path: '/api/graphql'
::API::API.logger Rails.logger
mount ::API::API => '/'
diff --git a/config/routes/project.rb b/config/routes/project.rb
index 91613e3333f..c202463dadb 100644
--- a/config/routes/project.rb
+++ b/config/routes/project.rb
@@ -182,7 +182,10 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
#
# Templates
#
- get '/templates/:template_type/:key' => 'templates#show', as: :template, constraints: { key: %r{[^/]+} }
+ get '/templates/:template_type/:key' => 'templates#show',
+ as: :template,
+ defaults: { format: 'json' },
+ constraints: { key: %r{[^/]+}, template_type: %r{issue|merge_request}, format: 'json' }
resources :commit, only: [:show], constraints: { id: /\h{7,40}/ } do
member do
diff --git a/config/routes/uploads.rb b/config/routes/uploads.rb
index b594f55f8a0..920f8454ce2 100644
--- a/config/routes/uploads.rb
+++ b/config/routes/uploads.rb
@@ -7,7 +7,7 @@ scope path: :uploads do
# show uploads for models, snippets (notes) available for now
get '-/system/:model/:id/:secret/:filename',
to: 'uploads#show',
- constraints: { model: /personal_snippet/, id: /\d+/, filename: %r{[^/]+} }
+ constraints: { model: /personal_snippet|user/, id: /\d+/, filename: %r{[^/]+} }
# show temporary uploads
get '-/system/temp/:secret/:filename',
@@ -28,7 +28,7 @@ scope path: :uploads do
# create uploads for models, snippets (notes) available for now
post ':model',
to: 'uploads#create',
- constraints: { model: /personal_snippet/, id: /\d+/ },
+ constraints: { model: /personal_snippet|user/, id: /\d+/ },
as: 'upload'
end
diff --git a/config/sidekiq_queues.yml b/config/sidekiq_queues.yml
index 25fd65d8644..80791795390 100644
--- a/config/sidekiq_queues.yml
+++ b/config/sidekiq_queues.yml
@@ -94,6 +94,7 @@
- [migrate_external_diffs, 1]
- [update_project_statistics, 1]
- [phabricator_import_import_tasks, 1]
+ - [update_namespace_statistics, 1]
# EE-specific queues
- [ldap_group_sync, 2]
diff --git a/config/unicorn.rb.example b/config/unicorn.rb.example
index 4637eb8bc6e..581fde84c95 100644
--- a/config/unicorn.rb.example
+++ b/config/unicorn.rb.example
@@ -88,9 +88,21 @@ before_exec do |server|
Gitlab::Cluster::LifecycleEvents.do_master_restart
end
+run_once = true
+
before_fork do |server, worker|
- # Signal application hooks that we're about to fork
- Gitlab::Cluster::LifecycleEvents.do_before_fork
+ if run_once
+ # There is a difference between Puma and Unicorn:
+ # - Puma calls before_fork once when booting up master process
+ # - Unicorn runs before_fork whenever new work is spawned
+ # To unify this behavior we call before_fork only once (we use
+ # this callback for deleting Prometheus files so for our purposes
+ # it makes sense to align behavior with Puma)
+ run_once = false
+
+ # Signal application hooks that we're about to fork
+ Gitlab::Cluster::LifecycleEvents.do_before_fork
+ end
# The following is only recommended for memory/DB-constrained
# installations. It is not needed if your system can house
diff --git a/config/unicorn.rb.example.development b/config/unicorn.rb.example.development
index ae3dc2e37e1..9a02d5f1007 100644
--- a/config/unicorn.rb.example.development
+++ b/config/unicorn.rb.example.development
@@ -21,9 +21,21 @@ before_exec do |server|
Gitlab::Cluster::LifecycleEvents.do_master_restart
end
+run_once = true
+
before_fork do |server, worker|
- # Signal application hooks that we're about to fork
- Gitlab::Cluster::LifecycleEvents.do_before_fork
+ if run_once
+ # There is a difference between Puma and Unicorn:
+ # - Puma calls before_fork once when booting up master process
+ # - Unicorn runs before_fork whenever new work is spawned
+ # To unify this behavior we call before_fork only once (we use
+ # this callback for deleting Prometheus files so for our purposes
+ # it makes sense to align behavior with Puma)
+ run_once = false
+
+ # Signal application hooks that we're about to fork
+ Gitlab::Cluster::LifecycleEvents.do_before_fork
+ end
# The following is only recommended for memory/DB-constrained
# installations. It is not needed if your system can house
diff --git a/config/webpack.config.js b/config/webpack.config.js
index 19b48845305..a81590e8b8e 100644
--- a/config/webpack.config.js
+++ b/config/webpack.config.js
@@ -322,7 +322,10 @@ module.exports = {
}),
new webpack.DefinePlugin({
+ // This one is used to define window.gon.ee and other things properly in tests:
'process.env.IS_GITLAB_EE': JSON.stringify(IS_EE),
+ // This one is used to check against "EE" properly in application code
+ IS_EE: IS_EE ? 'window.gon && window.gon.ee' : JSON.stringify(false),
}),
].filter(Boolean),
diff --git a/danger/database/Dangerfile b/danger/database/Dangerfile
index 4dadf60ad24..083e95b8da7 100644
--- a/danger/database/Dangerfile
+++ b/danger/database/Dangerfile
@@ -1,21 +1,5 @@
# frozen_string_literal: true
-# All the files/directories that should be reviewed by the DB team.
-DB_FILES = [
- 'db/',
- 'app/models/project_authorization.rb',
- 'app/services/users/refresh_authorized_projects_service.rb',
- 'lib/gitlab/background_migration.rb',
- 'lib/gitlab/background_migration/',
- 'lib/gitlab/database.rb',
- 'lib/gitlab/database/',
- 'lib/gitlab/github_import.rb',
- 'lib/gitlab/github_import/',
- 'lib/gitlab/sql/',
- 'rubocop/cop/migration',
- 'ee/lib/gitlab/database/'
-].freeze
-
SCHEMA_NOT_UPDATED_MESSAGE = <<~MSG
**New %<migrations>s added but %<schema>s wasn't updated.**
@@ -24,20 +8,6 @@ updated too (unless the migration isn't changing the DB schema
and isn't the most recent one).
MSG
-def database_paths_requiring_review(files)
- to_review = []
-
- files.each do |file|
- review = DB_FILES.any? do |pattern|
- file.start_with?(pattern)
- end
-
- to_review << file if review
- end
-
- to_review
-end
-
non_geo_db_schema_updated = !git.modified_files.grep(%r{\Adb/schema\.rb}).empty?
geo_db_schema_updated = !git.modified_files.grep(%r{\Aee/db/geo/schema\.rb}).empty?
@@ -52,7 +22,7 @@ if geo_migration_created && !geo_db_schema_updated
warn format(SCHEMA_NOT_UPDATED_MESSAGE, migrations: 'Geo migrations', schema: gitlab.html_link("ee/db/geo/schema.rb"))
end
-db_paths_to_review = database_paths_requiring_review(helper.all_changed_files)
+db_paths_to_review = helper.changes_by_category[:database]
unless db_paths_to_review.empty?
message 'This merge request adds or changes files that require a ' \
diff --git a/danger/only_documentation/Dangerfile b/danger/only_documentation/Dangerfile
index 8e4564f22b6..ff65f8713d2 100644
--- a/danger/only_documentation/Dangerfile
+++ b/danger/only_documentation/Dangerfile
@@ -1,7 +1,7 @@
# rubocop:disable Style/SignalException
# frozen_string_literal: true
-has_only_docs_changes = helper.all_changed_files.all? { |file| file.start_with?('doc/') }
+has_only_docs_changes = helper.all_changed_files.all? { |file| file.start_with?('doc/', '.gitlab/ci/docs.gitlab-ci.yml', '.mdlrc') }
is_docs_only_branch = gitlab.branch_for_head =~ /(^docs[\/-].*|.*-docs$)/
if is_docs_only_branch && !has_only_docs_changes
diff --git a/db/fixtures/development/17_cycle_analytics.rb b/db/fixtures/development/17_cycle_analytics.rb
index 7a86fe2eb7c..78ceb74da65 100644
--- a/db/fixtures/development/17_cycle_analytics.rb
+++ b/db/fixtures/development/17_cycle_analytics.rb
@@ -146,11 +146,13 @@ class Gitlab::Seeder::CycleAnalytics
commit_sha = issue.project.repository.create_file(@user, filename, "content", message: "Commit for #{issue.to_reference}", branch_name: branch_name)
issue.project.repository.commit(commit_sha)
- GitPushService.new(issue.project,
- @user,
- oldrev: issue.project.repository.commit("master").sha,
- newrev: commit_sha,
- ref: 'refs/heads/master').execute
+ Git::BranchPushService.new(
+ issue.project,
+ @user,
+ oldrev: issue.project.repository.commit("master").sha,
+ newrev: commit_sha,
+ ref: 'refs/heads/master'
+ ).execute
branch_name
end
diff --git a/db/fixtures/development/24_forks.rb b/db/fixtures/development/24_forks.rb
index 5eb5956ec74..d05d27c3ed5 100644
--- a/db/fixtures/development/24_forks.rb
+++ b/db/fixtures/development/24_forks.rb
@@ -13,9 +13,9 @@ Sidekiq::Testing.inline! do
fork_project = Projects::ForkService.new(source_project, user, namespace: user.namespace).execute
if fork_project.valid?
- puts '.'
+ print '.'
else
- puts 'F'
+ print 'F'
end
end
end
diff --git a/db/migrate/20140313092127_init_schema.rb b/db/migrate/20140313092127_init_schema.rb
deleted file mode 100644
index 4188599b4b4..00000000000
--- a/db/migrate/20140313092127_init_schema.rb
+++ /dev/null
@@ -1,338 +0,0 @@
-class InitSchema < ActiveRecord::Migration[4.2]
- DOWNTIME = true
-
- # rubocop:disable Metrics/AbcSize
- def up
- create_table "broadcast_messages", force: :cascade do |t|
- t.text "message", null: false
- t.datetime "starts_at"
- t.datetime "ends_at"
- t.integer "alert_type"
- t.datetime "created_at"
- t.datetime "updated_at"
- t.string "color"
- t.string "font"
- end
- create_table "deploy_keys_projects", force: :cascade do |t|
- t.integer "deploy_key_id", null: false
- t.integer "project_id", null: false
- t.datetime "created_at"
- t.datetime "updated_at"
- end
- add_index "deploy_keys_projects", ["project_id"], name: "index_deploy_keys_projects_on_project_id", using: :btree
- create_table "emails", force: :cascade do |t|
- t.integer "user_id", null: false
- t.string "email", null: false
- t.datetime "created_at"
- t.datetime "updated_at"
- end
- add_index "emails", ["email"], name: "index_emails_on_email", unique: true, using: :btree
- add_index "emails", ["user_id"], name: "index_emails_on_user_id", using: :btree
- create_table "events", force: :cascade do |t|
- t.string "target_type"
- t.integer "target_id"
- t.string "title"
- t.text "data"
- t.integer "project_id"
- t.datetime "created_at"
- t.datetime "updated_at"
- t.integer "action"
- t.integer "author_id"
- end
- add_index "events", ["action"], name: "index_events_on_action", using: :btree
- add_index "events", ["author_id"], name: "index_events_on_author_id", using: :btree
- add_index "events", ["created_at"], name: "index_events_on_created_at", using: :btree
- add_index "events", ["project_id"], name: "index_events_on_project_id", using: :btree
- add_index "events", ["target_id"], name: "index_events_on_target_id", using: :btree
- add_index "events", ["target_type"], name: "index_events_on_target_type", using: :btree
- create_table "forked_project_links", force: :cascade do |t|
- t.integer "forked_to_project_id", null: false
- t.integer "forked_from_project_id", null: false
- t.datetime "created_at"
- t.datetime "updated_at"
- end
- add_index "forked_project_links", ["forked_to_project_id"], name: "index_forked_project_links_on_forked_to_project_id", unique: true, using: :btree
- create_table "issues", force: :cascade do |t|
- t.string "title"
- t.integer "assignee_id"
- t.integer "author_id"
- t.integer "project_id"
- t.datetime "created_at"
- t.datetime "updated_at"
- t.integer "position", default: 0
- t.string "branch_name"
- t.text "description"
- t.integer "milestone_id"
- t.string "state"
- t.integer "iid"
- end
- add_index "issues", ["assignee_id"], name: "index_issues_on_assignee_id", using: :btree
- add_index "issues", ["author_id"], name: "index_issues_on_author_id", using: :btree
- add_index "issues", ["created_at"], name: "index_issues_on_created_at", using: :btree
- add_index "issues", ["milestone_id"], name: "index_issues_on_milestone_id", using: :btree
- add_index "issues", ["project_id"], name: "index_issues_on_project_id", using: :btree
- add_index "issues", ["title"], name: "index_issues_on_title", using: :btree
- create_table "keys", force: :cascade do |t|
- t.integer "user_id"
- t.datetime "created_at"
- t.datetime "updated_at"
- t.text "key"
- t.string "title"
- t.string "type"
- t.string "fingerprint"
- end
- add_index "keys", ["user_id"], name: "index_keys_on_user_id", using: :btree
- create_table "merge_request_diffs", force: :cascade do |t|
- t.string "state", default: "collected", null: false
- t.text "st_commits"
- t.text "st_diffs"
- t.integer "merge_request_id", null: false
- t.datetime "created_at"
- t.datetime "updated_at"
- end
- add_index "merge_request_diffs", ["merge_request_id"], name: "index_merge_request_diffs_on_merge_request_id", unique: true, using: :btree
- create_table "merge_requests", force: :cascade do |t|
- t.string "target_branch", null: false
- t.string "source_branch", null: false
- t.integer "source_project_id", null: false
- t.integer "author_id"
- t.integer "assignee_id"
- t.string "title"
- t.datetime "created_at"
- t.datetime "updated_at"
- t.integer "milestone_id"
- t.string "state"
- t.string "merge_status"
- t.integer "target_project_id", null: false
- t.integer "iid"
- t.text "description"
- end
- add_index "merge_requests", ["assignee_id"], name: "index_merge_requests_on_assignee_id", using: :btree
- add_index "merge_requests", ["author_id"], name: "index_merge_requests_on_author_id", using: :btree
- add_index "merge_requests", ["created_at"], name: "index_merge_requests_on_created_at", using: :btree
- add_index "merge_requests", ["milestone_id"], name: "index_merge_requests_on_milestone_id", using: :btree
- add_index "merge_requests", ["source_branch"], name: "index_merge_requests_on_source_branch", using: :btree
- add_index "merge_requests", ["source_project_id"], name: "index_merge_requests_on_source_project_id", using: :btree
- add_index "merge_requests", ["target_branch"], name: "index_merge_requests_on_target_branch", using: :btree
- add_index "merge_requests", ["title"], name: "index_merge_requests_on_title", using: :btree
- create_table "milestones", force: :cascade do |t|
- t.string "title", null: false
- t.integer "project_id", null: false
- t.text "description"
- t.date "due_date"
- t.datetime "created_at"
- t.datetime "updated_at"
- t.string "state"
- t.integer "iid"
- end
- add_index "milestones", ["due_date"], name: "index_milestones_on_due_date", using: :btree
- add_index "milestones", ["project_id"], name: "index_milestones_on_project_id", using: :btree
- create_table "namespaces", force: :cascade do |t|
- t.string "name", null: false
- t.string "path", null: false
- t.integer "owner_id"
- t.datetime "created_at"
- t.datetime "updated_at"
- t.string "type"
- t.string "description", default: "", null: false
- t.string "avatar"
- end
- add_index "namespaces", ["name"], name: "index_namespaces_on_name", using: :btree
- add_index "namespaces", ["owner_id"], name: "index_namespaces_on_owner_id", using: :btree
- add_index "namespaces", ["path"], name: "index_namespaces_on_path", using: :btree
- add_index "namespaces", ["type"], name: "index_namespaces_on_type", using: :btree
- create_table "notes", force: :cascade do |t|
- t.text "note"
- t.string "noteable_type"
- t.integer "author_id"
- t.datetime "created_at"
- t.datetime "updated_at"
- t.integer "project_id"
- t.string "attachment"
- t.string "line_code"
- t.string "commit_id"
- t.integer "noteable_id"
- t.boolean "system", default: false, null: false
- t.text "st_diff"
- end
- add_index "notes", ["author_id"], name: "index_notes_on_author_id", using: :btree
- add_index "notes", ["commit_id"], name: "index_notes_on_commit_id", using: :btree
- add_index "notes", ["created_at"], name: "index_notes_on_created_at", using: :btree
- add_index "notes", %w[noteable_id noteable_type], name: "index_notes_on_noteable_id_and_noteable_type", using: :btree
- add_index "notes", ["noteable_type"], name: "index_notes_on_noteable_type", using: :btree
- add_index "notes", %w[project_id noteable_type], name: "index_notes_on_project_id_and_noteable_type", using: :btree
- add_index "notes", ["project_id"], name: "index_notes_on_project_id", using: :btree
- create_table "project_group_links", force: :cascade do |t|
- t.integer "project_id", null: false
- t.integer "group_id", null: false
- t.datetime "created_at"
- t.datetime "updated_at"
- t.integer "group_access", default: 30, null: false
- end
- create_table "projects", force: :cascade do |t|
- t.string "name"
- t.string "path"
- t.text "description"
- t.datetime "created_at"
- t.datetime "updated_at"
- t.integer "creator_id"
- t.boolean "issues_enabled", default: true, null: false
- t.boolean "wall_enabled", default: true, null: false
- t.boolean "merge_requests_enabled", default: true, null: false
- t.boolean "wiki_enabled", default: true, null: false
- t.integer "namespace_id"
- t.string "issues_tracker", default: "gitlab", null: false
- t.string "issues_tracker_id"
- t.boolean "snippets_enabled", default: true, null: false
- t.datetime "last_activity_at"
- t.string "import_url"
- t.integer "visibility_level", default: 0, null: false
- t.boolean "archived", default: false, null: false
- t.string "avatar"
- t.string "import_status"
- end
- add_index "projects", ["creator_id"], name: "index_projects_on_creator_id", using: :btree
- add_index "projects", ["last_activity_at"], name: "index_projects_on_last_activity_at", using: :btree
- add_index "projects", ["namespace_id"], name: "index_projects_on_namespace_id", using: :btree
- create_table "protected_branches", force: :cascade do |t|
- t.integer "project_id", null: false
- t.string "name", null: false
- t.datetime "created_at"
- t.datetime "updated_at"
- end
- add_index "protected_branches", ["project_id"], name: "index_protected_branches_on_project_id", using: :btree
- create_table "services", force: :cascade do |t|
- t.string "type"
- t.string "title"
- t.string "token"
- t.integer "project_id", null: false
- t.datetime "created_at"
- t.datetime "updated_at"
- t.boolean "active", default: false, null: false
- t.string "project_url"
- t.string "subdomain"
- t.string "room"
- t.text "recipients"
- t.string "api_key"
- end
- add_index "services", ["project_id"], name: "index_services_on_project_id", using: :btree
- create_table "snippets", force: :cascade do |t|
- t.string "title"
- t.text "content"
- t.integer "author_id", null: false
- t.integer "project_id"
- t.datetime "created_at"
- t.datetime "updated_at"
- t.string "file_name"
- t.datetime "expires_at"
- t.boolean "private", default: true, null: false
- t.string "type"
- end
- add_index "snippets", ["author_id"], name: "index_snippets_on_author_id", using: :btree
- add_index "snippets", ["created_at"], name: "index_snippets_on_created_at", using: :btree
- add_index "snippets", ["expires_at"], name: "index_snippets_on_expires_at", using: :btree
- add_index "snippets", ["project_id"], name: "index_snippets_on_project_id", using: :btree
- create_table "taggings", force: :cascade do |t|
- t.integer "tag_id"
- t.integer "taggable_id"
- t.string "taggable_type"
- t.integer "tagger_id"
- t.string "tagger_type"
- t.string "context"
- t.datetime "created_at"
- end
- add_index "taggings", ["tag_id"], name: "index_taggings_on_tag_id", using: :btree
- add_index "taggings", %w[taggable_id taggable_type context], name: "index_taggings_on_taggable_id_and_taggable_type_and_context", using: :btree
- create_table "tags", force: :cascade do |t|
- t.string "name"
- end
- create_table "users", force: :cascade do |t|
- t.string "email", default: "", null: false
- t.string "encrypted_password", default: "", null: false
- t.string "reset_password_token"
- t.datetime "reset_password_sent_at"
- t.datetime "remember_created_at"
- t.integer "sign_in_count", default: 0
- t.datetime "current_sign_in_at"
- t.datetime "last_sign_in_at"
- t.string "current_sign_in_ip"
- t.string "last_sign_in_ip"
- t.datetime "created_at"
- t.datetime "updated_at"
- t.string "name"
- t.boolean "admin", default: false, null: false
- t.integer "projects_limit", default: 10
- t.string "skype", default: "", null: false
- t.string "linkedin", default: "", null: false
- t.string "twitter", default: "", null: false
- t.string "authentication_token"
- t.integer "theme_id", default: 1, null: false
- t.string "bio"
- t.integer "failed_attempts", default: 0
- t.datetime "locked_at"
- t.string "extern_uid"
- t.string "provider"
- t.string "username"
- t.boolean "can_create_group", default: true, null: false
- t.boolean "can_create_team", default: true, null: false
- t.string "state"
- t.integer "color_scheme_id", default: 1, null: false
- t.integer "notification_level", default: 1, null: false
- t.datetime "password_expires_at"
- t.integer "created_by_id"
- t.datetime "last_credential_check_at"
- t.string "avatar"
- t.string "confirmation_token"
- t.datetime "confirmed_at"
- t.datetime "confirmation_sent_at"
- t.string "unconfirmed_email"
- t.boolean "hide_no_ssh_key", default: false
- t.string "website_url", default: "", null: false
- end
- add_index "users", ["admin"], name: "index_users_on_admin", using: :btree
- add_index "users", ["authentication_token"], name: "index_users_on_authentication_token", unique: true, using: :btree
- add_index "users", ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true, using: :btree
- add_index "users", ["email"], name: "index_users_on_email", unique: true, using: :btree
- add_index "users", %w[extern_uid provider], name: "index_users_on_extern_uid_and_provider", unique: true, using: :btree
- add_index "users", ["name"], name: "index_users_on_name", using: :btree
- add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, using: :btree
- add_index "users", ["username"], name: "index_users_on_username", using: :btree
- create_table "users_groups", force: :cascade do |t|
- t.integer "group_access", null: false
- t.integer "group_id", null: false
- t.integer "user_id", null: false
- t.datetime "created_at"
- t.datetime "updated_at"
- t.integer "notification_level", default: 3, null: false
- end
- add_index "users_groups", ["user_id"], name: "index_users_groups_on_user_id", using: :btree
- create_table "users_projects", force: :cascade do |t|
- t.integer "user_id", null: false
- t.integer "project_id", null: false
- t.datetime "created_at"
- t.datetime "updated_at"
- t.integer "project_access", default: 0, null: false
- t.integer "notification_level", default: 3, null: false
- end
- add_index "users_projects", ["project_access"], name: "index_users_projects_on_project_access", using: :btree
- add_index "users_projects", ["project_id"], name: "index_users_projects_on_project_id", using: :btree
- add_index "users_projects", ["user_id"], name: "index_users_projects_on_user_id", using: :btree
- create_table "web_hooks", force: :cascade do |t|
- t.string "url"
- t.integer "project_id"
- t.datetime "created_at"
- t.datetime "updated_at"
- t.string "type", default: "ProjectHook"
- t.integer "service_id"
- t.boolean "push_events", default: true, null: false
- t.boolean "issues_events", default: false, null: false
- t.boolean "merge_requests_events", default: false, null: false
- t.boolean "tag_push_events", default: false
- end
- add_index "web_hooks", ["project_id"], name: "index_web_hooks_on_project_id", using: :btree
- end
-
- def down
- raise ActiveRecord::IrreversibleMigration, "The initial migration is not revertable"
- end
-end
diff --git a/db/migrate/20140407135544_fix_namespaces.rb b/db/migrate/20140407135544_fix_namespaces.rb
deleted file mode 100644
index b16d65c4b51..00000000000
--- a/db/migrate/20140407135544_fix_namespaces.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-class FixNamespaces < ActiveRecord::Migration[4.2]
- DOWNTIME = false
-
- def up
- namespaces = exec_query('SELECT id, path FROM namespaces WHERE name <> path and type is null')
-
- namespaces.each do |row|
- id = row['id']
- path = row['path']
- exec_query("UPDATE namespaces SET name = '#{path}' WHERE id = #{id}")
- end
- end
-
- def down
- end
-end
diff --git a/db/migrate/20140414131055_change_state_to_allow_empty_merge_request_diffs.rb b/db/migrate/20140414131055_change_state_to_allow_empty_merge_request_diffs.rb
deleted file mode 100644
index 1f9ae3f0080..00000000000
--- a/db/migrate/20140414131055_change_state_to_allow_empty_merge_request_diffs.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-class ChangeStateToAllowEmptyMergeRequestDiffs < ActiveRecord::Migration[4.2]
- def up
- change_column :merge_request_diffs, :state, :string, null: true,
- default: nil
- end
-
- def down
- change_column :merge_request_diffs, :state, :string, null: false,
- default: 'collected'
- end
-end
diff --git a/db/migrate/20140415124820_limits_to_mysql.rb b/db/migrate/20140415124820_limits_to_mysql.rb
deleted file mode 100644
index 3f6e62617c5..00000000000
--- a/db/migrate/20140415124820_limits_to_mysql.rb
+++ /dev/null
@@ -1 +0,0 @@
-require_relative 'limits_to_mysql'
diff --git a/db/migrate/20140416074002_add_index_on_iid.rb b/db/migrate/20140416074002_add_index_on_iid.rb
deleted file mode 100644
index c7f707ca123..00000000000
--- a/db/migrate/20140416074002_add_index_on_iid.rb
+++ /dev/null
@@ -1,33 +0,0 @@
-# rubocop:disable all
-class AddIndexOnIid < ActiveRecord::Migration[4.2]
- def change
- RemoveDuplicateIid.clean(Issue)
- RemoveDuplicateIid.clean(MergeRequest, 'target_project_id')
- RemoveDuplicateIid.clean(Milestone)
-
- add_index :issues, [:project_id, :iid], unique: true
- add_index :merge_requests, [:target_project_id, :iid], unique: true
- add_index :milestones, [:project_id, :iid], unique: true
- end
-end
-
-class RemoveDuplicateIid
- def self.clean(klass, project_field = 'project_id')
- duplicates = klass.find_by_sql("SELECT iid, #{project_field} FROM #{klass.table_name} GROUP BY #{project_field}, iid HAVING COUNT(*) > 1")
-
- duplicates.each do |duplicate|
- project_id = duplicate.send(project_field)
- iid = duplicate.iid
- items = klass.of_projects(project_id).where(iid: iid)
-
- if items.size > 1
- puts "Remove #{klass.name} duplicates for iid: #{iid} and project_id: #{project_id}"
- items.shift
- items.each do |item|
- item.destroy
- puts '.'
- end
- end
- end
- end
-end
diff --git a/db/migrate/20140416185734_index_on_current_sign_in_at.rb b/db/migrate/20140416185734_index_on_current_sign_in_at.rb
deleted file mode 100644
index 7dabcb937b3..00000000000
--- a/db/migrate/20140416185734_index_on_current_sign_in_at.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-# rubocop:disable all
-class IndexOnCurrentSignInAt < ActiveRecord::Migration[4.2]
- def change
- add_index :users, :current_sign_in_at
- end
-end
diff --git a/db/migrate/20140428105831_add_notes_index_updated_at.rb b/db/migrate/20140428105831_add_notes_index_updated_at.rb
deleted file mode 100644
index 25bdf477e24..00000000000
--- a/db/migrate/20140428105831_add_notes_index_updated_at.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-# rubocop:disable all
-class AddNotesIndexUpdatedAt < ActiveRecord::Migration[4.2]
- def change
- add_index :notes, :updated_at
- end
-end
diff --git a/db/migrate/20140502115131_add_repo_size_to_db.rb b/db/migrate/20140502115131_add_repo_size_to_db.rb
deleted file mode 100644
index 4cb7a01bbf2..00000000000
--- a/db/migrate/20140502115131_add_repo_size_to_db.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-# rubocop:disable all
-class AddRepoSizeToDb < ActiveRecord::Migration[4.2]
- def change
- add_column :projects, :repository_size, :float, default: 0
- end
-end
diff --git a/db/migrate/20140502125220_migrate_repo_size.rb b/db/migrate/20140502125220_migrate_repo_size.rb
deleted file mode 100644
index bff1f01c654..00000000000
--- a/db/migrate/20140502125220_migrate_repo_size.rb
+++ /dev/null
@@ -1,31 +0,0 @@
-# rubocop:disable all
-class MigrateRepoSize < ActiveRecord::Migration[4.2]
- DOWNTIME = false
-
- def up
- project_data = execute('SELECT projects.id, namespaces.path AS namespace_path, projects.path AS project_path FROM projects LEFT JOIN namespaces ON projects.namespace_id = namespaces.id')
-
- project_data.each do |project|
- id = project['id']
- namespace_path = project['namespace_path'] || ''
- path = File.join(namespace_path, project['project_path'] + '.git')
-
- begin
- repo = Gitlab::Git::Repository.new('default', path, '', '')
- if repo.empty?
- print '-'
- else
- size = repo.size
- print '.'
- execute("UPDATE projects SET repository_size = #{size} WHERE id = #{id}")
- end
- rescue => e
- puts "\nFailed to update project #{id}: #{e}"
- end
- end
- puts "\nDone"
- end
-
- def down
- end
-end
diff --git a/db/migrate/20140611135229_add_position_to_merge_request.rb b/db/migrate/20140611135229_add_position_to_merge_request.rb
deleted file mode 100644
index 6ec644eecce..00000000000
--- a/db/migrate/20140611135229_add_position_to_merge_request.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-# rubocop:disable all
-class AddPositionToMergeRequest < ActiveRecord::Migration[4.2]
- def change
- add_column :merge_requests, :position, :integer, default: 0
- end
-end
diff --git a/db/migrate/20140625115202_create_users_star_projects.rb b/db/migrate/20140625115202_create_users_star_projects.rb
deleted file mode 100644
index 2237927fc78..00000000000
--- a/db/migrate/20140625115202_create_users_star_projects.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-# rubocop:disable all
-class CreateUsersStarProjects < ActiveRecord::Migration[4.2]
- DOWNTIME = false
-
- def change
- create_table :users_star_projects do |t|
- t.integer :project_id, null: false
- t.integer :user_id, null: false
- t.timestamps null: true
- end
- add_index :users_star_projects, :user_id
- add_index :users_star_projects, :project_id
- add_index :users_star_projects, [:user_id, :project_id], unique: true
-
- add_column :projects, :star_count, :integer, default: 0, null: false
- add_index :projects, :star_count, using: :btree
- end
-end
diff --git a/db/migrate/20140729134820_create_labels.rb b/db/migrate/20140729134820_create_labels.rb
deleted file mode 100644
index 1060610b660..00000000000
--- a/db/migrate/20140729134820_create_labels.rb
+++ /dev/null
@@ -1,14 +0,0 @@
-# rubocop:disable all
-class CreateLabels < ActiveRecord::Migration[4.2]
- DOWNTIME = false
-
- def change
- create_table :labels do |t|
- t.string :title
- t.string :color
- t.integer :project_id
-
- t.timestamps null: true
- end
- end
-end
diff --git a/db/migrate/20140729140420_create_label_links.rb b/db/migrate/20140729140420_create_label_links.rb
deleted file mode 100644
index b8596a44a21..00000000000
--- a/db/migrate/20140729140420_create_label_links.rb
+++ /dev/null
@@ -1,14 +0,0 @@
-# rubocop:disable all
-class CreateLabelLinks < ActiveRecord::Migration[4.2]
- DOWNTIME = false
-
- def change
- create_table :label_links do |t|
- t.integer :label_id
- t.integer :target_id
- t.string :target_type
-
- t.timestamps null: true
- end
- end
-end
diff --git a/db/migrate/20140729145339_migrate_project_tags.rb b/db/migrate/20140729145339_migrate_project_tags.rb
deleted file mode 100644
index 711a2d262aa..00000000000
--- a/db/migrate/20140729145339_migrate_project_tags.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-class MigrateProjectTags < ActiveRecord::Migration[4.2]
- def up
- ActsAsTaggableOn::Tagging.where(taggable_type: 'Project', context: 'labels').update_all(context: 'tags')
- end
-
- def down
- ActsAsTaggableOn::Tagging.where(taggable_type: 'Project', context: 'tags').update_all(context: 'labels')
- end
-end
diff --git a/db/migrate/20140729152420_migrate_taggable_labels.rb b/db/migrate/20140729152420_migrate_taggable_labels.rb
deleted file mode 100644
index a8bf8022dfc..00000000000
--- a/db/migrate/20140729152420_migrate_taggable_labels.rb
+++ /dev/null
@@ -1,36 +0,0 @@
-# rubocop:disable all
-class MigrateTaggableLabels < ActiveRecord::Migration[4.2]
- def up
- taggings = ActsAsTaggableOn::Tagging.where(taggable_type: ['Issue', 'MergeRequest'], context: 'labels')
- taggings.find_each(batch_size: 500) do |tagging|
- # Clean up orphaned taggings while we are here
- if tagging.taggable.blank? || tagging.tag.nil?
- tagging.destroy
- print 'D'
- next
- end
- create_label_from_tagging(tagging)
- end
- end
-
- def down
- Label.destroy_all
- LabelLink.destroy_all
- end
-
- private
-
- def create_label_from_tagging(tagging)
- target = tagging.taggable
- label_name = tagging.tag.name
- # '?', '&' and ',' are no longer allowed in label names so we remove them
- label_name.tr!('?&,', '')
- label = target.project.labels.find_or_create_by(title: label_name, color: Label::DEFAULT_COLOR)
-
- if label.valid? && LabelLink.create(label: label, target: target)
- print '.'
- else
- print 'F'
- end
- end
-end
diff --git a/db/migrate/20140730111702_add_index_to_labels.rb b/db/migrate/20140730111702_add_index_to_labels.rb
deleted file mode 100644
index 21f9dfd5d47..00000000000
--- a/db/migrate/20140730111702_add_index_to_labels.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-# rubocop:disable all
-class AddIndexToLabels < ActiveRecord::Migration[4.2]
- def change
- add_index "labels", :project_id
- add_index "label_links", :label_id
- add_index "label_links", [:target_id, :target_type]
- end
-end
diff --git a/db/migrate/20140903115954_migrate_to_new_shell.rb b/db/migrate/20140903115954_migrate_to_new_shell.rb
deleted file mode 100644
index cc0cce483b1..00000000000
--- a/db/migrate/20140903115954_migrate_to_new_shell.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-# rubocop:disable all
-class MigrateToNewShell < ActiveRecord::Migration[4.2]
- def change
- return if Rails.env.test?
-
- gitlab_shell_path = Gitlab.config.gitlab_shell.path
- if system("#{gitlab_shell_path}/bin/create-hooks")
- puts 'Repositories updated with new hooks'
- else
- raise 'Failed to rewrite gitlab-shell hooks in repositories'
- end
- end
-end
diff --git a/db/migrate/20140907220153_serialize_service_properties.rb b/db/migrate/20140907220153_serialize_service_properties.rb
deleted file mode 100644
index bf94c64654b..00000000000
--- a/db/migrate/20140907220153_serialize_service_properties.rb
+++ /dev/null
@@ -1,43 +0,0 @@
-# rubocop:disable all
-class SerializeServiceProperties < ActiveRecord::Migration[4.2]
- def change
- unless column_exists?(:services, :properties)
- add_column :services, :properties, :text
- end
-
- Service.reset_column_information
-
- associations =
- {
- AssemblaService: [:token, :subdomain],
- CampfireService: [:token, :subdomain, :room],
- EmailsOnPushService: [:recipients],
- FlowdockService: [:token],
- GemnasiumService: [:api_key, :token],
- GitlabCiService: [:token, :project_url],
- HipchatService: [:token, :room],
- PivotaltrackerService: [:token],
- SlackService: [:subdomain, :token, :room],
- JenkinsService: [:project_url],
- JiraService: [:project_url, :username, :password,
- :api_version, :jira_issue_transition_id],
- }
-
- Service.find_each(batch_size: 500).each do |service|
- associations[service.type.to_sym].each do |attribute|
- service.send("#{attribute}=", service.attributes[attribute.to_s])
- end
-
- service.save(validate: false)
- end
-
- if column_exists?(:services, :project_url)
- remove_column :services, :project_url, :string
- remove_column :services, :subdomain, :string
- remove_column :services, :room, :string
- remove_column :services, :recipients, :text
- remove_column :services, :api_key, :string
- remove_column :services, :token, :string
- end
- end
-end
diff --git a/db/migrate/20140914113604_add_members_table.rb b/db/migrate/20140914113604_add_members_table.rb
deleted file mode 100644
index 312ea1b94df..00000000000
--- a/db/migrate/20140914113604_add_members_table.rb
+++ /dev/null
@@ -1,22 +0,0 @@
-# rubocop:disable all
-class AddMembersTable < ActiveRecord::Migration[4.2]
- DOWNTIME = false
-
- def change
- create_table :members do |t|
- t.integer :access_level, null: false
- t.integer :source_id, null: false
- t.string :source_type, null: false
- t.integer :user_id, null: false
- t.integer :notification_level, null: false
- t.string :type
-
- t.timestamps null: true
- end
-
- add_index :members, :type
- add_index :members, :user_id
- add_index :members, :access_level
- add_index :members, [:source_id, :source_type]
- end
-end
diff --git a/db/migrate/20140914145549_migrate_to_new_members_model.rb b/db/migrate/20140914145549_migrate_to_new_members_model.rb
deleted file mode 100644
index 22d8b3d651b..00000000000
--- a/db/migrate/20140914145549_migrate_to_new_members_model.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-# rubocop:disable all
-class MigrateToNewMembersModel < ActiveRecord::Migration[4.2]
- def up
- execute "INSERT INTO members ( user_id, source_id, source_type, access_level, notification_level, type ) SELECT user_id, group_id, 'Namespace', group_access, notification_level, 'GroupMember' FROM users_groups"
- execute "INSERT INTO members ( user_id, source_id, source_type, access_level, notification_level, type ) SELECT user_id, project_id, 'Project', project_access, notification_level, 'ProjectMember' FROM users_projects"
- end
-
- def down
- Member.delete_all
- end
-end
-
diff --git a/db/migrate/20140914173417_remove_old_member_tables.rb b/db/migrate/20140914173417_remove_old_member_tables.rb
deleted file mode 100644
index edd69caa470..00000000000
--- a/db/migrate/20140914173417_remove_old_member_tables.rb
+++ /dev/null
@@ -1,29 +0,0 @@
-# rubocop:disable all
-class RemoveOldMemberTables < ActiveRecord::Migration[4.2]
- DOWNTIME = false
-
- def up
- drop_table :users_groups
- drop_table :users_projects
- end
-
- def down
- create_table :users_groups do |t|
- t.integer :group_access, null: false
- t.integer :group_id, null: false
- t.integer :user_id, null: false
- t.integer :notification_level, null: false, default: 3
-
- t.timestamps null: true
- end
-
- create_table :users_projects do |t|
- t.integer :project_access, null: false
- t.integer :project_id, null: false
- t.integer :user_id, null: false
- t.integer :notification_level, null: false, default: 3
-
- t.timestamps null: true
- end
- end
-end
diff --git a/db/migrate/20141006143943_move_slack_service_to_webhook.rb b/db/migrate/20141006143943_move_slack_service_to_webhook.rb
deleted file mode 100644
index 1c9a1a74a4e..00000000000
--- a/db/migrate/20141006143943_move_slack_service_to_webhook.rb
+++ /dev/null
@@ -1,22 +0,0 @@
-# rubocop:disable all
-class MoveSlackServiceToWebhook < ActiveRecord::Migration[4.2]
-
- DOWNTIME = true
- DOWNTIME_REASON = 'Move old fields "token" and "subdomain" to one single field "webhook"'
-
- def change
- SlackService.all.each do |slack_service|
- if ["token", "subdomain"].all? { |property| slack_service.properties.key? property }
- token = slack_service.properties['token']
- subdomain = slack_service.properties['subdomain']
- webhook = "https://#{subdomain}.slack.com/services/hooks/incoming-webhook?token=#{token}"
- slack_service.properties['webhook'] = webhook
- slack_service.properties.delete('token')
- slack_service.properties.delete('subdomain')
- # Room is configured on the Slack side
- slack_service.properties.delete('room')
- slack_service.save(validate: false)
- end
- end
- end
-end
diff --git a/db/migrate/20141007100818_add_visibility_level_to_snippet.rb b/db/migrate/20141007100818_add_visibility_level_to_snippet.rb
deleted file mode 100644
index 9501aed8931..00000000000
--- a/db/migrate/20141007100818_add_visibility_level_to_snippet.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-# rubocop:disable all
-class AddVisibilityLevelToSnippet < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- def up
- add_column :snippets, :visibility_level, :integer, :default => 0, :null => false
-
- execute("UPDATE snippets SET visibility_level = #{Gitlab::VisibilityLevel::PRIVATE} WHERE private = #{true_value}")
- execute("UPDATE snippets SET visibility_level = #{Gitlab::VisibilityLevel::INTERNAL} WHERE private = #{false_value}")
-
- add_index :snippets, :visibility_level
-
- remove_column :snippets, :private
- end
-
- def down
- add_column :snippets, :private, :boolean, :default => false, :null => false
-
- execute("UPDATE snippets SET private = #{false_value} WHERE visibility_level = #{Gitlab::VisibilityLevel::INTERNAL}")
- execute("UPDATE snippets SET private = #{true_value} WHERE visibility_level = #{Gitlab::VisibilityLevel::PRIVATE}")
-
- remove_column :snippets, :visibility_level
- end
-end
diff --git a/db/migrate/20141118150935_add_audit_event.rb b/db/migrate/20141118150935_add_audit_event.rb
deleted file mode 100644
index 1e7dba568c9..00000000000
--- a/db/migrate/20141118150935_add_audit_event.rb
+++ /dev/null
@@ -1,25 +0,0 @@
-# rubocop:disable all
-class AddAuditEvent < ActiveRecord::Migration[4.2]
- DOWNTIME = false
-
- def change
- create_table :audit_events do |t|
- t.integer :author_id, null: false
- t.string :type, null: false
-
- # "Namespace" where the change occurs
- # eg. On a project, group or user
- t.integer :entity_id, null: false
- t.string :entity_type, null: false
-
- # Details for the event
- t.text :details
-
- t.timestamps null: true
- end
-
- add_index :audit_events, :author_id
- add_index :audit_events, :type
- add_index :audit_events, [:entity_id, :entity_type]
- end
-end
diff --git a/db/migrate/20141121133009_add_timestamps_to_members.rb b/db/migrate/20141121133009_add_timestamps_to_members.rb
deleted file mode 100644
index cb575fc9ed7..00000000000
--- a/db/migrate/20141121133009_add_timestamps_to_members.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-# In 20140914145549_migrate_to_new_members_model.rb we forgot to set the
-# created_at and updated_at times for new records in the 'members' table. This
-# became a problem after commit c8e78d972a5a628870eefca0f2ccea0199c55bda which
-# was added in GitLab 7.5. With this migration we ensure that all rows in
-# 'members' have at least some created_at and updated_at timestamp.
-class AddTimestampsToMembers < ActiveRecord::Migration[4.2]
- def up
- execute "UPDATE members SET created_at = NOW() WHERE created_at is NULL"
- execute "UPDATE members SET updated_at = NOW() WHERE updated_at is NULL"
- end
-
- def down
- # no change
- end
-end
diff --git a/db/migrate/20141121161704_add_identity_table.rb b/db/migrate/20141121161704_add_identity_table.rb
deleted file mode 100644
index 92f7a568077..00000000000
--- a/db/migrate/20141121161704_add_identity_table.rb
+++ /dev/null
@@ -1,47 +0,0 @@
-# rubocop:disable all
-class AddIdentityTable < ActiveRecord::Migration[4.2]
- def up
- create_table :identities do |t|
- t.string :extern_uid
- t.string :provider
- t.references :user
- end
-
- add_index :identities, :user_id
-
- execute <<eos
-INSERT INTO identities (provider, extern_uid, user_id)
-SELECT provider, extern_uid, id FROM users
-WHERE provider IS NOT NULL
-eos
-
- if index_exists?(:users, ["extern_uid", "provider"])
- remove_index :users, ["extern_uid", "provider"]
- end
-
- remove_column :users, :extern_uid
- remove_column :users, :provider
- end
-
- def down
- add_column :users, :extern_uid, :string
- add_column :users, :provider, :string
-
- if ActiveRecord::Base.connection.adapter_name == 'PostgreSQL'
- execute <<eos
-UPDATE users u
-SET provider = i.provider, extern_uid = i.extern_uid
-FROM identities i
-WHERE i.user_id = u.id
-eos
- else
- execute "UPDATE users u, identities i SET u.provider = i.provider, u.extern_uid = i.extern_uid WHERE u.id = i.user_id"
- end
-
- drop_table :identities
-
- unless index_exists?(:users, ["extern_uid", "provider"])
- add_index "users", ["extern_uid", "provider"], name: "index_users_on_extern_uid_and_provider", unique: true, using: :btree
- end
- end
-end
diff --git a/db/migrate/20141126120926_add_merge_request_rebase_enabled_to_projects.rb b/db/migrate/20141126120926_add_merge_request_rebase_enabled_to_projects.rb
deleted file mode 100644
index b9d8a5cb435..00000000000
--- a/db/migrate/20141126120926_add_merge_request_rebase_enabled_to_projects.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-# rubocop:disable all
-class AddMergeRequestRebaseEnabledToProjects < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- add_column_with_default(:projects, :merge_requests_rebase_enabled, :boolean, default: false)
- end
-
- def down
- remove_column(:projects, :merge_requests_rebase_enabled)
- end
-end
diff --git a/db/migrate/20141205134006_add_locked_at_to_merge_request.rb b/db/migrate/20141205134006_add_locked_at_to_merge_request.rb
deleted file mode 100644
index 6fdfb3eb974..00000000000
--- a/db/migrate/20141205134006_add_locked_at_to_merge_request.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-# rubocop:disable all
-class AddLockedAtToMergeRequest < ActiveRecord::Migration[4.2]
- def change
- add_column :merge_requests, :locked_at, :datetime
- end
-end
diff --git a/db/migrate/20141216155758_create_doorkeeper_tables.rb b/db/migrate/20141216155758_create_doorkeeper_tables.rb
deleted file mode 100644
index 7bd0a15e7f5..00000000000
--- a/db/migrate/20141216155758_create_doorkeeper_tables.rb
+++ /dev/null
@@ -1,45 +0,0 @@
-# rubocop:disable all
-class CreateDoorkeeperTables < ActiveRecord::Migration[4.2]
- DOWNTIME = false
-
- def change
- create_table :oauth_applications do |t|
- t.string :name, null: false
- t.string :uid, null: false
- t.string :secret, null: false
- t.text :redirect_uri, null: false
- t.string :scopes, null: false, default: ''
- t.timestamps null: true
- end
-
- add_index :oauth_applications, :uid, unique: true
-
- create_table :oauth_access_grants do |t|
- t.integer :resource_owner_id, null: false
- t.integer :application_id, null: false
- t.string :token, null: false
- t.integer :expires_in, null: false
- t.text :redirect_uri, null: false
- t.datetime :created_at, null: false
- t.datetime :revoked_at
- t.string :scopes
- end
-
- add_index :oauth_access_grants, :token, unique: true
-
- create_table :oauth_access_tokens do |t|
- t.integer :resource_owner_id
- t.integer :application_id
- t.string :token, null: false
- t.string :refresh_token
- t.integer :expires_in
- t.datetime :revoked_at
- t.datetime :created_at, null: false
- t.string :scopes
- end
-
- add_index :oauth_access_tokens, :token, unique: true
- add_index :oauth_access_tokens, :resource_owner_id
- add_index :oauth_access_tokens, :refresh_token, unique: true
- end
-end
diff --git a/db/migrate/20141217125223_add_owner_to_application.rb b/db/migrate/20141217125223_add_owner_to_application.rb
deleted file mode 100644
index 482a53f3ad5..00000000000
--- a/db/migrate/20141217125223_add_owner_to_application.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-# rubocop:disable all
-class AddOwnerToApplication < ActiveRecord::Migration[4.2]
- def change
- add_column :oauth_applications, :owner_id, :integer, null: true
- add_column :oauth_applications, :owner_type, :string, null: true
- add_index :oauth_applications, [:owner_id, :owner_type]
- end
-end \ No newline at end of file
diff --git a/db/migrate/20141223135007_add_import_data_to_project_table.rb b/db/migrate/20141223135007_add_import_data_to_project_table.rb
deleted file mode 100644
index 516f58d645e..00000000000
--- a/db/migrate/20141223135007_add_import_data_to_project_table.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-class AddImportDataToProjectTable < ActiveRecord::Migration[4.2]
- def change
- add_column :projects, :import_type, :string
- add_column :projects, :import_source, :string
-
- add_column :users, :github_access_token, :string
- end
-end
diff --git a/db/migrate/20141226080412_add_developers_can_push_to_protected_branches.rb b/db/migrate/20141226080412_add_developers_can_push_to_protected_branches.rb
deleted file mode 100644
index 43b7de85228..00000000000
--- a/db/migrate/20141226080412_add_developers_can_push_to_protected_branches.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-# rubocop:disable all
-class AddDevelopersCanPushToProtectedBranches < ActiveRecord::Migration[4.2]
- def change
- add_column :protected_branches, :developers_can_push, :boolean, default: false, null: false
- end
-end
diff --git a/db/migrate/20150108073740_create_application_settings.rb b/db/migrate/20150108073740_create_application_settings.rb
deleted file mode 100644
index be139fee63a..00000000000
--- a/db/migrate/20150108073740_create_application_settings.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-# rubocop:disable all
-class CreateApplicationSettings < ActiveRecord::Migration[4.2]
- DOWNTIME = false
-
- def change
- create_table :application_settings do |t|
- t.integer :default_projects_limit
- t.boolean :signup_enabled
- t.boolean :signin_enabled
- t.boolean :gravatar_enabled
- t.text :sign_in_text
-
- t.timestamps null: true
- end
- end
-end
diff --git a/db/migrate/20150116234544_add_home_page_url_for_application_settings.rb b/db/migrate/20150116234544_add_home_page_url_for_application_settings.rb
deleted file mode 100644
index e630e2cc878..00000000000
--- a/db/migrate/20150116234544_add_home_page_url_for_application_settings.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class AddHomePageUrlForApplicationSettings < ActiveRecord::Migration[4.2]
- def change
- add_column :application_settings, :home_page_url, :string
- end
-end
diff --git a/db/migrate/20150116234545_add_gitlab_access_token_to_user.rb b/db/migrate/20150116234545_add_gitlab_access_token_to_user.rb
deleted file mode 100644
index 673628e106b..00000000000
--- a/db/migrate/20150116234545_add_gitlab_access_token_to_user.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class AddGitlabAccessTokenToUser < ActiveRecord::Migration[4.2]
- def change
- add_column :users, :gitlab_access_token, :string
- end
-end
diff --git a/db/migrate/20150125163100_add_default_branch_protection_setting.rb b/db/migrate/20150125163100_add_default_branch_protection_setting.rb
deleted file mode 100644
index f6bfa422124..00000000000
--- a/db/migrate/20150125163100_add_default_branch_protection_setting.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-# rubocop:disable all
-class AddDefaultBranchProtectionSetting < ActiveRecord::Migration[4.2]
- def change
- add_column :application_settings, :default_branch_protection, :integer, :default => 2
- end
-end
diff --git a/db/migrate/20150205211843_add_timestamps_to_identities.rb b/db/migrate/20150205211843_add_timestamps_to_identities.rb
deleted file mode 100644
index c535a7ec781..00000000000
--- a/db/migrate/20150205211843_add_timestamps_to_identities.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-# rubocop:disable all
-class AddTimestampsToIdentities < ActiveRecord::Migration[4.2]
- def change
- add_timestamps(:identities)
- end
-end
diff --git a/db/migrate/20150206181414_add_index_to_created_at.rb b/db/migrate/20150206181414_add_index_to_created_at.rb
deleted file mode 100644
index 501acd6a720..00000000000
--- a/db/migrate/20150206181414_add_index_to_created_at.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-# rubocop:disable all
-class AddIndexToCreatedAt < ActiveRecord::Migration[4.2]
- def change
- add_index "users", [:created_at, :id]
- add_index "members", [:created_at, :id]
- add_index "projects", [:created_at, :id]
- add_index "issues", [:created_at, :id]
- add_index "merge_requests", [:created_at, :id]
- add_index "milestones", [:created_at, :id]
- add_index "namespaces", [:created_at, :id]
- add_index "notes", [:created_at, :id]
- add_index "identities", [:created_at, :id]
- add_index "keys", [:created_at, :id]
- add_index "web_hooks", [:created_at, :id]
- add_index "snippets", [:created_at, :id]
- end
-end
diff --git a/db/migrate/20150206222854_add_notification_email_to_user.rb b/db/migrate/20150206222854_add_notification_email_to_user.rb
deleted file mode 100644
index 7b0c251db4f..00000000000
--- a/db/migrate/20150206222854_add_notification_email_to_user.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-class AddNotificationEmailToUser < ActiveRecord::Migration[4.2]
- def up
- add_column :users, :notification_email, :string
-
- execute "UPDATE users SET notification_email = email"
- end
-
- def down
- remove_column :users, :notification_email
- end
-end
diff --git a/db/migrate/20150209222013_add_missing_index.rb b/db/migrate/20150209222013_add_missing_index.rb
deleted file mode 100644
index 99544ab3928..00000000000
--- a/db/migrate/20150209222013_add_missing_index.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-# rubocop:disable all
-class AddMissingIndex < ActiveRecord::Migration[4.2]
- def change
- add_index "services", [:created_at, :id]
- end
-end
diff --git a/db/migrate/20150211172122_add_template_to_service.rb b/db/migrate/20150211172122_add_template_to_service.rb
deleted file mode 100644
index dd192a0fe76..00000000000
--- a/db/migrate/20150211172122_add_template_to_service.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-# rubocop:disable all
-class AddTemplateToService < ActiveRecord::Migration[4.2]
- def change
- add_column :services, :template, :boolean, default: false
- end
-end
diff --git a/db/migrate/20150211174341_allow_null_in_services_project_id.rb b/db/migrate/20150211174341_allow_null_in_services_project_id.rb
deleted file mode 100644
index 4c90bf9c419..00000000000
--- a/db/migrate/20150211174341_allow_null_in_services_project_id.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class AllowNullInServicesProjectId < ActiveRecord::Migration[4.2]
- def change
- change_column :services, :project_id, :integer, null: true
- end
-end
diff --git a/db/migrate/20150213104043_add_twitter_sharing_enabled_to_application_settings.rb b/db/migrate/20150213104043_add_twitter_sharing_enabled_to_application_settings.rb
deleted file mode 100644
index 7d7b9242cd6..00000000000
--- a/db/migrate/20150213104043_add_twitter_sharing_enabled_to_application_settings.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-# rubocop:disable all
-class AddTwitterSharingEnabledToApplicationSettings < ActiveRecord::Migration[4.2]
- def change
- add_column :application_settings, :twitter_sharing_enabled, :boolean, default: true
- end
-end
diff --git a/db/migrate/20150213114800_add_hide_no_password_to_user.rb b/db/migrate/20150213114800_add_hide_no_password_to_user.rb
deleted file mode 100644
index 348c0d22aba..00000000000
--- a/db/migrate/20150213114800_add_hide_no_password_to_user.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-# rubocop:disable all
-class AddHideNoPasswordToUser < ActiveRecord::Migration[4.2]
- def change
- add_column :users, :hide_no_password, :boolean, default: false
- end
-end
diff --git a/db/migrate/20150213121042_add_password_automatically_set_to_user.rb b/db/migrate/20150213121042_add_password_automatically_set_to_user.rb
deleted file mode 100644
index d0eb753b887..00000000000
--- a/db/migrate/20150213121042_add_password_automatically_set_to_user.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-# rubocop:disable all
-class AddPasswordAutomaticallySetToUser < ActiveRecord::Migration[4.2]
- def change
- add_column :users, :password_automatically_set, :boolean, default: false
- end
-end
diff --git a/db/migrate/20150217123345_add_bitbucket_access_token_and_secret_to_user.rb b/db/migrate/20150217123345_add_bitbucket_access_token_and_secret_to_user.rb
deleted file mode 100644
index 639644174ca..00000000000
--- a/db/migrate/20150217123345_add_bitbucket_access_token_and_secret_to_user.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-class AddBitbucketAccessTokenAndSecretToUser < ActiveRecord::Migration[4.2]
- def change
- add_column :users, :bitbucket_access_token, :string
- add_column :users, :bitbucket_access_token_secret, :string
- end
-end
diff --git a/db/migrate/20150219004514_add_events_to_services.rb b/db/migrate/20150219004514_add_events_to_services.rb
deleted file mode 100644
index 7072056adcb..00000000000
--- a/db/migrate/20150219004514_add_events_to_services.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-# rubocop:disable all
-class AddEventsToServices < ActiveRecord::Migration[4.2]
- def change
- add_column :services, :push_events, :boolean, :default => true
- add_column :services, :issues_events, :boolean, :default => true
- add_column :services, :merge_requests_events, :boolean, :default => true
- add_column :services, :tag_push_events, :boolean, :default => true
- end
-end
diff --git a/db/migrate/20150223022001_set_missing_last_activity_at.rb b/db/migrate/20150223022001_set_missing_last_activity_at.rb
deleted file mode 100644
index c77ffbd4ebd..00000000000
--- a/db/migrate/20150223022001_set_missing_last_activity_at.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-class SetMissingLastActivityAt < ActiveRecord::Migration[4.2]
- def up
- execute "UPDATE projects SET last_activity_at = updated_at WHERE last_activity_at IS NULL"
- end
-
- def down
- end
-end
diff --git a/db/migrate/20150225065047_add_note_events_to_services.rb b/db/migrate/20150225065047_add_note_events_to_services.rb
deleted file mode 100644
index 32c538e8681..00000000000
--- a/db/migrate/20150225065047_add_note_events_to_services.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-# rubocop:disable all
-class AddNoteEventsToServices < ActiveRecord::Migration[4.2]
- def change
- add_column :services, :note_events, :boolean, default: true, null: false
- end
-end
diff --git a/db/migrate/20150301014758_add_restricted_visibility_levels_to_application_settings.rb b/db/migrate/20150301014758_add_restricted_visibility_levels_to_application_settings.rb
deleted file mode 100644
index 3091790f199..00000000000
--- a/db/migrate/20150301014758_add_restricted_visibility_levels_to_application_settings.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class AddRestrictedVisibilityLevelsToApplicationSettings < ActiveRecord::Migration[4.2]
- def change
- add_column :application_settings, :restricted_visibility_levels, :text
- end
-end
diff --git a/db/migrate/20150306023106_fix_namespace_duplication.rb b/db/migrate/20150306023106_fix_namespace_duplication.rb
deleted file mode 100644
index 49be152a75c..00000000000
--- a/db/migrate/20150306023106_fix_namespace_duplication.rb
+++ /dev/null
@@ -1,22 +0,0 @@
-# rubocop:disable all
-class FixNamespaceDuplication < ActiveRecord::Migration[4.2]
- def up
- #fixes path duplication
- select_all('SELECT MAX(id) max, COUNT(id) cnt, path FROM namespaces GROUP BY path HAVING COUNT(id) > 1').each do |nms|
- bad_nms_ids = select_all("SELECT id FROM namespaces WHERE path = '#{nms['path']}' AND id <> #{nms['max']}").map{|x| x["id"]}
- execute("UPDATE projects SET namespace_id = #{nms["max"]} WHERE namespace_id IN(#{bad_nms_ids.join(', ')})")
- execute("DELETE FROM namespaces WHERE id IN(#{bad_nms_ids.join(', ')})")
- end
-
- #fixes name duplication
- select_all('SELECT MAX(id) max, COUNT(id) cnt, name FROM namespaces GROUP BY name HAVING COUNT(id) > 1').each do |nms|
- bad_nms_ids = select_all("SELECT id FROM namespaces WHERE name = '#{nms['name']}' AND id <> #{nms['max']}").map{|x| x["id"]}
- execute("UPDATE projects SET namespace_id = #{nms["max"]} WHERE namespace_id IN(#{bad_nms_ids.join(', ')})")
- execute("DELETE FROM namespaces WHERE id IN(#{bad_nms_ids.join(', ')})")
- end
- end
-
- def down
- # not implemented
- end
-end
diff --git a/db/migrate/20150306023112_add_unique_index_to_namespace.rb b/db/migrate/20150306023112_add_unique_index_to_namespace.rb
deleted file mode 100644
index 11472324cbf..00000000000
--- a/db/migrate/20150306023112_add_unique_index_to_namespace.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-# rubocop:disable all
-class AddUniqueIndexToNamespace < ActiveRecord::Migration[4.2]
- def change
- remove_index :namespaces, column: :name if index_exists?(:namespaces, :name)
- remove_index :namespaces, column: :path if index_exists?(:namespaces, :path)
-
- add_index :namespaces, :name, unique: true
- add_index :namespaces, :path, unique: true
- end
-end
diff --git a/db/migrate/20150310194358_add_version_check_to_application_settings.rb b/db/migrate/20150310194358_add_version_check_to_application_settings.rb
deleted file mode 100644
index cc1b19f302e..00000000000
--- a/db/migrate/20150310194358_add_version_check_to_application_settings.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-# rubocop:disable all
-class AddVersionCheckToApplicationSettings < ActiveRecord::Migration[4.2]
- def change
- add_column :application_settings, :version_check_enabled, :boolean, default: true
- end
-end
diff --git a/db/migrate/20150313012111_create_subscriptions_table.rb b/db/migrate/20150313012111_create_subscriptions_table.rb
deleted file mode 100644
index 37011504b49..00000000000
--- a/db/migrate/20150313012111_create_subscriptions_table.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-# rubocop:disable all
-class CreateSubscriptionsTable < ActiveRecord::Migration[4.2]
- DOWNTIME = false
-
- def change
- create_table :subscriptions do |t|
- t.integer :user_id
- t.references :subscribable, polymorphic: true
- t.boolean :subscribed
-
- t.timestamps null: true
- end
-
- add_index :subscriptions,
- [:subscribable_id, :subscribable_type, :user_id],
- unique: true,
- name: 'subscriptions_user_id_and_ref_fields'
- end
-end
diff --git a/db/migrate/20150320234437_add_location_to_user.rb b/db/migrate/20150320234437_add_location_to_user.rb
deleted file mode 100644
index cf273ff916e..00000000000
--- a/db/migrate/20150320234437_add_location_to_user.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class AddLocationToUser < ActiveRecord::Migration[4.2]
- def change
- add_column :users, :location, :string
- end
-end
diff --git a/db/migrate/20150324155957_set_incorrect_assignee_id_to_null.rb b/db/migrate/20150324155957_set_incorrect_assignee_id_to_null.rb
deleted file mode 100644
index a895d5f24f5..00000000000
--- a/db/migrate/20150324155957_set_incorrect_assignee_id_to_null.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-class SetIncorrectAssigneeIdToNull < ActiveRecord::Migration[4.2]
- def up
- execute "UPDATE issues SET assignee_id = NULL WHERE assignee_id = -1"
- execute "UPDATE merge_requests SET assignee_id = NULL WHERE assignee_id = -1"
- end
-end
diff --git a/db/migrate/20150327122227_add_public_to_key.rb b/db/migrate/20150327122227_add_public_to_key.rb
deleted file mode 100644
index 58d8c16476f..00000000000
--- a/db/migrate/20150327122227_add_public_to_key.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-# rubocop:disable all
-class AddPublicToKey < ActiveRecord::Migration[4.2]
- def change
- add_column :keys, :public, :boolean, default: false, null: false
- end
-end
diff --git a/db/migrate/20150327150017_add_import_data_to_project.rb b/db/migrate/20150327150017_add_import_data_to_project.rb
deleted file mode 100644
index 5d393364ee6..00000000000
--- a/db/migrate/20150327150017_add_import_data_to_project.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class AddImportDataToProject < ActiveRecord::Migration[4.2]
- def change
- add_column :projects, :import_data, :text
- end
-end
diff --git a/db/migrate/20150327223628_add_devise_two_factor_to_users.rb b/db/migrate/20150327223628_add_devise_two_factor_to_users.rb
deleted file mode 100644
index 22202796547..00000000000
--- a/db/migrate/20150327223628_add_devise_two_factor_to_users.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-class AddDeviseTwoFactorToUsers < ActiveRecord::Migration[4.2]
- def change
- add_column :users, :encrypted_otp_secret, :string
- add_column :users, :encrypted_otp_secret_iv, :string
- add_column :users, :encrypted_otp_secret_salt, :string
- add_column :users, :otp_required_for_login, :boolean
- end
-end
diff --git a/db/migrate/20150328132231_add_max_attachment_size_to_application_settings.rb b/db/migrate/20150328132231_add_max_attachment_size_to_application_settings.rb
deleted file mode 100644
index 4ce60a257cb..00000000000
--- a/db/migrate/20150328132231_add_max_attachment_size_to_application_settings.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class AddMaxAttachmentSizeToApplicationSettings < ActiveRecord::Migration[4.2]
- def change
- add_column :application_settings, :max_attachment_size, :integer, default: 10, null: false
- end
-end
diff --git a/db/migrate/20150331183602_add_devise_two_factor_backupable_to_users.rb b/db/migrate/20150331183602_add_devise_two_factor_backupable_to_users.rb
deleted file mode 100644
index 792b98c91f0..00000000000
--- a/db/migrate/20150331183602_add_devise_two_factor_backupable_to_users.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class AddDeviseTwoFactorBackupableToUsers < ActiveRecord::Migration[4.2]
- def change
- add_column :users, :otp_backup_codes, :text
- end
-end
diff --git a/db/migrate/20150406133311_add_invite_data_to_member.rb b/db/migrate/20150406133311_add_invite_data_to_member.rb
deleted file mode 100644
index eee991185ab..00000000000
--- a/db/migrate/20150406133311_add_invite_data_to_member.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-# rubocop:disable all
-class AddInviteDataToMember < ActiveRecord::Migration[4.2]
- def up
- add_column :members, :created_by_id, :integer
- add_column :members, :invite_email, :string
- add_column :members, :invite_token, :string
- add_column :members, :invite_accepted_at, :datetime
-
- change_column :members, :user_id, :integer, null: true
-
- add_index :members, :invite_token, unique: true
- end
-
- def down
- remove_index :members, :invite_token
-
- change_column :members, :user_id, :integer, null: false
-
- remove_column :members, :invite_accepted_at
- remove_column :members, :invite_token
- remove_column :members, :invite_email
- remove_column :members, :created_by_id
- end
-end
diff --git a/db/migrate/20150411000035_fix_identities.rb b/db/migrate/20150411000035_fix_identities.rb
deleted file mode 100644
index a449fc51ecc..00000000000
--- a/db/migrate/20150411000035_fix_identities.rb
+++ /dev/null
@@ -1,45 +0,0 @@
-class FixIdentities < ActiveRecord::Migration[4.2]
- def up
- # Up until now, legacy 'ldap' references in the database were charitably
- # interpreted to point to the first LDAP server specified in the GitLab
- # configuration. So if the database said 'provider: ldap' but the first
- # LDAP server was called 'ldapmain', then we would try to interpret
- # 'provider: ldap' as if it said 'provider: ldapmain'. This migration (and
- # accompanying changes in the GitLab LDAP code) get rid of this complicated
- # behavior. Any database references to 'provider: ldap' get rewritten to
- # whatever the code would have interpreted it as, i.e. as a reference to
- # the first LDAP server specified in gitlab.yml / gitlab.rb.
- new_provider = if Gitlab.config.ldap.enabled
- first_ldap_server = Gitlab.config.ldap.servers.values.first
- first_ldap_server['provider_name']
- else
- 'ldapmain'
- end
-
- # Delete duplicate identities
- # We use a sort of self-join to find rows in identities which match on
- # user_id but where one has provider 'ldap'. We delete the duplicate row
- # with provider 'ldap'.
- delete_statement = ''
- case adapter_name.downcase
- when /^mysql/
- delete_statement << 'DELETE FROM id1 USING identities AS id1, identities AS id2'
- when 'postgresql'
- delete_statement << 'DELETE FROM identities AS id1 USING identities AS id2'
- else
- raise "Unknown DB adapter: #{adapter_name}"
- end
- delete_statement << " WHERE id1.user_id = id2.user_id AND id1.provider = 'ldap' AND id2.provider = '#{new_provider}'"
- execute delete_statement
-
- # Update legacy identities
- execute "UPDATE identities SET provider = '#{new_provider}' WHERE provider = 'ldap'"
-
- if table_exists?('ldap_group_links')
- execute "UPDATE ldap_group_links SET provider = '#{new_provider}' WHERE provider IS NULL OR provider = 'ldap'"
- end
- end
-
- def down
- end
-end
diff --git a/db/migrate/20150411180045_rename_buildbox_service.rb b/db/migrate/20150411180045_rename_buildbox_service.rb
deleted file mode 100644
index ac4ccdfb723..00000000000
--- a/db/migrate/20150411180045_rename_buildbox_service.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-class RenameBuildboxService < ActiveRecord::Migration[4.2]
- def up
- execute "UPDATE services SET type = 'BuildkiteService' WHERE type = 'BuildboxService';"
- end
-
- def down
- execute "UPDATE services SET type = 'BuildboxService' WHERE type = 'BuildkiteService';"
- end
-end
diff --git a/db/migrate/20150413192223_add_public_email_to_users.rb b/db/migrate/20150413192223_add_public_email_to_users.rb
deleted file mode 100644
index 991f0c668c3..00000000000
--- a/db/migrate/20150413192223_add_public_email_to_users.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-# rubocop:disable all
-class AddPublicEmailToUsers < ActiveRecord::Migration[4.2]
- def change
- add_column :users, :public_email, :string, default: "", null: false
- end
-end
diff --git a/db/migrate/20150417121913_create_project_import_data.rb b/db/migrate/20150417121913_create_project_import_data.rb
deleted file mode 100644
index 383f64fd2c6..00000000000
--- a/db/migrate/20150417121913_create_project_import_data.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-class CreateProjectImportData < ActiveRecord::Migration[4.2]
- def change
- create_table :project_import_data do |t|
- t.references :project
- t.text :data
- end
- end
-end
diff --git a/db/migrate/20150417122318_remove_import_data_from_project.rb b/db/migrate/20150417122318_remove_import_data_from_project.rb
deleted file mode 100644
index c9a225a9d17..00000000000
--- a/db/migrate/20150417122318_remove_import_data_from_project.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-# rubocop:disable all
-class RemoveImportDataFromProject < ActiveRecord::Migration[4.2]
- def up
- remove_column :projects, :import_data
- end
-
- def down
- add_column :projects, :import_data, :text
- end
-end
diff --git a/db/migrate/20150421120000_remove_periods_at_ends_of_usernames.rb b/db/migrate/20150421120000_remove_periods_at_ends_of_usernames.rb
deleted file mode 100644
index d2e7656c9d4..00000000000
--- a/db/migrate/20150421120000_remove_periods_at_ends_of_usernames.rb
+++ /dev/null
@@ -1,89 +0,0 @@
-# rubocop:disable all
-class RemovePeriodsAtEndsOfUsernames < ActiveRecord::Migration[4.2]
- include Gitlab::ShellAdapter
-
- class Namespace < ActiveRecord::Base
- class << self
- def find_by_path_or_name(path)
- find_by("lower(path) = :path OR lower(name) = :path", path: path.downcase)
- end
-
- def clean_path(path)
- path = path.dup
- # Get the email username by removing everything after an `@` sign.
- path.gsub!(/@.*\z/, "")
- # Usernames can't end in .git, so remove it.
- path.gsub!(/\.git\z/, "")
- # Remove dashes at the start of the username.
- path.gsub!(/\A-+/, "")
- # Remove periods at the end of the username.
- path.gsub!(/\.+\z/, "")
- # Remove everything that's not in the list of allowed characters.
- path.gsub!(/[^a-zA-Z0-9_\-\.]/, "")
-
- # Users with the great usernames of "." or ".." would end up with a blank username.
- # Work around that by setting their username to "blank", followed by a counter.
- path = "blank" if path.blank?
-
- counter = 0
- base = path
- while Namespace.find_by_path_or_name(path)
- counter += 1
- path = "#{base}#{counter}"
- end
-
- path
- end
- end
- end
-
- def up
- changed_paths = {}
-
- select_all("SELECT id, username FROM users WHERE username LIKE '%.'").each do |user|
- username_was = user["username"]
- username = Namespace.clean_path(username_was)
- changed_paths[username_was] = username
-
- username = quote_string(username)
- execute "UPDATE users SET username = '#{username}' WHERE id = #{user["id"]}"
- execute "UPDATE namespaces SET path = '#{username}', name = '#{username}' WHERE type IS NULL AND owner_id = #{user["id"]}"
- end
-
- select_all("SELECT id, path FROM namespaces WHERE type = 'Group' AND path LIKE '%.'").each do |group|
- path_was = group["path"]
- path = Namespace.clean_path(path_was)
- changed_paths[path_was] = path
-
- path = quote_string(path)
- execute "UPDATE namespaces SET path = '#{path}' WHERE id = #{group["id"]}"
- end
-
- changed_paths.each do |path_was, path|
- # Don't attempt to move if original path only contains periods.
- next if path_was =~ /\A\.+\z/
-
- if gitlab_shell.mv_namespace(path_was, path)
- # If repositories moved successfully we need to remove old satellites
- # and send update instructions to users.
- # However we cannot allow rollback since we moved namespace dir
- # So we basically we mute exceptions in next actions
- begin
- gitlab_shell.rm_satellites(path_was)
- # We cannot send update instructions since models and mailers
- # can't safely be used from migrations as they may be written for
- # later versions of the database.
- # send_update_instructions
- rescue
- # Returning false does not rollback after_* transaction but gives
- # us information about failing some of tasks
- false
- end
- else
- # if we cannot move namespace directory we should rollback
- # db changes in order to prevent out of sync between db and fs
- raise Exception.new('namespace directory cannot be moved')
- end
- end
- end
-end
diff --git a/db/migrate/20150423033240_add_default_project_visibililty_to_application_settings.rb b/db/migrate/20150423033240_add_default_project_visibililty_to_application_settings.rb
deleted file mode 100644
index e0f35da422a..00000000000
--- a/db/migrate/20150423033240_add_default_project_visibililty_to_application_settings.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-class AddDefaultProjectVisibililtyToApplicationSettings < ActiveRecord::Migration[4.2]
- def up
- add_column :application_settings, :default_project_visibility, :integer
- visibility = Settings.gitlab.default_projects_features['visibility_level']
- execute("update application_settings set default_project_visibility = #{visibility}")
- end
-
- def down
- remove_column :application_settings, :default_project_visibility
- end
-end
diff --git a/db/migrate/20150425164646_gitlab_change_collation_for_tag_names.acts_as_taggable_on_engine.rb b/db/migrate/20150425164646_gitlab_change_collation_for_tag_names.acts_as_taggable_on_engine.rb
deleted file mode 100644
index 5b2e692eb17..00000000000
--- a/db/migrate/20150425164646_gitlab_change_collation_for_tag_names.acts_as_taggable_on_engine.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-# This migration is a duplicate of 20150425164651_change_collation_for_tag_names.acts_as_taggable_on_engine.rb
-# It shold be applied before the index additions to ensure that `name` is case sensitive.
-
-class GitlabChangeCollationForTagNames < ActiveRecord::Migration[4.2]
- def up
- if ActsAsTaggableOn::Utils.using_mysql?
- execute("ALTER TABLE tags MODIFY name varchar(255) CHARACTER SET utf8 COLLATE utf8_bin;")
- end
- end
-end
diff --git a/db/migrate/20150425164647_remove_duplicate_tags.rb b/db/migrate/20150425164647_remove_duplicate_tags.rb
deleted file mode 100644
index 5165eb65695..00000000000
--- a/db/migrate/20150425164647_remove_duplicate_tags.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-# rubocop:disable all
-class RemoveDuplicateTags < ActiveRecord::Migration[4.2]
- def up
- select_all("SELECT name, COUNT(id) as cnt FROM tags GROUP BY name HAVING COUNT(id) > 1").each do |tag|
- tag_name = quote_string(tag["name"])
- duplicate_ids = select_all("SELECT id FROM tags WHERE name = '#{tag_name}'").map{|tag| tag["id"]}
- origin_tag_id = duplicate_ids.first
- duplicate_ids.delete origin_tag_id
-
- execute("UPDATE taggings SET tag_id = #{origin_tag_id} WHERE tag_id IN(#{duplicate_ids.join(",")})")
- execute("DELETE FROM tags WHERE id IN(#{duplicate_ids.join(",")})")
- end
- end
-
- def down
-
- end
-end
diff --git a/db/migrate/20150425164648_add_missing_unique_indices.acts_as_taggable_on_engine.rb b/db/migrate/20150425164648_add_missing_unique_indices.acts_as_taggable_on_engine.rb
deleted file mode 100644
index d1951f640bb..00000000000
--- a/db/migrate/20150425164648_add_missing_unique_indices.acts_as_taggable_on_engine.rb
+++ /dev/null
@@ -1,28 +0,0 @@
-# rubocop:disable all
-# This migration comes from acts_as_taggable_on_engine (originally 2)
-class AddMissingUniqueIndices < ActiveRecord::Migration[4.2]
- def self.up
- add_index :tags, :name, unique: true
-
- # pre-GitLab v6.7.0 may not have these indices since there were no
- # migrations for them
- if index_exists?(:taggings, :tag_id)
- remove_index :taggings, :tag_id
- end
-
- if index_exists?(:taggings, [:taggable_id, :taggable_type, :context])
- remove_index :taggings, [:taggable_id, :taggable_type, :context]
- end
- add_index :taggings,
- [:tag_id, :taggable_id, :taggable_type, :context, :tagger_id, :tagger_type],
- unique: true, name: 'taggings_idx'
- end
-
- def self.down
- remove_index :tags, :name
-
- remove_index :taggings, name: 'taggings_idx'
- add_index :taggings, :tag_id
- add_index :taggings, [:taggable_id, :taggable_type, :context]
- end
-end
diff --git a/db/migrate/20150425164649_add_taggings_counter_cache_to_tags.acts_as_taggable_on_engine.rb b/db/migrate/20150425164649_add_taggings_counter_cache_to_tags.acts_as_taggable_on_engine.rb
deleted file mode 100644
index b9af394f09b..00000000000
--- a/db/migrate/20150425164649_add_taggings_counter_cache_to_tags.acts_as_taggable_on_engine.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-# rubocop:disable all
-# This migration comes from acts_as_taggable_on_engine (originally 3)
-class AddTaggingsCounterCacheToTags < ActiveRecord::Migration[4.2]
- def self.up
- add_column :tags, :taggings_count, :integer, default: 0
-
- ActsAsTaggableOn::Tag.reset_column_information
- ActsAsTaggableOn::Tag.find_each do |tag|
- ActsAsTaggableOn::Tag.reset_counters(tag.id, :taggings)
- end
- end
-
- def self.down
- remove_column :tags, :taggings_count
- end
-end
diff --git a/db/migrate/20150425164650_add_missing_taggable_index.acts_as_taggable_on_engine.rb b/db/migrate/20150425164650_add_missing_taggable_index.acts_as_taggable_on_engine.rb
deleted file mode 100644
index f28737615d7..00000000000
--- a/db/migrate/20150425164650_add_missing_taggable_index.acts_as_taggable_on_engine.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-# This migration comes from acts_as_taggable_on_engine (originally 4)
-class AddMissingTaggableIndex < ActiveRecord::Migration[4.2]
- def self.up
- add_index :taggings, [:taggable_id, :taggable_type, :context]
- end
-
- def self.down
- remove_index :taggings, [:taggable_id, :taggable_type, :context]
- end
-end
diff --git a/db/migrate/20150425164651_change_collation_for_tag_names.acts_as_taggable_on_engine.rb b/db/migrate/20150425164651_change_collation_for_tag_names.acts_as_taggable_on_engine.rb
deleted file mode 100644
index 4c144a8693f..00000000000
--- a/db/migrate/20150425164651_change_collation_for_tag_names.acts_as_taggable_on_engine.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-# This migration comes from acts_as_taggable_on_engine (originally 5)
-# This migration is added to circumvent issue #623 and have special characters
-# work properly
-class ChangeCollationForTagNames < ActiveRecord::Migration[4.2]
- def up
- if ActsAsTaggableOn::Utils.using_mysql?
- execute("ALTER TABLE tags MODIFY name varchar(255) CHARACTER SET utf8 COLLATE utf8_bin;")
- end
- end
-end
diff --git a/db/migrate/20150425173433_add_default_snippet_visibility_to_app_settings.rb b/db/migrate/20150425173433_add_default_snippet_visibility_to_app_settings.rb
deleted file mode 100644
index a3a86d26767..00000000000
--- a/db/migrate/20150425173433_add_default_snippet_visibility_to_app_settings.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-class AddDefaultSnippetVisibilityToAppSettings < ActiveRecord::Migration[4.2]
- def up
- add_column :application_settings, :default_snippet_visibility, :integer
- visibility = Settings.gitlab.default_projects_features['visibility_level']
- execute("update application_settings set default_snippet_visibility = #{visibility}")
- end
-
- def down
- remove_column :application_settings, :default_snippet_visibility
- end
-end
diff --git a/db/migrate/20150429002313_remove_abandoned_group_members_records.rb b/db/migrate/20150429002313_remove_abandoned_group_members_records.rb
deleted file mode 100644
index 370b807dd50..00000000000
--- a/db/migrate/20150429002313_remove_abandoned_group_members_records.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-class RemoveAbandonedGroupMembersRecords < ActiveRecord::Migration[4.2]
- def up
- execute("DELETE FROM members WHERE type = 'GroupMember' AND source_id NOT IN(\
- SELECT id FROM namespaces WHERE type='Group')")
- end
-
- def down
- end
-end
diff --git a/db/migrate/20150502064022_add_restricted_signup_domains_to_application_settings.rb b/db/migrate/20150502064022_add_restricted_signup_domains_to_application_settings.rb
deleted file mode 100644
index df777263ecb..00000000000
--- a/db/migrate/20150502064022_add_restricted_signup_domains_to_application_settings.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class AddRestrictedSignupDomainsToApplicationSettings < ActiveRecord::Migration[4.2]
- def change
- add_column :application_settings, :restricted_signup_domains, :text
- end
-end
diff --git a/db/migrate/20150509180749_convert_legacy_reference_notes.rb b/db/migrate/20150509180749_convert_legacy_reference_notes.rb
deleted file mode 100644
index 84d4eb9e51f..00000000000
--- a/db/migrate/20150509180749_convert_legacy_reference_notes.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-# Convert legacy Markdown-emphasized notes to the current, non-emphasized format
-#
-# _mentioned in 54f7727c850972f0401c1312a7c4a6a380de5666_
-#
-# becomes
-#
-# mentioned in 54f7727c850972f0401c1312a7c4a6a380de5666
-class ConvertLegacyReferenceNotes < ActiveRecord::Migration[4.2]
- def up
- quoted_column_name = ActiveRecord::Base.connection.quote_column_name('system')
- execute %Q{UPDATE notes SET note = trim(both '_' from note) WHERE #{quoted_column_name} = true AND note LIKE '\_%\_'}
- end
-
- def down
- # noop
- end
-end
diff --git a/db/migrate/20150516060434_add_note_events_to_web_hooks.rb b/db/migrate/20150516060434_add_note_events_to_web_hooks.rb
deleted file mode 100644
index ddf26240b8b..00000000000
--- a/db/migrate/20150516060434_add_note_events_to_web_hooks.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-# rubocop:disable all
-class AddNoteEventsToWebHooks < ActiveRecord::Migration[4.2]
- def up
- add_column :web_hooks, :note_events, :boolean, default: false, null: false
- end
-
- def down
- remove_column :web_hooks, :note_events, :boolean
- end
-end
diff --git a/db/migrate/20150529111607_add_user_oauth_applications_to_application_settings.rb b/db/migrate/20150529111607_add_user_oauth_applications_to_application_settings.rb
deleted file mode 100644
index 507e905acd6..00000000000
--- a/db/migrate/20150529111607_add_user_oauth_applications_to_application_settings.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class AddUserOauthApplicationsToApplicationSettings < ActiveRecord::Migration[4.2]
- def change
- add_column :application_settings, :user_oauth_applications, :bool, default: true
- end
-end
diff --git a/db/migrate/20150529150354_add_after_sign_out_path_for_application_settings.rb b/db/migrate/20150529150354_add_after_sign_out_path_for_application_settings.rb
deleted file mode 100644
index f43f20def5b..00000000000
--- a/db/migrate/20150529150354_add_after_sign_out_path_for_application_settings.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-# rubocop:disable all
-class AddAfterSignOutPathForApplicationSettings < ActiveRecord::Migration[4.2]
- def change
- add_column :application_settings, :after_sign_out_path, :string
- end
-end \ No newline at end of file
diff --git a/db/migrate/20150609141121_add_session_expire_delay_for_application_settings.rb b/db/migrate/20150609141121_add_session_expire_delay_for_application_settings.rb
deleted file mode 100644
index 93959a9010f..00000000000
--- a/db/migrate/20150609141121_add_session_expire_delay_for_application_settings.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-class AddSessionExpireDelayForApplicationSettings < ActiveRecord::Migration[4.2]
- def change
- unless column_exists?(:application_settings, :session_expire_delay)
- add_column :application_settings, :session_expire_delay, :integer, default: 10080, null: false
- end
- end
-end
diff --git a/db/migrate/20150610065936_add_dashboard_to_users.rb b/db/migrate/20150610065936_add_dashboard_to_users.rb
deleted file mode 100644
index a0bf5f31f00..00000000000
--- a/db/migrate/20150610065936_add_dashboard_to_users.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-# rubocop:disable all
-class AddDashboardToUsers < ActiveRecord::Migration[4.2]
- def up
- add_column :users, :dashboard, :integer, default: 0
- end
-
- def down
- remove_column :users, :dashboard
- end
-end
diff --git a/db/migrate/20150620233230_add_default_otp_required_for_login_value.rb b/db/migrate/20150620233230_add_default_otp_required_for_login_value.rb
deleted file mode 100644
index 4a085ff06f3..00000000000
--- a/db/migrate/20150620233230_add_default_otp_required_for_login_value.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-class AddDefaultOtpRequiredForLoginValue < ActiveRecord::Migration[4.2]
- def up
- execute %q{UPDATE users SET otp_required_for_login = FALSE WHERE otp_required_for_login IS NULL}
-
- change_column :users, :otp_required_for_login, :boolean, default: false, null: false
- end
-
- def down
- change_column :users, :otp_required_for_login, :boolean, null: true
- end
-end
diff --git a/db/migrate/20150713160110_add_project_view_to_users.rb b/db/migrate/20150713160110_add_project_view_to_users.rb
deleted file mode 100644
index fea63576187..00000000000
--- a/db/migrate/20150713160110_add_project_view_to_users.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-# rubocop:disable all
-class AddProjectViewToUsers < ActiveRecord::Migration[4.2]
- def change
- add_column :users, :project_view, :integer, default: 0
- end
-end
diff --git a/db/migrate/20150717130904_add_commits_count_to_project.rb b/db/migrate/20150717130904_add_commits_count_to_project.rb
deleted file mode 100644
index df6c88f2961..00000000000
--- a/db/migrate/20150717130904_add_commits_count_to_project.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-# rubocop:disable all
-class AddCommitsCountToProject < ActiveRecord::Migration[4.2]
- def change
- add_column :projects, :commit_count, :integer, default: 0
- end
-end
diff --git a/db/migrate/20150730122406_add_updated_by_to_issuables_and_notes.rb b/db/migrate/20150730122406_add_updated_by_to_issuables_and_notes.rb
deleted file mode 100644
index fab126c3d04..00000000000
--- a/db/migrate/20150730122406_add_updated_by_to_issuables_and_notes.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-class AddUpdatedByToIssuablesAndNotes < ActiveRecord::Migration[4.2]
- def change
- add_column :notes, :updated_by_id, :integer
- add_column :issues, :updated_by_id, :integer
- add_column :merge_requests, :updated_by_id, :integer
- end
-end
diff --git a/db/migrate/20150806104937_create_abuse_reports.rb b/db/migrate/20150806104937_create_abuse_reports.rb
deleted file mode 100644
index be4fe8d1cfd..00000000000
--- a/db/migrate/20150806104937_create_abuse_reports.rb
+++ /dev/null
@@ -1,14 +0,0 @@
-# rubocop:disable all
-class CreateAbuseReports < ActiveRecord::Migration[4.2]
- DOWNTIME = false
-
- def change
- create_table :abuse_reports do |t|
- t.integer :reporter_id
- t.integer :user_id
- t.text :message
-
- t.timestamps null: true
- end
- end
-end
diff --git a/db/migrate/20150812080800_add_settings_import_sources.rb b/db/migrate/20150812080800_add_settings_import_sources.rb
deleted file mode 100644
index 59db31c868a..00000000000
--- a/db/migrate/20150812080800_add_settings_import_sources.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-# rubocop:disable all
-require 'yaml'
-
-class AddSettingsImportSources < ActiveRecord::Migration[4.2]
- def change
- unless column_exists?(:application_settings, :import_sources)
- add_column :application_settings, :import_sources, :text
- import_sources = YAML::dump(Settings.gitlab['import_sources'])
- execute("update application_settings set import_sources = '#{import_sources}'")
- end
- end
-end
diff --git a/db/migrate/20150814065925_remove_oauth_tokens_from_users.rb b/db/migrate/20150814065925_remove_oauth_tokens_from_users.rb
deleted file mode 100644
index f0080ee0b46..00000000000
--- a/db/migrate/20150814065925_remove_oauth_tokens_from_users.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-# rubocop:disable all
-class RemoveOauthTokensFromUsers < ActiveRecord::Migration[4.2]
- def change
- remove_column :users, :github_access_token, :string
- remove_column :users, :gitlab_access_token, :string
- remove_column :users, :bitbucket_access_token, :string
- remove_column :users, :bitbucket_access_token_secret, :string
- end
-end
diff --git a/db/migrate/20150817163600_deduplicate_user_identities.rb b/db/migrate/20150817163600_deduplicate_user_identities.rb
deleted file mode 100644
index 973a87e07ea..00000000000
--- a/db/migrate/20150817163600_deduplicate_user_identities.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-# rubocop:disable all
-class DeduplicateUserIdentities < ActiveRecord::Migration[4.2]
- def change
- execute 'DROP TABLE IF EXISTS tt_migration_DeduplicateUserIdentities;'
- execute 'CREATE TABLE tt_migration_DeduplicateUserIdentities AS SELECT id,provider,user_id FROM identities;'
- execute 'DELETE FROM identities WHERE id NOT IN ( SELECT MIN(id) FROM tt_migration_DeduplicateUserIdentities GROUP BY user_id, provider);'
- execute 'DROP TABLE IF EXISTS tt_migration_DeduplicateUserIdentities;'
- end
-
- def down
- # This is an irreversible migration;
- # If someone is trying to rollback for other reasons, we should not throw an Exception.
- # raise ActiveRecord::IrreversibleMigration
- end
-end
diff --git a/db/migrate/20150818213832_add_sent_notifications.rb b/db/migrate/20150818213832_add_sent_notifications.rb
deleted file mode 100644
index 45e95a843e1..00000000000
--- a/db/migrate/20150818213832_add_sent_notifications.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-class AddSentNotifications < ActiveRecord::Migration[4.2]
- def change
- create_table :sent_notifications do |t|
- t.references :project
- t.references :noteable, polymorphic: true
- t.references :recipient
- t.string :commit_id
- t.string :reply_key, null: false
- end
-
- add_index :sent_notifications, :reply_key, unique: true
- end
-end
diff --git a/db/migrate/20150824002011_add_enable_ssl_verification.rb b/db/migrate/20150824002011_add_enable_ssl_verification.rb
deleted file mode 100644
index 2d877914f39..00000000000
--- a/db/migrate/20150824002011_add_enable_ssl_verification.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-# rubocop:disable all
-class AddEnableSslVerification < ActiveRecord::Migration[4.2]
- def change
- add_column :web_hooks, :enable_ssl_verification, :boolean, default: false
- end
-end
diff --git a/db/migrate/20150826001931_add_ci_tables.rb b/db/migrate/20150826001931_add_ci_tables.rb
deleted file mode 100644
index aa2af44a15b..00000000000
--- a/db/migrate/20150826001931_add_ci_tables.rb
+++ /dev/null
@@ -1,191 +0,0 @@
-# rubocop:disable all
-class AddCiTables < ActiveRecord::Migration[4.2]
- def change
- create_table "ci_application_settings", force: true do |t|
- t.boolean "all_broken_builds"
- t.boolean "add_pusher"
- t.datetime "created_at"
- t.datetime "updated_at"
- end
-
- create_table "ci_builds", force: true do |t|
- t.integer "project_id"
- t.string "status"
- t.datetime "finished_at"
- t.text "trace"
- t.datetime "created_at"
- t.datetime "updated_at"
- t.datetime "started_at"
- t.integer "runner_id"
- t.float "coverage"
- t.integer "commit_id"
- t.text "commands"
- t.integer "job_id"
- t.string "name"
- t.boolean "deploy", default: false
- t.text "options"
- t.boolean "allow_failure", default: false, null: false
- t.string "stage"
- t.integer "trigger_request_id"
- end
-
- add_index "ci_builds", ["commit_id"], name: "index_ci_builds_on_commit_id", using: :btree
- add_index "ci_builds", ["project_id", "commit_id"], name: "index_ci_builds_on_project_id_and_commit_id", using: :btree
- add_index "ci_builds", ["project_id"], name: "index_ci_builds_on_project_id", using: :btree
- add_index "ci_builds", ["runner_id"], name: "index_ci_builds_on_runner_id", using: :btree
-
- create_table "ci_commits", force: true do |t|
- t.integer "project_id"
- t.string "ref"
- t.string "sha"
- t.string "before_sha"
- t.text "push_data"
- t.datetime "created_at"
- t.datetime "updated_at"
- t.boolean "tag", default: false
- t.text "yaml_errors"
- t.datetime "committed_at"
- end
-
- add_index "ci_commits", ["project_id", "committed_at"], name: "index_ci_commits_on_project_id_and_committed_at", using: :btree
- add_index "ci_commits", ["project_id", "sha"], name: "index_ci_commits_on_project_id_and_sha", using: :btree
- add_index "ci_commits", ["project_id"], name: "index_ci_commits_on_project_id", using: :btree
- add_index "ci_commits", ["sha"], name: "index_ci_commits_on_sha", using: :btree
-
- create_table "ci_events", force: true do |t|
- t.integer "project_id"
- t.integer "user_id"
- t.integer "is_admin"
- t.text "description"
- t.datetime "created_at"
- t.datetime "updated_at"
- end
-
- add_index "ci_events", ["created_at"], name: "index_ci_events_on_created_at", using: :btree
- add_index "ci_events", ["is_admin"], name: "index_ci_events_on_is_admin", using: :btree
- add_index "ci_events", ["project_id"], name: "index_ci_events_on_project_id", using: :btree
-
- create_table "ci_jobs", force: true do |t|
- t.integer "project_id", null: false
- t.text "commands"
- t.boolean "active", default: true, null: false
- t.datetime "created_at"
- t.datetime "updated_at"
- t.string "name"
- t.boolean "build_branches", default: true, null: false
- t.boolean "build_tags", default: false, null: false
- t.string "job_type", default: "parallel"
- t.string "refs"
- t.datetime "deleted_at"
- end
-
- add_index "ci_jobs", ["deleted_at"], name: "index_ci_jobs_on_deleted_at", using: :btree
- add_index "ci_jobs", ["project_id"], name: "index_ci_jobs_on_project_id", using: :btree
-
- create_table "ci_projects", force: true do |t|
- t.string "name", null: false
- t.integer "timeout", default: 3600, null: false
- t.datetime "created_at"
- t.datetime "updated_at"
- t.string "token"
- t.string "default_ref"
- t.string "path"
- t.boolean "always_build", default: false, null: false
- t.integer "polling_interval"
- t.boolean "public", default: false, null: false
- t.string "ssh_url_to_repo"
- t.integer "gitlab_id"
- t.boolean "allow_git_fetch", default: true, null: false
- t.string "email_recipients", default: "", null: false
- t.boolean "email_add_pusher", default: true, null: false
- t.boolean "email_only_broken_builds", default: true, null: false
- t.string "skip_refs"
- t.string "coverage_regex"
- t.boolean "shared_runners_enabled", default: false
- t.text "generated_yaml_config"
- end
-
- create_table "ci_runner_projects", force: true do |t|
- t.integer "runner_id", null: false
- t.integer "project_id", null: false
- t.datetime "created_at"
- t.datetime "updated_at"
- end
-
- add_index "ci_runner_projects", ["project_id"], name: "index_ci_runner_projects_on_project_id", using: :btree
- add_index "ci_runner_projects", ["runner_id"], name: "index_ci_runner_projects_on_runner_id", using: :btree
-
- create_table "ci_runners", force: true do |t|
- t.string "token"
- t.datetime "created_at"
- t.datetime "updated_at"
- t.string "description"
- t.datetime "contacted_at"
- t.boolean "active", default: true, null: false
- t.boolean "is_shared", default: false
- t.string "name"
- t.string "version"
- t.string "revision"
- t.string "platform"
- t.string "architecture"
- end
-
- create_table "ci_services", force: true do |t|
- t.string "type"
- t.string "title"
- t.integer "project_id", null: false
- t.datetime "created_at"
- t.datetime "updated_at"
- t.boolean "active", default: false, null: false
- t.text "properties"
- end
-
- add_index "ci_services", ["project_id"], name: "index_ci_services_on_project_id", using: :btree
-
- create_table "ci_sessions", force: true do |t|
- t.string "session_id", null: false
- t.text "data"
- t.datetime "created_at"
- t.datetime "updated_at"
- end
-
- add_index "ci_sessions", ["session_id"], name: "index_ci_sessions_on_session_id", using: :btree
- add_index "ci_sessions", ["updated_at"], name: "index_ci_sessions_on_updated_at", using: :btree
-
- create_table "ci_trigger_requests", force: true do |t|
- t.integer "trigger_id", null: false
- t.text "variables"
- t.datetime "created_at"
- t.datetime "updated_at"
- t.integer "commit_id"
- end
-
- create_table "ci_triggers", force: true do |t|
- t.string "token"
- t.integer "project_id", null: false
- t.datetime "deleted_at"
- t.datetime "created_at"
- t.datetime "updated_at"
- end
-
- add_index "ci_triggers", ["deleted_at"], name: "index_ci_triggers_on_deleted_at", using: :btree
-
- create_table "ci_variables", force: true do |t|
- t.integer "project_id", null: false
- t.string "key"
- t.text "value"
- t.text "encrypted_value"
- t.string "encrypted_value_salt"
- t.string "encrypted_value_iv"
- end
-
- add_index "ci_variables", ["project_id"], name: "index_ci_variables_on_project_id", using: :btree
-
- create_table "ci_web_hooks", force: true do |t|
- t.string "url", null: false
- t.integer "project_id", null: false
- t.datetime "created_at"
- t.datetime "updated_at"
- end
- end
-end
diff --git a/db/migrate/20150827121444_add_fast_forward_option_to_project.rb b/db/migrate/20150827121444_add_fast_forward_option_to_project.rb
deleted file mode 100644
index bf7db2fb12b..00000000000
--- a/db/migrate/20150827121444_add_fast_forward_option_to_project.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-# rubocop:disable all
-class AddFastForwardOptionToProject < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- # We put condition here because of a mistake we made a couple of years ago
- # see https://gitlab.com/gitlab-org/gitlab-ce/issues/39382#note_45716103
- unless column_exists?(:projects, :merge_requests_ff_only_enabled)
- add_column_with_default(:projects, :merge_requests_ff_only_enabled, :boolean, default: false)
- end
- end
-
- def down
- if column_exists?(:projects, :merge_requests_ff_only_enabled)
- remove_column(:projects, :merge_requests_ff_only_enabled)
- end
- end
-end
diff --git a/db/migrate/20150902001023_add_template_to_label.rb b/db/migrate/20150902001023_add_template_to_label.rb
deleted file mode 100644
index 10769f29baa..00000000000
--- a/db/migrate/20150902001023_add_template_to_label.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-# rubocop:disable all
-class AddTemplateToLabel < ActiveRecord::Migration[4.2]
- def change
- add_column :labels, :template, :boolean, default: false
- end
-end \ No newline at end of file
diff --git a/db/migrate/20150914215247_add_ci_tags.rb b/db/migrate/20150914215247_add_ci_tags.rb
deleted file mode 100644
index 9afa4540540..00000000000
--- a/db/migrate/20150914215247_add_ci_tags.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-# rubocop:disable all
-class AddCiTags < ActiveRecord::Migration[4.2]
- def change
- create_table "ci_taggings", force: true do |t|
- t.integer "tag_id"
- t.integer "taggable_id"
- t.string "taggable_type"
- t.integer "tagger_id"
- t.string "tagger_type"
- t.string "context", limit: 128
- t.datetime "created_at"
- end
-
- add_index "ci_taggings", ["tag_id", "taggable_id", "taggable_type", "context", "tagger_id", "tagger_type"], name: "ci_taggings_idx", unique: true, using: :btree
- add_index "ci_taggings", ["taggable_id", "taggable_type", "context"], name: "index_ci_taggings_on_taggable_id_and_taggable_type_and_context", using: :btree
-
- create_table "ci_tags", force: true do |t|
- t.string "name"
- t.integer "taggings_count", default: 0
- end
-
- add_index "ci_tags", ["name"], name: "index_ci_tags_on_name", unique: true, using: :btree
- end
-end
diff --git a/db/migrate/20150915001905_enable_ssl_verification_by_default.rb b/db/migrate/20150915001905_enable_ssl_verification_by_default.rb
deleted file mode 100644
index ddd07179753..00000000000
--- a/db/migrate/20150915001905_enable_ssl_verification_by_default.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class EnableSslVerificationByDefault < ActiveRecord::Migration[4.2]
- def change
- change_column :web_hooks, :enable_ssl_verification, :boolean, default: true
- end
-end
diff --git a/db/migrate/20150916000405_enable_ssl_verification_for_web_hooks.rb b/db/migrate/20150916000405_enable_ssl_verification_for_web_hooks.rb
deleted file mode 100644
index 49081c9d749..00000000000
--- a/db/migrate/20150916000405_enable_ssl_verification_for_web_hooks.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-class EnableSslVerificationForWebHooks < ActiveRecord::Migration[4.2]
- def up
- execute("UPDATE web_hooks SET enable_ssl_verification = true")
- end
-
- def down
- end
-end
diff --git a/db/migrate/20150916114643_add_help_page_text_to_application_settings.rb b/db/migrate/20150916114643_add_help_page_text_to_application_settings.rb
deleted file mode 100644
index 52867632880..00000000000
--- a/db/migrate/20150916114643_add_help_page_text_to_application_settings.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class AddHelpPageTextToApplicationSettings < ActiveRecord::Migration[4.2]
- def change
- add_column :application_settings, :help_page_text, :text
- end
-end
diff --git a/db/migrate/20150916145038_add_index_for_committed_at_and_id.rb b/db/migrate/20150916145038_add_index_for_committed_at_and_id.rb
deleted file mode 100644
index bf78aacd9f4..00000000000
--- a/db/migrate/20150916145038_add_index_for_committed_at_and_id.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-# rubocop:disable all
-class AddIndexForCommittedAtAndId < ActiveRecord::Migration[4.2]
- def change
- add_index :ci_commits, [:project_id, :committed_at, :id]
- end
-end
diff --git a/db/migrate/20150918084513_add_ci_enabled_to_application_settings.rb b/db/migrate/20150918084513_add_ci_enabled_to_application_settings.rb
deleted file mode 100644
index 153c1a798c3..00000000000
--- a/db/migrate/20150918084513_add_ci_enabled_to_application_settings.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class AddCiEnabledToApplicationSettings < ActiveRecord::Migration[4.2]
- def change
- add_column :application_settings, :ci_enabled, :boolean, null: false, default: true
- end
-end
diff --git a/db/migrate/20150918161719_remove_invalid_milestones_from_merge_requests.rb b/db/migrate/20150918161719_remove_invalid_milestones_from_merge_requests.rb
deleted file mode 100644
index 52651e16324..00000000000
--- a/db/migrate/20150918161719_remove_invalid_milestones_from_merge_requests.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class RemoveInvalidMilestonesFromMergeRequests < ActiveRecord::Migration[4.2]
- def up
- execute("UPDATE merge_requests SET milestone_id = NULL where milestone_id NOT IN (SELECT id FROM milestones)")
- end
-end
diff --git a/db/migrate/20150920010715_add_consumed_timestep_to_users.rb b/db/migrate/20150920010715_add_consumed_timestep_to_users.rb
deleted file mode 100644
index c69944b1e94..00000000000
--- a/db/migrate/20150920010715_add_consumed_timestep_to_users.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class AddConsumedTimestepToUsers < ActiveRecord::Migration[4.2]
- def change
- add_column :users, :consumed_timestep, :integer
- end
-end
diff --git a/db/migrate/20150920161119_add_line_code_to_sent_notification.rb b/db/migrate/20150920161119_add_line_code_to_sent_notification.rb
deleted file mode 100644
index 671476f0b07..00000000000
--- a/db/migrate/20150920161119_add_line_code_to_sent_notification.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class AddLineCodeToSentNotification < ActiveRecord::Migration[4.2]
- def change
- add_column :sent_notifications, :line_code, :string
- end
-end
diff --git a/db/migrate/20150924125150_add_project_id_to_ci_commit.rb b/db/migrate/20150924125150_add_project_id_to_ci_commit.rb
deleted file mode 100644
index c9f16b0f3f9..00000000000
--- a/db/migrate/20150924125150_add_project_id_to_ci_commit.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class AddProjectIdToCiCommit < ActiveRecord::Migration[4.2]
- def up
- add_column :ci_commits, :gl_project_id, :integer
- end
-end
diff --git a/db/migrate/20150924125436_migrate_project_id_for_ci_commits.rb b/db/migrate/20150924125436_migrate_project_id_for_ci_commits.rb
deleted file mode 100644
index ff31e70874f..00000000000
--- a/db/migrate/20150924125436_migrate_project_id_for_ci_commits.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-class MigrateProjectIdForCiCommits < ActiveRecord::Migration[4.2]
- def up
- subquery = 'SELECT gitlab_id FROM ci_projects WHERE ci_projects.id = ci_commits.project_id'
- execute("UPDATE ci_commits SET gl_project_id=(#{subquery}) WHERE gl_project_id IS NULL")
- end
-end
diff --git a/db/migrate/20150930001110_merge_request_error_field.rb b/db/migrate/20150930001110_merge_request_error_field.rb
deleted file mode 100644
index 30f012b0a92..00000000000
--- a/db/migrate/20150930001110_merge_request_error_field.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class MergeRequestErrorField < ActiveRecord::Migration[4.2]
- def up
- add_column :merge_requests, :merge_error, :string
- end
-end
diff --git a/db/migrate/20150930095736_add_null_to_name_for_ci_projects.rb b/db/migrate/20150930095736_add_null_to_name_for_ci_projects.rb
deleted file mode 100644
index 181f9f059ac..00000000000
--- a/db/migrate/20150930095736_add_null_to_name_for_ci_projects.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-class AddNullToNameForCiProjects < ActiveRecord::Migration[4.2]
- def up
- change_column_null :ci_projects, :name, true
- end
-
- def down
- change_column_null :ci_projects, :name, false
- end
-end
diff --git a/db/migrate/20150930110012_add_group_share_lock.rb b/db/migrate/20150930110012_add_group_share_lock.rb
deleted file mode 100644
index 62755765457..00000000000
--- a/db/migrate/20150930110012_add_group_share_lock.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-# rubocop:disable all
-class AddGroupShareLock < ActiveRecord::Migration[4.2]
- def change
- add_column :namespaces, :share_with_group_lock, :boolean, default: false
- end
-end
diff --git a/db/migrate/20151002112914_add_stage_idx_to_builds.rb b/db/migrate/20151002112914_add_stage_idx_to_builds.rb
deleted file mode 100644
index f73df9dc284..00000000000
--- a/db/migrate/20151002112914_add_stage_idx_to_builds.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class AddStageIdxToBuilds < ActiveRecord::Migration[4.2]
- def change
- add_column :ci_builds, :stage_idx, :integer
- end
-end
diff --git a/db/migrate/20151002121400_add_index_for_builds.rb b/db/migrate/20151002121400_add_index_for_builds.rb
deleted file mode 100644
index 5e6f80a1d3d..00000000000
--- a/db/migrate/20151002121400_add_index_for_builds.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-# rubocop:disable all
-class AddIndexForBuilds < ActiveRecord::Migration[4.2]
- def up
- add_index :ci_builds, [:commit_id, :stage_idx, :created_at]
- end
-end
diff --git a/db/migrate/20151002122929_add_ref_and_tag_to_builds.rb b/db/migrate/20151002122929_add_ref_and_tag_to_builds.rb
deleted file mode 100644
index ea41921b6ee..00000000000
--- a/db/migrate/20151002122929_add_ref_and_tag_to_builds.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-class AddRefAndTagToBuilds < ActiveRecord::Migration[4.2]
- def change
- add_column :ci_builds, :tag, :boolean
- add_column :ci_builds, :ref, :string
- end
-end
diff --git a/db/migrate/20151002122943_migrate_ref_and_tag_to_build.rb b/db/migrate/20151002122943_migrate_ref_and_tag_to_build.rb
deleted file mode 100644
index b4038e6fa83..00000000000
--- a/db/migrate/20151002122943_migrate_ref_and_tag_to_build.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-# rubocop:disable all
-class MigrateRefAndTagToBuild < ActiveRecord::Migration[4.2]
- def change
- execute('UPDATE ci_builds SET ref=(SELECT ref FROM ci_commits WHERE ci_commits.id = ci_builds.commit_id) WHERE ref IS NULL')
- execute('UPDATE ci_builds SET tag=(SELECT tag FROM ci_commits WHERE ci_commits.id = ci_builds.commit_id) WHERE tag IS NULL')
- end
-end
diff --git a/db/migrate/20151005075649_add_user_id_to_build.rb b/db/migrate/20151005075649_add_user_id_to_build.rb
deleted file mode 100644
index 45372bf7cba..00000000000
--- a/db/migrate/20151005075649_add_user_id_to_build.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class AddUserIdToBuild < ActiveRecord::Migration[4.2]
- def change
- add_column :ci_builds, :user_id, :integer
- end
-end
diff --git a/db/migrate/20151005150751_add_layout_option_for_users.rb b/db/migrate/20151005150751_add_layout_option_for_users.rb
deleted file mode 100644
index 66cba21320a..00000000000
--- a/db/migrate/20151005150751_add_layout_option_for_users.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-# rubocop:disable all
-class AddLayoutOptionForUsers < ActiveRecord::Migration[4.2]
- def change
- add_column :users, :layout, :integer, default: 0
- end
-end \ No newline at end of file
diff --git a/db/migrate/20151005162154_remove_ci_enabled_from_application_settings.rb b/db/migrate/20151005162154_remove_ci_enabled_from_application_settings.rb
deleted file mode 100644
index a8e6e54062a..00000000000
--- a/db/migrate/20151005162154_remove_ci_enabled_from_application_settings.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-# rubocop:disable all
-class RemoveCiEnabledFromApplicationSettings < ActiveRecord::Migration[4.2]
- def change
- remove_column :application_settings, :ci_enabled, :boolean, null: false, default: true
- end
-end
diff --git a/db/migrate/20151007120511_namespaces_projects_path_lower_indexes.rb b/db/migrate/20151007120511_namespaces_projects_path_lower_indexes.rb
deleted file mode 100644
index d6c21bf8639..00000000000
--- a/db/migrate/20151007120511_namespaces_projects_path_lower_indexes.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-# rubocop:disable all
-class NamespacesProjectsPathLowerIndexes < ActiveRecord::Migration[4.2]
- disable_ddl_transaction!
-
- def up
- return unless Gitlab::Database.postgresql?
-
- execute 'CREATE INDEX CONCURRENTLY index_on_namespaces_lower_path ON namespaces (LOWER(path));'
- execute 'CREATE INDEX CONCURRENTLY index_on_projects_lower_path ON projects (LOWER(path));'
- end
-
- def down
- return unless Gitlab::Database.postgresql?
-
- remove_index :namespaces, name: :index_on_namespaces_lower_path
- remove_index :projects, name: :index_on_projects_lower_path
- end
-end
diff --git a/db/migrate/20151008110232_add_users_lower_username_email_indexes.rb b/db/migrate/20151008110232_add_users_lower_username_email_indexes.rb
deleted file mode 100644
index 2ba1a6146e2..00000000000
--- a/db/migrate/20151008110232_add_users_lower_username_email_indexes.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-# rubocop:disable all
-class AddUsersLowerUsernameEmailIndexes < ActiveRecord::Migration[4.2]
- disable_ddl_transaction!
-
- def up
- return unless Gitlab::Database.postgresql?
-
- execute 'CREATE INDEX CONCURRENTLY index_on_users_lower_username ON users (LOWER(username));'
- execute 'CREATE INDEX CONCURRENTLY index_on_users_lower_email ON users (LOWER(email));'
- end
-
- def down
- return unless Gitlab::Database.postgresql?
-
- remove_index :users, :index_on_users_lower_username
- remove_index :users, :index_on_users_lower_email
- end
-end
diff --git a/db/migrate/20151008123042_add_type_and_description_to_builds.rb b/db/migrate/20151008123042_add_type_and_description_to_builds.rb
deleted file mode 100644
index 309655cf195..00000000000
--- a/db/migrate/20151008123042_add_type_and_description_to_builds.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-# rubocop:disable all
-class AddTypeAndDescriptionToBuilds < ActiveRecord::Migration[4.2]
- def change
- add_column :ci_builds, :type, :string
- add_column :ci_builds, :target_url, :string
- add_column :ci_builds, :description, :string
- add_index :ci_builds, [:commit_id, :type, :ref]
- add_index :ci_builds, [:commit_id, :type, :name, :ref]
- end
-end
diff --git a/db/migrate/20151008130321_migrate_name_to_description_for_builds.rb b/db/migrate/20151008130321_migrate_name_to_description_for_builds.rb
deleted file mode 100644
index f4445277a6f..00000000000
--- a/db/migrate/20151008130321_migrate_name_to_description_for_builds.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-# rubocop:disable all
-class MigrateNameToDescriptionForBuilds < ActiveRecord::Migration[4.2]
- def change
- execute("UPDATE ci_builds SET type='Ci::Build' WHERE type IS NULL")
- end
-end
diff --git a/db/migrate/20151008143519_add_admin_notification_email_setting.rb b/db/migrate/20151008143519_add_admin_notification_email_setting.rb
deleted file mode 100644
index 60e0986e5a8..00000000000
--- a/db/migrate/20151008143519_add_admin_notification_email_setting.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class AddAdminNotificationEmailSetting < ActiveRecord::Migration[4.2]
- def change
- add_column :application_settings, :admin_notification_email, :string
- end
-end
diff --git a/db/migrate/20151012173029_set_jira_service_api_url.rb b/db/migrate/20151012173029_set_jira_service_api_url.rb
deleted file mode 100644
index 91cc6bbc783..00000000000
--- a/db/migrate/20151012173029_set_jira_service_api_url.rb
+++ /dev/null
@@ -1,51 +0,0 @@
-# rubocop:disable all
-class SetJiraServiceApiUrl < ActiveRecord::Migration[4.2]
- # This migration can be performed online without errors, but some Jira API calls may be missed
- # when doing so because api_url is not yet available.
-
- def build_api_url_from_project_url(project_url, api_version)
- # this is the exact logic previously used to build the Jira API URL from project_url
- server = URI(project_url)
- default_ports = [80, 443].include?(server.port)
- server_url = "#{server.scheme}://#{server.host}"
- server_url.concat(":#{server.port}") unless default_ports
- "#{server_url}/rest/api/#{api_version}"
- end
-
- def get_api_version_from_api_url(api_url)
- match = /\/rest\/api\/(?<api_version>\w+)$/.match(api_url)
- match && match['api_version']
- end
-
- def change
- reversible do |dir|
- select_all("SELECT id, properties FROM services WHERE services.type IN ('JiraService')").each do |jira_service|
- id = jira_service["id"]
- properties = JSON.parse(jira_service["properties"])
- properties_was = properties.clone
-
- dir.up do
- # remove api_version and set api_url
- if properties['api_version'].present? && properties['project_url'].present?
- begin
- properties['api_url'] ||= build_api_url_from_project_url(properties['project_url'], properties['api_version'])
- rescue
- # looks like project_url was not a valid URL. Do nothing.
- end
- end
- properties.delete('api_version') if properties.include?('api_version')
- end
-
- dir.down do
- # remove api_url and set api_version (default to '2')
- properties['api_version'] ||= get_api_version_from_api_url(properties['api_url']) || '2'
- properties.delete('api_url') if properties.include?('api_url')
- end
-
- if properties != properties_was
- execute("UPDATE services SET properties = '#{quote_string(properties.to_json)}' WHERE id = #{id}")
- end
- end
- end
- end
-end
diff --git a/db/migrate/20151013092124_add_artifacts_file_to_builds.rb b/db/migrate/20151013092124_add_artifacts_file_to_builds.rb
deleted file mode 100644
index 3936386a2c0..00000000000
--- a/db/migrate/20151013092124_add_artifacts_file_to_builds.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class AddArtifactsFileToBuilds < ActiveRecord::Migration[4.2]
- def change
- add_column :ci_builds, :artifacts_file, :text
- end
-end
diff --git a/db/migrate/20151016131433_add_ci_projects_gl_project_id_index.rb b/db/migrate/20151016131433_add_ci_projects_gl_project_id_index.rb
deleted file mode 100644
index a9290fef11a..00000000000
--- a/db/migrate/20151016131433_add_ci_projects_gl_project_id_index.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-# rubocop:disable all
-class AddCiProjectsGlProjectIdIndex < ActiveRecord::Migration[4.2]
- def change
- add_index :ci_commits, :gl_project_id
- end
-end
diff --git a/db/migrate/20151016195451_add_ci_builds_and_projects_indexes.rb b/db/migrate/20151016195451_add_ci_builds_and_projects_indexes.rb
deleted file mode 100644
index c8a79f25ae5..00000000000
--- a/db/migrate/20151016195451_add_ci_builds_and_projects_indexes.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-# rubocop:disable all
-class AddCiBuildsAndProjectsIndexes < ActiveRecord::Migration[4.2]
- def change
- add_index :ci_projects, :gitlab_id
- add_index :ci_projects, :shared_runners_enabled
-
- add_index :ci_builds, :type
- add_index :ci_builds, :status
- end
-end
diff --git a/db/migrate/20151016195706_add_notes_line_code_index.rb b/db/migrate/20151016195706_add_notes_line_code_index.rb
deleted file mode 100644
index 0a3ad103009..00000000000
--- a/db/migrate/20151016195706_add_notes_line_code_index.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-# rubocop:disable all
-class AddNotesLineCodeIndex < ActiveRecord::Migration[4.2]
- def change
- add_index :notes, :line_code
- end
-end
diff --git a/db/migrate/20151019111551_fix_build_tags.rb b/db/migrate/20151019111551_fix_build_tags.rb
deleted file mode 100644
index 3c64388314d..00000000000
--- a/db/migrate/20151019111551_fix_build_tags.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-class FixBuildTags < ActiveRecord::Migration[4.2]
- def up
- execute("UPDATE taggings SET taggable_type='CommitStatus' WHERE taggable_type='Ci::Build'")
- end
-
- def down
- execute("UPDATE taggings SET taggable_type='Ci::Build' WHERE taggable_type='CommitStatus'")
- end
-end
diff --git a/db/migrate/20151019111703_fail_build_without_names.rb b/db/migrate/20151019111703_fail_build_without_names.rb
deleted file mode 100644
index 2dc9ffa32b9..00000000000
--- a/db/migrate/20151019111703_fail_build_without_names.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-class FailBuildWithoutNames < ActiveRecord::Migration[4.2]
- def up
- execute("UPDATE ci_builds SET status='failed' WHERE name IS NULL AND status='pending'")
- end
-
- def down
- end
-end
diff --git a/db/migrate/20151020145526_add_services_template_index.rb b/db/migrate/20151020145526_add_services_template_index.rb
deleted file mode 100644
index 24c373855e2..00000000000
--- a/db/migrate/20151020145526_add_services_template_index.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-# rubocop:disable all
-class AddServicesTemplateIndex < ActiveRecord::Migration[4.2]
- def change
- add_index :services, :template
- end
-end
diff --git a/db/migrate/20151020173516_ci_limits_to_mysql.rb b/db/migrate/20151020173516_ci_limits_to_mysql.rb
deleted file mode 100644
index 573922b851b..00000000000
--- a/db/migrate/20151020173516_ci_limits_to_mysql.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-class CiLimitsToMysql < ActiveRecord::Migration[4.2]
- def change
- return unless ActiveRecord::Base.configurations[Rails.env]['adapter'] =~ /^mysql/
-
- # CI
- change_column :ci_builds, :trace, :text, limit: 1073741823
- change_column :ci_commits, :push_data, :text, limit: 16777215
- end
-end
diff --git a/db/migrate/20151020173906_add_ci_builds_index_for_status.rb b/db/migrate/20151020173906_add_ci_builds_index_for_status.rb
deleted file mode 100644
index 231fc4f2a17..00000000000
--- a/db/migrate/20151020173906_add_ci_builds_index_for_status.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-# rubocop:disable all
-class AddCiBuildsIndexForStatus < ActiveRecord::Migration[4.2]
- def change
- add_index :ci_builds, [:commit_id, :status, :type]
- end
-end
diff --git a/db/migrate/20151023112551_fail_build_with_empty_name.rb b/db/migrate/20151023112551_fail_build_with_empty_name.rb
deleted file mode 100644
index 28f531463bc..00000000000
--- a/db/migrate/20151023112551_fail_build_with_empty_name.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-class FailBuildWithEmptyName < ActiveRecord::Migration[4.2]
- def up
- execute("UPDATE ci_builds SET status='failed' WHERE (name IS NULL OR name='') AND status='pending'")
- end
-
- def down
- end
-end
diff --git a/db/migrate/20151023144219_remove_satellites.rb b/db/migrate/20151023144219_remove_satellites.rb
deleted file mode 100644
index 2d1310b0208..00000000000
--- a/db/migrate/20151023144219_remove_satellites.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-require 'fileutils'
-
-class RemoveSatellites < ActiveRecord::Migration[4.2]
- def up
- satellites = Gitlab.config['satellites']
- return if satellites.nil?
-
- satellites_path = satellites['path']
- return if satellites_path.nil?
-
- FileUtils.rm_rf(satellites_path)
- end
-
- def down
- # Do nothing
- end
-end
diff --git a/db/migrate/20151026182941_add_project_path_index.rb b/db/migrate/20151026182941_add_project_path_index.rb
deleted file mode 100644
index bf0444450cd..00000000000
--- a/db/migrate/20151026182941_add_project_path_index.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-# rubocop:disable all
-class AddProjectPathIndex < ActiveRecord::Migration[4.2]
- def up
- add_index :projects, :path
- end
-
- def down
- remove_index :projects, :path
- end
-end
diff --git a/db/migrate/20151028152939_add_merge_when_build_succeeds_to_merge_request.rb b/db/migrate/20151028152939_add_merge_when_build_succeeds_to_merge_request.rb
deleted file mode 100644
index 5b11a430e30..00000000000
--- a/db/migrate/20151028152939_add_merge_when_build_succeeds_to_merge_request.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-# rubocop:disable all
-class AddMergeWhenBuildSucceedsToMergeRequest < ActiveRecord::Migration[4.2]
- def change
- add_column :merge_requests, :merge_params, :text
- add_column :merge_requests, :merge_when_build_succeeds, :boolean, default: false, null: false
- add_column :merge_requests, :merge_user_id, :integer
- end
-end
diff --git a/db/migrate/20151103001141_add_public_to_group.rb b/db/migrate/20151103001141_add_public_to_group.rb
deleted file mode 100644
index a5590bc1adc..00000000000
--- a/db/migrate/20151103001141_add_public_to_group.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-# rubocop:disable all
-class AddPublicToGroup < ActiveRecord::Migration[4.2]
- def change
- add_column :namespaces, :public, :boolean, default: false
- end
-end
diff --git a/db/migrate/20151103133339_add_shared_runners_setting.rb b/db/migrate/20151103133339_add_shared_runners_setting.rb
deleted file mode 100644
index 6fc845d1396..00000000000
--- a/db/migrate/20151103133339_add_shared_runners_setting.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class AddSharedRunnersSetting < ActiveRecord::Migration[4.2]
- def up
- add_column :application_settings, :shared_runners_enabled, :boolean, default: true, null: false
- end
-end
diff --git a/db/migrate/20151103134857_create_lfs_objects.rb b/db/migrate/20151103134857_create_lfs_objects.rb
deleted file mode 100644
index 2ba77e431a1..00000000000
--- a/db/migrate/20151103134857_create_lfs_objects.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-# rubocop:disable all
-class CreateLfsObjects < ActiveRecord::Migration[4.2]
- DOWNTIME = false
-
- def change
- create_table :lfs_objects do |t|
- t.string :oid, null: false, unique: true
- t.integer :size, null: false
-
- t.timestamps null: true
- end
- end
-end
diff --git a/db/migrate/20151103134958_create_lfs_objects_projects.rb b/db/migrate/20151103134958_create_lfs_objects_projects.rb
deleted file mode 100644
index 6f8488463b0..00000000000
--- a/db/migrate/20151103134958_create_lfs_objects_projects.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-# rubocop:disable all
-class CreateLfsObjectsProjects < ActiveRecord::Migration[4.2]
- DOWNTIME = false
-
- def change
- create_table :lfs_objects_projects do |t|
- t.integer :lfs_object_id, null: false
- t.integer :project_id, null: false
-
- t.timestamps null: true
- end
-
- add_index :lfs_objects_projects, :project_id
- end
-end
diff --git a/db/migrate/20151104105513_add_file_to_lfs_objects.rb b/db/migrate/20151104105513_add_file_to_lfs_objects.rb
deleted file mode 100644
index 050b1e07503..00000000000
--- a/db/migrate/20151104105513_add_file_to_lfs_objects.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class AddFileToLfsObjects < ActiveRecord::Migration[4.2]
- def change
- add_column :lfs_objects, :file, :string
- end
-end
diff --git a/db/migrate/20151105094515_create_releases.rb b/db/migrate/20151105094515_create_releases.rb
deleted file mode 100644
index 4b180a59486..00000000000
--- a/db/migrate/20151105094515_create_releases.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-# rubocop:disable all
-class CreateReleases < ActiveRecord::Migration[4.2]
- DOWNTIME = false
-
- def change
- create_table :releases do |t|
- t.string :tag
- t.text :description
- t.integer :project_id
-
- t.timestamps null: true
- end
-
- add_index :releases, :project_id
- add_index :releases, [:project_id, :tag]
- end
-end
diff --git a/db/migrate/20151106000015_add_is_award_to_notes.rb b/db/migrate/20151106000015_add_is_award_to_notes.rb
deleted file mode 100644
index 1d866fb3213..00000000000
--- a/db/migrate/20151106000015_add_is_award_to_notes.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-# rubocop:disable all
-class AddIsAwardToNotes < ActiveRecord::Migration[4.2]
- def change
- add_column :notes, :is_award, :boolean, default: false, null: false
- add_index :notes, :is_award
- end
-end
diff --git a/db/migrate/20151109100728_add_max_artifacts_size_to_application_settings.rb b/db/migrate/20151109100728_add_max_artifacts_size_to_application_settings.rb
deleted file mode 100644
index 9c14cfd4656..00000000000
--- a/db/migrate/20151109100728_add_max_artifacts_size_to_application_settings.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class AddMaxArtifactsSizeToApplicationSettings < ActiveRecord::Migration[4.2]
- def change
- add_column :application_settings, :max_artifacts_size, :integer, default: 100, null: false
- end
-end
diff --git a/db/migrate/20151109134526_add_issues_state_index.rb b/db/migrate/20151109134526_add_issues_state_index.rb
deleted file mode 100644
index c77ca90a0d6..00000000000
--- a/db/migrate/20151109134526_add_issues_state_index.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-# rubocop:disable all
-class AddIssuesStateIndex < ActiveRecord::Migration[4.2]
- def change
- add_index :issues, :state
- end
-end
diff --git a/db/migrate/20151109134916_add_projects_visibility_level_index.rb b/db/migrate/20151109134916_add_projects_visibility_level_index.rb
deleted file mode 100644
index 1e945f0e56f..00000000000
--- a/db/migrate/20151109134916_add_projects_visibility_level_index.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-# rubocop:disable all
-class AddProjectsVisibilityLevelIndex < ActiveRecord::Migration[4.2]
- def change
- add_index :projects, :visibility_level
- end
-end
diff --git a/db/migrate/20151110125604_add_import_error_to_project.rb b/db/migrate/20151110125604_add_import_error_to_project.rb
deleted file mode 100644
index 48a15ad0737..00000000000
--- a/db/migrate/20151110125604_add_import_error_to_project.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class AddImportErrorToProject < ActiveRecord::Migration[4.2]
- def change
- add_column :projects, :import_error, :text
- end
-end
diff --git a/db/migrate/20151114113410_add_index_for_lfs_oid_and_size.rb b/db/migrate/20151114113410_add_index_for_lfs_oid_and_size.rb
deleted file mode 100644
index f2788117cc2..00000000000
--- a/db/migrate/20151114113410_add_index_for_lfs_oid_and_size.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-# rubocop:disable all
-class AddIndexForLfsOidAndSize < ActiveRecord::Migration[4.2]
- def change
- add_index :lfs_objects, :oid
- add_index :lfs_objects, [:oid, :size]
- end
-end
diff --git a/db/migrate/20151116144118_add_unique_for_lfs_oid_index.rb b/db/migrate/20151116144118_add_unique_for_lfs_oid_index.rb
deleted file mode 100644
index 3bfbae67119..00000000000
--- a/db/migrate/20151116144118_add_unique_for_lfs_oid_index.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-# rubocop:disable all
-class AddUniqueForLfsOidIndex < ActiveRecord::Migration[4.2]
- def change
- remove_index :lfs_objects, :oid
- remove_index :lfs_objects, [:oid, :size]
- add_index :lfs_objects, :oid, unique: true
- end
-end
diff --git a/db/migrate/20151118162244_add_projects_public_index.rb b/db/migrate/20151118162244_add_projects_public_index.rb
deleted file mode 100644
index 3a525c69ad0..00000000000
--- a/db/migrate/20151118162244_add_projects_public_index.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-# rubocop:disable all
-class AddProjectsPublicIndex < ActiveRecord::Migration[4.2]
- def change
- add_index :namespaces, :public
- end
-end
diff --git a/db/migrate/20151201203948_raise_hook_url_limit.rb b/db/migrate/20151201203948_raise_hook_url_limit.rb
deleted file mode 100644
index c1a4974b8c9..00000000000
--- a/db/migrate/20151201203948_raise_hook_url_limit.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class RaiseHookUrlLimit < ActiveRecord::Migration[4.2]
- def change
- change_column :web_hooks, :url, :string, limit: 2000
- end
-end
diff --git a/db/migrate/20151203162133_add_hide_project_limit_to_users.rb b/db/migrate/20151203162133_add_hide_project_limit_to_users.rb
deleted file mode 100644
index 1b96a0dc550..00000000000
--- a/db/migrate/20151203162133_add_hide_project_limit_to_users.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-# rubocop:disable all
-class AddHideProjectLimitToUsers < ActiveRecord::Migration[4.2]
- def change
- add_column :users, :hide_project_limit, :boolean, default: false
- end
-end
diff --git a/db/migrate/20151203162134_add_build_events_to_services.rb b/db/migrate/20151203162134_add_build_events_to_services.rb
deleted file mode 100644
index c49604f8b61..00000000000
--- a/db/migrate/20151203162134_add_build_events_to_services.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-# rubocop:disable all
-class AddBuildEventsToServices < ActiveRecord::Migration[4.2]
- def change
- add_column :services, :build_events, :boolean, default: false, null: false
- add_column :web_hooks, :build_events, :boolean, default: false, null: false
- end
-end
diff --git a/db/migrate/20151209144329_migrate_ci_web_hooks.rb b/db/migrate/20151209144329_migrate_ci_web_hooks.rb
deleted file mode 100644
index 7562735cb1e..00000000000
--- a/db/migrate/20151209144329_migrate_ci_web_hooks.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-class MigrateCiWebHooks < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- def up
- execute(
- 'INSERT INTO web_hooks (url, project_id, type, created_at, updated_at, push_events, issues_events, merge_requests_events, tag_push_events, note_events, build_events) ' \
- "SELECT ci_web_hooks.url, projects.id, 'ProjectHook', ci_web_hooks.created_at, ci_web_hooks.updated_at, " \
- "#{false_value}, #{false_value}, #{false_value}, #{false_value}, #{false_value}, #{true_value} FROM ci_web_hooks " \
- 'JOIN ci_projects ON ci_web_hooks.project_id = ci_projects.id ' \
- 'JOIN projects ON ci_projects.gitlab_id = projects.id'
- )
- end
-
- def down
- end
-end
diff --git a/db/migrate/20151209145909_migrate_ci_emails.rb b/db/migrate/20151209145909_migrate_ci_emails.rb
deleted file mode 100644
index a1f51c55a55..00000000000
--- a/db/migrate/20151209145909_migrate_ci_emails.rb
+++ /dev/null
@@ -1,45 +0,0 @@
-class MigrateCiEmails < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- def up
- # This inserts a new service: BuildsEmailService
- # It "manually" constructs the properties (JSON-encoded)
- # Migrating all ci_projects e-mail related columns
- execute(
- 'INSERT INTO services (project_id, type, created_at, updated_at, active, push_events, issues_events, merge_requests_events, tag_push_events, note_events, build_events, properties) ' \
- "SELECT projects.id, 'BuildsEmailService', ci_services.created_at, ci_services.updated_at, " \
- "#{true_value}, #{false_value}, #{false_value}, #{false_value}, #{false_value}, #{false_value}, #{true_value}, " \
- "CONCAT('{\"notify_only_broken_builds\":\"', #{convert_bool('ci_projects.email_only_broken_builds')}, " \
- "'\",\"add_pusher\":\"', #{convert_bool('ci_projects.email_add_pusher')}, " \
- "'\",\"recipients\":\"', #{escape_text('ci_projects.email_recipients')}, " \
- "'\"}') " \
- 'FROM ci_services ' \
- 'JOIN ci_projects ON ci_services.project_id = ci_projects.id ' \
- 'JOIN projects ON ci_projects.gitlab_id = projects.id ' \
- "WHERE ci_services.type = 'Ci::MailService' AND ci_services.active"
- )
- end
-
- def down
- end
-
- # This function escapes double-quotes and slash
- def escape_text(name)
- if Gitlab::Database.postgresql?
- "REPLACE(REPLACE(#{name}, '\\', '\\\\'), '\"', '\\\"')"
- else
- "REPLACE(REPLACE(#{name}, '\\\\', '\\\\\\\\'), '\\\"', '\\\\\\\"')"
- end
- end
-
- # This function returns 0 or 1 for column
- def convert_bool(name)
- if Gitlab::Database.postgresql?
- # PostgreSQL uses BOOLEAN type
- "CASE WHEN #{name} IS TRUE THEN '1' ELSE '0' END"
- else
- # MySQL uses TINYINT
- "#{name}"
- end
- end
-end
diff --git a/db/migrate/20151210030143_add_unlock_token_to_user.rb b/db/migrate/20151210030143_add_unlock_token_to_user.rb
deleted file mode 100644
index 28b736adfb5..00000000000
--- a/db/migrate/20151210030143_add_unlock_token_to_user.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class AddUnlockTokenToUser < ActiveRecord::Migration[4.2]
- def change
- add_column :users, :unlock_token, :string
- end
-end
diff --git a/db/migrate/20151210072243_add_runners_registration_token_to_application_settings.rb b/db/migrate/20151210072243_add_runners_registration_token_to_application_settings.rb
deleted file mode 100644
index 5da33149b59..00000000000
--- a/db/migrate/20151210072243_add_runners_registration_token_to_application_settings.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class AddRunnersRegistrationTokenToApplicationSettings < ActiveRecord::Migration[4.2]
- def change
- add_column :application_settings, :runners_registration_token, :string
- end
-end
diff --git a/db/migrate/20151210125232_migrate_ci_slack_service.rb b/db/migrate/20151210125232_migrate_ci_slack_service.rb
deleted file mode 100644
index 72c90f92377..00000000000
--- a/db/migrate/20151210125232_migrate_ci_slack_service.rb
+++ /dev/null
@@ -1,33 +0,0 @@
-class MigrateCiSlackService < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- def up
- properties_query = 'SELECT properties FROM ci_services ' \
- 'JOIN ci_projects ON ci_services.project_id=ci_projects.id ' \
- "WHERE ci_projects.gitlab_id=services.project_id AND ci_services.type='Ci::SlackService' AND ci_services.active " \
- 'LIMIT 1'
-
- active_query = 'SELECT 1 FROM ci_services ' \
- 'JOIN ci_projects ON ci_services.project_id=ci_projects.id ' \
- "WHERE ci_projects.gitlab_id=services.project_id AND ci_services.type='Ci::SlackService' AND ci_services.active " \
- 'LIMIT 1'
-
- # We update the service since services are always generated for project, even if they are inactive
- # Activate service and migrate properties if currently the service is not active
- execute(
- "UPDATE services SET properties=(#{properties_query}), active=#{true_value}, " \
- "push_events=#{false_value}, issues_events=#{false_value}, merge_requests_events=#{false_value}, " \
- "tag_push_events=#{false_value}, note_events=#{false_value}, build_events=#{true_value} " \
- "WHERE NOT services.active AND services.type='SlackService' AND (#{active_query}) IS NOT NULL"
- )
-
- # Tick only build_events if the service is already active
- execute(
- "UPDATE services SET build_events=#{true_value} " \
- "WHERE services.active AND services.type='SlackService' AND (#{active_query}) IS NOT NULL"
- )
- end
-
- def down
- end
-end
diff --git a/db/migrate/20151210125927_migrate_ci_hip_chat_service.rb b/db/migrate/20151210125927_migrate_ci_hip_chat_service.rb
deleted file mode 100644
index 5ec0798c38f..00000000000
--- a/db/migrate/20151210125927_migrate_ci_hip_chat_service.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-class MigrateCiHipChatService < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- def up
- # From properties strip `hipchat_` key
- properties_query = "SELECT REPLACE(properties, '\"hipchat_', '\"') FROM ci_services " \
- 'JOIN ci_projects ON ci_services.project_id=ci_projects.id ' \
- "WHERE ci_projects.gitlab_id=services.project_id AND ci_services.type='Ci::HipChatService' AND ci_services.active " \
- 'LIMIT 1'
-
- active_query = 'SELECT 1 FROM ci_services ' \
- 'JOIN ci_projects ON ci_services.project_id=ci_projects.id ' \
- "WHERE ci_projects.gitlab_id=services.project_id AND ci_services.type='Ci::HipChatService' AND ci_services.active " \
- 'LIMIT 1'
-
- # We update the service since services are always generated for project, even if they are inactive
- # Activate service and migrate properties if currently the service is not active
- execute(
- "UPDATE services SET properties=(#{properties_query}), active=#{true_value}, " \
- "push_events=#{false_value}, issues_events=#{false_value}, merge_requests_events=#{false_value}, " \
- "tag_push_events=#{false_value}, note_events=#{false_value}, build_events=#{true_value} " \
- "WHERE NOT services.active AND services.type='HipchatService' AND (#{active_query}) IS NOT NULL"
- )
-
- # Tick only build_events if the service is already active
- execute(
- "UPDATE services SET build_events=#{true_value} " \
- "WHERE services.active AND services.type='HipchatService' AND (#{active_query}) IS NOT NULL"
- )
- end
-
- def down
- end
-end
diff --git a/db/migrate/20151210125928_add_ci_to_project.rb b/db/migrate/20151210125928_add_ci_to_project.rb
deleted file mode 100644
index 182f1e17b9a..00000000000
--- a/db/migrate/20151210125928_add_ci_to_project.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-# rubocop:disable all
-class AddCiToProject < ActiveRecord::Migration[4.2]
- def change
- add_column :projects, :ci_id, :integer
- add_column :projects, :builds_enabled, :boolean, default: true, null: false
- add_column :projects, :shared_runners_enabled, :boolean, default: true, null: false
- add_column :projects, :runners_token, :string
- add_column :projects, :build_coverage_regex, :string
- add_column :projects, :build_allow_git_fetch, :boolean, default: true, null: false
- add_column :projects, :build_timeout, :integer, default: 3600, null: false
- end
-end
diff --git a/db/migrate/20151210125929_add_project_id_to_ci.rb b/db/migrate/20151210125929_add_project_id_to_ci.rb
deleted file mode 100644
index f5f2c353f4a..00000000000
--- a/db/migrate/20151210125929_add_project_id_to_ci.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-class AddProjectIdToCi < ActiveRecord::Migration[4.2]
- def change
- add_column :ci_builds, :gl_project_id, :integer
- add_column :ci_runner_projects, :gl_project_id, :integer
- add_column :ci_triggers, :gl_project_id, :integer
- add_column :ci_variables, :gl_project_id, :integer
- end
-end
diff --git a/db/migrate/20151210125930_migrate_ci_to_project.rb b/db/migrate/20151210125930_migrate_ci_to_project.rb
deleted file mode 100644
index f7573ad1a8d..00000000000
--- a/db/migrate/20151210125930_migrate_ci_to_project.rb
+++ /dev/null
@@ -1,42 +0,0 @@
-class MigrateCiToProject < ActiveRecord::Migration[4.2]
- def up
- migrate_project_id_for_table('ci_runner_projects')
- migrate_project_id_for_table('ci_triggers')
- migrate_project_id_for_table('ci_variables')
- migrate_project_id_for_builds
-
- migrate_project_column('id', 'ci_id')
- migrate_project_column('shared_runners_enabled', 'shared_runners_enabled')
- migrate_project_column('token', 'runners_token')
- migrate_project_column('coverage_regex', 'build_coverage_regex')
- migrate_project_column('allow_git_fetch', 'build_allow_git_fetch')
- migrate_project_column('timeout', 'build_timeout')
- migrate_ci_service
- end
-
- def down
- # We can't reverse the data
- end
-
- def migrate_project_id_for_table(table)
- subquery = "SELECT gitlab_id FROM ci_projects WHERE ci_projects.id = #{table}.project_id"
- execute("UPDATE #{table} SET gl_project_id=(#{subquery}) WHERE gl_project_id IS NULL")
- end
-
- def migrate_project_id_for_builds
- subquery = 'SELECT gl_project_id FROM ci_commits WHERE ci_commits.id = ci_builds.commit_id'
- execute("UPDATE ci_builds SET gl_project_id=(#{subquery}) WHERE gl_project_id IS NULL")
- end
-
- def migrate_project_column(column, new_column = nil)
- new_column ||= column
- subquery = "SELECT ci_projects.#{column} FROM ci_projects WHERE projects.id = ci_projects.gitlab_id " \
- 'ORDER BY ci_projects.updated_at DESC LIMIT 1'
- execute("UPDATE projects SET #{new_column}=(#{subquery}) WHERE (#{subquery}) IS NOT NULL")
- end
-
- def migrate_ci_service
- subquery = "SELECT active FROM services WHERE projects.id = services.project_id AND type='GitlabCiService' LIMIT 1"
- execute("UPDATE projects SET builds_enabled=(#{subquery}) WHERE (#{subquery}) IS NOT NULL")
- end
-end
diff --git a/db/migrate/20151210125931_add_index_to_ci_tables.rb b/db/migrate/20151210125931_add_index_to_ci_tables.rb
deleted file mode 100644
index 2cbc5b50538..00000000000
--- a/db/migrate/20151210125931_add_index_to_ci_tables.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-# rubocop:disable all
-class AddIndexToCiTables < ActiveRecord::Migration[4.2]
- def change
- add_index :ci_builds, :gl_project_id
- add_index :ci_runner_projects, :gl_project_id
- add_index :ci_triggers, :gl_project_id
- add_index :ci_variables, :gl_project_id
- add_index :projects, :runners_token
- add_index :projects, :builds_enabled
- add_index :projects, [:builds_enabled, :shared_runners_enabled]
- add_index :projects, [:ci_id]
- end
-end
diff --git a/db/migrate/20151210125932_drop_null_for_ci_tables.rb b/db/migrate/20151210125932_drop_null_for_ci_tables.rb
deleted file mode 100644
index b48fef4b749..00000000000
--- a/db/migrate/20151210125932_drop_null_for_ci_tables.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-# rubocop:disable all
-class DropNullForCiTables < ActiveRecord::Migration[4.2]
- def change
- remove_index :ci_variables, :project_id
- remove_index :ci_runner_projects, :project_id
- change_column_null :ci_triggers, :project_id, true
- change_column_null :ci_variables, :project_id, true
- change_column_null :ci_runner_projects, :project_id, true
- end
-end
diff --git a/db/migrate/20151215132013_add_pages_size_to_application_settings.rb b/db/migrate/20151215132013_add_pages_size_to_application_settings.rb
deleted file mode 100644
index 7190d476dc7..00000000000
--- a/db/migrate/20151215132013_add_pages_size_to_application_settings.rb
+++ /dev/null
@@ -1,14 +0,0 @@
-class AddPagesSizeToApplicationSettings < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
- disable_ddl_transaction!
-
- DOWNTIME = false
-
- def up
- add_column_with_default :application_settings, :max_pages_size, :integer, default: 100, allow_null: false
- end
-
- def down
- remove_column(:application_settings, :max_pages_size)
- end
-end
diff --git a/db/migrate/20151218154042_add_tfa_to_application_settings.rb b/db/migrate/20151218154042_add_tfa_to_application_settings.rb
deleted file mode 100644
index a981fe2720f..00000000000
--- a/db/migrate/20151218154042_add_tfa_to_application_settings.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-class AddTfaToApplicationSettings < ActiveRecord::Migration[4.2]
- def change
- change_table :application_settings do |t|
- t.boolean :require_two_factor_authentication, default: false
- t.integer :two_factor_grace_period, default: 48
- end
- end
-end
diff --git a/db/migrate/20151221234414_add_tfa_additional_fields.rb b/db/migrate/20151221234414_add_tfa_additional_fields.rb
deleted file mode 100644
index fed734f77f4..00000000000
--- a/db/migrate/20151221234414_add_tfa_additional_fields.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-class AddTfaAdditionalFields < ActiveRecord::Migration[4.2]
- def change
- change_table :users do |t|
- t.datetime :otp_grace_period_started_at, null: true
- end
- end
-end
diff --git a/db/migrate/20151224123230_rename_emojis.rb b/db/migrate/20151224123230_rename_emojis.rb
deleted file mode 100644
index f1e4b1fe181..00000000000
--- a/db/migrate/20151224123230_rename_emojis.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-# Migration type: online without errors (works on previous version and new one)
-class RenameEmojis < ActiveRecord::Migration[4.2]
- def up
- # Renames aliases to main names
- execute("UPDATE notes SET note ='thumbsup' WHERE is_award = true AND note = '+1'")
- execute("UPDATE notes SET note ='thumbsdown' WHERE is_award = true AND note = '-1'")
- execute("UPDATE notes SET note ='poop' WHERE is_award = true AND note = 'shit'")
- end
-
- def down
- execute("UPDATE notes SET note ='+1' WHERE is_award = true AND note = 'thumbsup'")
- execute("UPDATE notes SET note ='-1' WHERE is_award = true AND note = 'thumbsdown'")
- execute("UPDATE notes SET note ='shit' WHERE is_award = true AND note = 'poop'")
- end
-end
diff --git a/db/migrate/20151228111122_remove_public_from_namespace.rb b/db/migrate/20151228111122_remove_public_from_namespace.rb
deleted file mode 100644
index ad922e3fc58..00000000000
--- a/db/migrate/20151228111122_remove_public_from_namespace.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-# rubocop:disable all
-# Migration type: online
-class RemovePublicFromNamespace < ActiveRecord::Migration[4.2]
- def change
- remove_column :namespaces, :public, :boolean
- end
-end
diff --git a/db/migrate/20151228150906_influxdb_settings.rb b/db/migrate/20151228150906_influxdb_settings.rb
deleted file mode 100644
index 8266e3c5044..00000000000
--- a/db/migrate/20151228150906_influxdb_settings.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-# rubocop:disable all
-class InfluxdbSettings < ActiveRecord::Migration[4.2]
- def change
- add_column :application_settings, :metrics_enabled, :boolean, default: false
-
- add_column :application_settings, :metrics_host, :string,
- default: 'localhost'
-
- add_column :application_settings, :metrics_database, :string,
- default: 'gitlab'
-
- add_column :application_settings, :metrics_username, :string
- add_column :application_settings, :metrics_password, :string
- add_column :application_settings, :metrics_pool_size, :integer, default: 16
- add_column :application_settings, :metrics_timeout, :integer, default: 10
- add_column :application_settings, :metrics_method_call_threshold,
- :integer, default: 10
- end
-end
diff --git a/db/migrate/20151228175719_add_recaptcha_to_application_settings.rb b/db/migrate/20151228175719_add_recaptcha_to_application_settings.rb
deleted file mode 100644
index 523f2cae092..00000000000
--- a/db/migrate/20151228175719_add_recaptcha_to_application_settings.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-class AddRecaptchaToApplicationSettings < ActiveRecord::Migration[4.2]
- def change
- change_table :application_settings do |t|
- t.boolean :recaptcha_enabled, default: false
- t.string :recaptcha_site_key
- t.string :recaptcha_private_key
- end
- end
-end
diff --git a/db/migrate/20151229102248_influxdb_udp_port_setting.rb b/db/migrate/20151229102248_influxdb_udp_port_setting.rb
deleted file mode 100644
index da37e3bc148..00000000000
--- a/db/migrate/20151229102248_influxdb_udp_port_setting.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class InfluxdbUdpPortSetting < ActiveRecord::Migration[4.2]
- def change
- add_column :application_settings, :metrics_port, :integer, default: 8089
- end
-end
diff --git a/db/migrate/20151229112614_influxdb_remote_database_setting.rb b/db/migrate/20151229112614_influxdb_remote_database_setting.rb
deleted file mode 100644
index 5fdf4c6d4cb..00000000000
--- a/db/migrate/20151229112614_influxdb_remote_database_setting.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-# rubocop:disable all
-class InfluxdbRemoteDatabaseSetting < ActiveRecord::Migration[4.2]
- def change
- remove_column :application_settings, :metrics_database
- end
-end
diff --git a/db/migrate/20151230132518_add_artifacts_metadata_to_ci_build.rb b/db/migrate/20151230132518_add_artifacts_metadata_to_ci_build.rb
deleted file mode 100644
index 61a3d6486f3..00000000000
--- a/db/migrate/20151230132518_add_artifacts_metadata_to_ci_build.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class AddArtifactsMetadataToCiBuild < ActiveRecord::Migration[4.2]
- def change
- add_column :ci_builds, :artifacts_metadata, :text
- end
-end
diff --git a/db/migrate/20151231152326_add_akismet_to_application_settings.rb b/db/migrate/20151231152326_add_akismet_to_application_settings.rb
deleted file mode 100644
index ef51ea03a5b..00000000000
--- a/db/migrate/20151231152326_add_akismet_to_application_settings.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-class AddAkismetToApplicationSettings < ActiveRecord::Migration[4.2]
- def change
- change_table :application_settings do |t|
- t.boolean :akismet_enabled, default: false
- t.string :akismet_api_key
- end
- end
-end
diff --git a/db/migrate/20151231202530_remove_alert_type_from_broadcast_messages.rb b/db/migrate/20151231202530_remove_alert_type_from_broadcast_messages.rb
deleted file mode 100644
index 2d8b44840f0..00000000000
--- a/db/migrate/20151231202530_remove_alert_type_from_broadcast_messages.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-# rubocop:disable all
-class RemoveAlertTypeFromBroadcastMessages < ActiveRecord::Migration[4.2]
- def change
- remove_column :broadcast_messages, :alert_type, :integer
- end
-end
diff --git a/db/migrate/20160106162223_add_index_milestones_title.rb b/db/migrate/20160106162223_add_index_milestones_title.rb
deleted file mode 100644
index d42bddefe64..00000000000
--- a/db/migrate/20160106162223_add_index_milestones_title.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-# rubocop:disable all
-class AddIndexMilestonesTitle < ActiveRecord::Migration[4.2]
- def change
- add_index :milestones, :title
- end
-end
diff --git a/db/migrate/20160106164438_remove_influxdb_credentials.rb b/db/migrate/20160106164438_remove_influxdb_credentials.rb
deleted file mode 100644
index 569d5a0cf36..00000000000
--- a/db/migrate/20160106164438_remove_influxdb_credentials.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-# rubocop:disable all
-class RemoveInfluxdbCredentials < ActiveRecord::Migration[4.2]
- def change
- remove_column :application_settings, :metrics_username, :string
- remove_column :application_settings, :metrics_password, :string
- end
-end
diff --git a/db/migrate/20160109054846_create_spam_logs.rb b/db/migrate/20160109054846_create_spam_logs.rb
deleted file mode 100644
index dc97d03f7ff..00000000000
--- a/db/migrate/20160109054846_create_spam_logs.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-# rubocop:disable all
-class CreateSpamLogs < ActiveRecord::Migration[4.2]
- def change
- create_table :spam_logs do |t|
- t.integer :user_id
- t.string :source_ip
- t.string :user_agent
- t.boolean :via_api
- t.integer :project_id
- t.string :noteable_type
- t.string :title
- t.text :description
-
- t.timestamps null: false
- end
- end
-end
diff --git a/db/migrate/20160113111034_add_metrics_sample_interval.rb b/db/migrate/20160113111034_add_metrics_sample_interval.rb
deleted file mode 100644
index 9c3377571aa..00000000000
--- a/db/migrate/20160113111034_add_metrics_sample_interval.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-class AddMetricsSampleInterval < ActiveRecord::Migration[4.2]
- def change
- add_column :application_settings, :metrics_sample_interval, :integer,
- default: 15
- end
-end
diff --git a/db/migrate/20160118155830_add_sentry_to_application_settings.rb b/db/migrate/20160118155830_add_sentry_to_application_settings.rb
deleted file mode 100644
index 20f3925b964..00000000000
--- a/db/migrate/20160118155830_add_sentry_to_application_settings.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-class AddSentryToApplicationSettings < ActiveRecord::Migration[4.2]
- def change
- change_table :application_settings do |t|
- t.boolean :sentry_enabled, default: false
- t.string :sentry_dsn
- end
- end
-end
diff --git a/db/migrate/20160118232755_add_ip_blocking_settings_to_application_settings.rb b/db/migrate/20160118232755_add_ip_blocking_settings_to_application_settings.rb
deleted file mode 100644
index 809a6cceef5..00000000000
--- a/db/migrate/20160118232755_add_ip_blocking_settings_to_application_settings.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-# rubocop:disable all
-class AddIpBlockingSettingsToApplicationSettings < ActiveRecord::Migration[4.2]
- def change
- add_column :application_settings, :ip_blocking_enabled, :boolean, default: false
- add_column :application_settings, :dnsbl_servers_list, :text
- end
-end
diff --git a/db/migrate/20160119111158_add_services_category.rb b/db/migrate/20160119111158_add_services_category.rb
deleted file mode 100644
index 979a48584a9..00000000000
--- a/db/migrate/20160119111158_add_services_category.rb
+++ /dev/null
@@ -1,40 +0,0 @@
-# rubocop:disable all
-class AddServicesCategory < ActiveRecord::Migration[4.2]
- def up
- add_column :services, :category, :string, default: 'common', null: false
-
- category = quote_column_name('category')
- type = quote_column_name('type')
-
- execute <<-EOF
-UPDATE services
-SET #{category} = 'issue_tracker'
-WHERE #{type} IN (
- 'CustomIssueTrackerService',
- 'GitlabIssueTrackerService',
- 'IssueTrackerService',
- 'JiraService',
- 'RedmineService'
-);
-EOF
-
- execute <<-EOF
-UPDATE services
-SET #{category} = 'ci'
-WHERE #{type} IN (
- 'BambooService',
- 'BuildkiteService',
- 'CiService',
- 'DroneCiService',
- 'GitlabCiService',
- 'TeamcityService'
-);
- EOF
-
- add_index :services, :category
- end
-
- def down
- remove_column :services, :category
- end
-end
diff --git a/db/migrate/20160119112418_add_services_default.rb b/db/migrate/20160119112418_add_services_default.rb
deleted file mode 100644
index 41ba5d98afe..00000000000
--- a/db/migrate/20160119112418_add_services_default.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-# rubocop:disable all
-class AddServicesDefault < ActiveRecord::Migration[4.2]
- def up
- add_column :services, :default, :boolean, default: false
-
- default = quote_column_name('default')
- type = quote_column_name('type')
-
- execute <<-EOF
-UPDATE services
-SET #{default} = true
-WHERE #{type} = 'GitlabIssueTrackerService'
-EOF
-
- add_index :services, :default
- end
-
- def down
- remove_column :services, :default
- end
-end
diff --git a/db/migrate/20160119145451_add_ldap_email_to_users.rb b/db/migrate/20160119145451_add_ldap_email_to_users.rb
deleted file mode 100644
index bf8c27900b8..00000000000
--- a/db/migrate/20160119145451_add_ldap_email_to_users.rb
+++ /dev/null
@@ -1,31 +0,0 @@
-# rubocop:disable all
-class AddLdapEmailToUsers < ActiveRecord::Migration[4.2]
- def up
- add_column :users, :ldap_email, :boolean, default: false, null: false
-
- if Gitlab::Database.mysql?
- execute %{
- UPDATE users, identities
- SET users.ldap_email = TRUE
- WHERE identities.user_id = users.id
- AND users.email LIKE 'temp-email-for-oauth%'
- AND identities.provider LIKE 'ldap%'
- AND identities.extern_uid IS NOT NULL
- }
- else
- execute %{
- UPDATE users
- SET ldap_email = TRUE
- FROM identities
- WHERE identities.user_id = users.id
- AND users.email LIKE 'temp-email-for-oauth%'
- AND identities.provider LIKE 'ldap%'
- AND identities.extern_uid IS NOT NULL
- }
- end
- end
-
- def down
- remove_column :users, :ldap_email
- end
-end
diff --git a/db/migrate/20160120172143_add_base_commit_sha_to_merge_request_diffs.rb b/db/migrate/20160120172143_add_base_commit_sha_to_merge_request_diffs.rb
deleted file mode 100644
index 9c0a91758f5..00000000000
--- a/db/migrate/20160120172143_add_base_commit_sha_to_merge_request_diffs.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class AddBaseCommitShaToMergeRequestDiffs < ActiveRecord::Migration[4.2]
- def change
- add_column :merge_request_diffs, :base_commit_sha, :string
- end
-end
diff --git a/db/migrate/20160121030729_add_email_author_in_body_to_application_settings.rb b/db/migrate/20160121030729_add_email_author_in_body_to_application_settings.rb
deleted file mode 100644
index 0cb1fbe8641..00000000000
--- a/db/migrate/20160121030729_add_email_author_in_body_to_application_settings.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-# rubocop:disable all
-class AddEmailAuthorInBodyToApplicationSettings < ActiveRecord::Migration[4.2]
- def change
- add_column :application_settings, :email_author_in_body, :boolean, default: false
- end
-end
diff --git a/db/migrate/20160122185421_add_pending_delete_to_project.rb b/db/migrate/20160122185421_add_pending_delete_to_project.rb
deleted file mode 100644
index 8db0adc9221..00000000000
--- a/db/migrate/20160122185421_add_pending_delete_to_project.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-# rubocop:disable all
-class AddPendingDeleteToProject < ActiveRecord::Migration[4.2]
- def change
- add_column :projects, :pending_delete, :boolean, default: false
- end
-end
diff --git a/db/migrate/20160128212447_remove_ip_blocking_settings_from_application_settings.rb b/db/migrate/20160128212447_remove_ip_blocking_settings_from_application_settings.rb
deleted file mode 100644
index e76f0249ae5..00000000000
--- a/db/migrate/20160128212447_remove_ip_blocking_settings_from_application_settings.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-# rubocop:disable all
-class RemoveIpBlockingSettingsFromApplicationSettings < ActiveRecord::Migration[4.2]
- def change
- remove_column :application_settings, :ip_blocking_enabled, :boolean, default: false
- remove_column :application_settings, :dnsbl_servers_list, :text
- end
-end
diff --git a/db/migrate/20160128233227_change_lfs_objects_size_column.rb b/db/migrate/20160128233227_change_lfs_objects_size_column.rb
deleted file mode 100644
index 65aaf2d9a0b..00000000000
--- a/db/migrate/20160128233227_change_lfs_objects_size_column.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class ChangeLfsObjectsSizeColumn < ActiveRecord::Migration[4.2]
- def change
- change_column :lfs_objects, :size, :integer, limit: 8
- end
-end
diff --git a/db/migrate/20160129135155_remove_dot_atom_path_ending_of_projects.rb b/db/migrate/20160129135155_remove_dot_atom_path_ending_of_projects.rb
deleted file mode 100644
index 6254017615b..00000000000
--- a/db/migrate/20160129135155_remove_dot_atom_path_ending_of_projects.rb
+++ /dev/null
@@ -1,80 +0,0 @@
-class RemoveDotAtomPathEndingOfProjects < ActiveRecord::Migration[4.2]
- include Gitlab::ShellAdapter
-
- class ProjectPath
- attr_reader :old_path, :id, :namespace_path
-
- def initialize(old_path, id, namespace_path, namespace_id)
- @old_path = old_path
- @id = id
- @namespace_path = namespace_path
- @namespace_id = namespace_id
- end
-
- def clean_path
- @_clean_path ||= PathCleaner.clean(@old_path, @namespace_id)
- end
- end
-
- class PathCleaner
- def initialize(path, namespace_id)
- @namespace_id = namespace_id
- @path = path
- end
-
- def self.clean(*args)
- new(*args).clean
- end
-
- def clean
- path = cleaned_path
- count = 0
- while path_exists?(path)
- path = "#{cleaned_path}#{count}"
- count += 1
- end
- path
- end
-
- private
-
- def cleaned_path
- @_cleaned_path ||= @path.gsub(/\.atom\z/, '-atom')
- end
-
- def path_exists?(path)
- Project.find_by_path_and_namespace_id(path, @namespace_id)
- end
- end
-
- def projects_with_dot_atom
- select_all("SELECT p.id, p.path, n.path as namespace_path, n.id as namespace_id FROM projects p inner join namespaces n on n.id = p.namespace_id WHERE p.path LIKE '%.atom'")
- end
-
- def up
- projects_with_dot_atom.each do |project|
- project_path = ProjectPath.new(project['path'], project['id'], project['namespace_path'], project['namespace_id'])
- clean_path(project_path) if rename_project_repo(project_path)
- end
- end
-
- private
-
- def clean_path(project_path)
- execute "UPDATE projects SET path = #{sanitize(project_path.clean_path)} WHERE id = #{project_path.id}"
- end
-
- def rename_project_repo(project_path)
- old_path_with_namespace = File.join(project_path.namespace_path, project_path.old_path)
- new_path_with_namespace = File.join(project_path.namespace_path, project_path.clean_path)
-
- gitlab_shell.mv_repository("#{old_path_with_namespace}.wiki", "#{new_path_with_namespace}.wiki")
- gitlab_shell.mv_repository(old_path_with_namespace, new_path_with_namespace)
- rescue
- false
- end
-
- def sanitize(value)
- ActiveRecord::Base.connection.quote(value)
- end
-end
diff --git a/db/migrate/20160129155512_add_merge_commit_sha_to_merge_requests.rb b/db/migrate/20160129155512_add_merge_commit_sha_to_merge_requests.rb
deleted file mode 100644
index 8b84705ce7d..00000000000
--- a/db/migrate/20160129155512_add_merge_commit_sha_to_merge_requests.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class AddMergeCommitShaToMergeRequests < ActiveRecord::Migration[4.2]
- def change
- add_column :merge_requests, :merge_commit_sha, :string
- end
-end
diff --git a/db/migrate/20160202091601_add_erasable_to_ci_build.rb b/db/migrate/20160202091601_add_erasable_to_ci_build.rb
deleted file mode 100644
index 214028bd8d3..00000000000
--- a/db/migrate/20160202091601_add_erasable_to_ci_build.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-# rubocop:disable all
-class AddErasableToCiBuild < ActiveRecord::Migration[4.2]
- def change
- add_reference :ci_builds, :erased_by, references: :users, index: true
- add_column :ci_builds, :erased_at, :datetime
- end
-end
diff --git a/db/migrate/20160202164642_add_allow_guest_to_access_builds_project.rb b/db/migrate/20160202164642_add_allow_guest_to_access_builds_project.rb
deleted file mode 100644
index 542f9437911..00000000000
--- a/db/migrate/20160202164642_add_allow_guest_to_access_builds_project.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-# rubocop:disable all
-class AddAllowGuestToAccessBuildsProject < ActiveRecord::Migration[4.2]
- def change
- add_column :projects, :public_builds, :boolean, default: true, null: false
- end
-end
diff --git a/db/migrate/20160204144558_add_real_size_to_merge_request_diffs.rb b/db/migrate/20160204144558_add_real_size_to_merge_request_diffs.rb
deleted file mode 100644
index c1f1faf0279..00000000000
--- a/db/migrate/20160204144558_add_real_size_to_merge_request_diffs.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class AddRealSizeToMergeRequestDiffs < ActiveRecord::Migration[4.2]
- def change
- add_column :merge_request_diffs, :real_size, :string
- end
-end
diff --git a/db/migrate/20160209130428_add_index_to_snippet.rb b/db/migrate/20160209130428_add_index_to_snippet.rb
deleted file mode 100644
index 480ac193d63..00000000000
--- a/db/migrate/20160209130428_add_index_to_snippet.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-# rubocop:disable all
-class AddIndexToSnippet < ActiveRecord::Migration[4.2]
- def change
- add_index :snippets, :updated_at
- end
-end
diff --git a/db/migrate/20160210105555_create_pages_domain.rb b/db/migrate/20160210105555_create_pages_domain.rb
deleted file mode 100644
index a46906d64ca..00000000000
--- a/db/migrate/20160210105555_create_pages_domain.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-class CreatePagesDomain < ActiveRecord::Migration[4.2]
- DOWNTIME = false
-
- def change
- create_table :pages_domains do |t|
- t.integer :project_id
- t.text :certificate
- t.text :encrypted_key
- t.string :encrypted_key_iv
- t.string :encrypted_key_salt
- t.string :domain
- end
-
- add_index :pages_domains, :domain, unique: true
- end
-end
diff --git a/db/migrate/20160212123307_create_tasks.rb b/db/migrate/20160212123307_create_tasks.rb
deleted file mode 100644
index 33acc8af91f..00000000000
--- a/db/migrate/20160212123307_create_tasks.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-# rubocop:disable all
-class CreateTasks < ActiveRecord::Migration[4.2]
- DOWNTIME = false
-
- def change
- create_table :tasks do |t|
- t.references :user, null: false, index: true
- t.references :project, null: false, index: true
- t.references :target, polymorphic: true, null: false, index: true
- t.integer :author_id, index: true
- t.integer :action, null: false
- t.string :state, null: false, index: true
-
- t.timestamps null: true
- end
- end
-end
diff --git a/db/migrate/20160217100506_add_description_to_label.rb b/db/migrate/20160217100506_add_description_to_label.rb
deleted file mode 100644
index 116de8ddfa9..00000000000
--- a/db/migrate/20160217100506_add_description_to_label.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class AddDescriptionToLabel < ActiveRecord::Migration[4.2]
- def change
- add_column :labels, :description, :string
- end
-end
diff --git a/db/migrate/20160217174422_add_note_to_tasks.rb b/db/migrate/20160217174422_add_note_to_tasks.rb
deleted file mode 100644
index c2a42ce5dd8..00000000000
--- a/db/migrate/20160217174422_add_note_to_tasks.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class AddNoteToTasks < ActiveRecord::Migration[4.2]
- def change
- add_reference :tasks, :note, index: true
- end
-end
diff --git a/db/migrate/20160220123949_rename_tasks_to_todos.rb b/db/migrate/20160220123949_rename_tasks_to_todos.rb
deleted file mode 100644
index 0cc110a0a1a..00000000000
--- a/db/migrate/20160220123949_rename_tasks_to_todos.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class RenameTasksToTodos < ActiveRecord::Migration[4.2]
- def change
- rename_table :tasks, :todos
- end
-end
diff --git a/db/migrate/20160222153918_create_appearances_ce.rb b/db/migrate/20160222153918_create_appearances_ce.rb
deleted file mode 100644
index 37bbe62ad3d..00000000000
--- a/db/migrate/20160222153918_create_appearances_ce.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-# rubocop:disable all
-class CreateAppearancesCe < ActiveRecord::Migration[4.2]
- def change
- unless table_exists?(:appearances)
- create_table :appearances do |t|
- t.string :title
- t.text :description
- t.string :header_logo
- t.string :logo
-
- t.timestamps null: false
- end
- end
- end
-end
diff --git a/db/migrate/20160223192159_add_confidential_to_issues.rb b/db/migrate/20160223192159_add_confidential_to_issues.rb
deleted file mode 100644
index ca029f12337..00000000000
--- a/db/migrate/20160223192159_add_confidential_to_issues.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-# rubocop:disable all
-class AddConfidentialToIssues < ActiveRecord::Migration[4.2]
- def change
- add_column :issues, :confidential, :boolean, default: false
- add_index :issues, :confidential
- end
-end
diff --git a/db/migrate/20160225090018_add_delete_at_to_issues.rb b/db/migrate/20160225090018_add_delete_at_to_issues.rb
deleted file mode 100644
index 3ae74f491f6..00000000000
--- a/db/migrate/20160225090018_add_delete_at_to_issues.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-# rubocop:disable all
-class AddDeleteAtToIssues < ActiveRecord::Migration[4.2]
- def change
- add_column :issues, :deleted_at, :datetime
- add_index :issues, :deleted_at
- end
-end
diff --git a/db/migrate/20160225101956_add_delete_at_to_merge_requests.rb b/db/migrate/20160225101956_add_delete_at_to_merge_requests.rb
deleted file mode 100644
index ce8657ba88c..00000000000
--- a/db/migrate/20160225101956_add_delete_at_to_merge_requests.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-# rubocop:disable all
-class AddDeleteAtToMergeRequests < ActiveRecord::Migration[4.2]
- def change
- add_column :merge_requests, :deleted_at, :datetime
- add_index :merge_requests, :deleted_at
- end
-end
diff --git a/db/migrate/20160226114608_add_trigram_indexes_for_searching.rb b/db/migrate/20160226114608_add_trigram_indexes_for_searching.rb
deleted file mode 100644
index af8b08c095a..00000000000
--- a/db/migrate/20160226114608_add_trigram_indexes_for_searching.rb
+++ /dev/null
@@ -1,65 +0,0 @@
-# rubocop:disable all
-class AddTrigramIndexesForSearching < ActiveRecord::Migration[4.2]
- disable_ddl_transaction!
-
- def up
- return unless Gitlab::Database.postgresql?
-
- create_trigrams_extension
-
- unless trigrams_enabled?
- raise 'You must enable the pg_trgm extension. You can do so by running ' \
- '"CREATE EXTENSION pg_trgm;" as a PostgreSQL super user, this must be ' \
- 'done for every GitLab database. For more information see ' \
- 'http://www.postgresql.org/docs/current/static/sql-createextension.html'
- end
-
- # trigram indexes are case-insensitive so we can just index the column
- # instead of indexing lower(column)
- to_index.each do |table, columns|
- columns.each do |column|
- execute "CREATE INDEX CONCURRENTLY index_#{table}_on_#{column}_trigram ON #{table} USING gin(#{column} gin_trgm_ops);"
- end
- end
- end
-
- def down
- return unless Gitlab::Database.postgresql?
-
- to_index.each do |table, columns|
- columns.each do |column|
- remove_index table, name: "index_#{table}_on_#{column}_trigram"
- end
- end
- end
-
- def trigrams_enabled?
- res = execute("SELECT true AS enabled FROM pg_available_extensions WHERE name = 'pg_trgm' AND installed_version IS NOT NULL;")
- row = res.first
-
- row && row['enabled'] == true
- end
-
- def create_trigrams_extension
- # This may not work if the user doesn't have permission. We attempt in
- # case we do have permission, particularly for test/dev environments.
- begin
- enable_extension 'pg_trgm'
- rescue
- end
- end
-
- def to_index
- {
- ci_runners: [:token, :description],
- issues: [:title, :description],
- merge_requests: [:title, :description],
- milestones: [:title, :description],
- namespaces: [:name, :path],
- notes: [:note],
- projects: [:name, :path, :description],
- snippets: [:title, :file_name],
- users: [:username, :name, :email]
- }
- end
-end
diff --git a/db/migrate/20160227120001_add_event_field_for_web_hook.rb b/db/migrate/20160227120001_add_event_field_for_web_hook.rb
deleted file mode 100644
index 22bbd73114f..00000000000
--- a/db/migrate/20160227120001_add_event_field_for_web_hook.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-# rubocop:disable all
-class AddEventFieldForWebHook < ActiveRecord::Migration[4.2]
- def change
- add_column :web_hooks, :wiki_page_events, :boolean, default: false, null: false
- end
-end
diff --git a/db/migrate/20160227120047_add_event_to_services.rb b/db/migrate/20160227120047_add_event_to_services.rb
deleted file mode 100644
index a3b94734ec2..00000000000
--- a/db/migrate/20160227120047_add_event_to_services.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-# rubocop:disable all
-class AddEventToServices < ActiveRecord::Migration[4.2]
- def change
- add_column :services, :wiki_page_events, :boolean, default: true
- end
-end
diff --git a/db/migrate/20160229193553_add_main_language_to_repository.rb b/db/migrate/20160229193553_add_main_language_to_repository.rb
deleted file mode 100644
index 15f9a382802..00000000000
--- a/db/migrate/20160229193553_add_main_language_to_repository.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class AddMainLanguageToRepository < ActiveRecord::Migration[4.2]
- def change
- add_column :projects, :main_language, :string
- end
-end
diff --git a/db/migrate/20160301124843_add_visibility_level_to_groups.rb b/db/migrate/20160301124843_add_visibility_level_to_groups.rb
deleted file mode 100644
index ed4bca4f1ba..00000000000
--- a/db/migrate/20160301124843_add_visibility_level_to_groups.rb
+++ /dev/null
@@ -1,30 +0,0 @@
-# rubocop:disable all
-class AddVisibilityLevelToGroups < ActiveRecord::Migration[4.2]
- def up
- add_column :namespaces, :visibility_level, :integer, null: false, default: Gitlab::VisibilityLevel::PUBLIC
- add_index :namespaces, :visibility_level
-
- # Unfortunately, this is needed on top of the `default`, since we don't want the configuration specific
- # `allowed_visibility_level` to end up in schema.rb
- if allowed_visibility_level < Gitlab::VisibilityLevel::PUBLIC
- execute("UPDATE namespaces SET visibility_level = #{allowed_visibility_level}")
- end
- end
-
- def down
- remove_column :namespaces, :visibility_level
- end
-
- private
-
- def allowed_visibility_level
- application_settings = select_one("SELECT restricted_visibility_levels FROM application_settings ORDER BY id DESC LIMIT 1")
- if application_settings
- restricted_visibility_levels = YAML.safe_load(application_settings["restricted_visibility_levels"]) rescue nil
- end
- restricted_visibility_levels ||= []
-
- allowed_levels = Gitlab::VisibilityLevel.values - restricted_visibility_levels
- allowed_levels.max
- end
-end
diff --git a/db/migrate/20160301174731_add_fingerprint_index.rb b/db/migrate/20160301174731_add_fingerprint_index.rb
deleted file mode 100644
index b13373a0468..00000000000
--- a/db/migrate/20160301174731_add_fingerprint_index.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-# rubocop:disable all
-class AddFingerprintIndex < ActiveRecord::Migration[4.2]
- disable_ddl_transaction!
-
- DOWNTIME = false
-
- # https://gitlab.com/gitlab-org/gitlab-ee/issues/764
- def change
- args = [:keys, :fingerprint]
-
- if Gitlab::Database.postgresql?
- args << { algorithm: :concurrently }
- end
-
- add_index(*args) unless index_exists?(:keys, :fingerprint)
- end
-end
diff --git a/db/migrate/20160302151724_add_import_credentials_to_project_import_data.rb b/db/migrate/20160302151724_add_import_credentials_to_project_import_data.rb
deleted file mode 100644
index b0ea05bd6e1..00000000000
--- a/db/migrate/20160302151724_add_import_credentials_to_project_import_data.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-class AddImportCredentialsToProjectImportData < ActiveRecord::Migration[4.2]
- def change
- add_column :project_import_data, :encrypted_credentials, :text
- add_column :project_import_data, :encrypted_credentials_iv, :string
- add_column :project_import_data, :encrypted_credentials_salt, :string
- end
-end
diff --git a/db/migrate/20160302152808_remove_wrong_import_url_from_projects.rb b/db/migrate/20160302152808_remove_wrong_import_url_from_projects.rb
deleted file mode 100644
index 8a319554c28..00000000000
--- a/db/migrate/20160302152808_remove_wrong_import_url_from_projects.rb
+++ /dev/null
@@ -1,138 +0,0 @@
-# rubocop:disable all
-# Loops through old importer projects that kept a token/password in the import URL
-# and encrypts the credentials into a separate field in project#import_data
-# #down method not supported
-class RemoveWrongImportUrlFromProjects < ActiveRecord::Migration[4.2]
-
- class ProjectImportDataFake
- extend AttrEncrypted
- attr_accessor :credentials
- attr_encrypted :credentials,
- key: Settings.attr_encrypted_db_key_base,
- marshal: true,
- encode: true,
- :mode => :per_attribute_iv_and_salt,
- insecure_mode: true,
- algorithm: 'aes-256-cbc'
- end
-
- def up
- say("Encrypting and migrating project import credentials...")
-
- # This should cover GitHub, GitLab, Bitbucket user:password, token@domain, and other similar URLs.
- in_transaction(message: "Projects including GitHub and GitLab projects with an unsecured URL.") { process_projects_with_wrong_url }
-
- in_transaction(message: "Migrating Bitbucket credentials...") { process_project(import_type: 'bitbucket', credentials_keys: ['bb_session']) }
-
- in_transaction(message: "Migrating FogBugz credentials...") { process_project(import_type: 'fogbugz', credentials_keys: ['fb_session']) }
-
- end
-
- def process_projects_with_wrong_url
- projects_with_wrong_import_url.each do |project|
- begin
- import_url = Gitlab::UrlSanitizer.new(project["import_url"])
-
- update_import_url(import_url, project)
- update_import_data(import_url, project)
- rescue Addressable::URI::InvalidURIError
- nullify_import_url(project)
- end
- end
- end
-
- def process_project(import_type:, credentials_keys: [])
- unencrypted_import_data(import_type: import_type).each do |data|
- replace_data_credentials(data, credentials_keys)
- end
- end
-
- def replace_data_credentials(data, credentials_keys)
- data_hash = JSON.load(data['data']) if data['data']
- unless data_hash.blank?
- encrypted_data_hash = encrypt_data(data_hash, credentials_keys)
- unencrypted_data = data_hash.empty? ? ' NULL ' : quote(data_hash.to_json)
- update_with_encrypted_data(encrypted_data_hash, data['id'], unencrypted_data)
- end
- end
-
- def encrypt_data(data_hash, credentials_keys)
- new_data_hash = {}
- credentials_keys.each do |key|
- new_data_hash[key.to_sym] = data_hash.delete(key) if data_hash[key]
- end
- new_data_hash.deep_symbolize_keys
- end
-
- def in_transaction(message:)
- say_with_time(message) do
- ActiveRecord::Base.transaction do
- yield
- end
- end
- end
-
- def update_import_data(import_url, project)
- fake_import_data = ProjectImportDataFake.new
- fake_import_data.credentials = import_url.credentials
- import_data_id = project['import_data_id']
- if import_data_id
- execute(update_import_data_sql(import_data_id, fake_import_data))
- else
- execute(insert_import_data_sql(project['id'], fake_import_data))
- end
- end
-
- def update_with_encrypted_data(data_hash, import_data_id, unencrypted_data = ' NULL ')
- fake_import_data = ProjectImportDataFake.new
- fake_import_data.credentials = data_hash
- execute(update_import_data_sql(import_data_id, fake_import_data, unencrypted_data))
- end
-
- def update_import_url(import_url, project)
- execute("UPDATE projects SET import_url = #{quote(import_url.sanitized_url)} WHERE id = #{project['id']}")
- end
-
- def nullify_import_url(project)
- execute("UPDATE projects SET import_url = NULL WHERE id = #{project['id']}")
- end
-
- def insert_import_data_sql(project_id, fake_import_data)
- %(
- INSERT INTO project_import_data
- (encrypted_credentials,
- project_id,
- encrypted_credentials_iv,
- encrypted_credentials_salt)
- VALUES ( #{quote(fake_import_data.encrypted_credentials)},
- '#{project_id}',
- #{quote(fake_import_data.encrypted_credentials_iv)},
- #{quote(fake_import_data.encrypted_credentials_salt)})
- ).squish
- end
-
- def update_import_data_sql(id, fake_import_data, data = 'NULL')
- %(
- UPDATE project_import_data
- SET encrypted_credentials = #{quote(fake_import_data.encrypted_credentials)},
- encrypted_credentials_iv = #{quote(fake_import_data.encrypted_credentials_iv)},
- encrypted_credentials_salt = #{quote(fake_import_data.encrypted_credentials_salt)},
- data = #{data}
- WHERE id = '#{id}'
- ).squish
- end
-
- #GitHub projects with token, and any user:password@ based URL
- def projects_with_wrong_import_url
- select_all("SELECT p.id, p.import_url, i.id as import_data_id FROM projects p LEFT JOIN project_import_data i on p.id = i.project_id WHERE p.import_url <> '' AND p.import_url LIKE '%//%@%'")
- end
-
- # All imports with data for import_type
- def unencrypted_import_data(import_type: )
- select_all("SELECT i.id, p.import_url, i.data FROM projects p INNER JOIN project_import_data i ON p.id = i.project_id WHERE p.import_url <> '' AND p.import_type = '#{import_type}' ")
- end
-
- def quote(value)
- ActiveRecord::Base.connection.quote(value)
- end
-end
diff --git a/db/migrate/20160305220806_remove_expires_at_from_snippets.rb b/db/migrate/20160305220806_remove_expires_at_from_snippets.rb
deleted file mode 100644
index 6835f534926..00000000000
--- a/db/migrate/20160305220806_remove_expires_at_from_snippets.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-# rubocop:disable all
-class RemoveExpiresAtFromSnippets < ActiveRecord::Migration[4.2]
- def change
- remove_column :snippets, :expires_at, :datetime
- end
-end
diff --git a/db/migrate/20160307221555_disallow_blank_line_code_on_note.rb b/db/migrate/20160307221555_disallow_blank_line_code_on_note.rb
deleted file mode 100644
index 26b65ef7037..00000000000
--- a/db/migrate/20160307221555_disallow_blank_line_code_on_note.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-class DisallowBlankLineCodeOnNote < ActiveRecord::Migration[4.2]
- def up
- execute("UPDATE notes SET line_code = NULL WHERE line_code = ''")
- end
-
- def down
- # noop
- end
-end
diff --git a/db/migrate/20160308212903_add_default_group_visibility_to_application_settings.rb b/db/migrate/20160308212903_add_default_group_visibility_to_application_settings.rb
deleted file mode 100644
index 16053408fe0..00000000000
--- a/db/migrate/20160308212903_add_default_group_visibility_to_application_settings.rb
+++ /dev/null
@@ -1,32 +0,0 @@
-# rubocop:disable all
-# Create visibility level field on DB
-# Sets default_visibility_level to value on settings if not restricted
-# If value is restricted takes higher visibility level allowed
-
-class AddDefaultGroupVisibilityToApplicationSettings < ActiveRecord::Migration[4.2]
- def up
- add_column :application_settings, :default_group_visibility, :integer
- # Unfortunately, this can't be a `default`, since we don't want the configuration specific
- # `allowed_visibility_level` to end up in schema.rb
-
- visibility_level = allowed_visibility_level || Gitlab::VisibilityLevel::PRIVATE
- execute("UPDATE application_settings SET default_group_visibility = #{visibility_level}")
- end
-
- def down
- remove_column :application_settings, :default_group_visibility
- end
-
- private
-
- def allowed_visibility_level
- application_settings = select_one("SELECT restricted_visibility_levels FROM application_settings ORDER BY id DESC LIMIT 1")
- if application_settings
- restricted_visibility_levels = YAML.safe_load(application_settings["restricted_visibility_levels"]) rescue nil
- end
- restricted_visibility_levels ||= []
-
- allowed_levels = Gitlab::VisibilityLevel.values - restricted_visibility_levels
- allowed_levels.max
- end
-end
diff --git a/db/migrate/20160309140734_fix_todos.rb b/db/migrate/20160309140734_fix_todos.rb
deleted file mode 100644
index 917055f5036..00000000000
--- a/db/migrate/20160309140734_fix_todos.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-# rubocop:disable all
-class FixTodos < ActiveRecord::Migration[4.2]
- def up
- execute <<-SQL
- DELETE FROM todos
- WHERE todos.target_type IN ('Commit', 'ProjectSnippet')
- OR NOT EXISTS (
- SELECT *
- FROM projects
- WHERE projects.id = todos.project_id
- )
- SQL
- end
-
- def down
- end
-end
diff --git a/db/migrate/20160310124959_add_due_date_to_issues.rb b/db/migrate/20160310124959_add_due_date_to_issues.rb
deleted file mode 100644
index 8da38ea60b1..00000000000
--- a/db/migrate/20160310124959_add_due_date_to_issues.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-# rubocop:disable all
-class AddDueDateToIssues < ActiveRecord::Migration[4.2]
- def change
- add_column :issues, :due_date, :date
- add_index :issues, :due_date
- end
-end
diff --git a/db/migrate/20160310185910_add_external_flag_to_users.rb b/db/migrate/20160310185910_add_external_flag_to_users.rb
deleted file mode 100644
index 768bbe4cd42..00000000000
--- a/db/migrate/20160310185910_add_external_flag_to_users.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-# rubocop:disable all
-class AddExternalFlagToUsers < ActiveRecord::Migration[4.2]
- def change
- add_column :users, :external, :boolean, default: false
- end
-end
diff --git a/db/migrate/20160314094147_add_priority_to_label.rb b/db/migrate/20160314094147_add_priority_to_label.rb
deleted file mode 100644
index 8e2aaf50109..00000000000
--- a/db/migrate/20160314094147_add_priority_to_label.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-# rubocop:disable all
-class AddPriorityToLabel < ActiveRecord::Migration[4.2]
- def change
- add_column :labels, :priority, :integer
- add_index :labels, :priority
- end
-end
diff --git a/db/migrate/20160314114439_add_requested_at_to_members.rb b/db/migrate/20160314114439_add_requested_at_to_members.rb
deleted file mode 100644
index e7e03f96ef8..00000000000
--- a/db/migrate/20160314114439_add_requested_at_to_members.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-# rubocop:disable Migration/Datetime
-class AddRequestedAtToMembers < ActiveRecord::Migration[4.2]
- def change
- add_column :members, :requested_at, :datetime
- end
-end
diff --git a/db/migrate/20160314143402_projects_add_pushes_since_gc.rb b/db/migrate/20160314143402_projects_add_pushes_since_gc.rb
deleted file mode 100644
index e64093d39cf..00000000000
--- a/db/migrate/20160314143402_projects_add_pushes_since_gc.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-# rubocop:disable all
-class ProjectsAddPushesSinceGc < ActiveRecord::Migration[4.2]
- def change
- add_column :projects, :pushes_since_gc, :integer, default: 0
- end
-end
diff --git a/db/migrate/20160315135439_project_add_repository_check.rb b/db/migrate/20160315135439_project_add_repository_check.rb
deleted file mode 100644
index c03d8bb041c..00000000000
--- a/db/migrate/20160315135439_project_add_repository_check.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-# rubocop:disable all
-class ProjectAddRepositoryCheck < ActiveRecord::Migration[4.2]
- def change
- add_column :projects, :last_repository_check_failed, :boolean
- add_index :projects, :last_repository_check_failed
-
- add_column :projects, :last_repository_check_at, :datetime
- end
-end
diff --git a/db/migrate/20160316123110_ci_runners_token_index.rb b/db/migrate/20160316123110_ci_runners_token_index.rb
deleted file mode 100644
index 026846e6464..00000000000
--- a/db/migrate/20160316123110_ci_runners_token_index.rb
+++ /dev/null
@@ -1,14 +0,0 @@
-# rubocop:disable all
-class CiRunnersTokenIndex < ActiveRecord::Migration[4.2]
- disable_ddl_transaction!
-
- def change
- args = [:ci_runners, :token]
-
- if Gitlab::Database.postgresql?
- args << { algorithm: :concurrently }
- end
-
- add_index(*args)
- end
-end
diff --git a/db/migrate/20160316192622_change_target_id_to_null_on_todos.rb b/db/migrate/20160316192622_change_target_id_to_null_on_todos.rb
deleted file mode 100644
index 488c3d4945c..00000000000
--- a/db/migrate/20160316192622_change_target_id_to_null_on_todos.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class ChangeTargetIdToNullOnTodos < ActiveRecord::Migration[4.2]
- def change
- change_column_null :todos, :target_id, true
- end
-end
diff --git a/db/migrate/20160316204731_add_commit_id_to_todos.rb b/db/migrate/20160316204731_add_commit_id_to_todos.rb
deleted file mode 100644
index d1c004b2ced..00000000000
--- a/db/migrate/20160316204731_add_commit_id_to_todos.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-# rubocop:disable all
-class AddCommitIdToTodos < ActiveRecord::Migration[4.2]
- def change
- add_column :todos, :commit_id, :string
- add_index :todos, :commit_id
- end
-end
diff --git a/db/migrate/20160317092222_add_moved_to_to_issue.rb b/db/migrate/20160317092222_add_moved_to_to_issue.rb
deleted file mode 100644
index 8d81d84fd20..00000000000
--- a/db/migrate/20160317092222_add_moved_to_to_issue.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class AddMovedToToIssue < ActiveRecord::Migration[4.2]
- def change
- add_reference :issues, :moved_to, references: :issues # rubocop:disable Migration/AddReference
- end
-end
diff --git a/db/migrate/20160320204112_index_namespaces_on_visibility_level.rb b/db/migrate/20160320204112_index_namespaces_on_visibility_level.rb
deleted file mode 100644
index 9692def430c..00000000000
--- a/db/migrate/20160320204112_index_namespaces_on_visibility_level.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-# rubocop:disable all
-class IndexNamespacesOnVisibilityLevel < ActiveRecord::Migration[4.2]
- def change
- unless index_exists?(:namespaces, :visibility_level)
- add_index :namespaces, :visibility_level
- end
- end
-end
diff --git a/db/migrate/20160324020319_remove_todos_for_deleted_issues.rb b/db/migrate/20160324020319_remove_todos_for_deleted_issues.rb
deleted file mode 100644
index a25d15a81ef..00000000000
--- a/db/migrate/20160324020319_remove_todos_for_deleted_issues.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-class RemoveTodosForDeletedIssues < ActiveRecord::Migration[4.2]
- def up
- execute <<-SQL
- DELETE FROM todos
- WHERE todos.target_type = 'Issue'
- AND NOT EXISTS (
- SELECT *
- FROM issues
- WHERE issues.id = todos.target_id
- AND issues.deleted_at IS NULL
- )
- SQL
- end
-
- def down
- end
-end
diff --git a/db/migrate/20160328112808_create_notification_settings.rb b/db/migrate/20160328112808_create_notification_settings.rb
deleted file mode 100644
index db19d2e370c..00000000000
--- a/db/migrate/20160328112808_create_notification_settings.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-# rubocop:disable all
-class CreateNotificationSettings < ActiveRecord::Migration[4.2]
- def change
- create_table :notification_settings do |t|
- t.references :user, null: false
- t.references :source, polymorphic: true, null: false
- t.integer :level, default: 0, null: false
-
- t.timestamps null: false
- end
- end
-end
diff --git a/db/migrate/20160328115649_migrate_new_notification_setting.rb b/db/migrate/20160328115649_migrate_new_notification_setting.rb
deleted file mode 100644
index 5ba09e75145..00000000000
--- a/db/migrate/20160328115649_migrate_new_notification_setting.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-# This migration will create one row of NotificationSetting for each Member row
-# It can take long time on big instances.
-#
-# This migration can be done online but with following effects:
-# - during migration some users will receive notifications based on their global settings (project/group settings will be ignored)
-# - its possible to get duplicate records for notification settings since we don't create uniq index yet
-#
-class MigrateNewNotificationSetting < ActiveRecord::Migration[4.2]
- def up
- timestamp = Time.now.strftime('%F %T')
- execute "INSERT INTO notification_settings ( user_id, source_id, source_type, level, created_at, updated_at ) SELECT user_id, source_id, source_type, notification_level, '#{timestamp}', '#{timestamp}' FROM members WHERE user_id IS NOT NULL"
- end
-
- def down
- execute "DELETE FROM notification_settings"
- end
-end
diff --git a/db/migrate/20160328121138_add_notification_setting_index.rb b/db/migrate/20160328121138_add_notification_setting_index.rb
deleted file mode 100644
index ed82b172296..00000000000
--- a/db/migrate/20160328121138_add_notification_setting_index.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-# rubocop:disable all
-class AddNotificationSettingIndex < ActiveRecord::Migration[4.2]
- def change
- add_index :notification_settings, :user_id
- add_index :notification_settings, [:source_id, :source_type]
- end
-end
diff --git a/db/migrate/20160329144452_add_index_on_pending_delete_projects.rb b/db/migrate/20160329144452_add_index_on_pending_delete_projects.rb
deleted file mode 100644
index 15c44f74451..00000000000
--- a/db/migrate/20160329144452_add_index_on_pending_delete_projects.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-# rubocop:disable all
-class AddIndexOnPendingDeleteProjects < ActiveRecord::Migration[4.2]
- def change
- add_index :projects, :pending_delete
- end
-end
-
diff --git a/db/migrate/20160331133914_remove_todos_for_deleted_merge_requests.rb b/db/migrate/20160331133914_remove_todos_for_deleted_merge_requests.rb
deleted file mode 100644
index 634a696377c..00000000000
--- a/db/migrate/20160331133914_remove_todos_for_deleted_merge_requests.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-class RemoveTodosForDeletedMergeRequests < ActiveRecord::Migration[4.2]
- def up
- execute <<-SQL
- DELETE FROM todos
- WHERE todos.target_type = 'MergeRequest'
- AND NOT EXISTS (
- SELECT *
- FROM merge_requests
- WHERE merge_requests.id = todos.target_id
- AND merge_requests.deleted_at IS NULL
- )
- SQL
- end
-
- def down
- end
-end
diff --git a/db/migrate/20160331223143_remove_twitter_sharing_enabled_from_application_settings.rb b/db/migrate/20160331223143_remove_twitter_sharing_enabled_from_application_settings.rb
deleted file mode 100644
index 6e5a748d096..00000000000
--- a/db/migrate/20160331223143_remove_twitter_sharing_enabled_from_application_settings.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-# rubocop:disable all
-class RemoveTwitterSharingEnabledFromApplicationSettings < ActiveRecord::Migration[4.2]
- def change
- remove_column :application_settings, :twitter_sharing_enabled, :boolean
- end
-end
diff --git a/db/migrate/20160407120251_add_images_enabled_for_project.rb b/db/migrate/20160407120251_add_images_enabled_for_project.rb
deleted file mode 100644
index 2c42d89ccdf..00000000000
--- a/db/migrate/20160407120251_add_images_enabled_for_project.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class AddImagesEnabledForProject < ActiveRecord::Migration[4.2]
- def change
- add_column :projects, :container_registry_enabled, :boolean
- end
-end
diff --git a/db/migrate/20160412140240_add_repository_checks_enabled_setting.rb b/db/migrate/20160412140240_add_repository_checks_enabled_setting.rb
deleted file mode 100644
index a59563b835e..00000000000
--- a/db/migrate/20160412140240_add_repository_checks_enabled_setting.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-# rubocop:disable all
-class AddRepositoryChecksEnabledSetting < ActiveRecord::Migration[4.2]
- def change
- add_column :application_settings, :repository_checks_enabled, :boolean, default: true
- end
-end
diff --git a/db/migrate/20160412173416_add_fields_to_ci_commit.rb b/db/migrate/20160412173416_add_fields_to_ci_commit.rb
deleted file mode 100644
index 4b3d4e8bd30..00000000000
--- a/db/migrate/20160412173416_add_fields_to_ci_commit.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-# rubocop:disable all
-class AddFieldsToCiCommit < ActiveRecord::Migration[4.2]
- def change
- add_column :ci_commits, :status, :string
- add_column :ci_commits, :started_at, :timestamp
- add_column :ci_commits, :finished_at, :timestamp
- add_column :ci_commits, :duration, :integer
- end
-end
diff --git a/db/migrate/20160412173417_update_ci_commit.rb b/db/migrate/20160412173417_update_ci_commit.rb
deleted file mode 100644
index 91dd4582f7a..00000000000
--- a/db/migrate/20160412173417_update_ci_commit.rb
+++ /dev/null
@@ -1,36 +0,0 @@
-# rubocop:disable all
-class UpdateCiCommit < ActiveRecord::Migration[4.2]
- # This migration can be run online, but needs to be executed for the second time after restarting Unicorn workers
- # Otherwise Offline migration should be used.
- def change
- execute("UPDATE ci_commits SET status=#{status}, ref=#{ref}, tag=#{tag} WHERE status IS NULL")
- end
-
- private
-
- def status
- builds = '(SELECT COUNT(*) FROM ci_builds WHERE ci_builds.commit_id=ci_commits.id)'
- success = "(SELECT COUNT(*) FROM ci_builds WHERE ci_builds.commit_id=ci_commits.id AND status='success')"
- ignored = "(SELECT COUNT(*) FROM ci_builds WHERE ci_builds.commit_id=ci_commits.id AND (status='failed' OR status='canceled') AND allow_failure)"
- pending = "(SELECT COUNT(*) FROM ci_builds WHERE ci_builds.commit_id=ci_commits.id AND status='pending')"
- running = "(SELECT COUNT(*) FROM ci_builds WHERE ci_builds.commit_id=ci_commits.id AND status='running')"
- canceled = "(SELECT COUNT(*) FROM ci_builds WHERE ci_builds.commit_id=ci_commits.id AND status='canceled')"
-
- "(CASE
- WHEN #{builds}=0 THEN 'skipped'
- WHEN #{builds}=#{success}+#{ignored} THEN 'success'
- WHEN #{builds}=#{pending} THEN 'pending'
- WHEN #{builds}=#{canceled} THEN 'canceled'
- WHEN #{running}+#{pending}>0 THEN 'running'
- ELSE 'failed'
- END)"
- end
-
- def ref
- '(SELECT ref FROM ci_builds WHERE ci_builds.commit_id=ci_commits.id ORDER BY id DESC LIMIT 1)'
- end
-
- def tag
- '(SELECT tag FROM ci_builds WHERE ci_builds.commit_id=ci_commits.id ORDER BY id DESC LIMIT 1)'
- end
-end
diff --git a/db/migrate/20160412173418_add_ci_commit_indexes.rb b/db/migrate/20160412173418_add_ci_commit_indexes.rb
deleted file mode 100644
index 709e6b84d57..00000000000
--- a/db/migrate/20160412173418_add_ci_commit_indexes.rb
+++ /dev/null
@@ -1,20 +0,0 @@
-# rubocop:disable all
-class AddCiCommitIndexes < ActiveRecord::Migration[4.2]
- disable_ddl_transaction!
-
- def change
- add_index :ci_commits, [:gl_project_id, :sha], index_options
- add_index :ci_commits, [:gl_project_id, :status], index_options
- add_index :ci_commits, [:status], index_options
- end
-
- private
-
- def index_options
- if Gitlab::Database.postgresql?
- { algorithm: :concurrently }
- else
- { }
- end
- end
-end
diff --git a/db/migrate/20160413115152_add_token_to_web_hooks.rb b/db/migrate/20160413115152_add_token_to_web_hooks.rb
deleted file mode 100644
index 43fe46dfe5d..00000000000
--- a/db/migrate/20160413115152_add_token_to_web_hooks.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class AddTokenToWebHooks < ActiveRecord::Migration[4.2]
- def change
- add_column :web_hooks, :token, :string
- end
-end
diff --git a/db/migrate/20160415062917_create_personal_access_tokens.rb b/db/migrate/20160415062917_create_personal_access_tokens.rb
deleted file mode 100644
index 43599db799e..00000000000
--- a/db/migrate/20160415062917_create_personal_access_tokens.rb
+++ /dev/null
@@ -1,14 +0,0 @@
-# rubocop:disable Migration/Timestamps
-class CreatePersonalAccessTokens < ActiveRecord::Migration[4.2]
- def change
- create_table :personal_access_tokens do |t|
- t.references :user, index: true, foreign_key: true, null: false
- t.string :token, index: { unique: true }, null: false
- t.string :name, null: false
- t.boolean :revoked, default: false
- t.datetime :expires_at
-
- t.timestamps null: false
- end
- end
-end
diff --git a/db/migrate/20160415133440_add_shared_runners_text_to_application_settings.rb b/db/migrate/20160415133440_add_shared_runners_text_to_application_settings.rb
deleted file mode 100644
index e96c0591a07..00000000000
--- a/db/migrate/20160415133440_add_shared_runners_text_to_application_settings.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class AddSharedRunnersTextToApplicationSettings < ActiveRecord::Migration[4.2]
- def change
- add_column :application_settings, :shared_runners_text, :text
- end
-end
diff --git a/db/migrate/20160416180807_add_award_emoji.rb b/db/migrate/20160416180807_add_award_emoji.rb
deleted file mode 100644
index 99c984fd116..00000000000
--- a/db/migrate/20160416180807_add_award_emoji.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-# rubocop:disable all
-class AddAwardEmoji < ActiveRecord::Migration[4.2]
- DOWNTIME = false
-
- def change
- create_table :award_emoji do |t|
- t.string :name
- t.references :user
- t.references :awardable, polymorphic: true
-
- t.timestamps null: true
- end
-
- add_index :award_emoji, :user_id
- add_index :award_emoji, [:awardable_type, :awardable_id]
- end
-end
diff --git a/db/migrate/20160416182152_convert_award_note_to_emoji_award.rb b/db/migrate/20160416182152_convert_award_note_to_emoji_award.rb
deleted file mode 100644
index af2820986f0..00000000000
--- a/db/migrate/20160416182152_convert_award_note_to_emoji_award.rb
+++ /dev/null
@@ -1,36 +0,0 @@
-class ConvertAwardNoteToEmojiAward < ActiveRecord::Migration[4.2]
- disable_ddl_transaction!
-
- def up
- if Gitlab::Database.postgresql?
- migrate_postgresql
- else
- migrate_mysql
- end
- end
-
- def down
- add_column :notes, :is_award, :boolean
-
- # This migration does NOT move the awards on notes, if the table is dropped in another migration, these notes will be lost.
- execute "INSERT INTO notes (noteable_type, noteable_id, author_id, note, created_at, updated_at, is_award) (SELECT awardable_type, awardable_id, user_id, name, created_at, updated_at, TRUE FROM award_emoji)"
- end
-
- def migrate_postgresql
- connection.transaction do
- execute 'LOCK notes IN EXCLUSIVE MODE'
- execute "INSERT INTO award_emoji (awardable_type, awardable_id, user_id, name, created_at, updated_at) (SELECT noteable_type, noteable_id, author_id, note, created_at, updated_at FROM notes WHERE is_award = true)"
- execute "DELETE FROM notes WHERE is_award = true"
- remove_column :notes, :is_award, :boolean
- end
- end
-
- def migrate_mysql
- execute 'LOCK TABLES notes WRITE, award_emoji WRITE;'
- execute 'INSERT INTO award_emoji (awardable_type, awardable_id, user_id, name, created_at, updated_at) (SELECT noteable_type, noteable_id, author_id, note, created_at, updated_at FROM notes WHERE is_award = true);'
- execute "DELETE FROM notes WHERE is_award = true"
- remove_column :notes, :is_award, :boolean
- ensure
- execute 'UNLOCK TABLES'
- end
-end
diff --git a/db/migrate/20160419120017_add_metrics_packet_size.rb b/db/migrate/20160419120017_add_metrics_packet_size.rb
deleted file mode 100644
index 16c3ebfe22b..00000000000
--- a/db/migrate/20160419120017_add_metrics_packet_size.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class AddMetricsPacketSize < ActiveRecord::Migration[4.2]
- def change
- add_column :application_settings, :metrics_packet_size, :integer, default: 1
- end
-end
diff --git a/db/migrate/20160419122101_add_only_allow_merge_if_build_succeeds_to_projects.rb b/db/migrate/20160419122101_add_only_allow_merge_if_build_succeeds_to_projects.rb
deleted file mode 100644
index cf842a684a6..00000000000
--- a/db/migrate/20160419122101_add_only_allow_merge_if_build_succeeds_to_projects.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-# rubocop:disable Migration/UpdateLargeTable
-class AddOnlyAllowMergeIfBuildSucceedsToProjects < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
- disable_ddl_transaction!
-
- def up
- add_column_with_default(:projects,
- :only_allow_merge_if_build_succeeds,
- :boolean,
- default: false)
- end
-
- def down
- remove_column(:projects, :only_allow_merge_if_build_succeeds)
- end
-end
diff --git a/db/migrate/20160421130527_disable_repository_checks.rb b/db/migrate/20160421130527_disable_repository_checks.rb
deleted file mode 100644
index 8b3ce73c5e8..00000000000
--- a/db/migrate/20160421130527_disable_repository_checks.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-# rubocop:disable all
-class DisableRepositoryChecks < ActiveRecord::Migration[4.2]
- def up
- change_column_default :application_settings, :repository_checks_enabled, false
- execute 'UPDATE application_settings SET repository_checks_enabled = false'
- end
-
- def down
- change_column_default :application_settings, :repository_checks_enabled, true
- execute 'UPDATE application_settings SET repository_checks_enabled = true'
- end
-end
diff --git a/db/migrate/20160425045124_create_u2f_registrations.rb b/db/migrate/20160425045124_create_u2f_registrations.rb
deleted file mode 100644
index 9b48fc822b6..00000000000
--- a/db/migrate/20160425045124_create_u2f_registrations.rb
+++ /dev/null
@@ -1,14 +0,0 @@
-# rubocop:disable all
-class CreateU2fRegistrations < ActiveRecord::Migration[4.2]
- def change
- create_table :u2f_registrations do |t|
- t.text :certificate
- t.string :key_handle, index: true
- t.string :public_key
- t.integer :counter
- t.references :user, index: true, foreign_key: true
-
- t.timestamps null: false
- end
- end
-end
diff --git a/db/migrate/20160504091942_add_disabled_oauth_sign_in_sources_to_application_settings.rb b/db/migrate/20160504091942_add_disabled_oauth_sign_in_sources_to_application_settings.rb
deleted file mode 100644
index 9a0d1a2d316..00000000000
--- a/db/migrate/20160504091942_add_disabled_oauth_sign_in_sources_to_application_settings.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class AddDisabledOauthSignInSourcesToApplicationSettings < ActiveRecord::Migration[4.2]
- def change
- add_column :application_settings, :disabled_oauth_sign_in_sources, :text
- end
-end
diff --git a/db/migrate/20160504112519_add_run_untagged_to_ci_runner.rb b/db/migrate/20160504112519_add_run_untagged_to_ci_runner.rb
deleted file mode 100644
index 03ec29b9951..00000000000
--- a/db/migrate/20160504112519_add_run_untagged_to_ci_runner.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-class AddRunUntaggedToCiRunner < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
- disable_ddl_transaction!
-
- def up
- add_column_with_default(:ci_runners, :run_untagged, :boolean,
- default: true, allow_null: false)
- end
-
- def down
- remove_column(:ci_runners, :run_untagged)
- end
-end
diff --git a/db/migrate/20160508194200_remove_wall_enabled_from_projects.rb b/db/migrate/20160508194200_remove_wall_enabled_from_projects.rb
deleted file mode 100644
index 4edbeb09f74..00000000000
--- a/db/migrate/20160508194200_remove_wall_enabled_from_projects.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-# rubocop:disable all
-class RemoveWallEnabledFromProjects < ActiveRecord::Migration[4.2]
- def change
- remove_column :projects, :wall_enabled, :boolean, default: true, null: false
- end
-end
diff --git a/db/migrate/20160508202603_add_head_commit_id_to_merge_request_diffs.rb b/db/migrate/20160508202603_add_head_commit_id_to_merge_request_diffs.rb
deleted file mode 100644
index ee7c9326bfe..00000000000
--- a/db/migrate/20160508202603_add_head_commit_id_to_merge_request_diffs.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class AddHeadCommitIdToMergeRequestDiffs < ActiveRecord::Migration[4.2]
- def change
- add_column :merge_request_diffs, :head_commit_sha, :string
- end
-end
diff --git a/db/migrate/20160508215820_add_type_to_notes.rb b/db/migrate/20160508215820_add_type_to_notes.rb
deleted file mode 100644
index 343743a589c..00000000000
--- a/db/migrate/20160508215820_add_type_to_notes.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class AddTypeToNotes < ActiveRecord::Migration[4.2]
- def change
- add_column :notes, :type, :string
- end
-end
diff --git a/db/migrate/20160508215920_add_positions_to_diff_notes.rb b/db/migrate/20160508215920_add_positions_to_diff_notes.rb
deleted file mode 100644
index e0ee03d0fb5..00000000000
--- a/db/migrate/20160508215920_add_positions_to_diff_notes.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-class AddPositionsToDiffNotes < ActiveRecord::Migration[4.2]
- def change
- add_column :notes, :position, :text
- add_column :notes, :original_position, :text
- end
-end
diff --git a/db/migrate/20160508221410_set_type_on_legacy_diff_notes.rb b/db/migrate/20160508221410_set_type_on_legacy_diff_notes.rb
deleted file mode 100644
index 567754d4f4e..00000000000
--- a/db/migrate/20160508221410_set_type_on_legacy_diff_notes.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-# rubocop:disable all
-class SetTypeOnLegacyDiffNotes < ActiveRecord::Migration[4.2]
- def change
- execute "UPDATE notes SET type = 'LegacyDiffNote' WHERE line_code IS NOT NULL"
- end
-end
diff --git a/db/migrate/20160509091049_add_locked_to_ci_runner.rb b/db/migrate/20160509091049_add_locked_to_ci_runner.rb
deleted file mode 100644
index e19db5a4504..00000000000
--- a/db/migrate/20160509091049_add_locked_to_ci_runner.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-class AddLockedToCiRunner < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
- disable_ddl_transaction!
-
- def up
- add_column_with_default(:ci_runners, :locked, :boolean,
- default: false, allow_null: false)
- end
-
- def down
- remove_column(:ci_runners, :locked)
- end
-end
diff --git a/db/migrate/20160509201028_add_health_check_access_token_to_application_settings.rb b/db/migrate/20160509201028_add_health_check_access_token_to_application_settings.rb
deleted file mode 100644
index 54d615f7e21..00000000000
--- a/db/migrate/20160509201028_add_health_check_access_token_to_application_settings.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class AddHealthCheckAccessTokenToApplicationSettings < ActiveRecord::Migration[4.2]
- def change
- add_column :application_settings, :health_check_access_token, :string
- end
-end
diff --git a/db/migrate/20160516174813_add_send_user_confirmation_email_to_application_settings.rb b/db/migrate/20160516174813_add_send_user_confirmation_email_to_application_settings.rb
deleted file mode 100644
index 9e203b97a43..00000000000
--- a/db/migrate/20160516174813_add_send_user_confirmation_email_to_application_settings.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-# rubocop:disable all
-class AddSendUserConfirmationEmailToApplicationSettings < ActiveRecord::Migration[4.2]
- def up
- add_column :application_settings, :send_user_confirmation_email, :boolean, default: false
-
- #Sets confirmation email to true by default on existing installations.
- execute "UPDATE application_settings SET send_user_confirmation_email=true"
- end
-
- def down
- remove_column :application_settings, :send_user_confirmation_email
- end
-end
diff --git a/db/migrate/20160516224534_add_start_commit_id_to_merge_request_diffs.rb b/db/migrate/20160516224534_add_start_commit_id_to_merge_request_diffs.rb
deleted file mode 100644
index a84bfd64bda..00000000000
--- a/db/migrate/20160516224534_add_start_commit_id_to_merge_request_diffs.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class AddStartCommitIdToMergeRequestDiffs < ActiveRecord::Migration[4.2]
- def change
- add_column :merge_request_diffs, :start_commit_sha, :string
- end
-end
diff --git a/db/migrate/20160518200441_add_artifacts_expire_date_to_ci_builds.rb b/db/migrate/20160518200441_add_artifacts_expire_date_to_ci_builds.rb
deleted file mode 100644
index 143b84a1662..00000000000
--- a/db/migrate/20160518200441_add_artifacts_expire_date_to_ci_builds.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-# rubocop:disable Migration/Datetime
-class AddArtifactsExpireDateToCiBuilds < ActiveRecord::Migration[4.2]
- def change
- add_column :ci_builds, :artifacts_expire_at, :timestamp
- end
-end
diff --git a/db/migrate/20160519203051_add_developers_can_merge_to_protected_branches.rb b/db/migrate/20160519203051_add_developers_can_merge_to_protected_branches.rb
deleted file mode 100644
index ba0e1654379..00000000000
--- a/db/migrate/20160519203051_add_developers_can_merge_to_protected_branches.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-class AddDevelopersCanMergeToProtectedBranches < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- add_column_with_default :protected_branches, :developers_can_merge, :boolean, default: false, allow_null: false
- end
-
- def down
- remove_column :protected_branches, :developers_can_merge
- end
-end
diff --git a/db/migrate/20160522215720_add_note_type_and_position_to_sent_notification.rb b/db/migrate/20160522215720_add_note_type_and_position_to_sent_notification.rb
deleted file mode 100644
index f569fc7c73f..00000000000
--- a/db/migrate/20160522215720_add_note_type_and_position_to_sent_notification.rb
+++ /dev/null
@@ -1,22 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class AddNoteTypeAndPositionToSentNotification < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # When using the methods "add_concurrent_index" or "add_column_with_default"
- # you must disable the use of transactions as these methods can not run in an
- # existing transaction. When using "add_concurrent_index" make sure that this
- # method is the _only_ method called in the migration, any other changes
- # should go in a separate migration. This ensures that upon failure _only_ the
- # index creation fails and can be retried or reverted easily.
- #
- # To disable transactions uncomment the following line and remove these
- # comments:
- # disable_ddl_transaction!
-
- def change
- add_column :sent_notifications, :note_type, :string
- add_column :sent_notifications, :position, :text
- end
-end
diff --git a/db/migrate/20160525205328_remove_main_language_from_projects.rb b/db/migrate/20160525205328_remove_main_language_from_projects.rb
deleted file mode 100644
index 81d0fb5b080..00000000000
--- a/db/migrate/20160525205328_remove_main_language_from_projects.rb
+++ /dev/null
@@ -1,22 +0,0 @@
-# rubocop:disable all
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class RemoveMainLanguageFromProjects < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # When using the methods "add_concurrent_index" or "add_column_with_default"
- # you must disable the use of transactions as these methods can not run in an
- # existing transaction. When using "add_concurrent_index" make sure that this
- # method is the _only_ method called in the migration, any other changes
- # should go in a separate migration. This ensures that upon failure _only_ the
- # index creation fails and can be retried or reverted easily.
- #
- # To disable transactions uncomment the following line and remove these
- # comments:
- # disable_ddl_transaction!
-
- def change
- remove_column :projects, :main_language
- end
-end
diff --git a/db/migrate/20160527020117_remove_notification_settings_for_deleted_projects.rb b/db/migrate/20160527020117_remove_notification_settings_for_deleted_projects.rb
deleted file mode 100644
index c530c09859d..00000000000
--- a/db/migrate/20160527020117_remove_notification_settings_for_deleted_projects.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-class RemoveNotificationSettingsForDeletedProjects < ActiveRecord::Migration[4.2]
- def up
- execute <<-SQL
- DELETE FROM notification_settings
- WHERE notification_settings.source_type = 'Project'
- AND NOT EXISTS (
- SELECT *
- FROM projects
- WHERE projects.id = notification_settings.source_id
- )
- SQL
- end
-end
diff --git a/db/migrate/20160528043124_add_users_state_index.rb b/db/migrate/20160528043124_add_users_state_index.rb
deleted file mode 100644
index 3437b35a0c0..00000000000
--- a/db/migrate/20160528043124_add_users_state_index.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-# rubocop:disable all
-class AddUsersStateIndex < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- disable_ddl_transaction!
-
- def change
- add_concurrent_index :users, :state
- end
-end
diff --git a/db/migrate/20160530150109_add_container_registry_token_expire_delay_to_application_settings.rb b/db/migrate/20160530150109_add_container_registry_token_expire_delay_to_application_settings.rb
deleted file mode 100644
index 7b20146e21c..00000000000
--- a/db/migrate/20160530150109_add_container_registry_token_expire_delay_to_application_settings.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-# This is ONLINE migration
-
-class AddContainerRegistryTokenExpireDelayToApplicationSettings < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- def change
- add_column :application_settings, :container_registry_token_expire_delay, :integer, default: 5
- end
-end
diff --git a/db/migrate/20160603075128_add_has_external_issue_tracker_to_projects.rb b/db/migrate/20160603075128_add_has_external_issue_tracker_to_projects.rb
deleted file mode 100644
index a7d2d7f9952..00000000000
--- a/db/migrate/20160603075128_add_has_external_issue_tracker_to_projects.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class AddHasExternalIssueTrackerToProjects < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- def change
- add_column(:projects, :has_external_issue_tracker, :boolean)
- end
-end
diff --git a/db/migrate/20160603180330_remove_duplicated_notification_settings.rb b/db/migrate/20160603180330_remove_duplicated_notification_settings.rb
deleted file mode 100644
index 0d8c4bf011c..00000000000
--- a/db/migrate/20160603180330_remove_duplicated_notification_settings.rb
+++ /dev/null
@@ -1,32 +0,0 @@
-class RemoveDuplicatedNotificationSettings < ActiveRecord::Migration[4.2]
- def up
- duplicates = exec_query(%Q{
- SELECT user_id, source_type, source_id
- FROM notification_settings
- GROUP BY user_id, source_type, source_id
- HAVING COUNT(*) > 1
- })
-
- duplicates.each do |row|
- uid = row['user_id']
- stype = connection.quote(row['source_type'])
- sid = row['source_id']
-
- execute(%Q{
- DELETE FROM notification_settings
- WHERE user_id = #{uid}
- AND source_type = #{stype}
- AND source_id = #{sid}
- AND id != (
- SELECT id FROM (
- SELECT min(id) AS id
- FROM notification_settings
- WHERE user_id = #{uid}
- AND source_type = #{stype}
- AND source_id = #{sid}
- ) min_ids
- )
- })
- end
- end
-end
diff --git a/db/migrate/20160603182247_add_index_to_notification_settings.rb b/db/migrate/20160603182247_add_index_to_notification_settings.rb
deleted file mode 100644
index cea178d555c..00000000000
--- a/db/migrate/20160603182247_add_index_to_notification_settings.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-# rubocop:disable all
-class AddIndexToNotificationSettings < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- disable_ddl_transaction!
-
- def change
- add_concurrent_index :notification_settings, [:user_id, :source_id, :source_type], { unique: true, name: "index_notifications_on_user_id_and_source_id_and_source_type" }
- end
-end
diff --git a/db/migrate/20160608155312_add_after_sign_up_text_to_application_settings.rb b/db/migrate/20160608155312_add_after_sign_up_text_to_application_settings.rb
deleted file mode 100644
index 3b3f68529a5..00000000000
--- a/db/migrate/20160608155312_add_after_sign_up_text_to_application_settings.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class AddAfterSignUpTextToApplicationSettings < ActiveRecord::Migration[4.2]
- def change
- add_column :application_settings, :after_sign_up_text, :text
- end
-end
diff --git a/db/migrate/20160608195742_add_repository_storage_to_projects.rb b/db/migrate/20160608195742_add_repository_storage_to_projects.rb
deleted file mode 100644
index 2b20c9fbd5f..00000000000
--- a/db/migrate/20160608195742_add_repository_storage_to_projects.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-# rubocop:disable Migration/UpdateLargeTable
-class AddRepositoryStorageToProjects < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
- disable_ddl_transaction!
-
- def up
- add_column_with_default(:projects, :repository_storage, :string, default: 'default')
- end
-
- def down
- remove_column(:projects, :repository_storage)
- end
-end
diff --git a/db/migrate/20160608211215_add_user_default_external_to_application_settings.rb b/db/migrate/20160608211215_add_user_default_external_to_application_settings.rb
deleted file mode 100644
index 9b5cfc67d5a..00000000000
--- a/db/migrate/20160608211215_add_user_default_external_to_application_settings.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-class AddUserDefaultExternalToApplicationSettings < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
- disable_ddl_transaction!
-
- def up
- add_column_with_default(:application_settings, :user_default_external, :boolean,
- default: false, allow_null: false)
- end
-
- def down
- remove_column(:application_settings, :user_default_external)
- end
-end
diff --git a/db/migrate/20160610140403_remove_notification_setting_not_null_constraints.rb b/db/migrate/20160610140403_remove_notification_setting_not_null_constraints.rb
deleted file mode 100644
index d5301672dc5..00000000000
--- a/db/migrate/20160610140403_remove_notification_setting_not_null_constraints.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-class RemoveNotificationSettingNotNullConstraints < ActiveRecord::Migration[4.2]
- def up
- change_column :notification_settings, :source_type, :string, null: true
- change_column :notification_settings, :source_id, :integer, null: true
- end
-
- def down
- change_column :notification_settings, :source_type, :string, null: false
- change_column :notification_settings, :source_id, :integer, null: false
- end
-end
diff --git a/db/migrate/20160610194713_remove_deprecated_issues_tracker_columns_from_projects.rb b/db/migrate/20160610194713_remove_deprecated_issues_tracker_columns_from_projects.rb
deleted file mode 100644
index 1ac65997403..00000000000
--- a/db/migrate/20160610194713_remove_deprecated_issues_tracker_columns_from_projects.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-# rubocop:disable Migration/RemoveColumn
-class RemoveDeprecatedIssuesTrackerColumnsFromProjects < ActiveRecord::Migration[4.2]
- def change
- remove_column :projects, :issues_tracker, :string, default: 'gitlab', null: false
- remove_column :projects, :issues_tracker_id, :string
- end
-end
diff --git a/db/migrate/20160610201627_migrate_users_notification_level.rb b/db/migrate/20160610201627_migrate_users_notification_level.rb
deleted file mode 100644
index 553b7f074f2..00000000000
--- a/db/migrate/20160610201627_migrate_users_notification_level.rb
+++ /dev/null
@@ -1,25 +0,0 @@
-class MigrateUsersNotificationLevel < ActiveRecord::Migration[4.2]
- DOWNTIME = false
-
- # Migrates only users who changed their default notification level :participating
- # creating a new record on notification settings table
-
- DOWNTIME = false
-
- def up
- execute(%Q{
- INSERT INTO notification_settings
- (user_id, level, created_at, updated_at)
- (SELECT id, notification_level, created_at, updated_at FROM users WHERE notification_level != 1)
- })
- end
-
- # Migrates from notification settings back to user notification_level
- # If no value is found the default level of 1 will be used
- def down
- execute(%Q{
- UPDATE users u SET
- notification_level = COALESCE((SELECT level FROM notification_settings WHERE user_id = u.id AND source_type IS NULL), 1)
- })
- end
-end
diff --git a/db/migrate/20160610204157_add_deployments.rb b/db/migrate/20160610204157_add_deployments.rb
deleted file mode 100644
index 91b619e7d3d..00000000000
--- a/db/migrate/20160610204157_add_deployments.rb
+++ /dev/null
@@ -1,26 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-class AddDeployments < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- def change
- create_table :deployments, force: true do |t|
- t.integer :iid, null: false
- t.integer :project_id, null: false
- t.integer :environment_id, null: false
- t.string :ref, null: false
- t.boolean :tag, null: false
- t.string :sha, null: false
- t.integer :user_id
- t.integer :deployable_id
- t.string :deployable_type
- t.datetime :created_at
- t.datetime :updated_at
- end
-
- add_index :deployments, :project_id
- add_index :deployments, [:project_id, :iid], unique: true
- add_index :deployments, [:project_id, :environment_id]
- add_index :deployments, [:project_id, :environment_id, :iid]
- end
-end
diff --git a/db/migrate/20160610204158_add_environments.rb b/db/migrate/20160610204158_add_environments.rb
deleted file mode 100644
index 55fb8b1227b..00000000000
--- a/db/migrate/20160610204158_add_environments.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-class AddEnvironments < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- def change
- create_table :environments, force: true do |t|
- t.integer :project_id, null: false
- t.string :name, null: false
- t.datetime :created_at
- t.datetime :updated_at
- end
-
- add_index :environments, [:project_id, :name]
- end
-end
diff --git a/db/migrate/20160610211845_add_environment_to_builds.rb b/db/migrate/20160610211845_add_environment_to_builds.rb
deleted file mode 100644
index 16d5465cafa..00000000000
--- a/db/migrate/20160610211845_add_environment_to_builds.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class AddEnvironmentToBuilds < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- def change
- add_column :ci_builds, :environment, :string
- end
-end
diff --git a/db/migrate/20160610301627_remove_notification_level_from_users.rb b/db/migrate/20160610301627_remove_notification_level_from_users.rb
deleted file mode 100644
index 93f70c476d2..00000000000
--- a/db/migrate/20160610301627_remove_notification_level_from_users.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-# rubocop:disable Migration/RemoveColumn
-class RemoveNotificationLevelFromUsers < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- def change
- remove_column :users, :notification_level, :integer
- end
-end
diff --git a/db/migrate/20160614182521_add_repository_storage_to_application_settings.rb b/db/migrate/20160614182521_add_repository_storage_to_application_settings.rb
deleted file mode 100644
index a1bc0e5cd86..00000000000
--- a/db/migrate/20160614182521_add_repository_storage_to_application_settings.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-class AddRepositoryStorageToApplicationSettings < ActiveRecord::Migration[4.2]
- def change
- add_column :application_settings, :repository_storage, :string, default: 'default'
- end
-end
diff --git a/db/migrate/20160615142710_add_index_on_requested_at_to_members.rb b/db/migrate/20160615142710_add_index_on_requested_at_to_members.rb
deleted file mode 100644
index 1b1dab141f8..00000000000
--- a/db/migrate/20160615142710_add_index_on_requested_at_to_members.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-# rubocop:disable RemoveIndex
-class AddIndexOnRequestedAtToMembers < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- add_concurrent_index :members, :requested_at
- end
-
- def down
- remove_index :members, :requested_at if index_exists? :members, :requested_at
- end
-end
diff --git a/db/migrate/20160615173316_add_enabled_git_access_protocols_to_application_settings.rb b/db/migrate/20160615173316_add_enabled_git_access_protocols_to_application_settings.rb
deleted file mode 100644
index deb4b86a2fd..00000000000
--- a/db/migrate/20160615173316_add_enabled_git_access_protocols_to_application_settings.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class AddEnabledGitAccessProtocolsToApplicationSettings < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- def change
- add_column :application_settings, :enabled_git_access_protocol, :string
- end
-end
diff --git a/db/migrate/20160615191922_set_missing_stage_on_ci_builds.rb b/db/migrate/20160615191922_set_missing_stage_on_ci_builds.rb
deleted file mode 100644
index 11d15e7c15f..00000000000
--- a/db/migrate/20160615191922_set_missing_stage_on_ci_builds.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-# rubocop:disable Migration/UpdateLargeTable
-# rubocop:disable Migration/UpdateColumnInBatches
-class SetMissingStageOnCiBuilds < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- disable_ddl_transaction!
-
- def up
- update_column_in_batches(:ci_builds, :stage, :test) do |table, query|
- query.where(table[:stage].eq(nil))
- end
- end
-end
diff --git a/db/migrate/20160616084004_change_project_of_environment.rb b/db/migrate/20160616084004_change_project_of_environment.rb
deleted file mode 100644
index 23914a0325a..00000000000
--- a/db/migrate/20160616084004_change_project_of_environment.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class ChangeProjectOfEnvironment < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # When using the methods "add_concurrent_index" or "add_column_with_default"
- # you must disable the use of transactions as these methods can not run in an
- # existing transaction. When using "add_concurrent_index" make sure that this
- # method is the _only_ method called in the migration, any other changes
- # should go in a separate migration. This ensures that upon failure _only_ the
- # index creation fails and can be retried or reverted easily.
- #
- # To disable transactions uncomment the following line and remove these
- # comments:
- # disable_ddl_transaction!
-
- def change
- change_column_null :environments, :project_id, true
- end
-end
diff --git a/db/migrate/20160616102642_remove_duplicated_keys.rb b/db/migrate/20160616102642_remove_duplicated_keys.rb
deleted file mode 100644
index 0b896108292..00000000000
--- a/db/migrate/20160616102642_remove_duplicated_keys.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-class RemoveDuplicatedKeys < ActiveRecord::Migration[4.2]
- def up
- select_all("SELECT fingerprint FROM #{quote_table_name(:keys)} GROUP BY fingerprint HAVING COUNT(*) > 1").each do |row|
- fingerprint = connection.quote(row['fingerprint'])
- execute(%Q{
- DELETE FROM #{quote_table_name(:keys)}
- WHERE fingerprint = #{fingerprint}
- AND id != (
- SELECT id FROM (
- SELECT max(id) AS id
- FROM #{quote_table_name(:keys)}
- WHERE fingerprint = #{fingerprint}
- ) max_ids
- )
- })
- end
- end
-end
diff --git a/db/migrate/20160616103005_remove_keys_fingerprint_index_if_exists.rb b/db/migrate/20160616103005_remove_keys_fingerprint_index_if_exists.rb
deleted file mode 100644
index afccc40cc67..00000000000
--- a/db/migrate/20160616103005_remove_keys_fingerprint_index_if_exists.rb
+++ /dev/null
@@ -1,22 +0,0 @@
-# rubocop:disable RemoveIndex
-class RemoveKeysFingerprintIndexIfExists < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- disable_ddl_transaction!
-
- # https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/250
- # That MR was added on gitlab-ee so we need to check if the index
- # already exists because we want to do is create an unique index instead.
-
- def up
- if index_exists?(:keys, :fingerprint)
- remove_index :keys, :fingerprint
- end
- end
-
- def down
- unless index_exists?(:keys, :fingerprint)
- add_concurrent_index :keys, :fingerprint
- end
- end
-end
diff --git a/db/migrate/20160616103948_add_unique_index_to_keys_fingerprint.rb b/db/migrate/20160616103948_add_unique_index_to_keys_fingerprint.rb
deleted file mode 100644
index d619acad3d0..00000000000
--- a/db/migrate/20160616103948_add_unique_index_to_keys_fingerprint.rb
+++ /dev/null
@@ -1,14 +0,0 @@
-# rubocop:disable RemoveIndex
-class AddUniqueIndexToKeysFingerprint < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- disable_ddl_transaction!
-
- def up
- add_concurrent_index :keys, :fingerprint, unique: true
- end
-
- def down
- remove_index :keys, :fingerprint
- end
-end
diff --git a/db/migrate/20160617301627_add_events_to_notification_settings.rb b/db/migrate/20160617301627_add_events_to_notification_settings.rb
deleted file mode 100644
index 109817e3d8a..00000000000
--- a/db/migrate/20160617301627_add_events_to_notification_settings.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-class AddEventsToNotificationSettings < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- def change
- add_column :notification_settings, :events, :text
- end
-end
diff --git a/db/migrate/20160620115026_add_index_on_runners_locked.rb b/db/migrate/20160620115026_add_index_on_runners_locked.rb
deleted file mode 100644
index c619dc07a91..00000000000
--- a/db/migrate/20160620115026_add_index_on_runners_locked.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-# rubocop:disable RemoveIndex
-class AddIndexOnRunnersLocked < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- add_concurrent_index :ci_runners, :locked
- end
-
- def down
- remove_index :ci_runners, :locked if index_exists? :ci_runners, :locked
- end
-end
diff --git a/db/migrate/20160621123729_add_rebase_commit_sha_to_merge_requests.rb b/db/migrate/20160621123729_add_rebase_commit_sha_to_merge_requests.rb
deleted file mode 100644
index 2d3ab4e2583..00000000000
--- a/db/migrate/20160621123729_add_rebase_commit_sha_to_merge_requests.rb
+++ /dev/null
@@ -1,22 +0,0 @@
-# This migration is a duplicate of 20171230123729_add_rebase_commit_sha_to_merge_requests_ce.rb
-#
-# We backported this feature from EE using the same migration, but with a new
-# timestamp, which caused an error when the backport was then to be merged back
-# into EE.
-#
-# See discussion at https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/3932
-class AddRebaseCommitShaToMergeRequests < ActiveRecord::Migration[4.2]
- DOWNTIME = false
-
- def up
- unless column_exists?(:merge_requests, :rebase_commit_sha)
- add_column :merge_requests, :rebase_commit_sha, :string
- end
- end
-
- def down
- if column_exists?(:merge_requests, :rebase_commit_sha)
- remove_column :merge_requests, :rebase_commit_sha
- end
- end
-end
diff --git a/db/migrate/20160628085157_add_artifacts_size_to_ci_builds.rb b/db/migrate/20160628085157_add_artifacts_size_to_ci_builds.rb
deleted file mode 100644
index 60bd4c36eb6..00000000000
--- a/db/migrate/20160628085157_add_artifacts_size_to_ci_builds.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-class AddArtifactsSizeToCiBuilds < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- def change
- add_column(:ci_builds, :artifacts_size, :integer)
- end
-end
diff --git a/db/migrate/20160629025435_add_column_in_progress_merge_commit_sha_to_merge_requests.rb b/db/migrate/20160629025435_add_column_in_progress_merge_commit_sha_to_merge_requests.rb
deleted file mode 100644
index 13e1280b71a..00000000000
--- a/db/migrate/20160629025435_add_column_in_progress_merge_commit_sha_to_merge_requests.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class AddColumnInProgressMergeCommitShaToMergeRequests < ActiveRecord::Migration[4.2]
- def change
- add_column :merge_requests, :in_progress_merge_commit_sha, :string
- end
-end
diff --git a/db/migrate/20160703180340_add_index_on_award_emoji_user_and_name.rb b/db/migrate/20160703180340_add_index_on_award_emoji_user_and_name.rb
deleted file mode 100644
index 8a576b99de0..00000000000
--- a/db/migrate/20160703180340_add_index_on_award_emoji_user_and_name.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-# rubocop:disable all
-# Migration type: online without errors
-
-class AddIndexOnAwardEmojiUserAndName < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
- disable_ddl_transaction!
-
- def change
- add_concurrent_index(:award_emoji, [:user_id, :name])
- end
-end
diff --git a/db/migrate/20160705054938_add_protected_branches_push_access.rb b/db/migrate/20160705054938_add_protected_branches_push_access.rb
deleted file mode 100644
index 314d90efa90..00000000000
--- a/db/migrate/20160705054938_add_protected_branches_push_access.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-# rubocop:disable Migration/Timestamps
-class AddProtectedBranchesPushAccess < ActiveRecord::Migration[4.2]
- DOWNTIME = false
-
- def change
- create_table :protected_branch_push_access_levels do |t|
- t.references :protected_branch, index: { name: "index_protected_branch_push_access" }, foreign_key: true, null: false
-
- # Gitlab::Access::MAINTAINER == 40
- t.integer :access_level, default: 40, null: false
-
- t.timestamps null: false
- end
- end
-end
diff --git a/db/migrate/20160705054952_add_protected_branches_merge_access.rb b/db/migrate/20160705054952_add_protected_branches_merge_access.rb
deleted file mode 100644
index 672e0e291db..00000000000
--- a/db/migrate/20160705054952_add_protected_branches_merge_access.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-# rubocop:disable Migration/Timestamps
-class AddProtectedBranchesMergeAccess < ActiveRecord::Migration[4.2]
- DOWNTIME = false
-
- def change
- create_table :protected_branch_merge_access_levels do |t|
- t.references :protected_branch, index: { name: "index_protected_branch_merge_access" }, foreign_key: true, null: false
-
- # Gitlab::Access::MAINTAINER == 40
- t.integer :access_level, default: 40, null: false
-
- t.timestamps null: false
- end
- end
-end
diff --git a/db/migrate/20160705055254_move_from_developers_can_merge_to_protected_branches_merge_access.rb b/db/migrate/20160705055254_move_from_developers_can_merge_to_protected_branches_merge_access.rb
deleted file mode 100644
index 1bd462cab06..00000000000
--- a/db/migrate/20160705055254_move_from_developers_can_merge_to_protected_branches_merge_access.rb
+++ /dev/null
@@ -1,29 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class MoveFromDevelopersCanMergeToProtectedBranchesMergeAccess < ActiveRecord::Migration[4.2]
- DOWNTIME = true
- DOWNTIME_REASON = <<-HEREDOC
- We're creating a `merge_access_level` for each `protected_branch`. If a user creates a `protected_branch` while this
- is running, we might be left with a `protected_branch` _without_ an associated `merge_access_level`. The `protected_branches`
- table must not change while this is running, so downtime is required.
-
- https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/5081#note_13247410
- HEREDOC
-
- def up
- execute <<-HEREDOC
- INSERT into protected_branch_merge_access_levels (protected_branch_id, access_level, created_at, updated_at)
- SELECT id, (CASE WHEN developers_can_merge THEN 30 ELSE 40 END), now(), now()
- FROM protected_branches
- HEREDOC
- end
-
- def down
- execute <<-HEREDOC
- UPDATE protected_branches SET developers_can_merge = TRUE
- WHERE id IN (SELECT protected_branch_id FROM protected_branch_merge_access_levels
- WHERE access_level = 30);
- HEREDOC
- end
-end
diff --git a/db/migrate/20160705055308_move_from_developers_can_push_to_protected_branches_push_access.rb b/db/migrate/20160705055308_move_from_developers_can_push_to_protected_branches_push_access.rb
deleted file mode 100644
index d480dac777a..00000000000
--- a/db/migrate/20160705055308_move_from_developers_can_push_to_protected_branches_push_access.rb
+++ /dev/null
@@ -1,29 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class MoveFromDevelopersCanPushToProtectedBranchesPushAccess < ActiveRecord::Migration[4.2]
- DOWNTIME = true
- DOWNTIME_REASON = <<-HEREDOC
- We're creating a `push_access_level` for each `protected_branch`. If a user creates a `protected_branch` while this
- is running, we might be left with a `protected_branch` _without_ an associated `push_access_level`. The `protected_branches`
- table must not change while this is running, so downtime is required.
-
- https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/5081#note_13247410
- HEREDOC
-
- def up
- execute <<-HEREDOC
- INSERT into protected_branch_push_access_levels (protected_branch_id, access_level, created_at, updated_at)
- SELECT id, (CASE WHEN developers_can_push THEN 30 ELSE 40 END), now(), now()
- FROM protected_branches
- HEREDOC
- end
-
- def down
- execute <<-HEREDOC
- UPDATE protected_branches SET developers_can_push = TRUE
- WHERE id IN (SELECT protected_branch_id FROM protected_branch_push_access_levels
- WHERE access_level = 30);
- HEREDOC
- end
-end
diff --git a/db/migrate/20160705055809_remove_developers_can_push_from_protected_branches.rb b/db/migrate/20160705055809_remove_developers_can_push_from_protected_branches.rb
deleted file mode 100644
index e5c9da072cf..00000000000
--- a/db/migrate/20160705055809_remove_developers_can_push_from_protected_branches.rb
+++ /dev/null
@@ -1,20 +0,0 @@
-# rubocop:disable Migration/RemoveColumn
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class RemoveDevelopersCanPushFromProtectedBranches < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # This is only required for `#down`
- disable_ddl_transaction!
-
- DOWNTIME = false
-
- def up
- remove_column :protected_branches, :developers_can_push, :boolean
- end
-
- def down
- add_column_with_default(:protected_branches, :developers_can_push, :boolean, default: false, allow_null: false)
- end
-end
diff --git a/db/migrate/20160705055813_remove_developers_can_merge_from_protected_branches.rb b/db/migrate/20160705055813_remove_developers_can_merge_from_protected_branches.rb
deleted file mode 100644
index 2a623b55839..00000000000
--- a/db/migrate/20160705055813_remove_developers_can_merge_from_protected_branches.rb
+++ /dev/null
@@ -1,20 +0,0 @@
-# rubocop:disable Migration/RemoveColumn
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class RemoveDevelopersCanMergeFromProtectedBranches < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # This is only required for `#down`
- disable_ddl_transaction!
-
- DOWNTIME = false
-
- def up
- remove_column :protected_branches, :developers_can_merge, :boolean
- end
-
- def down
- add_column_with_default(:protected_branches, :developers_can_merge, :boolean, default: false, allow_null: false)
- end
-end
diff --git a/db/migrate/20160705163108_remove_requesters_that_are_owners.rb b/db/migrate/20160705163108_remove_requesters_that_are_owners.rb
deleted file mode 100644
index 449c67e1b6a..00000000000
--- a/db/migrate/20160705163108_remove_requesters_that_are_owners.rb
+++ /dev/null
@@ -1,40 +0,0 @@
-class RemoveRequestersThatAreOwners < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- def up
- # Delete requesters that are owner of their projects and actually requested
- # access to it
- execute <<-SQL
- DELETE FROM members
- WHERE members.source_type = 'Project'
- AND members.type = 'ProjectMember'
- AND members.requested_at IS NOT NULL
- AND members.user_id = (
- SELECT namespaces.owner_id
- FROM namespaces
- JOIN projects ON namespaces.id = projects.namespace_id
- WHERE namespaces.type IS NULL
- AND projects.id = members.source_id
- AND namespaces.owner_id = members.user_id);
- SQL
-
- # Delete requesters that are owner of their project's group and actually requested
- # access to it
- execute <<-SQL
- DELETE FROM members
- WHERE members.source_type = 'Project'
- AND members.type = 'ProjectMember'
- AND members.requested_at IS NOT NULL
- AND members.user_id = (
- SELECT namespaces.owner_id
- FROM namespaces
- JOIN projects ON namespaces.id = projects.namespace_id
- WHERE namespaces.type = 'Group'
- AND projects.id = members.source_id
- AND namespaces.owner_id = members.user_id);
- SQL
- end
-
- def down
- end
-end
diff --git a/db/migrate/20160707104333_add_lock_to_issuables.rb b/db/migrate/20160707104333_add_lock_to_issuables.rb
deleted file mode 100644
index fdc3abf46cc..00000000000
--- a/db/migrate/20160707104333_add_lock_to_issuables.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class AddLockToIssuables < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def up
- add_column :issues, :lock_version, :integer
- add_column :merge_requests, :lock_version, :integer
- end
-
- def down
- remove_column :issues, :lock_version
- remove_column :merge_requests, :lock_version
- end
-end
diff --git a/db/migrate/20160712171823_remove_award_emojis_with_no_user.rb b/db/migrate/20160712171823_remove_award_emojis_with_no_user.rb
deleted file mode 100644
index 0b553182a81..00000000000
--- a/db/migrate/20160712171823_remove_award_emojis_with_no_user.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class RemoveAwardEmojisWithNoUser < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # When using the methods "add_concurrent_index" or "add_column_with_default"
- # you must disable the use of transactions as these methods can not run in an
- # existing transaction. When using "add_concurrent_index" make sure that this
- # method is the _only_ method called in the migration, any other changes
- # should go in a separate migration. This ensures that upon failure _only_ the
- # index creation fails and can be retried or reverted easily.
- #
- # To disable transactions uncomment the following line and remove these
- # comments:
- # disable_ddl_transaction!
-
- def up
- AwardEmoji.joins('LEFT JOIN users ON users.id = user_id').where('users.id IS NULL').destroy_all # rubocop: disable DestroyAll
- end
-end
diff --git a/db/migrate/20160713200638_add_repository_read_only_to_projects.rb b/db/migrate/20160713200638_add_repository_read_only_to_projects.rb
deleted file mode 100644
index ba61bc8cbb0..00000000000
--- a/db/migrate/20160713200638_add_repository_read_only_to_projects.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-class AddRepositoryReadOnlyToProjects < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def change
- add_column :projects, :repository_read_only, :boolean
- end
-end
diff --git a/db/migrate/20160713205315_add_domain_blacklist_to_application_settings.rb b/db/migrate/20160713205315_add_domain_blacklist_to_application_settings.rb
deleted file mode 100644
index 4b9ac12253e..00000000000
--- a/db/migrate/20160713205315_add_domain_blacklist_to_application_settings.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-# rubocop:disable Migration/SaferBooleanColumn
-class AddDomainBlacklistToApplicationSettings < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # When using the methods "add_concurrent_index" or "add_column_with_default"
- # you must disable the use of transactions as these methods can not run in an
- # existing transaction. When using "add_concurrent_index" make sure that this
- # method is the _only_ method called in the migration, any other changes
- # should go in a separate migration. This ensures that upon failure _only_ the
- # index creation fails and can be retried or reverted easily.
- #
- # To disable transactions uncomment the following line and remove these
- # comments:
- # disable_ddl_transaction!
-
- def change
- add_column :application_settings, :domain_blacklist_enabled, :boolean, default: false
- add_column :application_settings, :domain_blacklist, :text
- end
-end
diff --git a/db/migrate/20160713222618_add_usage_ping_to_application_settings.rb b/db/migrate/20160713222618_add_usage_ping_to_application_settings.rb
deleted file mode 100644
index 7ef02316338..00000000000
--- a/db/migrate/20160713222618_add_usage_ping_to_application_settings.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-class AddUsagePingToApplicationSettings < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def change
- add_column :application_settings, :usage_ping_enabled, :boolean, default: true, null: false
- end
-end
diff --git a/db/migrate/20160715132507_add_user_id_to_pipeline.rb b/db/migrate/20160715132507_add_user_id_to_pipeline.rb
deleted file mode 100644
index b1e22b1c2bb..00000000000
--- a/db/migrate/20160715132507_add_user_id_to_pipeline.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-class AddUserIdToPipeline < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- def change
- add_column :ci_commits, :user_id, :integer
- end
-end
diff --git a/db/migrate/20160715134306_add_index_for_pipeline_user_id.rb b/db/migrate/20160715134306_add_index_for_pipeline_user_id.rb
deleted file mode 100644
index 8e7ac86a8b7..00000000000
--- a/db/migrate/20160715134306_add_index_for_pipeline_user_id.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-# rubocop:disable RemoveIndex
-class AddIndexForPipelineUserId < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- add_concurrent_index :ci_commits, :user_id
- end
-
- def down
- remove_index :ci_commits, :user_id if index_exists? :ci_commits, :user_id
- end
-end
diff --git a/db/migrate/20160715154212_add_request_access_enabled_to_projects.rb b/db/migrate/20160715154212_add_request_access_enabled_to_projects.rb
deleted file mode 100644
index 96260f5fd55..00000000000
--- a/db/migrate/20160715154212_add_request_access_enabled_to_projects.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-# rubocop:disable Migration/UpdateLargeTable
-class AddRequestAccessEnabledToProjects < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
- disable_ddl_transaction!
-
- def up
- add_column_with_default :projects, :request_access_enabled, :boolean, default: true
- end
-
- def down
- remove_column :projects, :request_access_enabled
- end
-end
diff --git a/db/migrate/20160715204316_add_request_access_enabled_to_groups.rb b/db/migrate/20160715204316_add_request_access_enabled_to_groups.rb
deleted file mode 100644
index 14065434523..00000000000
--- a/db/migrate/20160715204316_add_request_access_enabled_to_groups.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-# rubocop:disable Migration/UpdateLargeTable
-class AddRequestAccessEnabledToGroups < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
- disable_ddl_transaction!
-
- def up
- add_column_with_default :namespaces, :request_access_enabled, :boolean, default: true
- end
-
- def down
- remove_column :namespaces, :request_access_enabled
- end
-end
diff --git a/db/migrate/20160715230841_rename_application_settings_restricted_signup_domains.rb b/db/migrate/20160715230841_rename_application_settings_restricted_signup_domains.rb
deleted file mode 100644
index 6a2674fb604..00000000000
--- a/db/migrate/20160715230841_rename_application_settings_restricted_signup_domains.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class RenameApplicationSettingsRestrictedSignupDomains < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # When using the methods "add_concurrent_index" or "add_column_with_default"
- # you must disable the use of transactions as these methods can not run in an
- # existing transaction. When using "add_concurrent_index" make sure that this
- # method is the _only_ method called in the migration, any other changes
- # should go in a separate migration. This ensures that upon failure _only_ the
- # index creation fails and can be retried or reverted easily.
- #
- # To disable transactions uncomment the following line and remove these
- # comments:
- # disable_ddl_transaction!
-
- def change
- rename_column :application_settings, :restricted_signup_domains, :domain_whitelist
- end
-end
diff --git a/db/migrate/20160716115710_add_when_and_yaml_variables_to_ci_builds.rb b/db/migrate/20160716115710_add_when_and_yaml_variables_to_ci_builds.rb
deleted file mode 100644
index d403b0a3cc9..00000000000
--- a/db/migrate/20160716115710_add_when_and_yaml_variables_to_ci_builds.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-class AddWhenAndYamlVariablesToCiBuilds < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- def change
- add_column :ci_builds, :when, :string
- add_column :ci_builds, :yaml_variables, :text
- end
-end
diff --git a/db/migrate/20160716115711_add_queued_at_to_ci_builds.rb b/db/migrate/20160716115711_add_queued_at_to_ci_builds.rb
deleted file mode 100644
index 2bb9a30e3a3..00000000000
--- a/db/migrate/20160716115711_add_queued_at_to_ci_builds.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-# rubocop:disable Migration/Datetime
-class AddQueuedAtToCiBuilds < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def change
- add_column :ci_builds, :queued_at, :timestamp
- end
-end
diff --git a/db/migrate/20160718153603_add_has_external_wiki_to_projects.rb b/db/migrate/20160718153603_add_has_external_wiki_to_projects.rb
deleted file mode 100644
index e3e4afaf512..00000000000
--- a/db/migrate/20160718153603_add_has_external_wiki_to_projects.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-class AddHasExternalWikiToProjects < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- def change
- add_column :projects, :has_external_wiki, :boolean
- end
-end
diff --git a/db/migrate/20160721081015_drop_and_readd_has_external_wiki_in_projects.rb b/db/migrate/20160721081015_drop_and_readd_has_external_wiki_in_projects.rb
deleted file mode 100644
index d31bbb22392..00000000000
--- a/db/migrate/20160721081015_drop_and_readd_has_external_wiki_in_projects.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-# rubocop:disable Migration/UpdateLargeTable
-# rubocop:disable Migration/UpdateColumnInBatches
-class DropAndReaddHasExternalWikiInProjects < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- update_column_in_batches(:projects, :has_external_wiki, nil) do |table, query|
- query.where(table[:has_external_wiki].not_eq(nil))
- end
- end
-
- def down
- end
-end
diff --git a/db/migrate/20160722221922_nullify_blank_type_on_notes.rb b/db/migrate/20160722221922_nullify_blank_type_on_notes.rb
deleted file mode 100644
index 83ca5c1e6ec..00000000000
--- a/db/migrate/20160722221922_nullify_blank_type_on_notes.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-class NullifyBlankTypeOnNotes < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def up
- execute "UPDATE notes SET type = NULL WHERE type = ''"
- end
-end
diff --git a/db/migrate/20160724205507_add_resolved_to_notes.rb b/db/migrate/20160724205507_add_resolved_to_notes.rb
deleted file mode 100644
index fc56d3b1452..00000000000
--- a/db/migrate/20160724205507_add_resolved_to_notes.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-# rubocop:disable Migration/Datetime
-class AddResolvedToNotes < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def change
- add_column :notes, :resolved_at, :datetime
- add_column :notes, :resolved_by_id, :integer
- end
-end
diff --git a/db/migrate/20160725083350_add_external_url_to_enviroments.rb b/db/migrate/20160725083350_add_external_url_to_enviroments.rb
deleted file mode 100644
index e060c6a8499..00000000000
--- a/db/migrate/20160725083350_add_external_url_to_enviroments.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-class AddExternalUrlToEnviroments < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def change
- add_column(:environments, :external_url, :string)
- end
-end
diff --git a/db/migrate/20160725104020_merge_request_diff_remove_uniq.rb b/db/migrate/20160725104020_merge_request_diff_remove_uniq.rb
deleted file mode 100644
index d8b4696a246..00000000000
--- a/db/migrate/20160725104020_merge_request_diff_remove_uniq.rb
+++ /dev/null
@@ -1,36 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-# rubocop:disable RemoveIndex
-class MergeRequestDiffRemoveUniq < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
- disable_ddl_transaction!
-
- DOWNTIME = false
-
- def up
- constraint_name = 'merge_request_diffs_merge_request_id_key'
-
- transaction do
- if index_exists?(:merge_request_diffs, :merge_request_id)
- remove_index(:merge_request_diffs, :merge_request_id)
- end
-
- # In some bizarre cases PostgreSQL might have a separate unique constraint
- # that we'll need to drop.
- if constraint_exists?(constraint_name) && Gitlab::Database.postgresql?
- execute("ALTER TABLE merge_request_diffs DROP CONSTRAINT IF EXISTS #{constraint_name};")
- end
- end
- end
-
- def down
- unless index_exists?(:merge_request_diffs, :merge_request_id)
- add_concurrent_index(:merge_request_diffs, :merge_request_id, unique: true)
- end
- end
-
- def constraint_exists?(name)
- indexes(:merge_request_diffs).map(&:name).include?(name)
- end
-end
diff --git a/db/migrate/20160725104452_merge_request_diff_add_index.rb b/db/migrate/20160725104452_merge_request_diff_add_index.rb
deleted file mode 100644
index d3369b3f961..00000000000
--- a/db/migrate/20160725104452_merge_request_diff_add_index.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-# rubocop:disable RemoveIndex
-class MergeRequestDiffAddIndex < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
- disable_ddl_transaction!
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- def up
- add_concurrent_index :merge_request_diffs, :merge_request_id
- end
-
- def down
- if index_exists?(:merge_request_diffs, :merge_request_id)
- remove_index :merge_request_diffs, :merge_request_id
- end
- end
-end
diff --git a/db/migrate/20160727163552_create_user_agent_details.rb b/db/migrate/20160727163552_create_user_agent_details.rb
deleted file mode 100644
index 6ef54deca90..00000000000
--- a/db/migrate/20160727163552_create_user_agent_details.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-# rubocop:disable Migration/Timestamps
-class CreateUserAgentDetails < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- def change
- create_table :user_agent_details do |t|
- t.string :user_agent, null: false
- t.string :ip_address, null: false
- t.integer :subject_id, null: false
- t.string :subject_type, null: false
- t.boolean :submitted, default: false, null: false
-
- t.timestamps null: false
- end
- end
-end
diff --git a/db/migrate/20160727191041_create_boards.rb b/db/migrate/20160727191041_create_boards.rb
deleted file mode 100644
index 60ed5508b10..00000000000
--- a/db/migrate/20160727191041_create_boards.rb
+++ /dev/null
@@ -1,14 +0,0 @@
-# rubocop:disable Migration/Timestamps
-class CreateBoards < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def change
- create_table :boards do |t|
- t.references :project, index: true, foreign_key: true, null: false
-
- t.timestamps null: false
- end
- end
-end
diff --git a/db/migrate/20160727193336_create_lists.rb b/db/migrate/20160727193336_create_lists.rb
deleted file mode 100644
index 4591c9a120f..00000000000
--- a/db/migrate/20160727193336_create_lists.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-# rubocop:disable Migration/Timestamps
-class CreateLists < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def change
- create_table :lists do |t|
- t.references :board, index: true, foreign_key: true, null: false
- t.references :label, index: true, foreign_key: true
- t.integer :list_type, null: false, default: 1
- t.integer :position
-
- t.timestamps null: false
- end
- end
-end
diff --git a/db/migrate/20160728081025_add_pipeline_events_to_web_hooks.rb b/db/migrate/20160728081025_add_pipeline_events_to_web_hooks.rb
deleted file mode 100644
index fc3e9f03c74..00000000000
--- a/db/migrate/20160728081025_add_pipeline_events_to_web_hooks.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-class AddPipelineEventsToWebHooks < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- add_column_with_default(:web_hooks, :pipeline_events, :boolean,
- default: false, allow_null: false)
- end
-
- def down
- remove_column(:web_hooks, :pipeline_events)
- end
-end
diff --git a/db/migrate/20160728103734_add_pipeline_events_to_services.rb b/db/migrate/20160728103734_add_pipeline_events_to_services.rb
deleted file mode 100644
index 421859ff5fd..00000000000
--- a/db/migrate/20160728103734_add_pipeline_events_to_services.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-class AddPipelineEventsToServices < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- add_column_with_default(:services, :pipeline_events, :boolean,
- default: false, allow_null: false)
- end
-
- def down
- remove_column(:services, :pipeline_events)
- end
-end
diff --git a/db/migrate/20160729173930_remove_project_id_from_spam_logs.rb b/db/migrate/20160729173930_remove_project_id_from_spam_logs.rb
deleted file mode 100644
index 02e417e376f..00000000000
--- a/db/migrate/20160729173930_remove_project_id_from_spam_logs.rb
+++ /dev/null
@@ -1,30 +0,0 @@
-# rubocop:disable Migration/RemoveColumn
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class RemoveProjectIdFromSpamLogs < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = true
-
- # When a migration requires downtime you **must** uncomment the following
- # constant and define a short and easy to understand explanation as to why the
- # migration requires downtime.
- DOWNTIME_REASON = 'Removing a column that contains data that is not used anywhere.'
-
- # When using the methods "add_concurrent_index" or "add_column_with_default"
- # you must disable the use of transactions as these methods can not run in an
- # existing transaction. When using "add_concurrent_index" make sure that this
- # method is the _only_ method called in the migration, any other changes
- # should go in a separate migration. This ensures that upon failure _only_ the
- # index creation fails and can be retried or reverted easily.
- #
- # To disable transactions uncomment the following line and remove these
- # comments:
- # disable_ddl_transaction!
-
- def change
- remove_column :spam_logs, :project_id, :integer
- end
-end
diff --git a/db/migrate/20160801163421_add_expires_at_to_member.rb b/db/migrate/20160801163421_add_expires_at_to_member.rb
deleted file mode 100644
index 13ca1d04658..00000000000
--- a/db/migrate/20160801163421_add_expires_at_to_member.rb
+++ /dev/null
@@ -1,29 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class AddExpiresAtToMember < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- # When a migration requires downtime you **must** uncomment the following
- # constant and define a short and easy to understand explanation as to why the
- # migration requires downtime.
- # DOWNTIME_REASON = ''
-
- # When using the methods "add_concurrent_index" or "add_column_with_default"
- # you must disable the use of transactions as these methods can not run in an
- # existing transaction. When using "add_concurrent_index" make sure that this
- # method is the _only_ method called in the migration, any other changes
- # should go in a separate migration. This ensures that upon failure _only_ the
- # index creation fails and can be retried or reverted easily.
- #
- # To disable transactions uncomment the following line and remove these
- # comments:
- # disable_ddl_transaction!
-
- def change
- add_column :members, :expires_at, :date
- end
-end
diff --git a/db/migrate/20160801163709_add_submitted_as_ham_to_spam_logs.rb b/db/migrate/20160801163709_add_submitted_as_ham_to_spam_logs.rb
deleted file mode 100644
index fde9dee980e..00000000000
--- a/db/migrate/20160801163709_add_submitted_as_ham_to_spam_logs.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class AddSubmittedAsHamToSpamLogs < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- # When a migration requires downtime you **must** uncomment the following
- # constant and define a short and easy to understand explanation as to why the
- # migration requires downtime.
- # DOWNTIME_REASON = ''
-
- disable_ddl_transaction!
-
- def up
- add_column_with_default :spam_logs, :submitted_as_ham, :boolean, default: false
- end
-
- def down
- remove_column :spam_logs, :submitted_as_ham
- end
-end
diff --git a/db/migrate/20160802010328_remove_builds_enable_index_on_projects.rb b/db/migrate/20160802010328_remove_builds_enable_index_on_projects.rb
deleted file mode 100644
index 4ad740e0812..00000000000
--- a/db/migrate/20160802010328_remove_builds_enable_index_on_projects.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-# rubocop:disable RemoveIndex
-class RemoveBuildsEnableIndexOnProjects < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def change
- remove_index :projects, column: :builds_enabled if index_exists?(:projects, :builds_enabled)
- end
-end
diff --git a/db/migrate/20160803161903_add_unique_index_to_lists_label_id.rb b/db/migrate/20160803161903_add_unique_index_to_lists_label_id.rb
deleted file mode 100644
index f866fe15ec1..00000000000
--- a/db/migrate/20160803161903_add_unique_index_to_lists_label_id.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-# rubocop:disable RemoveIndex
-class AddUniqueIndexToListsLabelId < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- add_concurrent_index :lists, [:board_id, :label_id], unique: true
- end
-
- def down
- remove_index :lists, column: [:board_id, :label_id] if index_exists?(:lists, [:board_id, :label_id], unique: true)
- end
-end
diff --git a/db/migrate/20160804142904_add_ci_config_file_to_project.rb b/db/migrate/20160804142904_add_ci_config_file_to_project.rb
deleted file mode 100644
index abd94e63db3..00000000000
--- a/db/migrate/20160804142904_add_ci_config_file_to_project.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-class AddCiConfigFileToProject < ActiveRecord::Migration[4.2]
- DOWNTIME = false
-
- def change
- add_column :projects, :ci_config_path, :string
- end
-
- def down
- remove_column :projects, :ci_config_path
- end
-end
diff --git a/db/migrate/20160804150737_add_timestamps_to_members_again.rb b/db/migrate/20160804150737_add_timestamps_to_members_again.rb
deleted file mode 100644
index 4e71197b8e7..00000000000
--- a/db/migrate/20160804150737_add_timestamps_to_members_again.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-# rubocop:disable all
-# 20141121133009_add_timestamps_to_members.rb was meant to ensure that all
-# rows in the members table had created_at and updated_at set, following an
-# error in a previous migration. This failed to set all rows in at least one
-# case: https://gitlab.com/gitlab-org/gitlab-ce/issues/20568
-#
-# Why this happened is lost in the mists of time, so repeat the SQL query
-# without speculation, just in case more than one person was affected.
-class AddTimestampsToMembersAgain < ActiveRecord::Migration[4.2]
- DOWNTIME = false
-
- def up
- execute "UPDATE members SET created_at = NOW() WHERE created_at IS NULL"
- execute "UPDATE members SET updated_at = NOW() WHERE updated_at IS NULL"
- end
-
- def down
- # no change
- end
-
-end
diff --git a/db/migrate/20160805041956_add_deleted_at_to_namespaces.rb b/db/migrate/20160805041956_add_deleted_at_to_namespaces.rb
deleted file mode 100644
index a0dfa3259ec..00000000000
--- a/db/migrate/20160805041956_add_deleted_at_to_namespaces.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-# rubocop:disable Migration/Datetime
-# rubocop:disable RemoveIndex
-class AddDeletedAtToNamespaces < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- add_column :namespaces, :deleted_at, :datetime
-
- add_concurrent_index :namespaces, :deleted_at
- end
-
- def down
- remove_index :namespaces, :deleted_at if index_exists? :namespaces, :deleted_at
-
- remove_column :namespaces, :deleted_at
- end
-end
diff --git a/db/migrate/20160808085531_add_token_to_build.rb b/db/migrate/20160808085531_add_token_to_build.rb
deleted file mode 100644
index a1d8945a538..00000000000
--- a/db/migrate/20160808085531_add_token_to_build.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-class AddTokenToBuild < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- def change
- add_column :ci_builds, :token, :string
- end
-end
diff --git a/db/migrate/20160808085602_add_index_for_build_token.rb b/db/migrate/20160808085602_add_index_for_build_token.rb
deleted file mode 100644
index 22d50e4165a..00000000000
--- a/db/migrate/20160808085602_add_index_for_build_token.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-# rubocop:disable RemoveIndex
-class AddIndexForBuildToken < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- add_concurrent_index :ci_builds, :token, unique: true
- end
-
- def down
- remove_index :ci_builds, :token, unique: true if index_exists? :ci_builds, :token, unique: true
- end
-end
diff --git a/db/migrate/20160810102349_remove_ci_runner_trigram_indexes.rb b/db/migrate/20160810102349_remove_ci_runner_trigram_indexes.rb
deleted file mode 100644
index 738b93912b6..00000000000
--- a/db/migrate/20160810102349_remove_ci_runner_trigram_indexes.rb
+++ /dev/null
@@ -1,27 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class RemoveCiRunnerTrigramIndexes < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- # Disabled for the "down" method so the indexes can be re-created concurrently.
- disable_ddl_transaction!
-
- def up
- return unless Gitlab::Database.postgresql?
-
- transaction do
- execute 'DROP INDEX IF EXISTS index_ci_runners_on_token_trigram;'
- execute 'DROP INDEX IF EXISTS index_ci_runners_on_description_trigram;'
- end
- end
-
- def down
- return unless Gitlab::Database.postgresql?
-
- execute 'CREATE INDEX CONCURRENTLY index_ci_runners_on_token_trigram ON ci_runners USING gin(token gin_trgm_ops);'
- execute 'CREATE INDEX CONCURRENTLY index_ci_runners_on_description_trigram ON ci_runners USING gin(description gin_trgm_ops);'
- end
-end
diff --git a/db/migrate/20160810142633_remove_redundant_indexes.rb b/db/migrate/20160810142633_remove_redundant_indexes.rb
deleted file mode 100644
index 91f82cf9afa..00000000000
--- a/db/migrate/20160810142633_remove_redundant_indexes.rb
+++ /dev/null
@@ -1,113 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-# rubocop:disable RemoveIndex
-class RemoveRedundantIndexes < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- indexes = [
- [:ci_taggings, 'ci_taggings_idx'],
- [:audit_events, 'index_audit_events_on_author_id'],
- [:audit_events, 'index_audit_events_on_type'],
- [:ci_builds, 'index_ci_builds_on_erased_by_id'],
- [:ci_builds, 'index_ci_builds_on_project_id_and_commit_id'],
- [:ci_builds, 'index_ci_builds_on_type'],
- [:ci_commits, 'index_ci_commits_on_project_id'],
- [:ci_commits, 'index_ci_commits_on_project_id_and_committed_at'],
- [:ci_commits, 'index_ci_commits_on_project_id_and_committed_at_and_id'],
- [:ci_commits, 'index_ci_commits_on_project_id_and_sha'],
- [:ci_commits, 'index_ci_commits_on_sha'],
- [:ci_events, 'index_ci_events_on_created_at'],
- [:ci_events, 'index_ci_events_on_is_admin'],
- [:ci_events, 'index_ci_events_on_project_id'],
- [:ci_jobs, 'index_ci_jobs_on_deleted_at'],
- [:ci_jobs, 'index_ci_jobs_on_project_id'],
- [:ci_projects, 'index_ci_projects_on_gitlab_id'],
- [:ci_projects, 'index_ci_projects_on_shared_runners_enabled'],
- [:ci_services, 'index_ci_services_on_project_id'],
- [:ci_sessions, 'index_ci_sessions_on_session_id'],
- [:ci_sessions, 'index_ci_sessions_on_updated_at'],
- [:ci_tags, 'index_ci_tags_on_name'],
- [:ci_triggers, 'index_ci_triggers_on_deleted_at'],
- [:identities, 'index_identities_on_created_at_and_id'],
- [:issues, 'index_issues_on_title'],
- [:keys, 'index_keys_on_created_at_and_id'],
- [:members, 'index_members_on_created_at_and_id'],
- [:members, 'index_members_on_type'],
- [:milestones, 'index_milestones_on_created_at_and_id'],
- [:namespaces, 'index_namespaces_on_visibility_level'],
- [:projects, 'index_projects_on_builds_enabled_and_shared_runners_enabled'],
- [:services, 'index_services_on_category'],
- [:services, 'index_services_on_created_at_and_id'],
- [:services, 'index_services_on_default'],
- [:snippets, 'index_snippets_on_created_at'],
- [:snippets, 'index_snippets_on_created_at_and_id'],
- [:todos, 'index_todos_on_state'],
- [:web_hooks, 'index_web_hooks_on_created_at_and_id'],
-
- # These indexes _may_ be used but they can be replaced by other existing
- # indexes.
-
- # There's already a composite index on (project_id, iid) which means that
- # a separate index for _just_ project_id is not needed.
- [:issues, 'index_issues_on_project_id'],
-
- # These are all composite indexes for the columns (created_at, id). In all
- # these cases there's already a standalone index for "created_at" which
- # can be used instead.
- #
- # Because the "id" column of these composite indexes is never needed (due
- # to "id" already being indexed as its a primary key) these composite
- # indexes are useless.
- [:issues, 'index_issues_on_created_at_and_id'],
- [:merge_requests, 'index_merge_requests_on_created_at_and_id'],
- [:namespaces, 'index_namespaces_on_created_at_and_id'],
- [:notes, 'index_notes_on_created_at_and_id'],
- [:projects, 'index_projects_on_created_at_and_id'],
- [:users, 'index_users_on_created_at_and_id']
- ]
-
- transaction do
- indexes.each do |(table, index)|
- remove_index(table, name: index) if index_exists_by_name?(table, index)
- end
- end
-
- add_concurrent_index(:users, :created_at)
- add_concurrent_index(:projects, :created_at)
- add_concurrent_index(:namespaces, :created_at)
- end
-
- def down
- # We're only restoring the composite indexes that could be replaced with
- # individual ones, just in case somebody would ever want to revert.
- transaction do
- remove_index(:users, :created_at)
- remove_index(:projects, :created_at)
- remove_index(:namespaces, :created_at)
- end
-
- [:issues, :merge_requests, :namespaces, :notes, :projects, :users].each do |table|
- add_concurrent_index(table, [:created_at, :id],
- name: "index_#{table}_on_created_at_and_id")
- end
- end
-
- # Rails' index_exists? doesn't work when you only give it a table and index
- # name. As such we have to use some extra code to check if an index exists for
- # a given name.
- def index_exists_by_name?(table, index)
- indexes_for_table[table].include?(index)
- end
-
- def indexes_for_table
- @indexes_for_table ||= Hash.new do |hash, table_name|
- hash[table_name] = indexes(table_name).map(&:name)
- end
- end
-end
diff --git a/db/migrate/20160811172945_add_can_push_to_keys.rb b/db/migrate/20160811172945_add_can_push_to_keys.rb
deleted file mode 100644
index 2e78ab0249e..00000000000
--- a/db/migrate/20160811172945_add_can_push_to_keys.rb
+++ /dev/null
@@ -1,14 +0,0 @@
-class AddCanPushToKeys < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
- disable_ddl_transaction!
-
- DOWNTIME = false
-
- def up
- add_column_with_default(:keys, :can_push, :boolean, default: false, allow_null: false)
- end
-
- def down
- remove_column(:keys, :can_push)
- end
-end
diff --git a/db/migrate/20160816161312_add_column_name_to_u2f_registrations.rb b/db/migrate/20160816161312_add_column_name_to_u2f_registrations.rb
deleted file mode 100644
index 76b60787323..00000000000
--- a/db/migrate/20160816161312_add_column_name_to_u2f_registrations.rb
+++ /dev/null
@@ -1,29 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class AddColumnNameToU2fRegistrations < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- # When a migration requires downtime you **must** uncomment the following
- # constant and define a short and easy to understand explanation as to why the
- # migration requires downtime.
- # DOWNTIME_REASON = ''
-
- # When using the methods "add_concurrent_index" or "add_column_with_default"
- # you must disable the use of transactions as these methods can not run in an
- # existing transaction. When using "add_concurrent_index" make sure that this
- # method is the _only_ method called in the migration, any other changes
- # should go in a separate migration. This ensures that upon failure _only_ the
- # index creation fails and can be retried or reverted easily.
- #
- # To disable transactions uncomment the following line and remove these
- # comments:
- # disable_ddl_transaction!
-
- def change
- add_column :u2f_registrations, :name, :string
- end
-end
diff --git a/db/migrate/20160817133006_add_koding_to_application_settings.rb b/db/migrate/20160817133006_add_koding_to_application_settings.rb
deleted file mode 100644
index 04f9d7be29b..00000000000
--- a/db/migrate/20160817133006_add_koding_to_application_settings.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-# rubocop:disable Migration/SaferBooleanColumn
-class AddKodingToApplicationSettings < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def change
- add_column :application_settings, :koding_enabled, :boolean
- add_column :application_settings, :koding_url, :string
- end
-end
diff --git a/db/migrate/20160817154936_add_discussion_ids_to_notes.rb b/db/migrate/20160817154936_add_discussion_ids_to_notes.rb
deleted file mode 100644
index e735eeadac5..00000000000
--- a/db/migrate/20160817154936_add_discussion_ids_to_notes.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class AddDiscussionIdsToNotes < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def change
- add_column :notes, :discussion_id, :string
- add_column :notes, :original_discussion_id, :string
- end
-end
diff --git a/db/migrate/20160818205718_add_expires_at_to_project_group_links.rb b/db/migrate/20160818205718_add_expires_at_to_project_group_links.rb
deleted file mode 100644
index 06f621c6c2e..00000000000
--- a/db/migrate/20160818205718_add_expires_at_to_project_group_links.rb
+++ /dev/null
@@ -1,29 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class AddExpiresAtToProjectGroupLinks < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- # When a migration requires downtime you **must** uncomment the following
- # constant and define a short and easy to understand explanation as to why the
- # migration requires downtime.
- # DOWNTIME_REASON = ''
-
- # When using the methods "add_concurrent_index" or "add_column_with_default"
- # you must disable the use of transactions as these methods can not run in an
- # existing transaction. When using "add_concurrent_index" make sure that this
- # method is the _only_ method called in the migration, any other changes
- # should go in a separate migration. This ensures that upon failure _only_ the
- # index creation fails and can be retried or reverted easily.
- #
- # To disable transactions uncomment the following line and remove these
- # comments:
- # disable_ddl_transaction!
-
- def change
- add_column :project_group_links, :expires_at, :date
- end
-end
diff --git a/db/migrate/20160819221631_add_index_to_note_discussion_id.rb b/db/migrate/20160819221631_add_index_to_note_discussion_id.rb
deleted file mode 100644
index 1dbc0474fd2..00000000000
--- a/db/migrate/20160819221631_add_index_to_note_discussion_id.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-# rubocop:disable RemoveIndex
-class AddIndexToNoteDiscussionId < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- add_concurrent_index :notes, :discussion_id
- end
-
- def down
- remove_index :notes, :discussion_id if index_exists? :notes, :discussion_id
- end
-end
diff --git a/db/migrate/20160819221833_reset_diff_note_discussion_id_because_it_was_calculated_wrongly.rb b/db/migrate/20160819221833_reset_diff_note_discussion_id_because_it_was_calculated_wrongly.rb
deleted file mode 100644
index 61f593a52c5..00000000000
--- a/db/migrate/20160819221833_reset_diff_note_discussion_id_because_it_was_calculated_wrongly.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class ResetDiffNoteDiscussionIdBecauseItWasCalculatedWrongly < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def up
- execute "UPDATE notes SET discussion_id = NULL WHERE discussion_id IS NOT NULL AND type = 'DiffNote'"
- end
-end
diff --git a/db/migrate/20160819232256_add_incoming_email_token_to_users.rb b/db/migrate/20160819232256_add_incoming_email_token_to_users.rb
deleted file mode 100644
index 0a7190f632d..00000000000
--- a/db/migrate/20160819232256_add_incoming_email_token_to_users.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-# rubocop:disable RemoveIndex
-class AddIncomingEmailTokenToUsers < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- add_column :users, :incoming_email_token, :string
-
- add_concurrent_index :users, :incoming_email_token
- end
-
- def down
- remove_index :users, :incoming_email_token if index_exists? :users, :incoming_email_token
-
- remove_column :users, :incoming_email_token
- end
-end
diff --git a/db/migrate/20160823081327_change_merge_error_to_text.rb b/db/migrate/20160823081327_change_merge_error_to_text.rb
deleted file mode 100644
index 23b4f35a776..00000000000
--- a/db/migrate/20160823081327_change_merge_error_to_text.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-class ChangeMergeErrorToText < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = true
- DOWNTIME_REASON = 'This migration requires downtime because it alters a column from varchar(255) to text.'
-
- def change
- change_column :merge_requests, :merge_error, :text, limit: 65535
- end
-end
diff --git a/db/migrate/20160823083941_add_column_scopes_to_personal_access_tokens.rb b/db/migrate/20160823083941_add_column_scopes_to_personal_access_tokens.rb
deleted file mode 100644
index 4c320123088..00000000000
--- a/db/migrate/20160823083941_add_column_scopes_to_personal_access_tokens.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-# The default needs to be `[]`, but all existing access tokens need to have `scopes` set to `['api']`.
-# It's easier to achieve this by adding the column with the `['api']` default, and then changing the default to
-# `[]`.
-
-class AddColumnScopesToPersonalAccessTokens < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- add_column_with_default :personal_access_tokens, :scopes, :string, default: ['api'].to_yaml
- end
-
- def down
- remove_column :personal_access_tokens, :scopes
- end
-end
diff --git a/db/migrate/20160823213309_add_lfs_enabled_to_projects.rb b/db/migrate/20160823213309_add_lfs_enabled_to_projects.rb
deleted file mode 100644
index 87e6e8b6945..00000000000
--- a/db/migrate/20160823213309_add_lfs_enabled_to_projects.rb
+++ /dev/null
@@ -1,29 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class AddLfsEnabledToProjects < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- # When a migration requires downtime you **must** uncomment the following
- # constant and define a short and easy to understand explanation as to why the
- # migration requires downtime.
- # DOWNTIME_REASON = ''
-
- # When using the methods "add_concurrent_index" or "add_column_with_default"
- # you must disable the use of transactions as these methods can not run in an
- # existing transaction. When using "add_concurrent_index" make sure that this
- # method is the _only_ method called in the migration, any other changes
- # should go in a separate migration. This ensures that upon failure _only_ the
- # index creation fails and can be retried or reverted easily.
- #
- # To disable transactions uncomment the following line and remove these
- # comments:
- # disable_ddl_transaction!
-
- def change
- add_column :projects, :lfs_enabled, :boolean
- end
-end
diff --git a/db/migrate/20160824103857_drop_unused_ci_tables.rb b/db/migrate/20160824103857_drop_unused_ci_tables.rb
deleted file mode 100644
index 8a207683848..00000000000
--- a/db/migrate/20160824103857_drop_unused_ci_tables.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-class DropUnusedCiTables < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- def change
- drop_table(:ci_services)
- drop_table(:ci_web_hooks)
- end
-end
diff --git a/db/migrate/20160824124900_add_table_issue_metrics.rb b/db/migrate/20160824124900_add_table_issue_metrics.rb
deleted file mode 100644
index 4f34f377e22..00000000000
--- a/db/migrate/20160824124900_add_table_issue_metrics.rb
+++ /dev/null
@@ -1,37 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-# rubocop:disable Migration/Timestamps
-class AddTableIssueMetrics < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = true
-
- # When a migration requires downtime you **must** uncomment the following
- # constant and define a short and easy to understand explanation as to why the
- # migration requires downtime.
- DOWNTIME_REASON = 'Adding foreign key'
-
- # When using the methods "add_concurrent_index" or "add_column_with_default"
- # you must disable the use of transactions as these methods can not run in an
- # existing transaction. When using "add_concurrent_index" make sure that this
- # method is the _only_ method called in the migration, any other changes
- # should go in a separate migration. This ensures that upon failure _only_ the
- # index creation fails and can be retried or reverted easily.
- #
- # To disable transactions uncomment the following line and remove these
- # comments:
- # disable_ddl_transaction!
-
- def change
- create_table :issue_metrics do |t|
- t.references :issue, index: { name: "index_issue_metrics" }, foreign_key: { on_delete: :cascade }, null: false
-
- t.datetime 'first_mentioned_in_commit_at'
- t.datetime 'first_associated_with_milestone_at'
- t.datetime 'first_added_to_board_at'
-
- t.timestamps null: false
- end
- end
-end
diff --git a/db/migrate/20160825052008_add_table_merge_request_metrics.rb b/db/migrate/20160825052008_add_table_merge_request_metrics.rb
deleted file mode 100644
index 150f698869d..00000000000
--- a/db/migrate/20160825052008_add_table_merge_request_metrics.rb
+++ /dev/null
@@ -1,38 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-# rubocop:disable Migration/Timestamps
-class AddTableMergeRequestMetrics < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = true
-
- # When a migration requires downtime you **must** uncomment the following
- # constant and define a short and easy to understand explanation as to why the
- # migration requires downtime.
- DOWNTIME_REASON = 'Adding foreign key'
-
- # When using the methods "add_concurrent_index" or "add_column_with_default"
- # you must disable the use of transactions as these methods can not run in an
- # existing transaction. When using "add_concurrent_index" make sure that this
- # method is the _only_ method called in the migration, any other changes
- # should go in a separate migration. This ensures that upon failure _only_ the
- # index creation fails and can be retried or reverted easily.
- #
- # To disable transactions uncomment the following line and remove these
- # comments:
- # disable_ddl_transaction!
-
- def change
- create_table :merge_request_metrics do |t|
- t.references :merge_request, index: { name: "index_merge_request_metrics" }, foreign_key: { on_delete: :cascade }, null: false
-
- t.datetime 'latest_build_started_at'
- t.datetime 'latest_build_finished_at'
- t.datetime 'first_deployed_to_production_at', index: true
- t.datetime 'merged_at'
-
- t.timestamps null: false
- end
- end
-end
diff --git a/db/migrate/20160827011312_ensure_lock_version_has_no_default.rb b/db/migrate/20160827011312_ensure_lock_version_has_no_default.rb
deleted file mode 100644
index 18c0f0be3eb..00000000000
--- a/db/migrate/20160827011312_ensure_lock_version_has_no_default.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-class EnsureLockVersionHasNoDefault < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def up
- change_column_default :issues, :lock_version, nil
- change_column_default :merge_requests, :lock_version, nil
-
- execute('UPDATE issues SET lock_version = 1 WHERE lock_version = 0')
- execute('UPDATE merge_requests SET lock_version = 1 WHERE lock_version = 0')
- end
-
- def down
- end
-end
diff --git a/db/migrate/20160829114652_add_markdown_cache_columns.rb b/db/migrate/20160829114652_add_markdown_cache_columns.rb
deleted file mode 100644
index b1c5e38c3c4..00000000000
--- a/db/migrate/20160829114652_add_markdown_cache_columns.rb
+++ /dev/null
@@ -1,38 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class AddMarkdownCacheColumns < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- COLUMNS = {
- abuse_reports: [:message],
- appearances: [:description],
- application_settings: [
- :sign_in_text,
- :help_page_text,
- :shared_runners_text,
- :after_sign_up_text
- ],
- broadcast_messages: [:message],
- issues: [:title, :description],
- labels: [:description],
- merge_requests: [:title, :description],
- milestones: [:title, :description],
- namespaces: [:description],
- notes: [:note],
- projects: [:description],
- releases: [:description],
- snippets: [:title, :content]
- }.freeze
-
- def change
- COLUMNS.each do |table, columns|
- columns.each do |column|
- add_column table, "#{column}_html", :text
- end
- end
- end
-end
diff --git a/db/migrate/20160830203109_add_confidential_issues_events_to_web_hooks.rb b/db/migrate/20160830203109_add_confidential_issues_events_to_web_hooks.rb
deleted file mode 100644
index 771a6b84648..00000000000
--- a/db/migrate/20160830203109_add_confidential_issues_events_to_web_hooks.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-class AddConfidentialIssuesEventsToWebHooks < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- add_column_with_default :web_hooks, :confidential_issues_events, :boolean, default: false, allow_null: false
- end
-
- def down
- remove_column :web_hooks, :confidential_issues_events
- end
-end
diff --git a/db/migrate/20160830211132_add_confidential_issues_events_to_services.rb b/db/migrate/20160830211132_add_confidential_issues_events_to_services.rb
deleted file mode 100644
index a1807264341..00000000000
--- a/db/migrate/20160830211132_add_confidential_issues_events_to_services.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-class AddConfidentialIssuesEventsToServices < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- add_column_with_default :services, :confidential_issues_events, :boolean, default: true, allow_null: false
- end
-
- def down
- remove_column :services, :confidential_issues_events
- end
-end
diff --git a/db/migrate/20160830232601_change_lock_version_not_null.rb b/db/migrate/20160830232601_change_lock_version_not_null.rb
deleted file mode 100644
index 1e34b57e53f..00000000000
--- a/db/migrate/20160830232601_change_lock_version_not_null.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-class ChangeLockVersionNotNull < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def up
- change_column_null :issues, :lock_version, true
- change_column_null :merge_requests, :lock_version, true
- end
-
- def down
- end
-end
diff --git a/db/migrate/20160831214002_create_project_features.rb b/db/migrate/20160831214002_create_project_features.rb
deleted file mode 100644
index e1e61c3a4a2..00000000000
--- a/db/migrate/20160831214002_create_project_features.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-# rubocop:disable Migration/Timestamps
-class CreateProjectFeatures < ActiveRecord::Migration[4.2]
- DOWNTIME = false
-
- def change
- create_table :project_features do |t|
- t.belongs_to :project, index: true
- t.integer :merge_requests_access_level
- t.integer :issues_access_level
- t.integer :wiki_access_level
- t.integer :snippets_access_level
- t.integer :builds_access_level
-
- t.timestamps null: true
- end
- end
-end
diff --git a/db/migrate/20160831214543_migrate_project_features.rb b/db/migrate/20160831214543_migrate_project_features.rb
deleted file mode 100644
index ba7ffd7c9f2..00000000000
--- a/db/migrate/20160831214543_migrate_project_features.rb
+++ /dev/null
@@ -1,44 +0,0 @@
-class MigrateProjectFeatures < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = true
- DOWNTIME_REASON =
- <<-EOT.freeze
- Migrating issues_enabled, merge_requests_enabled, wiki_enabled, builds_enabled, snippets_enabled fields from projects to
- a new table called project_features.
- EOT
-
- def up
- sql =
- %Q{
- INSERT INTO project_features(project_id, issues_access_level, merge_requests_access_level, wiki_access_level,
- builds_access_level, snippets_access_level, created_at, updated_at)
- SELECT
- id AS project_id,
- CASE WHEN issues_enabled IS true THEN 20 ELSE 0 END AS issues_access_level,
- CASE WHEN merge_requests_enabled IS true THEN 20 ELSE 0 END AS merge_requests_access_level,
- CASE WHEN wiki_enabled IS true THEN 20 ELSE 0 END AS wiki_access_level,
- CASE WHEN builds_enabled IS true THEN 20 ELSE 0 END AS builds_access_level,
- CASE WHEN snippets_enabled IS true THEN 20 ELSE 0 END AS snippets_access_level,
- created_at,
- updated_at
- FROM projects
- }
-
- execute(sql)
- end
-
- def down
- sql = %Q{
- UPDATE projects
- SET
- issues_enabled = COALESCE((SELECT CASE WHEN issues_access_level = 20 THEN true ELSE false END AS issues_enabled FROM project_features WHERE project_features.project_id = projects.id), true),
- merge_requests_enabled = COALESCE((SELECT CASE WHEN merge_requests_access_level = 20 THEN true ELSE false END AS merge_requests_enabled FROM project_features WHERE project_features.project_id = projects.id),true),
- wiki_enabled = COALESCE((SELECT CASE WHEN wiki_access_level = 20 THEN true ELSE false END AS wiki_enabled FROM project_features WHERE project_features.project_id = projects.id), true),
- builds_enabled = COALESCE((SELECT CASE WHEN builds_access_level = 20 THEN true ELSE false END AS builds_enabled FROM project_features WHERE project_features.project_id = projects.id), true),
- snippets_enabled = COALESCE((SELECT CASE WHEN snippets_access_level = 20 THEN true ELSE false END AS snippets_enabled FROM project_features WHERE project_features.project_id = projects.id),true)
- }
-
- execute(sql)
- end
-end
diff --git a/db/migrate/20160831223750_remove_features_enabled_from_projects.rb b/db/migrate/20160831223750_remove_features_enabled_from_projects.rb
deleted file mode 100644
index 6d39d42882b..00000000000
--- a/db/migrate/20160831223750_remove_features_enabled_from_projects.rb
+++ /dev/null
@@ -1,31 +0,0 @@
-# rubocop:disable Migration/RemoveColumn
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-# rubocop:disable Migration/UpdateLargeTable
-class RemoveFeaturesEnabledFromProjects < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
- disable_ddl_transaction!
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = true
- DOWNTIME_REASON = "Removing fields from database requires downtine."
-
- def up
- remove_column :projects, :issues_enabled
- remove_column :projects, :merge_requests_enabled
- remove_column :projects, :builds_enabled
- remove_column :projects, :wiki_enabled
- remove_column :projects, :snippets_enabled
- end
-
- # Ugly SQL but the only way i found to make it work on both Postgres and Mysql
- # It will be slow but it is ok since it is a revert method
- def down
- add_column_with_default(:projects, :issues_enabled, :boolean, default: true, allow_null: false)
- add_column_with_default(:projects, :merge_requests_enabled, :boolean, default: true, allow_null: false)
- add_column_with_default(:projects, :builds_enabled, :boolean, default: true, allow_null: false)
- add_column_with_default(:projects, :wiki_enabled, :boolean, default: true, allow_null: false)
- add_column_with_default(:projects, :snippets_enabled, :boolean, default: true, allow_null: false)
- end
-end
diff --git a/db/migrate/20160901141443_set_confidential_issues_events_on_webhooks.rb b/db/migrate/20160901141443_set_confidential_issues_events_on_webhooks.rb
deleted file mode 100644
index 2921bb566c9..00000000000
--- a/db/migrate/20160901141443_set_confidential_issues_events_on_webhooks.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-# rubocop:disable Migration/UpdateColumnInBatches
-class SetConfidentialIssuesEventsOnWebhooks < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- update_column_in_batches(:web_hooks, :confidential_issues_events, true) do |table, query|
- query.where(table[:issues_events].eq(true))
- end
- end
-
- def down
- # noop
- end
-end
diff --git a/db/migrate/20160901213340_add_lfs_enabled_to_namespaces.rb b/db/migrate/20160901213340_add_lfs_enabled_to_namespaces.rb
deleted file mode 100644
index 1be5f3f6ab0..00000000000
--- a/db/migrate/20160901213340_add_lfs_enabled_to_namespaces.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class AddLfsEnabledToNamespaces < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def change
- add_column :namespaces, :lfs_enabled, :boolean
- end
-end
diff --git a/db/migrate/20160902122721_drop_gitorious_field_from_application_settings.rb b/db/migrate/20160902122721_drop_gitorious_field_from_application_settings.rb
deleted file mode 100644
index 6c2dc58876e..00000000000
--- a/db/migrate/20160902122721_drop_gitorious_field_from_application_settings.rb
+++ /dev/null
@@ -1,39 +0,0 @@
-class DropGitoriousFieldFromApplicationSettings < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # After the deploy the caches will be cold anyway
- DOWNTIME = false
-
- def up
- require 'yaml'
-
- import_sources = connection.execute('SELECT import_sources FROM application_settings;')
- return unless import_sources.first # support empty databases
-
- yaml = if Gitlab::Database.postgresql?
- import_sources.values[0][0]
- else
- import_sources.first[0]
- end
-
- yaml = YAML.safe_load(yaml)
- yaml.delete 'gitorious'
-
- # No need for a WHERE clause as there is only one
- connection.execute("UPDATE application_settings SET import_sources = #{update_yaml(yaml)}")
- end
-
- def down
- # noop, gitorious still yields a 404 anyway
- end
-
- private
-
- def connection
- ActiveRecord::Base.connection
- end
-
- def update_yaml(yaml)
- connection.quote(YAML.dump(yaml))
- end
-end
diff --git a/db/migrate/20160907131111_add_environment_type_to_environments.rb b/db/migrate/20160907131111_add_environment_type_to_environments.rb
deleted file mode 100644
index 34463178fca..00000000000
--- a/db/migrate/20160907131111_add_environment_type_to_environments.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-class AddEnvironmentTypeToEnvironments < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def change
- add_column :environments, :environment_type, :string
- end
-end
diff --git a/db/migrate/20160913162434_remove_projects_pushes_since_gc.rb b/db/migrate/20160913162434_remove_projects_pushes_since_gc.rb
deleted file mode 100644
index 51650c68170..00000000000
--- a/db/migrate/20160913162434_remove_projects_pushes_since_gc.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-# rubocop:disable Migration/RemoveColumn
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-# rubocop:disable Migration/UpdateLargeTable
-class RemoveProjectsPushesSinceGc < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = true
- DOWNTIME_REASON = 'This migration removes an existing column'
-
- disable_ddl_transaction!
-
- def up
- remove_column :projects, :pushes_since_gc
- end
-
- def down
- add_column_with_default :projects, :pushes_since_gc, :integer, default: 0
- end
-end
diff --git a/db/migrate/20160913212128_change_artifacts_size_column.rb b/db/migrate/20160913212128_change_artifacts_size_column.rb
deleted file mode 100644
index f2c2aaff9a8..00000000000
--- a/db/migrate/20160913212128_change_artifacts_size_column.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-class ChangeArtifactsSizeColumn < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = true
-
- DOWNTIME_REASON = 'Changing an integer column size requires a full table rewrite.'
-
- def up
- change_column :ci_builds, :artifacts_size, :integer, limit: 8
- end
-
- def down
- # do nothing
- end
-end
diff --git a/db/migrate/20160914131004_only_allow_merge_if_all_discussions_are_resolved.rb b/db/migrate/20160914131004_only_allow_merge_if_all_discussions_are_resolved.rb
deleted file mode 100644
index 81511f9861b..00000000000
--- a/db/migrate/20160914131004_only_allow_merge_if_all_discussions_are_resolved.rb
+++ /dev/null
@@ -1,14 +0,0 @@
-class OnlyAllowMergeIfAllDiscussionsAreResolved < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
- disable_ddl_transaction!
-
- def up
- add_column :projects, :only_allow_merge_if_all_discussions_are_resolved, :boolean
- end
-
- def down
- remove_column(:projects, :only_allow_merge_if_all_discussions_are_resolved)
- end
-end
diff --git a/db/migrate/20160915042921_create_merge_requests_closing_issues.rb b/db/migrate/20160915042921_create_merge_requests_closing_issues.rb
deleted file mode 100644
index 3efe8c8901b..00000000000
--- a/db/migrate/20160915042921_create_merge_requests_closing_issues.rb
+++ /dev/null
@@ -1,35 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-# rubocop:disable Migration/Timestamps
-class CreateMergeRequestsClosingIssues < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = true
-
- # When a migration requires downtime you **must** uncomment the following
- # constant and define a short and easy to understand explanation as to why the
- # migration requires downtime.
- DOWNTIME_REASON = 'Adding foreign keys'
-
- # When using the methods "add_concurrent_index" or "add_column_with_default"
- # you must disable the use of transactions as these methods can not run in an
- # existing transaction. When using "add_concurrent_index" make sure that this
- # method is the _only_ method called in the migration, any other changes
- # should go in a separate migration. This ensures that upon failure _only_ the
- # index creation fails and can be retried or reverted easily.
- #
- # To disable transactions uncomment the following line and remove these
- # comments:
- # disable_ddl_transaction!
-
- def change
- create_table :merge_requests_closing_issues do |t|
- t.references :merge_request, foreign_key: { on_delete: :cascade }, index: true, null: false
- t.references :issue, foreign_key: { on_delete: :cascade }, index: true, null: false
-
- t.timestamps null: false
- end
- end
-end
diff --git a/db/migrate/20160919144305_add_type_to_labels.rb b/db/migrate/20160919144305_add_type_to_labels.rb
deleted file mode 100644
index f897646d264..00000000000
--- a/db/migrate/20160919144305_add_type_to_labels.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-# rubocop:disable Migration/UpdateColumnInBatches
-class AddTypeToLabels < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = true
- DOWNTIME_REASON = 'Labels will not work as expected until this migration is complete.'
-
- disable_ddl_transaction!
-
- def change
- add_column :labels, :type, :string
-
- update_column_in_batches(:labels, :type, 'ProjectLabel') do |table, query|
- query.where(table[:project_id].not_eq(nil))
- end
- end
-end
diff --git a/db/migrate/20160919145149_add_group_id_to_labels.rb b/db/migrate/20160919145149_add_group_id_to_labels.rb
deleted file mode 100644
index df11a2fc4c8..00000000000
--- a/db/migrate/20160919145149_add_group_id_to_labels.rb
+++ /dev/null
@@ -1,20 +0,0 @@
-# rubocop:disable RemoveIndex
-class AddGroupIdToLabels < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- add_column :labels, :group_id, :integer
- add_foreign_key :labels, :namespaces, column: :group_id, on_delete: :cascade # rubocop: disable Migration/AddConcurrentForeignKey
- add_concurrent_index :labels, :group_id
- end
-
- def down
- remove_foreign_key :labels, column: :group_id
- remove_index :labels, :group_id if index_exists? :labels, :group_id
- remove_column :labels, :group_id
- end
-end
diff --git a/db/migrate/20160920160832_add_index_to_labels_title.rb b/db/migrate/20160920160832_add_index_to_labels_title.rb
deleted file mode 100644
index e6c87836d4e..00000000000
--- a/db/migrate/20160920160832_add_index_to_labels_title.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-# rubocop:disable RemoveIndex
-class AddIndexToLabelsTitle < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- add_concurrent_index :labels, :title
- end
-
- def down
- remove_index :labels, :title if index_exists? :labels, :title
- end
-end
diff --git a/db/migrate/20160926145521_add_organization_to_user.rb b/db/migrate/20160926145521_add_organization_to_user.rb
deleted file mode 100644
index 2d8d907591d..00000000000
--- a/db/migrate/20160926145521_add_organization_to_user.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class AddOrganizationToUser < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def change
- add_column :users, :organization, :string
- end
-end
diff --git a/db/migrate/20161006104309_add_state_to_environment.rb b/db/migrate/20161006104309_add_state_to_environment.rb
deleted file mode 100644
index c51dada9bca..00000000000
--- a/db/migrate/20161006104309_add_state_to_environment.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-class AddStateToEnvironment < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- disable_ddl_transaction!
-
- DOWNTIME = false
-
- def up
- add_column_with_default(:environments, :state, :string, default: :available)
- end
-
- def down
- remove_column(:environments, :state)
- end
-end
diff --git a/db/migrate/20161007073613_create_user_activities.rb b/db/migrate/20161007073613_create_user_activities.rb
deleted file mode 100644
index dc972bf4664..00000000000
--- a/db/migrate/20161007073613_create_user_activities.rb
+++ /dev/null
@@ -1,28 +0,0 @@
-
-class CreateUserActivities < ActiveRecord::Migration[4.2]
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = true
-
- # When a migration requires downtime you **must** uncomment the following
- # constant and define a short and easy to understand explanation as to why the
- # migration requires downtime.
- DOWNTIME_REASON = 'Adding foreign key'.freeze
-
- # When using the methods "add_concurrent_index" or "add_column_with_default"
- # you must disable the use of transactions as these methods can not run in an
- # existing transaction. When using "add_concurrent_index" make sure that this
- # method is the _only_ method called in the migration, any other changes
- # should go in a separate migration. This ensures that upon failure _only_ the
- # index creation fails and can be retried or reverted easily.
- #
- # To disable transactions uncomment the following line and remove these
- # comments:
- # disable_ddl_transaction!
-
- def change
- create_table :user_activities do |t|
- t.belongs_to :user, index: { unique: true }, foreign_key: { on_delete: :cascade }
- t.datetime :last_activity_at, null: false
- end
- end
-end
diff --git a/db/migrate/20161007133303_precalculate_trending_projects.rb b/db/migrate/20161007133303_precalculate_trending_projects.rb
deleted file mode 100644
index c7a678c9d8f..00000000000
--- a/db/migrate/20161007133303_precalculate_trending_projects.rb
+++ /dev/null
@@ -1,38 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class PrecalculateTrendingProjects < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def up
- create_table :trending_projects do |t|
- t.references :project, index: true, foreign_key: { on_delete: :cascade }, null: false
- end
-
- timestamp = connection.quote(1.month.ago)
-
- # We're hardcoding the visibility level (public) here so that if it ever
- # changes this query doesn't suddenly use the new value (which may break
- # later migrations).
- visibility = 20
-
- execute <<-EOF.strip_heredoc
- INSERT INTO trending_projects (project_id)
- SELECT project_id
- FROM notes
- INNER JOIN projects ON projects.id = notes.project_id
- WHERE notes.created_at >= #{timestamp}
- AND notes.system IS FALSE
- AND projects.visibility_level = #{visibility}
- GROUP BY project_id
- ORDER BY count(*) DESC
- LIMIT 100;
- EOF
- end
-
- def down
- drop_table :trending_projects
- end
-end
diff --git a/db/migrate/20161010142410_create_project_authorizations.rb b/db/migrate/20161010142410_create_project_authorizations.rb
deleted file mode 100644
index b340a4ece19..00000000000
--- a/db/migrate/20161010142410_create_project_authorizations.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-class CreateProjectAuthorizations < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def change
- create_table :project_authorizations do |t|
- t.references :user, foreign_key: { on_delete: :cascade }
- t.references :project, foreign_key: { on_delete: :cascade }
- t.integer :access_level
-
- t.index [:user_id, :project_id, :access_level], unique: true, name: 'index_project_authorizations_on_user_id_project_id_access_level'
- end
- end
-end
diff --git a/db/migrate/20161012180455_add_repository_access_level_to_project_feature.rb b/db/migrate/20161012180455_add_repository_access_level_to_project_feature.rb
deleted file mode 100644
index 3024ea81ed8..00000000000
--- a/db/migrate/20161012180455_add_repository_access_level_to_project_feature.rb
+++ /dev/null
@@ -1,14 +0,0 @@
-class AddRepositoryAccessLevelToProjectFeature < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
- disable_ddl_transaction!
-
- DOWNTIME = false
-
- def up
- add_column_with_default(:project_features, :repository_access_level, :integer, default: ProjectFeature::ENABLED)
- end
-
- def down
- remove_column :project_features, :repository_access_level
- end
-end
diff --git a/db/migrate/20161014173530_create_label_priorities.rb b/db/migrate/20161014173530_create_label_priorities.rb
deleted file mode 100644
index c7d60caa7d1..00000000000
--- a/db/migrate/20161014173530_create_label_priorities.rb
+++ /dev/null
@@ -1,26 +0,0 @@
-# rubocop:disable Migration/Timestamps
-class CreateLabelPriorities < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = true
- DOWNTIME_REASON = 'This migration adds foreign keys'
-
- disable_ddl_transaction!
-
- def up
- create_table :label_priorities do |t|
- t.references :project, foreign_key: { on_delete: :cascade }, null: false
- t.references :label, foreign_key: { on_delete: :cascade }, null: false
- t.integer :priority, null: false
-
- t.timestamps null: false
- end
-
- add_concurrent_index :label_priorities, [:project_id, :label_id], unique: true
- add_concurrent_index :label_priorities, :priority
- end
-
- def down
- drop_table :label_priorities
- end
-end
diff --git a/db/migrate/20161017091941_add_authorized_projects_populated_to_users.rb b/db/migrate/20161017091941_add_authorized_projects_populated_to_users.rb
deleted file mode 100644
index 11f4fa1a1f7..00000000000
--- a/db/migrate/20161017091941_add_authorized_projects_populated_to_users.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-class AddAuthorizedProjectsPopulatedToUsers < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def change
- add_column :users, :authorized_projects_populated, :boolean
- end
-end
diff --git a/db/migrate/20161017095000_add_properties_to_deployment.rb b/db/migrate/20161017095000_add_properties_to_deployment.rb
deleted file mode 100644
index 31bd4cd24ad..00000000000
--- a/db/migrate/20161017095000_add_properties_to_deployment.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-class AddPropertiesToDeployment < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def change
- add_column :deployments, :on_stop, :string
- end
-end
diff --git a/db/migrate/20161017125927_add_unique_index_to_labels.rb b/db/migrate/20161017125927_add_unique_index_to_labels.rb
deleted file mode 100644
index b5326789f52..00000000000
--- a/db/migrate/20161017125927_add_unique_index_to_labels.rb
+++ /dev/null
@@ -1,33 +0,0 @@
-# rubocop:disable RemoveIndex
-class AddUniqueIndexToLabels < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = true
- DOWNTIME_REASON = 'This migration removes duplicated labels.'
-
- disable_ddl_transaction!
-
- def up
- select_all('SELECT title, project_id, COUNT(id) as cnt FROM labels GROUP BY project_id, title HAVING COUNT(id) > 1').each do |label|
- label_title = quote_string(label['title'])
- duplicated_ids = select_all("SELECT id FROM labels WHERE project_id = #{label['project_id']} AND title = '#{label_title}' ORDER BY id ASC").map { |label| label['id'] }
- label_id = duplicated_ids.first
- duplicated_ids.delete(label_id)
-
- execute("UPDATE label_links SET label_id = #{label_id} WHERE label_id IN(#{duplicated_ids.join(",")})")
- execute("DELETE FROM labels WHERE id IN(#{duplicated_ids.join(",")})")
- end
-
- remove_index :labels, column: :project_id if index_exists?(:labels, :project_id)
- remove_index :labels, column: :title if index_exists?(:labels, :title)
-
- add_concurrent_index :labels, [:group_id, :project_id, :title], unique: true
- end
-
- def down
- remove_index :labels, column: [:group_id, :project_id, :title] if index_exists?(:labels, [:group_id, :project_id, :title], unique: true)
-
- add_concurrent_index :labels, :project_id
- add_concurrent_index :labels, :title
- end
-end
diff --git a/db/migrate/20161018024215_migrate_labels_priority.rb b/db/migrate/20161018024215_migrate_labels_priority.rb
deleted file mode 100644
index 3e2540c134c..00000000000
--- a/db/migrate/20161018024215_migrate_labels_priority.rb
+++ /dev/null
@@ -1,36 +0,0 @@
-class MigrateLabelsPriority < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = true
- DOWNTIME_REASON = 'Prioritized labels will not work as expected until this migration is complete.'
-
- disable_ddl_transaction!
-
- def up
- execute <<-EOF.strip_heredoc
- INSERT INTO label_priorities (project_id, label_id, priority, created_at, updated_at)
- SELECT labels.project_id, labels.id, labels.priority, NOW(), NOW()
- FROM labels
- WHERE labels.project_id IS NOT NULL
- AND labels.priority IS NOT NULL;
- EOF
- end
-
- def down
- if Gitlab::Database.mysql?
- execute <<-EOF.strip_heredoc
- UPDATE labels
- INNER JOIN label_priorities ON labels.id = label_priorities.label_id AND labels.project_id = label_priorities.project_id
- SET labels.priority = label_priorities.priority;
- EOF
- else
- execute <<-EOF.strip_heredoc
- UPDATE labels
- SET priority = label_priorities.priority
- FROM label_priorities
- WHERE labels.id = label_priorities.label_id
- AND labels.project_id = label_priorities.project_id;
- EOF
- end
- end
-end
diff --git a/db/migrate/20161018024550_remove_priority_from_labels.rb b/db/migrate/20161018024550_remove_priority_from_labels.rb
deleted file mode 100644
index e164d959bdf..00000000000
--- a/db/migrate/20161018024550_remove_priority_from_labels.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-# rubocop:disable Migration/RemoveColumn
-class RemovePriorityFromLabels < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = true
- DOWNTIME_REASON = 'This migration removes an existing column'
-
- disable_ddl_transaction!
-
- def up
- remove_column :labels, :priority, :integer, index: true
- end
-
- def down
- add_column :labels, :priority, :integer
- add_concurrent_index :labels, :priority
- end
-end
diff --git a/db/migrate/20161018124658_make_project_owners_masters.rb b/db/migrate/20161018124658_make_project_owners_masters.rb
deleted file mode 100644
index 132c17388dc..00000000000
--- a/db/migrate/20161018124658_make_project_owners_masters.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-# rubocop:disable Migration/UpdateColumnInBatches
-class MakeProjectOwnersMasters < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- update_column_in_batches(:members, :access_level, 40) do |table, query|
- query.where(table[:access_level].eq(50).and(table[:source_type].eq('Project')))
- end
- end
-
- def down
- # do nothing
- end
-end
diff --git a/db/migrate/20161019190736_migrate_sidekiq_queues_from_default.rb b/db/migrate/20161019190736_migrate_sidekiq_queues_from_default.rb
deleted file mode 100644
index fc6d9784638..00000000000
--- a/db/migrate/20161019190736_migrate_sidekiq_queues_from_default.rb
+++ /dev/null
@@ -1,109 +0,0 @@
-require 'json'
-
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class MigrateSidekiqQueuesFromDefault < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = true
-
- DOWNTIME_REASON = <<-EOF
- Moving Sidekiq jobs from queues requires Sidekiq to be stopped. Not stopping
- Sidekiq will result in the loss of jobs that are scheduled after this
- migration completes.
- EOF
-
- disable_ddl_transaction!
-
- # Jobs for which the queue names have been changed (e.g. multiple workers
- # using the same non-default queue).
- #
- # The keys are the old queue names, the values the jobs to move and their new
- # queue names.
- RENAMED_QUEUES = {
- gitlab_shell: {
- 'GitGarbageCollectorWorker' => :git_garbage_collector,
- 'ProjectExportWorker' => :project_export,
- 'RepositoryForkWorker' => :repository_fork,
- 'RepositoryImportWorker' => :repository_import
- },
- project_web_hook: {
- 'ProjectServiceWorker' => :project_service
- },
- incoming_email: {
- 'EmailReceiverWorker' => :email_receiver
- },
- mailers: {
- 'EmailsOnPushWorker' => :emails_on_push
- },
- default: {
- 'AdminEmailWorker' => :cronjob,
- 'BuildCoverageWorker' => :build,
- 'BuildEmailWorker' => :build,
- 'BuildFinishedWorker' => :build,
- 'BuildHooksWorker' => :build,
- 'BuildSuccessWorker' => :build,
- 'ClearDatabaseCacheWorker' => :clear_database_cache,
- 'DeleteUserWorker' => :delete_user,
- 'ExpireBuildArtifactsWorker' => :cronjob,
- 'ExpireBuildInstanceArtifactsWorker' => :expire_build_instance_artifacts,
- 'GroupDestroyWorker' => :group_destroy,
- 'ImportExportProjectCleanupWorker' => :cronjob,
- 'IrkerWorker' => :irker,
- 'MergeWorker' => :merge,
- 'NewNoteWorker' => :new_note,
- 'PipelineHooksWorker' => :pipeline,
- 'PipelineMetricsWorker' => :pipeline,
- 'PipelineProcessWorker' => :pipeline,
- 'PipelineSuccessWorker' => :pipeline,
- 'PipelineUpdateWorker' => :pipeline,
- 'ProjectCacheWorker' => :project_cache,
- 'ProjectDestroyWorker' => :project_destroy,
- 'PruneOldEventsWorker' => :cronjob,
- 'RemoveExpiredGroupLinksWorker' => :cronjob,
- 'RemoveExpiredMembersWorker' => :cronjob,
- 'RepositoryArchiveCacheWorker' => :cronjob,
- 'RepositoryCheck::BatchWorker' => :cronjob,
- 'RepositoryCheck::ClearWorker' => :repository_check,
- 'RepositoryCheck::SingleRepositoryWorker' => :repository_check,
- 'RequestsProfilesWorker' => :cronjob,
- 'StuckCiBuildsWorker' => :cronjob,
- 'UpdateMergeRequestsWorker' => :update_merge_requests
- }
- }.freeze
-
- def up
- Sidekiq.redis do |redis|
- RENAMED_QUEUES.each do |queue, jobs|
- migrate_from_queue(redis, queue, jobs)
- end
- end
- end
-
- def down
- Sidekiq.redis do |redis|
- RENAMED_QUEUES.each do |dest_queue, jobs|
- jobs.each do |worker, from_queue|
- migrate_from_queue(redis, from_queue, worker => dest_queue)
- end
- end
- end
- end
-
- def migrate_from_queue(redis, queue, job_mapping)
- while job = redis.lpop("queue:#{queue}")
- payload = JSON.parse(job)
- new_queue = job_mapping[payload['class']]
-
- # If we have no target queue to migrate to we're probably dealing with
- # some ancient job for which the worker no longer exists. In that case
- # there's no sane option we can take, other than just dropping the job.
- next unless new_queue
-
- payload['queue'] = new_queue
-
- redis.lpush("queue:#{new_queue}", JSON.dump(payload))
- end
- end
-end
diff --git a/db/migrate/20161019213545_generate_project_feature_for_projects.rb b/db/migrate/20161019213545_generate_project_feature_for_projects.rb
deleted file mode 100644
index 587bdf60f70..00000000000
--- a/db/migrate/20161019213545_generate_project_feature_for_projects.rb
+++ /dev/null
@@ -1,28 +0,0 @@
-class GenerateProjectFeatureForProjects < ActiveRecord::Migration[4.2]
- DOWNTIME = true
-
- DOWNTIME_REASON = <<-HEREDOC
- Application was eager loading project_feature for all projects generating an extra query
- everytime a project was fetched. We removed that behavior to avoid the extra query, this migration
- makes sure all projects have a project_feature record associated.
- HEREDOC
-
- def up
- # Generate enabled values for each project feature 20, 20, 20, 20, 20
- # All features are enabled by default
- enabled_values = [ProjectFeature::ENABLED] * 5
-
- execute <<-EOF.strip_heredoc
- INSERT INTO project_features
- (project_id, merge_requests_access_level, builds_access_level,
- issues_access_level, snippets_access_level, wiki_access_level)
- (SELECT projects.id, #{enabled_values.join(',')} FROM projects LEFT OUTER JOIN project_features
- ON project_features.project_id = projects.id
- WHERE project_features.id IS NULL)
- EOF
- end
-
- def down
- "Not needed"
- end
-end
diff --git a/db/migrate/20161020075734_default_request_access_groups.rb b/db/migrate/20161020075734_default_request_access_groups.rb
deleted file mode 100644
index 72aec86167e..00000000000
--- a/db/migrate/20161020075734_default_request_access_groups.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-class DefaultRequestAccessGroups < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
- DOWNTIME = false
-
- def up
- change_column_default :namespaces, :request_access_enabled, false
- end
-
- def down
- change_column_default :namespaces, :request_access_enabled, true
- end
-end
diff --git a/db/migrate/20161020075830_default_request_access_projects.rb b/db/migrate/20161020075830_default_request_access_projects.rb
deleted file mode 100644
index b457e39f838..00000000000
--- a/db/migrate/20161020075830_default_request_access_projects.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-class DefaultRequestAccessProjects < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
- DOWNTIME = false
-
- def up
- change_column_default :projects, :request_access_enabled, false
- end
-
- def down
- change_column_default :projects, :request_access_enabled, true
- end
-end
diff --git a/db/migrate/20161020083353_add_pipeline_id_to_merge_request_metrics.rb b/db/migrate/20161020083353_add_pipeline_id_to_merge_request_metrics.rb
deleted file mode 100644
index 60352363e42..00000000000
--- a/db/migrate/20161020083353_add_pipeline_id_to_merge_request_metrics.rb
+++ /dev/null
@@ -1,40 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-# rubocop:disable RemoveIndex
-class AddPipelineIdToMergeRequestMetrics < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- disable_ddl_transaction!
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = true
-
- # When a migration requires downtime you **must** uncomment the following
- # constant and define a short and easy to understand explanation as to why the
- # migration requires downtime.
- DOWNTIME_REASON = 'Adding a foreign key'
-
- # When using the methods "add_concurrent_index" or "add_column_with_default"
- # you must disable the use of transactions as these methods can not run in an
- # existing transaction. When using "add_concurrent_index" make sure that this
- # method is the _only_ method called in the migration, any other changes
- # should go in a separate migration. This ensures that upon failure _only_ the
- # index creation fails and can be retried or reverted easily.
- #
- # To disable transactions uncomment the following line and remove these
- # comments:
- # disable_ddl_transaction!
-
- def up
- add_column :merge_request_metrics, :pipeline_id, :integer
- add_foreign_key :merge_request_metrics, :ci_commits, column: :pipeline_id, on_delete: :cascade # rubocop: disable Migration/AddConcurrentForeignKey
- add_concurrent_index :merge_request_metrics, :pipeline_id
- end
-
- def down
- remove_foreign_key :merge_request_metrics, column: :pipeline_id
- remove_index :merge_request_metrics, :pipeline_id if index_exists? :merge_request_metrics, :pipeline_id
- remove_column :merge_request_metrics, :pipeline_id
- end
-end
diff --git a/db/migrate/20161020180657_add_minimum_key_length_to_application_settings.rb b/db/migrate/20161020180657_add_minimum_key_length_to_application_settings.rb
deleted file mode 100644
index 7839bee6a5b..00000000000
--- a/db/migrate/20161020180657_add_minimum_key_length_to_application_settings.rb
+++ /dev/null
@@ -1,29 +0,0 @@
-class AddMinimumKeyLengthToApplicationSettings < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- # A key restriction has these possible states:
- #
- # * -1 means "this key type is completely disabled"
- # * 0 means "all keys of this type are valid"
- # * > 0 means "keys must have at least this many bits to be valid"
- #
- # The default is 0, for backward compatibility
- add_column_with_default :application_settings, :rsa_key_restriction, :integer, default: 0
- add_column_with_default :application_settings, :dsa_key_restriction, :integer, default: 0
- add_column_with_default :application_settings, :ecdsa_key_restriction, :integer, default: 0
- add_column_with_default :application_settings, :ed25519_key_restriction, :integer, default: 0
- end
-
- def down
- remove_column :application_settings, :rsa_key_restriction
- remove_column :application_settings, :dsa_key_restriction
- remove_column :application_settings, :ecdsa_key_restriction
- remove_column :application_settings, :ed25519_key_restriction
- end
-end
diff --git a/db/migrate/20161021114307_add_lock_version_to_build_and_pipelines.rb b/db/migrate/20161021114307_add_lock_version_to_build_and_pipelines.rb
deleted file mode 100644
index e172dc3adf2..00000000000
--- a/db/migrate/20161021114307_add_lock_version_to_build_and_pipelines.rb
+++ /dev/null
@@ -1,14 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class AddLockVersionToBuildAndPipelines < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- def change
- add_column :ci_builds, :lock_version, :integer
- add_column :ci_commits, :lock_version, :integer
- end
-end
diff --git a/db/migrate/20161024042317_migrate_mailroom_queue_from_default.rb b/db/migrate/20161024042317_migrate_mailroom_queue_from_default.rb
deleted file mode 100644
index d27f8fc38c8..00000000000
--- a/db/migrate/20161024042317_migrate_mailroom_queue_from_default.rb
+++ /dev/null
@@ -1,63 +0,0 @@
-require 'json'
-
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class MigrateMailroomQueueFromDefault < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = true
-
- DOWNTIME_REASON = <<-EOF
- Moving Sidekiq jobs from queues requires Sidekiq to be stopped. Not stopping
- Sidekiq will result in the loss of jobs that are scheduled after this
- migration completes.
- EOF
-
- disable_ddl_transaction!
-
- # Jobs for which the queue names have been changed (e.g. multiple workers
- # using the same non-default queue).
- #
- # The keys are the old queue names, the values the jobs to move and their new
- # queue names.
- RENAMED_QUEUES = {
- incoming_email: {
- 'EmailReceiverWorker' => :email_receiver
- }
- }.freeze
-
- def up
- Sidekiq.redis do |redis|
- RENAMED_QUEUES.each do |queue, jobs|
- migrate_from_queue(redis, queue, jobs)
- end
- end
- end
-
- def down
- Sidekiq.redis do |redis|
- RENAMED_QUEUES.each do |dest_queue, jobs|
- jobs.each do |worker, from_queue|
- migrate_from_queue(redis, from_queue, worker => dest_queue)
- end
- end
- end
- end
-
- def migrate_from_queue(redis, queue, job_mapping)
- while job = redis.lpop("queue:#{queue}")
- payload = JSON.parse(job)
- new_queue = job_mapping[payload['class']]
-
- # If we have no target queue to migrate to we're probably dealing with
- # some ancient job for which the worker no longer exists. In that case
- # there's no sane option we can take, other than just dropping the job.
- next unless new_queue
-
- payload['queue'] = new_queue
-
- redis.lpush("queue:#{new_queue}", JSON.dump(payload))
- end
- end
-end
diff --git a/db/migrate/20161025231710_migrate_jira_to_gem.rb b/db/migrate/20161025231710_migrate_jira_to_gem.rb
deleted file mode 100644
index aa1c59ec9e6..00000000000
--- a/db/migrate/20161025231710_migrate_jira_to_gem.rb
+++ /dev/null
@@ -1,73 +0,0 @@
-class MigrateJiraToGem < ActiveRecord::Migration[4.2]
- DOWNTIME = true
-
- DOWNTIME_REASON = <<-HEREDOC
- Refactor all Jira services properties(serialized field) to use new jira-ruby gem.
- There were properties on old Jira service that are not needed anymore after the
- service refactoring: api_url, project_url, new_issue_url, issues_url.
- We extract the new necessary some properties from old keys and delete them:
- taking project_key from project_url and url from api_url
- HEREDOC
-
- def up
- active_services_query = "SELECT id, properties FROM services WHERE services.type IN ('JiraService') AND services.active = true"
-
- select_all(active_services_query).each do |service|
- id = service['id']
- properties = JSON.parse(service['properties'])
- properties_was = properties.clone
-
- # Migrate `project_url` to `project_key`
- # Ignore if `project_url` doesn't have jql project query with project key
- if properties['project_url'].present?
- jql = properties['project_url'].match('project=([A-Za-z]*)')
- properties['project_key'] = jql.captures.first if jql
- end
-
- # Migrate `api_url` to `url`
- if properties['api_url'].present?
- url = properties['api_url'].match('(.*)\/rest\/api')
- properties['url'] = url.captures.first if url
- end
-
- # Delete now unnecessary properties
- properties.delete('api_url')
- properties.delete('project_url')
- properties.delete('new_issue_url')
- properties.delete('issues_url')
-
- # Update changes properties
- if properties != properties_was
- execute("UPDATE services SET properties = '#{quote_string(properties.to_json)}' WHERE id = #{id}")
- end
- end
- end
-
- def down
- active_services_query = "SELECT id, properties FROM services WHERE services.type IN ('JiraService') AND services.active = true"
-
- select_all(active_services_query).each do |service|
- id = service['id']
- properties = JSON.parse(service['properties'])
- properties_was = properties.clone
-
- # Rebuild old properties based on sane defaults
- if properties['url'].present?
- properties['api_url'] = "#{properties['url']}/rest/api/2"
- properties['project_url'] =
- "#{properties['url']}/issues/?jql=project=#{properties['project_key']}"
- properties['issues_url'] = "#{properties['url']}/browse/:id"
- properties['new_issue_url'] = "#{properties['url']}/secure/CreateIssue.jspa"
- end
-
- # Delete the new properties
- properties.delete('url')
- properties.delete('project_key')
-
- # Update changes properties
- if properties != properties_was
- execute("UPDATE services SET properties = '#{quote_string(properties.to_json)}' WHERE id = #{id}")
- end
- end
- end
-end
diff --git a/db/migrate/20161031155516_add_housekeeping_to_application_settings.rb b/db/migrate/20161031155516_add_housekeeping_to_application_settings.rb
deleted file mode 100644
index 963358fe3e5..00000000000
--- a/db/migrate/20161031155516_add_housekeeping_to_application_settings.rb
+++ /dev/null
@@ -1,32 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class AddHousekeepingToApplicationSettings < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- # When a migration requires downtime you **must** uncomment the following
- # constant and define a short and easy to understand explanation as to why the
- # migration requires downtime.
- # DOWNTIME_REASON = ''
-
- disable_ddl_transaction!
-
- def up
- add_column_with_default(:application_settings, :housekeeping_enabled, :boolean, default: true, allow_null: false)
- add_column_with_default(:application_settings, :housekeeping_bitmaps_enabled, :boolean, default: true, allow_null: false)
- add_column_with_default(:application_settings, :housekeeping_incremental_repack_period, :integer, default: 10, allow_null: false)
- add_column_with_default(:application_settings, :housekeeping_full_repack_period, :integer, default: 50, allow_null: false)
- add_column_with_default(:application_settings, :housekeeping_gc_period, :integer, default: 200, allow_null: false)
- end
-
- def down
- remove_column(:application_settings, :housekeeping_enabled, :boolean, default: true, allow_null: false)
- remove_column(:application_settings, :housekeeping_bitmaps_enabled, :boolean, default: true, allow_null: false)
- remove_column(:application_settings, :housekeeping_incremental_repack_period, :integer, default: 10, allow_null: false)
- remove_column(:application_settings, :housekeeping_full_repack_period, :integer, default: 50, allow_null: false)
- remove_column(:application_settings, :housekeeping_gc_period, :integer, default: 200, allow_null: false)
- end
-end
diff --git a/db/migrate/20161031171301_add_project_id_to_subscriptions.rb b/db/migrate/20161031171301_add_project_id_to_subscriptions.rb
deleted file mode 100644
index 5fd10d9b359..00000000000
--- a/db/migrate/20161031171301_add_project_id_to_subscriptions.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-class AddProjectIdToSubscriptions < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def up
- add_column :subscriptions, :project_id, :integer
- add_foreign_key :subscriptions, :projects, column: :project_id, on_delete: :cascade # rubocop: disable Migration/AddConcurrentForeignKey
- end
-
- def down
- remove_foreign_key :subscriptions, column: :project_id
- remove_column :subscriptions, :project_id
- end
-end
diff --git a/db/migrate/20161031174110_migrate_subscriptions_project_id.rb b/db/migrate/20161031174110_migrate_subscriptions_project_id.rb
deleted file mode 100644
index 7f4087fdcd3..00000000000
--- a/db/migrate/20161031174110_migrate_subscriptions_project_id.rb
+++ /dev/null
@@ -1,44 +0,0 @@
-class MigrateSubscriptionsProjectId < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = true
- DOWNTIME_REASON = 'Subscriptions will not work as expected until this migration is complete.'
-
- def up
- execute <<-EOF.strip_heredoc
- UPDATE subscriptions
- SET project_id = (
- SELECT issues.project_id
- FROM issues
- WHERE issues.id = subscriptions.subscribable_id
- )
- WHERE subscriptions.subscribable_type = 'Issue';
- EOF
-
- execute <<-EOF.strip_heredoc
- UPDATE subscriptions
- SET project_id = (
- SELECT merge_requests.target_project_id
- FROM merge_requests
- WHERE merge_requests.id = subscriptions.subscribable_id
- )
- WHERE subscriptions.subscribable_type = 'MergeRequest';
- EOF
-
- execute <<-EOF.strip_heredoc
- UPDATE subscriptions
- SET project_id = (
- SELECT projects.id
- FROM labels INNER JOIN projects ON projects.id = labels.project_id
- WHERE labels.id = subscriptions.subscribable_id
- )
- WHERE subscriptions.subscribable_type = 'Label';
- EOF
- end
-
- def down
- execute <<-EOF.strip_heredoc
- UPDATE subscriptions SET project_id = NULL;
- EOF
- end
-end
diff --git a/db/migrate/20161031181638_add_unique_index_to_subscriptions.rb b/db/migrate/20161031181638_add_unique_index_to_subscriptions.rb
deleted file mode 100644
index 9005b42b41f..00000000000
--- a/db/migrate/20161031181638_add_unique_index_to_subscriptions.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-# rubocop:disable RemoveIndex
-class AddUniqueIndexToSubscriptions < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = true
- DOWNTIME_REASON = 'This migration requires downtime because it changes a column to not accept null values.'
-
- disable_ddl_transaction!
-
- def up
- add_concurrent_index :subscriptions, [:subscribable_id, :subscribable_type, :user_id, :project_id], { unique: true, name: 'index_subscriptions_on_subscribable_and_user_id_and_project_id' }
- remove_index :subscriptions, name: 'subscriptions_user_id_and_ref_fields' if index_name_exists?(:subscriptions, 'subscriptions_user_id_and_ref_fields')
- end
-
- def down
- add_concurrent_index :subscriptions, [:subscribable_id, :subscribable_type, :user_id], { unique: true, name: 'subscriptions_user_id_and_ref_fields' }
- remove_index :subscriptions, name: 'index_subscriptions_on_subscribable_and_user_id_and_project_id' if index_name_exists?(:subscriptions, 'index_subscriptions_on_subscribable_and_user_id_and_project_id')
- end
-end
diff --git a/db/migrate/20161103171205_rename_repository_storage_column.rb b/db/migrate/20161103171205_rename_repository_storage_column.rb
deleted file mode 100644
index d6050500e47..00000000000
--- a/db/migrate/20161103171205_rename_repository_storage_column.rb
+++ /dev/null
@@ -1,29 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class RenameRepositoryStorageColumn < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = true
-
- # When a migration requires downtime you **must** uncomment the following
- # constant and define a short and easy to understand explanation as to why the
- # migration requires downtime.
- DOWNTIME_REASON = 'Renaming the application_settings.repository_storage column'
-
- # When using the methods "add_concurrent_index" or "add_column_with_default"
- # you must disable the use of transactions as these methods can not run in an
- # existing transaction. When using "add_concurrent_index" make sure that this
- # method is the _only_ method called in the migration, any other changes
- # should go in a separate migration. This ensures that upon failure _only_ the
- # index creation fails and can be retried or reverted easily.
- #
- # To disable transactions uncomment the following line and remove these
- # comments:
- # disable_ddl_transaction!
-
- def change
- rename_column :application_settings, :repository_storage, :repository_storages
- end
-end
diff --git a/db/migrate/20161103191444_add_sidekiq_throttling_to_application_settings.rb b/db/migrate/20161103191444_add_sidekiq_throttling_to_application_settings.rb
deleted file mode 100644
index 83c51c83509..00000000000
--- a/db/migrate/20161103191444_add_sidekiq_throttling_to_application_settings.rb
+++ /dev/null
@@ -1,32 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-# rubocop:disable Migration/SaferBooleanColumn
-class AddSidekiqThrottlingToApplicationSettings < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- # When a migration requires downtime you **must** uncomment the following
- # constant and define a short and easy to understand explanation as to why the
- # migration requires downtime.
- # DOWNTIME_REASON = ''
-
- # When using the methods "add_concurrent_index" or "add_column_with_default"
- # you must disable the use of transactions as these methods can not run in an
- # existing transaction. When using "add_concurrent_index" make sure that this
- # method is the _only_ method called in the migration, any other changes
- # should go in a separate migration. This ensures that upon failure _only_ the
- # index creation fails and can be retried or reverted easily.
- #
- # To disable transactions uncomment the following line and remove these
- # comments:
- # disable_ddl_transaction!
-
- def change
- add_column :application_settings, :sidekiq_throttling_enabled, :boolean, default: false
- add_column :application_settings, :sidekiq_throttling_queues, :string
- add_column :application_settings, :sidekiq_throttling_factor, :decimal
- end
-end
diff --git a/db/migrate/20161106185620_add_project_import_data_project_index.rb b/db/migrate/20161106185620_add_project_import_data_project_index.rb
deleted file mode 100644
index 46809ca1707..00000000000
--- a/db/migrate/20161106185620_add_project_import_data_project_index.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-# rubocop:disable RemoveIndex
-class AddProjectImportDataProjectIndex < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- add_concurrent_index :project_import_data, :project_id
- end
-
- def down
- remove_index :project_import_data, :project_id if index_exists? :project_import_data, :project_id
- end
-end
diff --git a/db/migrate/20161113184239_create_user_chat_names_table.rb b/db/migrate/20161113184239_create_user_chat_names_table.rb
deleted file mode 100644
index 0031ca66afe..00000000000
--- a/db/migrate/20161113184239_create_user_chat_names_table.rb
+++ /dev/null
@@ -1,22 +0,0 @@
-# rubocop:disable Migration/Timestamps
-class CreateUserChatNamesTable < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def change
- create_table :chat_names do |t|
- t.integer :user_id, null: false
- t.integer :service_id, null: false
- t.string :team_id, null: false
- t.string :team_domain
- t.string :chat_id, null: false
- t.string :chat_name
- t.datetime :last_used_at
- t.timestamps null: false
- end
-
- add_index :chat_names, [:user_id, :service_id], unique: true
- add_index :chat_names, [:service_id, :team_id, :chat_id], unique: true
- end
-end
diff --git a/db/migrate/20161114024742_add_coverage_regex_to_builds.rb b/db/migrate/20161114024742_add_coverage_regex_to_builds.rb
deleted file mode 100644
index 631968b4aee..00000000000
--- a/db/migrate/20161114024742_add_coverage_regex_to_builds.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class AddCoverageRegexToBuilds < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- def change
- add_column :ci_builds, :coverage_regex, :string
- end
-end
diff --git a/db/migrate/20161115173905_add_start_date_to_milestones.rb b/db/migrate/20161115173905_add_start_date_to_milestones.rb
deleted file mode 100644
index 847c4f0bebb..00000000000
--- a/db/migrate/20161115173905_add_start_date_to_milestones.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class AddStartDateToMilestones < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def change
- add_column :milestones, :start_date, :date
- end
-end
diff --git a/db/migrate/20161118183841_add_commit_events_to_services.rb b/db/migrate/20161118183841_add_commit_events_to_services.rb
deleted file mode 100644
index 0eb08915118..00000000000
--- a/db/migrate/20161118183841_add_commit_events_to_services.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-class AddCommitEventsToServices < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- add_column_with_default(:services, :commit_events, :boolean, default: true, allow_null: false)
- end
-
- def down
- remove_column(:services, :commit_events)
- end
-end
diff --git a/db/migrate/20161124111390_add_parent_id_to_namespace.rb b/db/migrate/20161124111390_add_parent_id_to_namespace.rb
deleted file mode 100644
index 67f6aee2b9c..00000000000
--- a/db/migrate/20161124111390_add_parent_id_to_namespace.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class AddParentIdToNamespace < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def change
- add_column(:namespaces, :parent_id, :integer)
- end
-end
diff --git a/db/migrate/20161124111395_add_index_to_parent_id.rb b/db/migrate/20161124111395_add_index_to_parent_id.rb
deleted file mode 100644
index d7a51ec905a..00000000000
--- a/db/migrate/20161124111395_add_index_to_parent_id.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-# rubocop:disable RemoveIndex
-class AddIndexToParentId < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- add_concurrent_index(:namespaces, [:parent_id, :id], unique: true)
- end
-
- def down
- remove_index :namespaces, [:parent_id, :id] if index_exists? :namespaces, [:parent_id, :id]
- end
-end
diff --git a/db/migrate/20161124111402_add_routes_table.rb b/db/migrate/20161124111402_add_routes_table.rb
deleted file mode 100644
index 36f49ef8c97..00000000000
--- a/db/migrate/20161124111402_add_routes_table.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-# rubocop:disable Migration/Timestamps
-class AddRoutesTable < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def change
- create_table :routes do |t|
- t.integer :source_id, null: false
- t.string :source_type, null: false
- t.string :path, null: false
-
- t.timestamps
- end
- end
-end
diff --git a/db/migrate/20161124141322_migrate_process_commit_worker_jobs.rb b/db/migrate/20161124141322_migrate_process_commit_worker_jobs.rb
deleted file mode 100644
index 0772821210c..00000000000
--- a/db/migrate/20161124141322_migrate_process_commit_worker_jobs.rb
+++ /dev/null
@@ -1,105 +0,0 @@
-class MigrateProcessCommitWorkerJobs < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- class Repository
- attr_reader :storage
-
- def initialize(storage, relative_path)
- @storage = storage
- @relative_path = relative_path
- end
-
- def gitaly_repository
- Gitaly::Repository.new(storage_name: @storage, relative_path: @relative_path)
- end
- end
-
- class Project < ActiveRecord::Base
- def self.find_including_path(id)
- select("projects.*, CONCAT(namespaces.path, '/', projects.path) AS path_with_namespace")
- .joins('INNER JOIN namespaces ON namespaces.id = projects.namespace_id')
- .find_by(id: id)
- end
-
- def commit(rev)
- Gitlab::GitalyClient::CommitService.new(repository).find_commit(rev)
- end
-
- def repository
- @repository ||= Repository.new(repository_storage, read_attribute(:path_with_namespace) + '.git')
- end
- end
-
- DOWNTIME = true
- DOWNTIME_REASON = 'Existing workers will error until they are using a newer version of the code'
-
- disable_ddl_transaction!
-
- def up
- Sidekiq.redis do |redis|
- new_jobs = []
-
- while job = redis.lpop('queue:process_commit')
- payload = JSON.parse(job)
- project = Project.find_including_path(payload['args'][0])
-
- next unless project
-
- commit = project.commit(payload['args'][2])
- next unless commit
-
- hash = {
- id: commit.id,
- message: encode(commit.body),
- parent_ids: commit.parent_ids.to_a,
- authored_date: Time.at(commit.author.date.seconds).utc,
- author_name: encode(commit.author.name),
- author_email: encode(commit.author.email),
- committed_date: Time.at(commit.committer.date.seconds).utc,
- committer_email: encode(commit.committer.email),
- committer_name: encode(commit.committer.name)
- }
-
- payload['args'][2] = hash
-
- new_jobs << JSON.dump(payload)
- end
-
- redis.multi do |multi|
- new_jobs.each do |j|
- multi.lpush('queue:process_commit', j)
- end
- end
- end
- end
-
- def down
- Sidekiq.redis do |redis|
- new_jobs = []
-
- while job = redis.lpop('queue:process_commit')
- payload = JSON.parse(job)
-
- payload['args'][2] = payload['args'][2]['id']
-
- new_jobs << JSON.dump(payload)
- end
-
- redis.multi do |multi|
- new_jobs.each do |j|
- multi.lpush('queue:process_commit', j)
- end
- end
- end
- end
-
- def encode(data)
- encoding = Encoding::UTF_8
-
- if data.encoding == encoding
- data
- else
- data.encode(encoding, invalid: :replace, undef: :replace)
- end
- end
-end
diff --git a/db/migrate/20161128095517_add_in_reply_to_discussion_id_to_sent_notifications.rb b/db/migrate/20161128095517_add_in_reply_to_discussion_id_to_sent_notifications.rb
deleted file mode 100644
index a2971486014..00000000000
--- a/db/migrate/20161128095517_add_in_reply_to_discussion_id_to_sent_notifications.rb
+++ /dev/null
@@ -1,29 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class AddInReplyToDiscussionIdToSentNotifications < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- # When a migration requires downtime you **must** uncomment the following
- # constant and define a short and easy to understand explanation as to why the
- # migration requires downtime.
- # DOWNTIME_REASON = ''
-
- # When using the methods "add_concurrent_index" or "add_column_with_default"
- # you must disable the use of transactions as these methods can not run in an
- # existing transaction. When using "add_concurrent_index" make sure that this
- # method is the _only_ method called in the migration, any other changes
- # should go in a separate migration. This ensures that upon failure _only_ the
- # index creation fails and can be retried or reverted easily.
- #
- # To disable transactions uncomment the following line and remove these
- # comments:
- # disable_ddl_transaction!
-
- def change
- add_column :sent_notifications, :in_reply_to_discussion_id, :string
- end
-end
diff --git a/db/migrate/20161128142110_remove_unnecessary_indexes.rb b/db/migrate/20161128142110_remove_unnecessary_indexes.rb
deleted file mode 100644
index b6c6e303ec7..00000000000
--- a/db/migrate/20161128142110_remove_unnecessary_indexes.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-# rubocop:disable RemoveIndex
-class RemoveUnnecessaryIndexes < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
- disable_ddl_transaction!
-
- DOWNTIME = false
-
- def up
- remove_index :labels, column: :group_id if index_exists?(:labels, :group_id)
- remove_index :award_emoji, column: :user_id if index_exists?(:award_emoji, :user_id)
- remove_index :ci_builds, column: :commit_id if index_exists?(:ci_builds, :commit_id)
- remove_index :deployments, column: :project_id if index_exists?(:deployments, :project_id)
- remove_index :deployments, column: %w(project_id environment_id) if index_exists?(:deployments, %w(project_id environment_id))
- remove_index :lists, column: :board_id if index_exists?(:lists, :board_id)
- remove_index :milestones, column: :project_id if index_exists?(:milestones, :project_id)
- remove_index :notes, column: :project_id if index_exists?(:notes, :project_id)
- remove_index :users_star_projects, column: :user_id if index_exists?(:users_star_projects, :user_id)
- end
-
- def down
- add_concurrent_index :labels, :group_id
- add_concurrent_index :award_emoji, :user_id
- add_concurrent_index :ci_builds, :commit_id
- add_concurrent_index :deployments, :project_id
- add_concurrent_index :deployments, %w(project_id environment_id)
- add_concurrent_index :lists, :board_id
- add_concurrent_index :milestones, :project_id
- add_concurrent_index :notes, :project_id
- add_concurrent_index :users_star_projects, :user_id
- end
-end
diff --git a/db/migrate/20161128161412_add_html_emails_enabled_to_application_settings.rb b/db/migrate/20161128161412_add_html_emails_enabled_to_application_settings.rb
deleted file mode 100644
index 63139eb97bd..00000000000
--- a/db/migrate/20161128161412_add_html_emails_enabled_to_application_settings.rb
+++ /dev/null
@@ -1,30 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-# rubocop:disable Migration/SaferBooleanColumn
-class AddHtmlEmailsEnabledToApplicationSettings < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- # When a migration requires downtime you **must** uncomment the following
- # constant and define a short and easy to understand explanation as to why the
- # migration requires downtime.
- # DOWNTIME_REASON = ''
-
- # When using the methods "add_concurrent_index" or "add_column_with_default"
- # you must disable the use of transactions as these methods can not run in an
- # existing transaction. When using "add_concurrent_index" make sure that this
- # method is the _only_ method called in the migration, any other changes
- # should go in a separate migration. This ensures that upon failure _only_ the
- # index creation fails and can be retried or reverted easily.
- #
- # To disable transactions uncomment the following line and remove these
- # comments:
- # disable_ddl_transaction!
-
- def change
- add_column :application_settings, :html_emails_enabled, :boolean, default: true
- end
-end
diff --git a/db/migrate/20161130095245_fill_routes_table.rb b/db/migrate/20161130095245_fill_routes_table.rb
deleted file mode 100644
index 712be187c7c..00000000000
--- a/db/migrate/20161130095245_fill_routes_table.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class FillRoutesTable < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = true
- DOWNTIME_REASON = 'No new namespaces should be created during data copy'
-
- def up
- execute <<-EOF
- INSERT INTO routes
- (source_id, source_type, path)
- (SELECT id, 'Namespace', path FROM namespaces)
- EOF
- end
-
- def down
- execute("DELETE FROM routes WHERE source_type = 'Namespace'")
- end
-end
diff --git a/db/migrate/20161130101252_fill_projects_routes_table.rb b/db/migrate/20161130101252_fill_projects_routes_table.rb
deleted file mode 100644
index 1900d6c8013..00000000000
--- a/db/migrate/20161130101252_fill_projects_routes_table.rb
+++ /dev/null
@@ -1,30 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class FillProjectsRoutesTable < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = true
- DOWNTIME_REASON = 'No new projects should be created during data copy'
-
- def up
- if Gitlab::Database.postgresql?
- execute <<-EOF
- INSERT INTO routes (source_id, source_type, path)
- (SELECT DISTINCT ON (namespaces.path, projects.path) projects.id, 'Project', concat(namespaces.path, '/', projects.path)
- FROM projects INNER JOIN namespaces ON projects.namespace_id = namespaces.id
- ORDER BY namespaces.path, projects.path, projects.id DESC)
- EOF
- else
- execute <<-EOF
- INSERT INTO routes (source_id, source_type, path)
- (SELECT projects.id, 'Project', concat(namespaces.path, '/', projects.path)
- FROM projects INNER JOIN namespaces ON projects.namespace_id = namespaces.id)
- EOF
- end
- end
-
- def down
- execute("DELETE FROM routes WHERE source_type = 'Project'")
- end
-end
diff --git a/db/migrate/20161201001911_add_plant_uml_url_to_application_settings.rb b/db/migrate/20161201001911_add_plant_uml_url_to_application_settings.rb
deleted file mode 100644
index 79558a6b3b9..00000000000
--- a/db/migrate/20161201001911_add_plant_uml_url_to_application_settings.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class AddPlantUmlUrlToApplicationSettings < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def change
- add_column :application_settings, :plantuml_url, :string
- end
-end
diff --git a/db/migrate/20161201155511_create_project_statistics.rb b/db/migrate/20161201155511_create_project_statistics.rb
deleted file mode 100644
index 6dcb5adb82b..00000000000
--- a/db/migrate/20161201155511_create_project_statistics.rb
+++ /dev/null
@@ -1,20 +0,0 @@
-class CreateProjectStatistics < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def change
- # use bigint columns to support values >2GB
- counter_column = { limit: 8, null: false, default: 0 }
-
- create_table :project_statistics do |t|
- t.references :project, null: false, index: { unique: true }, foreign_key: { on_delete: :cascade }
- t.references :namespace, null: false, index: true
- t.integer :commit_count, counter_column
- t.integer :storage_size, counter_column
- t.integer :repository_size, counter_column
- t.integer :lfs_objects_size, counter_column
- t.integer :build_artifacts_size, counter_column
- end
- end
-end
diff --git a/db/migrate/20161201160452_migrate_project_statistics.rb b/db/migrate/20161201160452_migrate_project_statistics.rb
deleted file mode 100644
index 42c5be07e83..00000000000
--- a/db/migrate/20161201160452_migrate_project_statistics.rb
+++ /dev/null
@@ -1,25 +0,0 @@
-# rubocop:disable Migration/RemoveColumn
-class MigrateProjectStatistics < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = true
- DOWNTIME_REASON = 'Removes two columns from the projects table'
-
- def up
- # convert repository_size in float (megabytes) to integer (bytes),
- # initialize total storage_size with repository_size
- execute <<-EOF
- INSERT INTO project_statistics (project_id, namespace_id, commit_count, storage_size, repository_size)
- SELECT id, namespace_id, commit_count, (repository_size * 1024 * 1024), (repository_size * 1024 * 1024) FROM projects
- EOF
-
- remove_column :projects, :repository_size
- remove_column :projects, :commit_count
- end
-
- # rubocop: disable Migration/AddColumn
- def down
- add_column :projects, :repository_size, :float, default: 0.0
- add_column :projects, :commit_count, :integer, default: 0
- end
-end
diff --git a/db/migrate/20161202152031_remove_duplicates_from_routes.rb b/db/migrate/20161202152031_remove_duplicates_from_routes.rb
deleted file mode 100644
index 0615f683859..00000000000
--- a/db/migrate/20161202152031_remove_duplicates_from_routes.rb
+++ /dev/null
@@ -1,29 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class RemoveDuplicatesFromRoutes < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def up
- # We can skip this migration when running a PostgreSQL database because
- # we use an optimized query in the "FillProjectsRoutesTable" migration
- # to fill these values that avoid duplicate entries in the routes table.
- return unless Gitlab::Database.mysql?
-
- execute <<-EOF
- DELETE duplicated_rows.*
- FROM routes AS duplicated_rows
- INNER JOIN (
- SELECT path, MAX(id) as max_id
- FROM routes
- GROUP BY path
- HAVING COUNT(*) > 1
- ) AS good_rows ON good_rows.path = duplicated_rows.path AND good_rows.max_id <> duplicated_rows.id;
- EOF
- end
-
- def down
- end
-end
diff --git a/db/migrate/20161202152035_add_index_to_routes.rb b/db/migrate/20161202152035_add_index_to_routes.rb
deleted file mode 100644
index ad2e0cd13c9..00000000000
--- a/db/migrate/20161202152035_add_index_to_routes.rb
+++ /dev/null
@@ -1,22 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-# rubocop:disable RemoveIndex
-class AddIndexToRoutes < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- add_concurrent_index(:routes, :path, unique: true)
- add_concurrent_index(:routes, [:source_type, :source_id], unique: true)
- end
-
- def down
- remove_index(:routes, :path) if index_exists? :routes, :path
- remove_index(:routes, [:source_type, :source_id]) if index_exists? :routes, [:source_type, :source_id]
- end
-end
diff --git a/db/migrate/20161206003819_add_plant_uml_enabled_to_application_settings.rb b/db/migrate/20161206003819_add_plant_uml_enabled_to_application_settings.rb
deleted file mode 100644
index bb44d56ee56..00000000000
--- a/db/migrate/20161206003819_add_plant_uml_enabled_to_application_settings.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-# rubocop:disable Migration/SaferBooleanColumn
-class AddPlantUmlEnabledToApplicationSettings < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def change
- add_column :application_settings, :plantuml_enabled, :boolean
- end
-end
diff --git a/db/migrate/20161206153749_remove_uniq_path_index_from_namespace.rb b/db/migrate/20161206153749_remove_uniq_path_index_from_namespace.rb
deleted file mode 100644
index c301d76646e..00000000000
--- a/db/migrate/20161206153749_remove_uniq_path_index_from_namespace.rb
+++ /dev/null
@@ -1,37 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-# rubocop:disable RemoveIndex
-class RemoveUniqPathIndexFromNamespace < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- disable_ddl_transaction!
-
- DOWNTIME = false
-
- def up
- constraint_name = 'namespaces_path_key'
-
- transaction do
- if index_exists?(:namespaces, :path)
- remove_index(:namespaces, :path)
- end
-
- # In some bizarre cases PostgreSQL might have a separate unique constraint
- # that we'll need to drop.
- if constraint_exists?(constraint_name) && Gitlab::Database.postgresql?
- execute("ALTER TABLE namespaces DROP CONSTRAINT IF EXISTS #{constraint_name};")
- end
- end
- end
-
- def down
- unless index_exists?(:namespaces, :path)
- add_concurrent_index(:namespaces, :path, unique: true)
- end
- end
-
- def constraint_exists?(name)
- indexes(:namespaces).map(&:name).include?(name)
- end
-end
diff --git a/db/migrate/20161206153751_add_path_index_to_namespace.rb b/db/migrate/20161206153751_add_path_index_to_namespace.rb
deleted file mode 100644
index f0848cc59a5..00000000000
--- a/db/migrate/20161206153751_add_path_index_to_namespace.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-# rubocop:disable RemoveIndex
-class AddPathIndexToNamespace < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- disable_ddl_transaction!
-
- DOWNTIME = false
-
- def up
- add_concurrent_index :namespaces, :path
- end
-
- def down
- if index_exists?(:namespaces, :path)
- remove_index :namespaces, :path
- end
- end
-end
diff --git a/db/migrate/20161206153753_remove_uniq_name_index_from_namespace.rb b/db/migrate/20161206153753_remove_uniq_name_index_from_namespace.rb
deleted file mode 100644
index 13660cec7aa..00000000000
--- a/db/migrate/20161206153753_remove_uniq_name_index_from_namespace.rb
+++ /dev/null
@@ -1,37 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-# rubocop:disable RemoveIndex
-class RemoveUniqNameIndexFromNamespace < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- disable_ddl_transaction!
-
- DOWNTIME = false
-
- def up
- constraint_name = 'namespaces_name_key'
-
- transaction do
- if index_exists?(:namespaces, :name)
- remove_index(:namespaces, :name)
- end
-
- # In some bizarre cases PostgreSQL might have a separate unique constraint
- # that we'll need to drop.
- if constraint_exists?(constraint_name) && Gitlab::Database.postgresql?
- execute("ALTER TABLE namespaces DROP CONSTRAINT IF EXISTS #{constraint_name};")
- end
- end
- end
-
- def down
- unless index_exists?(:namespaces, :name)
- add_concurrent_index(:namespaces, :name, unique: true)
- end
- end
-
- def constraint_exists?(name)
- indexes(:namespaces).map(&:name).include?(name)
- end
-end
diff --git a/db/migrate/20161206153754_add_name_index_to_namespace.rb b/db/migrate/20161206153754_add_name_index_to_namespace.rb
deleted file mode 100644
index 14152a6dc07..00000000000
--- a/db/migrate/20161206153754_add_name_index_to_namespace.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-# rubocop:disable RemoveIndex
-class AddNameIndexToNamespace < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- disable_ddl_transaction!
-
- DOWNTIME = false
-
- def up
- add_concurrent_index(:namespaces, [:name, :parent_id], unique: true)
- end
-
- def down
- if index_exists?(:namespaces, [:name, :parent_id])
- remove_index :namespaces, [:name, :parent_id]
- end
- end
-end
diff --git a/db/migrate/20161207231620_fixup_environment_name_uniqueness.rb b/db/migrate/20161207231620_fixup_environment_name_uniqueness.rb
deleted file mode 100644
index 420f0ccb45c..00000000000
--- a/db/migrate/20161207231620_fixup_environment_name_uniqueness.rb
+++ /dev/null
@@ -1,53 +0,0 @@
-class FixupEnvironmentNameUniqueness < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = true
- DOWNTIME_REASON = 'Renaming non-unique environments'
-
- def up
- environments = Arel::Table.new(:environments)
-
- # Get all [project_id, name] pairs that occur more than once
- finder_sql = environments
- .group(environments[:project_id], environments[:name])
- .having(Arel.sql("COUNT(1)").gt(1))
- .project(environments[:project_id], environments[:name])
- .to_sql
-
- conflicting = connection.exec_query(finder_sql)
-
- conflicting.rows.each do |project_id, name|
- fix_duplicates(project_id, name)
- end
- end
-
- def down
- # Nothing to do
- end
-
- # Rename conflicting environments by appending "-#{id}" to all but the first
- def fix_duplicates(project_id, name)
- environments = Arel::Table.new(:environments)
- finder_sql = environments
- .where(environments[:project_id].eq(project_id))
- .where(environments[:name].eq(name))
- .order(environments[:id].asc)
- .project(environments[:id], environments[:name])
- .to_sql
-
- # Now we have the data for all the conflicting rows
- conflicts = connection.exec_query(finder_sql).rows
- conflicts.shift # Leave the first row alone
-
- conflicts.each do |id, name|
- update_sql =
- Arel::UpdateManager.new
- .table(environments)
- .set(environments[:name] => name + "-" + id.to_s)
- .where(environments[:id].eq(id))
- .to_sql
-
- connection.exec_update(update_sql, self.class.name, [])
- end
- end
-end
diff --git a/db/migrate/20161207231621_create_environment_name_unique_index.rb b/db/migrate/20161207231621_create_environment_name_unique_index.rb
deleted file mode 100644
index 28d22664405..00000000000
--- a/db/migrate/20161207231621_create_environment_name_unique_index.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-# rubocop:disable RemoveIndex
-class CreateEnvironmentNameUniqueIndex < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- disable_ddl_transaction!
-
- DOWNTIME = true
- DOWNTIME_REASON = 'Making a non-unique index into a unique index'
-
- def up
- remove_index :environments, [:project_id, :name]
- add_concurrent_index :environments, [:project_id, :name], unique: true
- end
-
- def down
- remove_index :environments, [:project_id, :name]
- add_concurrent_index :environments, [:project_id, :name], unique: true
- end
-end
diff --git a/db/migrate/20161207231626_add_environment_slug.rb b/db/migrate/20161207231626_add_environment_slug.rb
deleted file mode 100644
index 993b9bd3330..00000000000
--- a/db/migrate/20161207231626_add_environment_slug.rb
+++ /dev/null
@@ -1,68 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class AddEnvironmentSlug < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = true
- DOWNTIME_REASON = 'Adding NOT NULL column environments.slug with dependent data'
-
- # Used to generate random suffixes for the slug
- LETTERS = 'a'..'z'
- NUMBERS = '0'..'9'
- SUFFIX_CHARS = LETTERS.to_a + NUMBERS.to_a
-
- def up
- environments = Arel::Table.new(:environments)
-
- add_column :environments, :slug, :string
- finder = environments.project(:id, :name)
-
- connection.exec_query(finder.to_sql).rows.each do |id, name|
- updater = Arel::UpdateManager.new
- .table(environments)
- .set(environments[:slug] => generate_slug(name))
- .where(environments[:id].eq(id))
-
- connection.exec_update(updater.to_sql, self.class.name, [])
- end
-
- change_column_null :environments, :slug, false
- end
-
- def down
- remove_column :environments, :slug
- end
-
- # Copy of the Environment#generate_slug implementation
- def generate_slug(name)
- # Lowercase letters and numbers only
- slugified = name.to_s.downcase.gsub(/[^a-z0-9]/, '-')
-
- # Must start with a letter
- slugified = 'env-' + slugified unless LETTERS.cover?(slugified[0])
-
- # Repeated dashes are invalid (OpenShift limitation)
- slugified.gsub!(/\-+/, '-')
-
- # Maximum length: 24 characters (OpenShift limitation)
- slugified = slugified[0..23]
-
- # Cannot end with a dash (Kubernetes label limitation)
- slugified.chop! if slugified.end_with?('-')
-
- # Add a random suffix, shortening the current string if necessary, if it
- # has been slugified. This ensures uniqueness.
- if slugified != name
- slugified = slugified[0..16]
- slugified << '-' unless slugified.end_with?('-')
- slugified << random_suffix
- end
-
- slugified
- end
-
- def random_suffix
- (0..5).map { SUFFIX_CHARS.sample }.join
- end
-end
diff --git a/db/migrate/20161209153400_add_unique_index_for_environment_slug.rb b/db/migrate/20161209153400_add_unique_index_for_environment_slug.rb
deleted file mode 100644
index 57606a33cb9..00000000000
--- a/db/migrate/20161209153400_add_unique_index_for_environment_slug.rb
+++ /dev/null
@@ -1,20 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-# rubocop:disable RemoveIndex
-class AddUniqueIndexForEnvironmentSlug < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = true
- DOWNTIME_REASON = 'Adding a *unique* index to environments.slug'
-
- disable_ddl_transaction!
-
- def up
- add_concurrent_index :environments, [:project_id, :slug], unique: true
- end
-
- def down
- remove_index :environments, [:project_id, :slug] if index_exists? :environments, [:project_id, :slug]
- end
-end
diff --git a/db/migrate/20161209165216_create_doorkeeper_openid_connect_tables.rb b/db/migrate/20161209165216_create_doorkeeper_openid_connect_tables.rb
deleted file mode 100644
index e8ea9cf8fda..00000000000
--- a/db/migrate/20161209165216_create_doorkeeper_openid_connect_tables.rb
+++ /dev/null
@@ -1,37 +0,0 @@
-class CreateDoorkeeperOpenidConnectTables < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- create_table :oauth_openid_requests do |t|
- t.integer :access_grant_id, null: false
- t.string :nonce, null: false
- end
-
- if Gitlab::Database.postgresql?
- # add foreign key without validation to avoid downtime on PostgreSQL,
- # also see db/post_migrate/20170209140523_validate_foreign_keys_on_oauth_openid_requests.rb
- execute %q{
- ALTER TABLE "oauth_openid_requests"
- ADD CONSTRAINT "fk_oauth_openid_requests_oauth_access_grants_access_grant_id"
- FOREIGN KEY ("access_grant_id")
- REFERENCES "oauth_access_grants" ("id")
- NOT VALID;
- }
- else
- execute %q{
- ALTER TABLE oauth_openid_requests
- ADD CONSTRAINT fk_oauth_openid_requests_oauth_access_grants_access_grant_id
- FOREIGN KEY (access_grant_id)
- REFERENCES oauth_access_grants (id);
- }
- end
- end
-
- def down
- drop_table :oauth_openid_requests
- end
-end
diff --git a/db/migrate/20161212142807_add_lower_path_index_to_routes.rb b/db/migrate/20161212142807_add_lower_path_index_to_routes.rb
deleted file mode 100644
index 92a12dbc699..00000000000
--- a/db/migrate/20161212142807_add_lower_path_index_to_routes.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-# rubocop:disable RemoveIndex
-class AddLowerPathIndexToRoutes < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- return unless Gitlab::Database.postgresql?
-
- execute 'CREATE INDEX CONCURRENTLY index_on_routes_lower_path ON routes (LOWER(path));'
- end
-
- def down
- return unless Gitlab::Database.postgresql?
-
- remove_index :routes, name: :index_on_routes_lower_path if index_exists?(:routes, name: :index_on_routes_lower_path)
- end
-end
diff --git a/db/migrate/20161213172958_change_slack_service_to_slack_notification_service.rb b/db/migrate/20161213172958_change_slack_service_to_slack_notification_service.rb
deleted file mode 100644
index babac6bfc4f..00000000000
--- a/db/migrate/20161213172958_change_slack_service_to_slack_notification_service.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-class ChangeSlackServiceToSlackNotificationService < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- # This migration is a no-op, as it existed in an RC but we renamed
- # SlackNotificationService back to SlackService:
- # https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/8191#note_20310845
- def change
- end
-end
diff --git a/db/migrate/20161220141214_remove_dot_git_from_group_names.rb b/db/migrate/20161220141214_remove_dot_git_from_group_names.rb
deleted file mode 100644
index 5c0b083325e..00000000000
--- a/db/migrate/20161220141214_remove_dot_git_from_group_names.rb
+++ /dev/null
@@ -1,82 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class RemoveDotGitFromGroupNames < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
- include Gitlab::ShellAdapter
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- def up
- invalid_groups.each do |group|
- path_was = group['path']
- path_was_wildcard = quote_string("#{path_was}/%")
- path = quote_string(rename_path(path_was))
-
- move_namespace(group['id'], path_was, path)
-
- execute "UPDATE routes SET path = '#{path}' WHERE source_type = 'Namespace' AND source_id = #{group['id']}"
- execute "UPDATE namespaces SET path = '#{path}' WHERE id = #{group['id']}"
-
- select_all("SELECT id, path FROM routes WHERE path LIKE '#{path_was_wildcard}'").each do |route|
- new_path = "#{path}/#{route['path'].split('/').last}"
- execute "UPDATE routes SET path = '#{new_path}' WHERE id = #{route['id']}"
- end
- end
- end
-
- def down
- # nothing to do here
- end
-
- private
-
- def invalid_groups
- select_all("SELECT id, path FROM namespaces WHERE type = 'Group' AND path LIKE '%.git'")
- end
-
- def route_exists?(path)
- select_all("SELECT id, path FROM routes WHERE path = '#{quote_string(path)}'").present?
- end
-
- # Accepts invalid path like test.git and returns test_git or
- # test_git1 if test_git already taken
- def rename_path(path)
- # To stay closer with original name and reduce risk of duplicates
- # we rename suffix instead of removing it
- path = path.sub(/\.git\z/, '_git')
-
- counter = 0
- base = path
-
- while route_exists?(path)
- counter += 1
- path = "#{base}#{counter}"
- end
-
- path
- end
-
- def move_namespace(group_id, path_was, path)
- repository_storages = select_all("SELECT distinct(repository_storage) FROM projects WHERE namespace_id = #{group_id}").map do |row|
- row['repository_storage']
- end.compact
-
- # Move the namespace directory in all storages paths used by member projects
- repository_storages.each do |repository_storage|
- # Ensure old directory exists before moving it
- gitlab_shell.add_namespace(repository_storage, path_was)
-
- unless gitlab_shell.mv_namespace(repository_storage, path_was, path)
- Rails.logger.error "Exception moving on shard #{repository_storage} from #{path_was} to #{path}"
-
- # if we cannot move namespace directory we should rollback
- # db changes in order to prevent out of sync between db and fs
- raise Exception.new('namespace directory cannot be moved')
- end
- end
-
- Gitlab::UploadsTransfer.new.rename_namespace(path_was, path)
- end
-end
diff --git a/db/migrate/20161221152132_add_last_used_at_to_key.rb b/db/migrate/20161221152132_add_last_used_at_to_key.rb
deleted file mode 100644
index a5b3f2b6f4b..00000000000
--- a/db/migrate/20161221152132_add_last_used_at_to_key.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-# rubocop:disable Migration/Datetime
-class AddLastUsedAtToKey < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def change
- add_column :keys, :last_used_at, :datetime
- end
-end
diff --git a/db/migrate/20161223034433_add_estimate_to_issuables_ce.rb b/db/migrate/20161223034433_add_estimate_to_issuables_ce.rb
deleted file mode 100644
index 75bea41387c..00000000000
--- a/db/migrate/20161223034433_add_estimate_to_issuables_ce.rb
+++ /dev/null
@@ -1,25 +0,0 @@
-class AddEstimateToIssuablesCe < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def up
- unless column_exists?(:issues, :time_estimate)
- add_column :issues, :time_estimate, :integer
- end
-
- unless column_exists?(:merge_requests, :time_estimate)
- add_column :merge_requests, :time_estimate, :integer
- end
- end
-
- def down
- if column_exists?(:issues, :time_estimate)
- remove_column :issues, :time_estimate
- end
-
- if column_exists?(:merge_requests, :time_estimate)
- remove_column :merge_requests, :time_estimate
- end
- end
-end
diff --git a/db/migrate/20161223034646_create_timelogs_ce.rb b/db/migrate/20161223034646_create_timelogs_ce.rb
deleted file mode 100644
index 489a2b35dfd..00000000000
--- a/db/migrate/20161223034646_create_timelogs_ce.rb
+++ /dev/null
@@ -1,25 +0,0 @@
-# rubocop:disable Migration/Timestamps
-class CreateTimelogsCe < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def up
- unless table_exists?(:timelogs)
- create_table :timelogs do |t|
- t.integer :time_spent, null: false
- t.references :trackable, polymorphic: true
- t.references :user
-
- t.timestamps null: false
- end
-
- add_index :timelogs, [:trackable_type, :trackable_id]
- add_index :timelogs, :user_id
- end
- end
-
- def down
- drop_table :timelogs if table_exists?(:timelogs)
- end
-end
diff --git a/db/migrate/20161226122833_remove_dot_git_from_usernames.rb b/db/migrate/20161226122833_remove_dot_git_from_usernames.rb
deleted file mode 100644
index e3318780151..00000000000
--- a/db/migrate/20161226122833_remove_dot_git_from_usernames.rb
+++ /dev/null
@@ -1,110 +0,0 @@
-class RemoveDotGitFromUsernames < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
- include Gitlab::ShellAdapter
-
- DOWNTIME = false
-
- def up
- invalid_users.each do |user|
- id = user['id']
- namespace_id = user['namespace_id']
- path_was = user['username']
- path_was_wildcard = quote_string("#{path_was}/%")
- path = quote_string(new_path(path_was))
-
- move_namespace(namespace_id, path_was, path)
-
- begin
- execute "UPDATE routes SET path = '#{path}' WHERE source_type = 'Namespace' AND source_id = #{namespace_id}"
- execute "UPDATE namespaces SET path = '#{path}' WHERE id = #{namespace_id}"
- execute "UPDATE users SET username = '#{path}' WHERE id = #{id}"
-
- select_all("SELECT id, path FROM routes WHERE path LIKE '#{path_was_wildcard}'").each do |route|
- new_path = "#{path}/#{route['path'].split('/').last}"
- execute "UPDATE routes SET path = '#{new_path}' WHERE id = #{route['id']}"
- end
- rescue => e
- say("Couldn't update routes for path #{path_was} to #{path}")
- # Move namespace back
- move_namespace(namespace_id, path, path_was)
-
- raise e
- end
- end
- end
-
- def down
- # nothing to do here
- end
-
- private
-
- def invalid_users
- select_all("SELECT u.id, u.username, n.path AS namespace_path, n.id AS namespace_id FROM users u
- INNER JOIN namespaces n ON n.owner_id = u.id
- WHERE n.type is NULL AND n.path LIKE '%.git'")
- end
-
- def route_exists?(path)
- select_all("SELECT id, path FROM routes WHERE path = '#{quote_string(path)}'").present?
- end
-
- def path_exists?(shard, repository_storage_path)
- repository_storage_path && gitlab_shell.exists?(shard, repository_storage_path)
- end
-
- # Accepts invalid path like test.git and returns test_git or
- # test_git1 if test_git already taken
- def new_path(path)
- # To stay closer with original name and reduce risk of duplicates
- # we rename suffix instead of removing it
- path = path.sub(/\.git\z/, '_git')
-
- check_routes(path.dup, 0, path)
- end
-
- def check_routes(base, counter, path)
- route_exists = route_exists?(path)
-
- Gitlab.config.repositories.storages.each do |shard, _storage|
- if route_exists || path_exists?(shard, path)
- counter += 1
- path = "#{base}#{counter}"
-
- return check_routes(base, counter, path)
- end
- end
-
- path
- end
-
- def move_namespace(namespace_id, path_was, path)
- repository_storages = select_all("SELECT distinct(repository_storage) FROM projects WHERE namespace_id = #{namespace_id}").map do |row|
- row['repository_storage']
- end.compact
-
- # Move the namespace directory in all storages used by member projects
- repository_storages.each do |repository_storage|
- # Ensure old directory exists before moving it
- gitlab_shell.add_namespace(repository_storage, path_was)
-
- unless gitlab_shell.mv_namespace(repository_storage, path_was, path)
- Rails.logger.error "Exception moving on shard #{repository_storage} from #{path_was} to #{path}"
-
- # if we cannot move namespace directory we should rollback
- # db changes in order to prevent out of sync between db and fs
- raise Exception.new('namespace directory cannot be moved')
- end
- end
-
- begin
- Gitlab::UploadsTransfer.new.rename_namespace(path_was, path)
- rescue => e
- if path.nil?
- say("Couldn't find a storage path for #{namespace_id}, #{path_was} -- skipping")
- else
- raise e
- end
- end
- end
-end
diff --git a/db/migrate/20161227192806_rename_slack_and_mattermost_notification_services.rb b/db/migrate/20161227192806_rename_slack_and_mattermost_notification_services.rb
deleted file mode 100644
index df5714278f2..00000000000
--- a/db/migrate/20161227192806_rename_slack_and_mattermost_notification_services.rb
+++ /dev/null
@@ -1,28 +0,0 @@
-# rubocop:disable Migration/UpdateColumnInBatches
-class RenameSlackAndMattermostNotificationServices < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- update_column_in_batches(:services, :type, 'SlackService') do |table, query|
- query.where(table[:type].eq('SlackNotificationService'))
- end
-
- update_column_in_batches(:services, :type, 'MattermostService') do |table, query|
- query.where(table[:type].eq('MattermostNotificationService'))
- end
- end
-
- def down
- update_column_in_batches(:services, :type, 'SlackNotificationService') do |table, query|
- query.where(table[:type].eq('SlackService'))
- end
-
- update_column_in_batches(:services, :type, 'MattermostNotificationService') do |table, query|
- query.where(table[:type].eq('MattermostService'))
- end
- end
-end
diff --git a/db/migrate/20161228124936_change_expires_at_to_date_in_personal_access_tokens.rb b/db/migrate/20161228124936_change_expires_at_to_date_in_personal_access_tokens.rb
deleted file mode 100644
index f9f8f11316d..00000000000
--- a/db/migrate/20161228124936_change_expires_at_to_date_in_personal_access_tokens.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-# rubocop:disable Migration/Datetime
-class ChangeExpiresAtToDateInPersonalAccessTokens < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = true
- DOWNTIME_REASON = 'This migration requires downtime because it alters expires_at column from datetime to date'
-
- def up
- change_column :personal_access_tokens, :expires_at, :date
- end
-
- def down
- change_column :personal_access_tokens, :expires_at, :datetime
- end
-end
diff --git a/db/migrate/20161228135550_add_impersonation_to_personal_access_tokens.rb b/db/migrate/20161228135550_add_impersonation_to_personal_access_tokens.rb
deleted file mode 100644
index 489d7fb8b75..00000000000
--- a/db/migrate/20161228135550_add_impersonation_to_personal_access_tokens.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class AddImpersonationToPersonalAccessTokens < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
- disable_ddl_transaction!
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- def up
- add_column_with_default :personal_access_tokens, :impersonation, :boolean, default: false, allow_null: false
- end
-
- def down
- remove_column :personal_access_tokens, :impersonation
- end
-end
diff --git a/db/migrate/20170120131253_create_chat_teams.rb b/db/migrate/20170120131253_create_chat_teams.rb
deleted file mode 100644
index e9b9bd7bd2f..00000000000
--- a/db/migrate/20170120131253_create_chat_teams.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-# rubocop:disable Migration/Timestamps
-class CreateChatTeams < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = true
- DOWNTIME_REASON = "Adding a foreign key"
-
- disable_ddl_transaction!
-
- def change
- create_table :chat_teams do |t|
- t.references :namespace, null: false, index: { unique: true }, foreign_key: { on_delete: :cascade }
- t.string :team_id
- t.string :name
-
- t.timestamps null: false
- end
- end
-end
diff --git a/db/migrate/20170121123724_add_index_to_ci_builds_for_status_runner_id_and_type.rb b/db/migrate/20170121123724_add_index_to_ci_builds_for_status_runner_id_and_type.rb
deleted file mode 100644
index cc1a4d2db59..00000000000
--- a/db/migrate/20170121123724_add_index_to_ci_builds_for_status_runner_id_and_type.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-# rubocop:disable RemoveIndex
-class AddIndexToCiBuildsForStatusRunnerIdAndType < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- add_concurrent_index :ci_builds, [:status, :type, :runner_id]
- end
-
- def down
- if index_exists?(:ci_builds, [:status, :type, :runner_id])
- remove_index :ci_builds, column: [:status, :type, :runner_id]
- end
- end
-end
diff --git a/db/migrate/20170121130655_add_index_to_ci_runners_for_is_shared.rb b/db/migrate/20170121130655_add_index_to_ci_runners_for_is_shared.rb
deleted file mode 100644
index 1b83ce4cfe3..00000000000
--- a/db/migrate/20170121130655_add_index_to_ci_runners_for_is_shared.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-# rubocop:disable RemoveIndex
-class AddIndexToCiRunnersForIsShared < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- add_concurrent_index :ci_runners, :is_shared
- end
-
- def down
- if index_exists?(:ci_runners, :is_shared)
- remove_index :ci_runners, :is_shared
- end
- end
-end
diff --git a/db/migrate/20170124174637_add_foreign_keys_to_timelogs.rb b/db/migrate/20170124174637_add_foreign_keys_to_timelogs.rb
deleted file mode 100644
index ffd966be086..00000000000
--- a/db/migrate/20170124174637_add_foreign_keys_to_timelogs.rb
+++ /dev/null
@@ -1,57 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class AddForeignKeysToTimelogs < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
- # When a migration requires downtime you **must** uncomment the following
- # constant and define a short and easy to understand explanation as to why the
- # migration requires downtime.
- DOWNTIME_REASON = ''
-
- # When using the methods "add_concurrent_index" or "add_column_with_default"
- # you must disable the use of transactions as these methods can not run in an
- # existing transaction. When using "add_concurrent_index" make sure that this
- # method is the _only_ method called in the migration, any other changes
- # should go in a separate migration. This ensures that upon failure _only_ the
- # index creation fails and can be retried or reverted easily.
- #
- # To disable transactions uncomment the following line and remove these
- # comments:
- disable_ddl_transaction!
-
- def up
- change_table :timelogs do |t|
- t.column :issue_id, :integer
- t.column :merge_request_id, :integer
- end
-
- add_concurrent_index :timelogs, :issue_id
- add_concurrent_index :timelogs, :merge_request_id
-
- if Gitlab::Database.postgresql?
- execute <<-EOF
- ALTER TABLE timelogs ADD CONSTRAINT "fk_timelogs_issues_issue_id" FOREIGN KEY (issue_id) REFERENCES "issues" (id) ON DELETE CASCADE NOT VALID;
- ALTER TABLE timelogs ADD CONSTRAINT "fk_timelogs_merge_requests_merge_request_id" FOREIGN KEY (merge_request_id) REFERENCES "merge_requests" (id) ON DELETE CASCADE NOT VALID;
- EOF
- else
- execute "ALTER TABLE timelogs ADD CONSTRAINT fk_timelogs_issues_issue_id FOREIGN KEY (issue_id) REFERENCES issues(id) ON DELETE CASCADE;"
- execute "ALTER TABLE timelogs ADD CONSTRAINT fk_timelogs_merge_requests_merge_request_id FOREIGN KEY (merge_request_id) REFERENCES merge_requests(id) ON DELETE CASCADE;"
- end
-
- Timelog.where(trackable_type: 'Issue').update_all("issue_id = trackable_id")
- Timelog.where(trackable_type: 'MergeRequest').update_all("merge_request_id = trackable_id")
- end
-
- def down
- Timelog.where('issue_id IS NOT NULL').update_all("trackable_id = issue_id, trackable_type = 'Issue'")
- Timelog.where('merge_request_id IS NOT NULL').update_all("trackable_id = merge_request_id, trackable_type = 'MergeRequest'")
-
- remove_foreign_key :timelogs, name: 'fk_timelogs_issues_issue_id'
- remove_foreign_key :timelogs, name: 'fk_timelogs_merge_requests_merge_request_id'
-
- remove_columns :timelogs, :issue_id, :merge_request_id
- end
-end
diff --git a/db/migrate/20170124193147_add_two_factor_columns_to_namespaces.rb b/db/migrate/20170124193147_add_two_factor_columns_to_namespaces.rb
deleted file mode 100644
index 324e051666b..00000000000
--- a/db/migrate/20170124193147_add_two_factor_columns_to_namespaces.rb
+++ /dev/null
@@ -1,22 +0,0 @@
-# rubocop:disable Migration/UpdateLargeTable
-class AddTwoFactorColumnsToNamespaces < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- add_column_with_default(:namespaces, :require_two_factor_authentication, :boolean, default: false)
- add_column_with_default(:namespaces, :two_factor_grace_period, :integer, default: 48)
-
- add_concurrent_index(:namespaces, :require_two_factor_authentication)
- end
-
- def down
- remove_column(:namespaces, :require_two_factor_authentication)
- remove_column(:namespaces, :two_factor_grace_period)
-
- remove_concurrent_index(:namespaces, :require_two_factor_authentication) if index_exists?(:namespaces, :require_two_factor_authentication)
- end
-end
diff --git a/db/migrate/20170124193205_add_two_factor_columns_to_users.rb b/db/migrate/20170124193205_add_two_factor_columns_to_users.rb
deleted file mode 100644
index 6c80dbfc965..00000000000
--- a/db/migrate/20170124193205_add_two_factor_columns_to_users.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-# rubocop:disable Migration/UpdateLargeTable
-class AddTwoFactorColumnsToUsers < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- add_column_with_default(:users, :require_two_factor_authentication_from_group, :boolean, default: false)
- add_column_with_default(:users, :two_factor_grace_period, :integer, default: 48)
- end
-
- def down
- remove_column(:users, :require_two_factor_authentication_from_group)
- remove_column(:users, :two_factor_grace_period)
- end
-end
diff --git a/db/migrate/20170126174819_add_terminal_max_session_time_to_application_settings.rb b/db/migrate/20170126174819_add_terminal_max_session_time_to_application_settings.rb
deleted file mode 100644
index 70f1669108a..00000000000
--- a/db/migrate/20170126174819_add_terminal_max_session_time_to_application_settings.rb
+++ /dev/null
@@ -1,33 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class AddTerminalMaxSessionTimeToApplicationSettings < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- # When a migration requires downtime you **must** uncomment the following
- # constant and define a short and easy to understand explanation as to why the
- # migration requires downtime.
- # DOWNTIME_REASON = ''
-
- # When using the methods "add_concurrent_index" or "add_column_with_default"
- # you must disable the use of transactions as these methods can not run in an
- # existing transaction. When using "add_concurrent_index" make sure that this
- # method is the _only_ method called in the migration, any other changes
- # should go in a separate migration. This ensures that upon failure _only_ the
- # index creation fails and can be retried or reverted easily.
- #
- # To disable transactions uncomment the following line and remove these
- # comments:
- disable_ddl_transaction!
-
- def up
- add_column_with_default :application_settings, :terminal_max_session_time, :integer, default: 0, allow_null: false
- end
-
- def down
- remove_column :application_settings, :terminal_max_session_time
- end
-end
diff --git a/db/migrate/20170127032550_remove_backlog_lists_from_boards.rb b/db/migrate/20170127032550_remove_backlog_lists_from_boards.rb
deleted file mode 100644
index 2e2fecfa2a7..00000000000
--- a/db/migrate/20170127032550_remove_backlog_lists_from_boards.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-class RemoveBacklogListsFromBoards < ActiveRecord::Migration[4.2]
- DOWNTIME = false
-
- def up
- execute <<-SQL
- DELETE FROM lists WHERE list_type = 0;
- SQL
- end
-
- def down
- execute <<-SQL
- INSERT INTO lists (board_id, list_type, created_at, updated_at)
- SELECT boards.id, 0, NOW(), NOW()
- FROM boards;
- SQL
- end
-end
diff --git a/db/migrate/20170130204620_add_index_to_project_authorizations.rb b/db/migrate/20170130204620_add_index_to_project_authorizations.rb
deleted file mode 100644
index 28c4480e9c6..00000000000
--- a/db/migrate/20170130204620_add_index_to_project_authorizations.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-# rubocop:disable RemoveIndex
-class AddIndexToProjectAuthorizations < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- unless index_exists?(:project_authorizations, :project_id)
- add_concurrent_index(:project_authorizations, :project_id)
- end
- end
-
- def down
- remove_index(:project_authorizations, :project_id) if
- Gitlab::Database.postgresql?
- end
-end
diff --git a/db/migrate/20170130221926_create_uploads.rb b/db/migrate/20170130221926_create_uploads.rb
deleted file mode 100644
index 7bf15ca4978..00000000000
--- a/db/migrate/20170130221926_create_uploads.rb
+++ /dev/null
@@ -1,20 +0,0 @@
-class CreateUploads < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def change
- create_table :uploads do |t|
- t.integer :size, limit: 8, null: false
- t.string :path, null: false
- t.string :checksum, limit: 64
- t.references :model, polymorphic: true
- t.string :uploader, null: false
- t.datetime :created_at, null: false
- end
-
- add_index :uploads, :path
- add_index :uploads, :checksum
- add_index :uploads, [:model_id, :model_type]
- end
-end
diff --git a/db/migrate/20170131221752_add_relative_position_to_issues.rb b/db/migrate/20170131221752_add_relative_position_to_issues.rb
deleted file mode 100644
index 126cb9e5415..00000000000
--- a/db/migrate/20170131221752_add_relative_position_to_issues.rb
+++ /dev/null
@@ -1,38 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-# rubocop:disable RemoveIndex
-class AddRelativePositionToIssues < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- # When a migration requires downtime you **must** uncomment the following
- # constant and define a short and easy to understand explanation as to why the
- # migration requires downtime.
- # DOWNTIME_REASON = ''
-
- # When using the methods "add_concurrent_index" or "add_column_with_default"
- # you must disable the use of transactions as these methods can not run in an
- # existing transaction. When using "add_concurrent_index" make sure that this
- # method is the _only_ method called in the migration, any other changes
- # should go in a separate migration. This ensures that upon failure _only_ the
- # index creation fails and can be retried or reverted easily.
- #
- # To disable transactions uncomment the following line and remove these
- # comments:
- disable_ddl_transaction!
-
- def up
- add_column :issues, :relative_position, :integer
-
- add_concurrent_index :issues, :relative_position
- end
-
- def down
- remove_column :issues, :relative_position
-
- remove_index :issues, :relative_position if index_exists? :issues, :relative_position
- end
-end
diff --git a/db/migrate/20170204172458_add_name_to_route.rb b/db/migrate/20170204172458_add_name_to_route.rb
deleted file mode 100644
index e7c94aceb26..00000000000
--- a/db/migrate/20170204172458_add_name_to_route.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class AddNameToRoute < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def change
- add_column :routes, :name, :string
- end
-end
diff --git a/db/migrate/20170204181513_add_index_to_labels_for_type_and_project.rb b/db/migrate/20170204181513_add_index_to_labels_for_type_and_project.rb
deleted file mode 100644
index 746322885b1..00000000000
--- a/db/migrate/20170204181513_add_index_to_labels_for_type_and_project.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-# rubocop:disable RemoveIndex
-class AddIndexToLabelsForTypeAndProject < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- add_concurrent_index :labels, [:type, :project_id]
- end
-
- def down
- remove_index :labels, [:type, :project_id] if index_exists? :labels, [:type, :project_id]
- end
-end
diff --git a/db/migrate/20170206071414_add_recaptcha_verified_to_spam_logs.rb b/db/migrate/20170206071414_add_recaptcha_verified_to_spam_logs.rb
deleted file mode 100644
index 06338ac943e..00000000000
--- a/db/migrate/20170206071414_add_recaptcha_verified_to_spam_logs.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-class AddRecaptchaVerifiedToSpamLogs < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- disable_ddl_transaction!
-
- DOWNTIME = false
-
- def up
- add_column_with_default(:spam_logs, :recaptcha_verified, :boolean, default: false)
- end
-
- def down
- remove_column(:spam_logs, :recaptcha_verified)
- end
-end
diff --git a/db/migrate/20170206115204_add_column_ghost_to_users.rb b/db/migrate/20170206115204_add_column_ghost_to_users.rb
deleted file mode 100644
index 4b86814e05d..00000000000
--- a/db/migrate/20170206115204_add_column_ghost_to_users.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-class AddColumnGhostToUsers < ActiveRecord::Migration[4.2]
- DOWNTIME = false
-
- def up
- add_column :users, :ghost, :boolean
- end
-
- def down
- remove_column :users, :ghost
- end
-end
diff --git a/db/migrate/20170210062829_add_index_to_labels_for_title_and_project.rb b/db/migrate/20170210062829_add_index_to_labels_for_title_and_project.rb
deleted file mode 100644
index d0b440b8ccb..00000000000
--- a/db/migrate/20170210062829_add_index_to_labels_for_title_and_project.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-# rubocop:disable RemoveIndex
-class AddIndexToLabelsForTitleAndProject < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- add_concurrent_index :labels, :title
- add_concurrent_index :labels, :project_id
- end
-
- def down
- remove_index :labels, :title if index_exists? :labels, :title
- remove_index :labels, :project_id if index_exists? :labels, :project_id
- end
-end
diff --git a/db/migrate/20170210075922_add_index_to_ci_trigger_requests_for_commit_id.rb b/db/migrate/20170210075922_add_index_to_ci_trigger_requests_for_commit_id.rb
deleted file mode 100644
index 753d6c77e35..00000000000
--- a/db/migrate/20170210075922_add_index_to_ci_trigger_requests_for_commit_id.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-# rubocop:disable RemoveIndex
-class AddIndexToCiTriggerRequestsForCommitId < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- add_concurrent_index :ci_trigger_requests, :commit_id
- end
-
- def down
- remove_index :ci_trigger_requests, :commit_id if index_exists? :ci_trigger_requests, :commit_id
- end
-end
diff --git a/db/migrate/20170210103609_add_index_to_user_agent_detail.rb b/db/migrate/20170210103609_add_index_to_user_agent_detail.rb
deleted file mode 100644
index a2d6528ea82..00000000000
--- a/db/migrate/20170210103609_add_index_to_user_agent_detail.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-# rubocop:disable RemoveIndex
-class AddIndexToUserAgentDetail < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- add_concurrent_index :user_agent_details, [:subject_id, :subject_type]
- end
-
- def down
- remove_index :user_agent_details, [:subject_id, :subject_type] if index_exists? :user_agent_details, [:subject_id, :subject_type]
- end
-end
diff --git a/db/migrate/20170210131347_add_unique_ips_limit_to_application_settings.rb b/db/migrate/20170210131347_add_unique_ips_limit_to_application_settings.rb
deleted file mode 100644
index c286354f476..00000000000
--- a/db/migrate/20170210131347_add_unique_ips_limit_to_application_settings.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-class AddUniqueIpsLimitToApplicationSettings < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
- DOWNTIME = false
- disable_ddl_transaction!
-
- def up
- add_column :application_settings, :unique_ips_limit_per_user, :integer
- add_column :application_settings, :unique_ips_limit_time_window, :integer
- add_column_with_default :application_settings, :unique_ips_limit_enabled, :boolean, default: false
- end
-
- def down
- remove_column :application_settings, :unique_ips_limit_per_user
- remove_column :application_settings, :unique_ips_limit_time_window
- remove_column :application_settings, :unique_ips_limit_enabled
- end
-end
diff --git a/db/migrate/20170214084746_add_default_artifacts_expiration_to_application_settings.rb b/db/migrate/20170214084746_add_default_artifacts_expiration_to_application_settings.rb
deleted file mode 100644
index 84814c2f8f2..00000000000
--- a/db/migrate/20170214084746_add_default_artifacts_expiration_to_application_settings.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-class AddDefaultArtifactsExpirationToApplicationSettings < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def change
- add_column :application_settings,
- :default_artifacts_expire_in, :string,
- null: false, default: '0'
- end
-end
diff --git a/db/migrate/20170216135621_add_index_for_latest_successful_pipeline.rb b/db/migrate/20170216135621_add_index_for_latest_successful_pipeline.rb
deleted file mode 100644
index be393bd496d..00000000000
--- a/db/migrate/20170216135621_add_index_for_latest_successful_pipeline.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-# rubocop:disable RemoveIndex
-class AddIndexForLatestSuccessfulPipeline < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- add_concurrent_index(:ci_commits, [:gl_project_id, :ref, :status])
- end
-
- def down
- remove_index :ci_commits, [:gl_project_id, :ref, :status] if index_exists? :ci_commits, [:gl_project_id, :ref, :status]
- end
-end
diff --git a/db/migrate/20170216141440_drop_index_for_builds_project_status.rb b/db/migrate/20170216141440_drop_index_for_builds_project_status.rb
deleted file mode 100644
index 7edf7dd7e10..00000000000
--- a/db/migrate/20170216141440_drop_index_for_builds_project_status.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-# rubocop:disable RemoveIndex
-class DropIndexForBuildsProjectStatus < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
- DOWNTIME = false
-
- def change
- remove_index(:ci_commits, column: [:gl_project_id, :status])
- end
-end
diff --git a/db/migrate/20170217132157_rename_merge_when_build_succeeds.rb b/db/migrate/20170217132157_rename_merge_when_build_succeeds.rb
deleted file mode 100644
index ee8838eff56..00000000000
--- a/db/migrate/20170217132157_rename_merge_when_build_succeeds.rb
+++ /dev/null
@@ -1,29 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class RenameMergeWhenBuildSucceeds < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = true
-
- # When a migration requires downtime you **must** uncomment the following
- # constant and define a short and easy to understand explanation as to why the
- # migration requires downtime.
- DOWNTIME_REASON = 'Renaming the column merge_when_build_succeeds'
-
- # When using the methods "add_concurrent_index" or "add_column_with_default"
- # you must disable the use of transactions as these methods can not run in an
- # existing transaction. When using "add_concurrent_index" make sure that this
- # method is the _only_ method called in the migration, any other changes
- # should go in a separate migration. This ensures that upon failure _only_ the
- # index creation fails and can be retried or reverted easily.
- #
- # To disable transactions uncomment the following line and remove these
- # comments:
- # disable_ddl_transaction!
-
- def change
- rename_column :merge_requests, :merge_when_build_succeeds, :merge_when_pipeline_succeeds
- end
-end
diff --git a/db/migrate/20170217151947_rename_only_allow_merge_if_build_succeeds.rb b/db/migrate/20170217151947_rename_only_allow_merge_if_build_succeeds.rb
deleted file mode 100644
index 5d35216f3af..00000000000
--- a/db/migrate/20170217151947_rename_only_allow_merge_if_build_succeeds.rb
+++ /dev/null
@@ -1,29 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class RenameOnlyAllowMergeIfBuildSucceeds < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = true
-
- # When a migration requires downtime you **must** uncomment the following
- # constant and define a short and easy to understand explanation as to why the
- # migration requires downtime.
- DOWNTIME_REASON = 'Renaming the column only_allow_merge_if_build_succeeds'
-
- # When using the methods "add_concurrent_index" or "add_column_with_default"
- # you must disable the use of transactions as these methods can not run in an
- # existing transaction. When using "add_concurrent_index" make sure that this
- # method is the _only_ method called in the migration, any other changes
- # should go in a separate migration. This ensures that upon failure _only_ the
- # index creation fails and can be retried or reverted easily.
- #
- # To disable transactions uncomment the following line and remove these
- # comments:
- # disable_ddl_transaction!
-
- def change
- rename_column :projects, :only_allow_merge_if_build_succeeds, :only_allow_merge_if_pipeline_succeeds
- end
-end
diff --git a/db/migrate/20170217151948_add_owner_id_to_triggers.rb b/db/migrate/20170217151948_add_owner_id_to_triggers.rb
deleted file mode 100644
index a28711ae59a..00000000000
--- a/db/migrate/20170217151948_add_owner_id_to_triggers.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-class AddOwnerIdToTriggers < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def change
- add_column :ci_triggers, :owner_id, :integer
- end
-end
diff --git a/db/migrate/20170217151949_add_description_to_triggers.rb b/db/migrate/20170217151949_add_description_to_triggers.rb
deleted file mode 100644
index 27cb4b3ab31..00000000000
--- a/db/migrate/20170217151949_add_description_to_triggers.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-class AddDescriptionToTriggers < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def change
- add_column :ci_triggers, :description, :string
- end
-end
diff --git a/db/migrate/20170222111732_create_gpg_keys.rb b/db/migrate/20170222111732_create_gpg_keys.rb
deleted file mode 100644
index 012e8ef5854..00000000000
--- a/db/migrate/20170222111732_create_gpg_keys.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-class CreateGpgKeys < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def change
- create_table :gpg_keys do |t|
- t.timestamps_with_timezone null: false
-
- t.references :user, index: true, foreign_key: { on_delete: :cascade }
-
- t.binary :primary_keyid
- t.binary :fingerprint
-
- t.text :key
-
- 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/20170222143317_drop_ci_projects.rb b/db/migrate/20170222143317_drop_ci_projects.rb
deleted file mode 100644
index 9f3aa2da382..00000000000
--- a/db/migrate/20170222143317_drop_ci_projects.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-class DropCiProjects < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def up
- drop_table :ci_projects
- end
-
- def down
- create_table "ci_projects", force: :cascade do |t|
- t.string "name"
- t.integer "timeout", default: 3600, null: false
- t.datetime "created_at"
- t.datetime "updated_at"
- t.string "token"
- t.string "default_ref"
- t.string "path"
- t.boolean "always_build", default: false, null: false
- t.integer "polling_interval"
- t.boolean "public", default: false, null: false
- t.string "ssh_url_to_repo"
- t.integer "gitlab_id"
- t.boolean "allow_git_fetch", default: true, null: false
- t.string "email_recipients", default: "", null: false
- t.boolean "email_add_pusher", default: true, null: false
- t.boolean "email_only_broken_builds", default: true, null: false
- t.string "skip_refs"
- t.string "coverage_regex"
- t.boolean "shared_runners_enabled", default: false
- t.text "generated_yaml_config"
- end
- end
-end
diff --git a/db/migrate/20170222143500_remove_old_project_id_columns.rb b/db/migrate/20170222143500_remove_old_project_id_columns.rb
deleted file mode 100644
index 356dee4a060..00000000000
--- a/db/migrate/20170222143500_remove_old_project_id_columns.rb
+++ /dev/null
@@ -1,30 +0,0 @@
-# rubocop:disable Migration/RemoveColumn
-# rubocop:disable RemoveIndex
-class RemoveOldProjectIdColumns < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
- disable_ddl_transaction!
-
- DOWNTIME = true
- DOWNTIME_REASON = 'Unused columns are being removed.'
-
- def up
- remove_index :ci_builds, :project_id if
- index_exists?(:ci_builds, :project_id)
-
- remove_column :ci_builds, :project_id
- remove_column :ci_commits, :project_id
- remove_column :ci_runner_projects, :project_id
- remove_column :ci_triggers, :project_id
- remove_column :ci_variables, :project_id
- end
-
- def down
- add_column :ci_builds, :project_id, :integer
- add_column :ci_commits, :project_id, :integer
- add_column :ci_runner_projects, :project_id, :integer
- add_column :ci_triggers, :project_id, :integer
- add_column :ci_variables, :project_id, :integer
-
- add_concurrent_index :ci_builds, :project_id
- end
-end
diff --git a/db/migrate/20170222143603_rename_gl_project_id_to_project_id.rb b/db/migrate/20170222143603_rename_gl_project_id_to_project_id.rb
deleted file mode 100644
index 390b2c33d91..00000000000
--- a/db/migrate/20170222143603_rename_gl_project_id_to_project_id.rb
+++ /dev/null
@@ -1,14 +0,0 @@
-class RenameGlProjectIdToProjectId < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = true
- DOWNTIME_REASON = 'Renaming an actively used column.'
-
- def change
- rename_column :ci_builds, :gl_project_id, :project_id
- rename_column :ci_commits, :gl_project_id, :project_id
- rename_column :ci_runner_projects, :gl_project_id, :project_id
- rename_column :ci_triggers, :gl_project_id, :project_id
- rename_column :ci_variables, :gl_project_id, :project_id
- end
-end
diff --git a/db/migrate/20170301101006_add_ci_runner_namespaces.rb b/db/migrate/20170301101006_add_ci_runner_namespaces.rb
deleted file mode 100644
index aa2d8a14242..00000000000
--- a/db/migrate/20170301101006_add_ci_runner_namespaces.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-class AddCiRunnerNamespaces < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def change
- create_table :ci_runner_namespaces do |t|
- t.integer :runner_id
- t.integer :namespace_id
-
- t.index [:runner_id, :namespace_id], unique: true
- t.index :namespace_id
- t.foreign_key :ci_runners, column: :runner_id, on_delete: :cascade
- t.foreign_key :namespaces, column: :namespace_id, on_delete: :cascade
- end
- end
-end
diff --git a/db/migrate/20170301125302_add_printing_merge_request_link_enabled_to_project.rb b/db/migrate/20170301125302_add_printing_merge_request_link_enabled_to_project.rb
deleted file mode 100644
index a7efeb8ae6f..00000000000
--- a/db/migrate/20170301125302_add_printing_merge_request_link_enabled_to_project.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-# rubocop:disable Migration/UpdateLargeTable
-class AddPrintingMergeRequestLinkEnabledToProject < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
- disable_ddl_transaction!
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- def up
- add_column_with_default(:projects, :printing_merge_request_link_enabled, :boolean, default: true)
- end
-
- def down
- remove_column(:projects, :printing_merge_request_link_enabled)
- end
-end
diff --git a/db/migrate/20170301195939_rename_ci_commits_to_ci_pipelines.rb b/db/migrate/20170301195939_rename_ci_commits_to_ci_pipelines.rb
deleted file mode 100644
index 791e9c845a6..00000000000
--- a/db/migrate/20170301195939_rename_ci_commits_to_ci_pipelines.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-class RenameCiCommitsToCiPipelines < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = true
- DOWNTIME_REASON = 'Rename table ci_commits to ci_pipelines'
-
- def change
- rename_table 'ci_commits', 'ci_pipelines'
- end
-end
diff --git a/db/migrate/20170301205639_remove_unused_ci_tables_and_columns.rb b/db/migrate/20170301205639_remove_unused_ci_tables_and_columns.rb
deleted file mode 100644
index 08a11aee992..00000000000
--- a/db/migrate/20170301205639_remove_unused_ci_tables_and_columns.rb
+++ /dev/null
@@ -1,84 +0,0 @@
-# rubocop:disable Migration/RemoveColumn
-class RemoveUnusedCiTablesAndColumns < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = true
- DOWNTIME_REASON =
- 'Remove unused columns in used tables.' \
- ' Downtime required in case Rails caches them'
-
- def up
- %w[ci_application_settings
- ci_events
- ci_jobs
- ci_sessions
- ci_taggings
- ci_tags].each do |table|
- drop_table(table)
- end
-
- remove_column :ci_pipelines, :push_data, :text
- remove_column :ci_builds, :job_id, :integer if column_exists?(:ci_builds, :job_id)
- remove_column :ci_builds, :deploy, :boolean
- end
-
- def down
- add_column :ci_builds, :deploy, :boolean
- add_column :ci_builds, :job_id, :integer
- add_column :ci_pipelines, :push_data, :text
-
- create_table "ci_tags", force: :cascade do |t|
- t.string "name"
- t.integer "taggings_count", default: 0
- end
-
- create_table "ci_taggings", force: :cascade do |t|
- t.integer "tag_id"
- t.integer "taggable_id"
- t.string "taggable_type"
- t.integer "tagger_id"
- t.string "tagger_type"
- t.string "context", limit: 128
- t.datetime "created_at"
- end
-
- add_index "ci_taggings", %w[taggable_id taggable_type context]
-
- create_table "ci_sessions", force: :cascade do |t|
- t.string "session_id", null: false
- t.text "data"
- t.datetime "created_at"
- t.datetime "updated_at"
- end
-
- create_table "ci_jobs", force: :cascade do |t|
- t.integer "project_id", null: false
- t.text "commands"
- t.boolean "active", default: true, null: false
- t.datetime "created_at"
- t.datetime "updated_at"
- t.string "name"
- t.boolean "build_branches", default: true, null: false
- t.boolean "build_tags", default: false, null: false
- t.string "job_type", default: "parallel"
- t.string "refs"
- t.datetime "deleted_at"
- end
-
- create_table "ci_events", force: :cascade do |t|
- t.integer "project_id"
- t.integer "user_id"
- t.integer "is_admin"
- t.text "description"
- t.datetime "created_at"
- t.datetime "updated_at"
- end
-
- create_table "ci_application_settings", force: :cascade do |t|
- t.boolean "all_broken_builds"
- t.boolean "add_pusher"
- t.datetime "created_at"
- t.datetime "updated_at"
- end
- end
-end
diff --git a/db/migrate/20170305180853_add_auto_cancel_pending_pipelines_to_project.rb b/db/migrate/20170305180853_add_auto_cancel_pending_pipelines_to_project.rb
deleted file mode 100644
index 3e317bb5248..00000000000
--- a/db/migrate/20170305180853_add_auto_cancel_pending_pipelines_to_project.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-# rubocop:disable Migration/UpdateLargeTable
-class AddAutoCancelPendingPipelinesToProject < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- add_column_with_default(:projects, :auto_cancel_pending_pipelines, :integer, default: 0)
- end
-
- def down
- remove_column(:projects, :auto_cancel_pending_pipelines)
- end
-end
diff --git a/db/migrate/20170305203726_add_owner_id_foreign_key.rb b/db/migrate/20170305203726_add_owner_id_foreign_key.rb
deleted file mode 100644
index b3bd441ff9c..00000000000
--- a/db/migrate/20170305203726_add_owner_id_foreign_key.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-class AddOwnerIdForeignKey < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- add_concurrent_foreign_key :ci_triggers, :users, column: :owner_id, on_delete: :cascade
- end
-
- def down
- remove_foreign_key :ci_triggers, column: :owner_id
- end
-end
diff --git a/db/migrate/20170307125949_add_last_activity_on_to_users.rb b/db/migrate/20170307125949_add_last_activity_on_to_users.rb
deleted file mode 100644
index 42331eab753..00000000000
--- a/db/migrate/20170307125949_add_last_activity_on_to_users.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-class AddLastActivityOnToUsers < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def change
- add_column :users, :last_activity_on, :date
- end
-end
diff --git a/db/migrate/20170309173138_create_protected_tags.rb b/db/migrate/20170309173138_create_protected_tags.rb
deleted file mode 100644
index f518b500bd4..00000000000
--- a/db/migrate/20170309173138_create_protected_tags.rb
+++ /dev/null
@@ -1,28 +0,0 @@
-# rubocop:disable Migration/Timestamps
-class CreateProtectedTags < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- GITLAB_ACCESS_MASTER = 40
-
- def change
- create_table :protected_tags do |t|
- t.integer :project_id, null: false
- t.string :name, null: false
- t.timestamps null: false
- end
-
- add_index :protected_tags, :project_id
-
- create_table :protected_tag_create_access_levels do |t|
- t.references :protected_tag, index: { name: "index_protected_tag_create_access" }, foreign_key: true, null: false
- t.integer :access_level, default: GITLAB_ACCESS_MASTER, null: true
- t.references :user, foreign_key: true, index: true
- t.integer :group_id
- t.timestamps null: false
- end
-
- add_foreign_key :protected_tag_create_access_levels, :namespaces, column: :group_id # rubocop: disable Migration/AddConcurrentForeignKey
- end
-end
diff --git a/db/migrate/20170312114329_add_auto_canceled_by_id_to_pipeline.rb b/db/migrate/20170312114329_add_auto_canceled_by_id_to_pipeline.rb
deleted file mode 100644
index 26187a9e8b3..00000000000
--- a/db/migrate/20170312114329_add_auto_canceled_by_id_to_pipeline.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-class AddAutoCanceledByIdToPipeline < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def change
- add_column :ci_pipelines, :auto_canceled_by_id, :integer
- end
-end
diff --git a/db/migrate/20170312114529_add_auto_canceled_by_id_foreign_key_to_pipeline.rb b/db/migrate/20170312114529_add_auto_canceled_by_id_foreign_key_to_pipeline.rb
deleted file mode 100644
index a2b5c1c4533..00000000000
--- a/db/migrate/20170312114529_add_auto_canceled_by_id_foreign_key_to_pipeline.rb
+++ /dev/null
@@ -1,22 +0,0 @@
-class AddAutoCanceledByIdForeignKeyToPipeline < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- on_delete =
- if Gitlab::Database.mysql?
- :nullify
- else
- 'SET NULL'
- end
-
- add_concurrent_foreign_key :ci_pipelines, :ci_pipelines, column: :auto_canceled_by_id, on_delete: on_delete
- end
-
- def down
- remove_foreign_key :ci_pipelines, column: :auto_canceled_by_id
- end
-end
diff --git a/db/migrate/20170313213916_add_index_to_user_ghost.rb b/db/migrate/20170313213916_add_index_to_user_ghost.rb
deleted file mode 100644
index 66e57b444a0..00000000000
--- a/db/migrate/20170313213916_add_index_to_user_ghost.rb
+++ /dev/null
@@ -1,25 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-# rubocop:disable RemoveIndex
-class AddIndexToUserGhost < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- # When a migration requires downtime you **must** uncomment the following
- # constant and define a short and easy to understand explanation as to why the
- # migration requires downtime.
- # DOWNTIME_REASON = ''
-
- disable_ddl_transaction!
-
- def up
- add_concurrent_index :users, :ghost
- end
-
- def down
- remove_index :users, :ghost
- end
-end
diff --git a/db/migrate/20170314082049_create_system_note_metadata.rb b/db/migrate/20170314082049_create_system_note_metadata.rb
deleted file mode 100644
index d0cc6e3be36..00000000000
--- a/db/migrate/20170314082049_create_system_note_metadata.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-# rubocop:disable Migration/Timestamps
-class CreateSystemNoteMetadata < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- create_table :system_note_metadata do |t|
- t.references :note, null: false
- t.integer :commit_count
- t.string :action
-
- t.timestamps null: false
- end
-
- add_concurrent_foreign_key :system_note_metadata, :notes, column: :note_id
- end
-
- def down
- drop_table :system_note_metadata
- end
-end
diff --git a/db/migrate/20170315174634_revert_add_notified_of_own_activity_to_users.rb b/db/migrate/20170315174634_revert_add_notified_of_own_activity_to_users.rb
deleted file mode 100644
index 8773c7ea657..00000000000
--- a/db/migrate/20170315174634_revert_add_notified_of_own_activity_to_users.rb
+++ /dev/null
@@ -1,26 +0,0 @@
-# rubocop:disable Migration/RemoveColumn
-# rubocop:disable Migration/UpdateLargeTable
-class RevertAddNotifiedOfOwnActivityToUsers < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
- disable_ddl_transaction!
-
- DOWNTIME = false
-
- def up
- if our_column_exists?
- remove_column :users, :notified_of_own_activity
- end
- end
-
- def down
- unless our_column_exists?
- add_column_with_default :users, :notified_of_own_activity, :boolean, default: false
- end
- end
-
- private
-
- def our_column_exists?
- column_exists?(:users, :notified_of_own_activity)
- end
-end
diff --git a/db/migrate/20170315194013_add_closed_at_to_issues.rb b/db/migrate/20170315194013_add_closed_at_to_issues.rb
deleted file mode 100644
index 0b06ee6e74c..00000000000
--- a/db/migrate/20170315194013_add_closed_at_to_issues.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-# rubocop:disable Migration/Datetime
-class AddClosedAtToIssues < ActiveRecord::Migration[4.2]
- DOWNTIME = false
-
- def change
- add_column :issues, :closed_at, :datetime
- end
-end
diff --git a/db/migrate/20170316061730_readd_notified_of_own_activity_to_users.rb b/db/migrate/20170316061730_readd_notified_of_own_activity_to_users.rb
deleted file mode 100644
index 82029dfd3fc..00000000000
--- a/db/migrate/20170316061730_readd_notified_of_own_activity_to_users.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-class ReaddNotifiedOfOwnActivityToUsers < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
- disable_ddl_transaction!
-
- DOWNTIME = false
-
- def change
- add_column :users, :notified_of_own_activity, :boolean
- end
-end
diff --git a/db/migrate/20170316163845_move_uploads_to_system_dir.rb b/db/migrate/20170316163845_move_uploads_to_system_dir.rb
deleted file mode 100644
index d24527b55cd..00000000000
--- a/db/migrate/20170316163845_move_uploads_to_system_dir.rb
+++ /dev/null
@@ -1,59 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class MoveUploadsToSystemDir < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
- disable_ddl_transaction!
-
- DOWNTIME = false
- DIRECTORIES_TO_MOVE = %w(user project note group appearance).freeze
-
- def up
- return unless file_storage?
-
- FileUtils.mkdir_p(new_upload_dir)
-
- DIRECTORIES_TO_MOVE.each do |dir|
- source = File.join(old_upload_dir, dir)
- destination = File.join(new_upload_dir, dir)
- next unless File.directory?(source)
- next if File.directory?(destination)
-
- say "Moving #{source} -> #{destination}"
- FileUtils.mv(source, destination)
- FileUtils.ln_s(destination, source)
- end
- end
-
- def down
- return unless file_storage?
- return unless File.directory?(new_upload_dir)
-
- DIRECTORIES_TO_MOVE.each do |dir|
- source = File.join(new_upload_dir, dir)
- destination = File.join(old_upload_dir, dir)
- next unless File.directory?(source)
- next if File.directory?(destination) && !File.symlink?(destination)
-
- say "Moving #{source} -> #{destination}"
- FileUtils.rm(destination) if File.symlink?(destination)
- FileUtils.mv(source, destination)
- end
- end
-
- def file_storage?
- CarrierWave::Uploader::Base.storage == CarrierWave::Storage::File
- end
-
- def base_directory
- Rails.root
- end
-
- def old_upload_dir
- File.join(base_directory, "public", "uploads")
- end
-
- def new_upload_dir
- File.join(base_directory, "public", "uploads", "-", "system")
- end
-end
diff --git a/db/migrate/20170317203554_index_routes_path_for_like.rb b/db/migrate/20170317203554_index_routes_path_for_like.rb
deleted file mode 100644
index a1bee3c8783..00000000000
--- a/db/migrate/20170317203554_index_routes_path_for_like.rb
+++ /dev/null
@@ -1,28 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class IndexRoutesPathForLike < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- INDEX_NAME = 'index_routes_on_path_text_pattern_ops'
-
- disable_ddl_transaction!
-
- def up
- return unless Gitlab::Database.postgresql?
-
- unless index_exists?(:routes, :path, name: INDEX_NAME)
- execute("CREATE INDEX CONCURRENTLY #{INDEX_NAME} ON routes (path varchar_pattern_ops);")
- end
- end
-
- def down
- return unless Gitlab::Database.postgresql?
- return unless index_exists?(:routes, :path, name: INDEX_NAME)
-
- remove_concurrent_index_by_name(:routes, INDEX_NAME)
- end
-end
diff --git a/db/migrate/20170320173259_migrate_assignees.rb b/db/migrate/20170320173259_migrate_assignees.rb
deleted file mode 100644
index 43a90758bd9..00000000000
--- a/db/migrate/20170320173259_migrate_assignees.rb
+++ /dev/null
@@ -1,43 +0,0 @@
-# rubocop:disable Migration/UpdateLargeTable
-# rubocop:disable Migration/UpdateColumnInBatches
-class MigrateAssignees < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- # When a migration requires downtime you **must** uncomment the following
- # constant and define a short and easy to understand explanation as to why the
- # migration requires downtime.
- # DOWNTIME_REASON = ''
-
- # When using the methods "add_concurrent_index" or "add_column_with_default"
- # you must disable the use of transactions as these methods can not run in an
- # existing transaction. When using "add_concurrent_index" make sure that this
- # method is the _only_ method called in the migration, any other changes
- # should go in a separate migration. This ensures that upon failure _only_ the
- # index creation fails and can be retried or reverted easily.
- #
- # To disable transactions uncomment the following line and remove these
- # comments:
- disable_ddl_transaction!
-
- def up
- # Optimisation: this accounts for most of the invalid assignee IDs on GitLab.com
- update_column_in_batches(:issues, :assignee_id, nil) do |table, query|
- query.where(table[:assignee_id].eq(0))
- end
-
- users = Arel::Table.new(:users)
-
- update_column_in_batches(:issues, :assignee_id, nil) do |table, query|
- query.where(table[:assignee_id].not_eq(nil)\
- .and(
- users.project("true").where(users[:id].eq(table[:assignee_id])).exists.not
- ))
- end
- end
-
- def down
- end
-end
diff --git a/db/migrate/20170322013926_create_container_repository.rb b/db/migrate/20170322013926_create_container_repository.rb
deleted file mode 100644
index b1e778671b2..00000000000
--- a/db/migrate/20170322013926_create_container_repository.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-# rubocop:disable Migration/Timestamps
-class CreateContainerRepository < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def change
- create_table :container_repositories do |t|
- t.references :project, foreign_key: true, index: true, null: false
- t.string :name, null: false
-
- t.timestamps null: false
- end
-
- add_index :container_repositories, [:project_id, :name], unique: true
- end
-end
diff --git a/db/migrate/20170327091750_add_created_at_index_to_deployments.rb b/db/migrate/20170327091750_add_created_at_index_to_deployments.rb
deleted file mode 100644
index f29fff7d5b9..00000000000
--- a/db/migrate/20170327091750_add_created_at_index_to_deployments.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-class AddCreatedAtIndexToDeployments < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- add_concurrent_index :deployments, :created_at
- end
-
- def down
- remove_concurrent_index :deployments, :created_at
- end
-end
diff --git a/db/migrate/20170328010804_add_uuid_to_application_settings.rb b/db/migrate/20170328010804_add_uuid_to_application_settings.rb
deleted file mode 100644
index 95a01c2dc8f..00000000000
--- a/db/migrate/20170328010804_add_uuid_to_application_settings.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-class AddUuidToApplicationSettings < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- add_column :application_settings, :uuid, :string
- execute("UPDATE application_settings SET uuid = #{quote(SecureRandom.uuid)}")
- end
-
- def down
- remove_column :application_settings, :uuid
- end
-end
diff --git a/db/migrate/20170329095325_add_ref_to_triggers.rb b/db/migrate/20170329095325_add_ref_to_triggers.rb
deleted file mode 100644
index db09b36db17..00000000000
--- a/db/migrate/20170329095325_add_ref_to_triggers.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-class AddRefToTriggers < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def change
- add_column :ci_triggers, :ref, :string
- end
-end
diff --git a/db/migrate/20170329095907_create_ci_trigger_schedules.rb b/db/migrate/20170329095907_create_ci_trigger_schedules.rb
deleted file mode 100644
index 7f759f908cd..00000000000
--- a/db/migrate/20170329095907_create_ci_trigger_schedules.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-class CreateCiTriggerSchedules < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def change
- create_table :ci_trigger_schedules do |t|
- t.integer "project_id"
- t.integer "trigger_id", null: false
- t.datetime "deleted_at"
- t.datetime "created_at"
- t.datetime "updated_at"
- t.string "cron"
- t.string "cron_timezone"
- t.datetime "next_run_at"
- end
-
- add_index :ci_trigger_schedules, :next_run_at
- add_index :ci_trigger_schedules, :project_id
- end
-end
diff --git a/db/migrate/20170329124448_add_polling_interval_multiplier_to_application_settings.rb b/db/migrate/20170329124448_add_polling_interval_multiplier_to_application_settings.rb
deleted file mode 100644
index 17307879a2a..00000000000
--- a/db/migrate/20170329124448_add_polling_interval_multiplier_to_application_settings.rb
+++ /dev/null
@@ -1,33 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class AddPollingIntervalMultiplierToApplicationSettings < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- # When a migration requires downtime you **must** uncomment the following
- # constant and define a short and easy to understand explanation as to why the
- # migration requires downtime.
- # DOWNTIME_REASON = ''
-
- # When using the methods "add_concurrent_index" or "add_column_with_default"
- # you must disable the use of transactions as these methods can not run in an
- # existing transaction. When using "add_concurrent_index" make sure that this
- # method is the _only_ method called in the migration, any other changes
- # should go in a separate migration. This ensures that upon failure _only_ the
- # index creation fails and can be retried or reverted easily.
- #
- # To disable transactions uncomment the following line and remove these
- # comments:
- disable_ddl_transaction!
-
- def up
- add_column_with_default :application_settings, :polling_interval_multiplier, :decimal, default: 1, allow_null: false
- end
-
- def down
- remove_column :application_settings, :polling_interval_multiplier
- end
-end
diff --git a/db/migrate/20170330141723_disable_invalid_service_templates2.rb b/db/migrate/20170330141723_disable_invalid_service_templates2.rb
deleted file mode 100644
index f09f3b3e355..00000000000
--- a/db/migrate/20170330141723_disable_invalid_service_templates2.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-# This is the same as DisableInvalidServiceTemplates. Later migrations may have
-# inadvertently enabled some invalid templates again.
-#
-class DisableInvalidServiceTemplates2 < ActiveRecord::Migration[4.2]
- DOWNTIME = false
-
- unless defined?(Service)
- class Service < ActiveRecord::Base
- self.inheritance_column = nil
- end
- end
-
- def up
- Service.where(template: true, active: true).each do |template|
- template.update(active: false) unless template.valid?
- end
- end
-end
diff --git a/db/migrate/20170402231018_remove_index_for_users_current_sign_in_at.rb b/db/migrate/20170402231018_remove_index_for_users_current_sign_in_at.rb
deleted file mode 100644
index 4c417ce2f71..00000000000
--- a/db/migrate/20170402231018_remove_index_for_users_current_sign_in_at.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-class RemoveIndexForUsersCurrentSignInAt < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- remove_concurrent_index :users, :current_sign_in_at
- end
-
- def down
- add_concurrent_index :users, :current_sign_in_at
- end
-end
diff --git a/db/migrate/20170404163427_add_trigger_id_foreign_key.rb b/db/migrate/20170404163427_add_trigger_id_foreign_key.rb
deleted file mode 100644
index f35730c8e45..00000000000
--- a/db/migrate/20170404163427_add_trigger_id_foreign_key.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-class AddTriggerIdForeignKey < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- add_concurrent_foreign_key :ci_trigger_schedules, :ci_triggers, column: :trigger_id, on_delete: :cascade
- end
-
- def down
- remove_foreign_key :ci_trigger_schedules, column: :trigger_id
- end
-end
diff --git a/db/migrate/20170405080720_add_import_jid_to_projects.rb b/db/migrate/20170405080720_add_import_jid_to_projects.rb
deleted file mode 100644
index ddbea9d7ab6..00000000000
--- a/db/migrate/20170405080720_add_import_jid_to_projects.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-class AddImportJidToProjects < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def change
- add_column :projects, :import_jid, :string
- end
-end
diff --git a/db/migrate/20170406114958_add_auto_canceled_by_id_to_ci_builds.rb b/db/migrate/20170406114958_add_auto_canceled_by_id_to_ci_builds.rb
deleted file mode 100644
index ba43a070587..00000000000
--- a/db/migrate/20170406114958_add_auto_canceled_by_id_to_ci_builds.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-class AddAutoCanceledByIdToCiBuilds < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def change
- add_column :ci_builds, :auto_canceled_by_id, :integer
- end
-end
diff --git a/db/migrate/20170406115029_add_auto_canceled_by_id_foreign_key_to_ci_builds.rb b/db/migrate/20170406115029_add_auto_canceled_by_id_foreign_key_to_ci_builds.rb
deleted file mode 100644
index 2ec281e20c1..00000000000
--- a/db/migrate/20170406115029_add_auto_canceled_by_id_foreign_key_to_ci_builds.rb
+++ /dev/null
@@ -1,22 +0,0 @@
-class AddAutoCanceledByIdForeignKeyToCiBuilds < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- on_delete =
- if Gitlab::Database.mysql?
- :nullify
- else
- 'SET NULL'
- end
-
- add_concurrent_foreign_key :ci_builds, :ci_pipelines, column: :auto_canceled_by_id, on_delete: on_delete
- end
-
- def down
- remove_foreign_key :ci_builds, column: :auto_canceled_by_id
- end
-end
diff --git a/db/migrate/20170407114956_add_ref_to_ci_trigger_schedule.rb b/db/migrate/20170407114956_add_ref_to_ci_trigger_schedule.rb
deleted file mode 100644
index 5d156b7ef2e..00000000000
--- a/db/migrate/20170407114956_add_ref_to_ci_trigger_schedule.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-class AddRefToCiTriggerSchedule < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def change
- add_column :ci_trigger_schedules, :ref, :string
- end
-end
diff --git a/db/migrate/20170407122426_add_active_to_ci_trigger_schedule.rb b/db/migrate/20170407122426_add_active_to_ci_trigger_schedule.rb
deleted file mode 100644
index 33295bd3f2e..00000000000
--- a/db/migrate/20170407122426_add_active_to_ci_trigger_schedule.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-class AddActiveToCiTriggerSchedule < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def change
- add_column :ci_trigger_schedules, :active, :boolean
- end
-end
diff --git a/db/migrate/20170407135259_add_foreigh_key_trigger_requests_trigger.rb b/db/migrate/20170407135259_add_foreigh_key_trigger_requests_trigger.rb
deleted file mode 100644
index 9aaa4d0eddf..00000000000
--- a/db/migrate/20170407135259_add_foreigh_key_trigger_requests_trigger.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-class AddForeighKeyTriggerRequestsTrigger < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- add_concurrent_foreign_key(:ci_trigger_requests, :ci_triggers, column: :trigger_id)
- end
-
- def down
- remove_foreign_key(:ci_trigger_requests, column: :trigger_id)
- end
-end
diff --git a/db/migrate/20170407140450_add_index_to_next_run_at_and_active.rb b/db/migrate/20170407140450_add_index_to_next_run_at_and_active.rb
deleted file mode 100644
index 0bde4f69b3b..00000000000
--- a/db/migrate/20170407140450_add_index_to_next_run_at_and_active.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class AddIndexToNextRunAtAndActive < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- add_concurrent_index :ci_trigger_schedules, [:active, :next_run_at]
- end
-
- def down
- remove_concurrent_index :ci_trigger_schedules, [:active, :next_run_at]
- end
-end
diff --git a/db/migrate/20170410133135_add_version_field_to_markdown_cache.rb b/db/migrate/20170410133135_add_version_field_to_markdown_cache.rb
deleted file mode 100644
index c019e0627d3..00000000000
--- a/db/migrate/20170410133135_add_version_field_to_markdown_cache.rb
+++ /dev/null
@@ -1,25 +0,0 @@
-class AddVersionFieldToMarkdownCache < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def change
- %i[
- abuse_reports
- appearances
- application_settings
- broadcast_messages
- issues
- labels
- merge_requests
- milestones
- namespaces
- notes
- projects
- releases
- snippets
- ].each do |table|
- add_column table, :cached_markdown_version, :integer, limit: 4
- end
- end
-end
diff --git a/db/migrate/20170413035209_add_preferred_language_to_users.rb b/db/migrate/20170413035209_add_preferred_language_to_users.rb
deleted file mode 100644
index 5b5f00ea60f..00000000000
--- a/db/migrate/20170413035209_add_preferred_language_to_users.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class AddPreferredLanguageToUsers < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def up
- add_column :users, :preferred_language, :string
- end
-
- def down
- remove_column :users, :preferred_language
- end
-end
diff --git a/db/migrate/20170418103908_delete_orphan_notification_settings.rb b/db/migrate/20170418103908_delete_orphan_notification_settings.rb
deleted file mode 100644
index c99729b9127..00000000000
--- a/db/migrate/20170418103908_delete_orphan_notification_settings.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-class DeleteOrphanNotificationSettings < ActiveRecord::Migration[4.2]
- DOWNTIME = false
-
- def up
- execute("DELETE FROM notification_settings WHERE EXISTS (SELECT true FROM (#{orphan_notification_settings}) AS ns WHERE ns.id = notification_settings.id)")
- end
-
- def down
- # This is a no-op method to make the migration reversible.
- # If someone is trying to rollback for other reasons, we should not throw an Exception.
- # raise ActiveRecord::IrreversibleMigration
- end
-
- def orphan_notification_settings
- <<-SQL
- SELECT notification_settings.id
- FROM notification_settings
- LEFT OUTER JOIN namespaces
- ON namespaces.id = notification_settings.source_id
- WHERE notification_settings.source_type = 'Namespace'
- AND namespaces.id IS NULL
- SQL
- end
-end
diff --git a/db/migrate/20170419001229_add_index_to_system_note_metadata.rb b/db/migrate/20170419001229_add_index_to_system_note_metadata.rb
deleted file mode 100644
index 59cd55395fc..00000000000
--- a/db/migrate/20170419001229_add_index_to_system_note_metadata.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-class AddIndexToSystemNoteMetadata < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- # MySQL automatically creates an index on a foreign-key constraint; PostgreSQL does not
- add_concurrent_index :system_note_metadata, :note_id, unique: true if Gitlab::Database.postgresql?
- end
-
- def down
- remove_concurrent_index :system_note_metadata, :note_id, unique: true if Gitlab::Database.postgresql?
- end
-end
diff --git a/db/migrate/20170421102337_remove_nil_type_services.rb b/db/migrate/20170421102337_remove_nil_type_services.rb
deleted file mode 100644
index 561eddf69e0..00000000000
--- a/db/migrate/20170421102337_remove_nil_type_services.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-class RemoveNilTypeServices < ActiveRecord::Migration[4.2]
- DOWNTIME = false
-
- def up
- execute <<-SQL
- DELETE FROM services WHERE type IS NULL OR type = '';
- SQL
- end
-
- def down
- end
-end
diff --git a/db/migrate/20170423064036_add_index_on_ci_builds_updated_at.rb b/db/migrate/20170423064036_add_index_on_ci_builds_updated_at.rb
deleted file mode 100644
index 76252378c2e..00000000000
--- a/db/migrate/20170423064036_add_index_on_ci_builds_updated_at.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class AddIndexOnCiBuildsUpdatedAt < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- add_concurrent_index :ci_builds, :updated_at
- end
-
- def down
- remove_concurrent_index :ci_builds, :updated_at if index_exists?(:ci_builds, :updated_at)
- end
-end
diff --git a/db/migrate/20170424095707_add_index_on_ci_builds_user_id.rb b/db/migrate/20170424095707_add_index_on_ci_builds_user_id.rb
deleted file mode 100644
index ab2501da941..00000000000
--- a/db/migrate/20170424095707_add_index_on_ci_builds_user_id.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class AddIndexOnCiBuildsUserId < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- add_concurrent_index :ci_builds, :user_id
- end
-
- def down
- remove_concurrent_index :ci_builds, :user_id if index_exists?(:ci_builds, :user_id)
- end
-end
diff --git a/db/migrate/20170424142900_add_index_to_web_hooks_type.rb b/db/migrate/20170424142900_add_index_to_web_hooks_type.rb
deleted file mode 100644
index 1c56c1ed65a..00000000000
--- a/db/migrate/20170424142900_add_index_to_web_hooks_type.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-class AddIndexToWebHooksType < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- add_concurrent_index :web_hooks, :type
- end
-
- def down
- remove_concurrent_index :web_hooks, :type
- end
-end
diff --git a/db/migrate/20170425112128_create_pipeline_schedules_table.rb b/db/migrate/20170425112128_create_pipeline_schedules_table.rb
deleted file mode 100644
index e66e81b34be..00000000000
--- a/db/migrate/20170425112128_create_pipeline_schedules_table.rb
+++ /dev/null
@@ -1,29 +0,0 @@
-# rubocop:disable Migration/Timestamps
-class CreatePipelineSchedulesTable < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def up
- create_table :ci_pipeline_schedules do |t|
- t.string :description
- t.string :ref
- t.string :cron
- t.string :cron_timezone
- t.datetime :next_run_at
- t.integer :project_id
- t.integer :owner_id
- t.boolean :active, default: true
- t.datetime :deleted_at
-
- t.timestamps null: true
- end
-
- add_index(:ci_pipeline_schedules, :project_id)
- add_index(:ci_pipeline_schedules, [:next_run_at, :active])
- end
-
- def down
- drop_table :ci_pipeline_schedules
- end
-end
diff --git a/db/migrate/20170425112628_remove_foreigh_key_ci_trigger_schedules.rb b/db/migrate/20170425112628_remove_foreigh_key_ci_trigger_schedules.rb
deleted file mode 100644
index d89c4c61cbe..00000000000
--- a/db/migrate/20170425112628_remove_foreigh_key_ci_trigger_schedules.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-class RemoveForeighKeyCiTriggerSchedules < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def up
- if fk_on_trigger_schedules?
- remove_foreign_key :ci_trigger_schedules, column: :trigger_id
- end
- end
-
- def down
- # no op, the foreign key should not have been here
- end
-
- private
-
- # Not made more generic and lifted to the helpers as Rails 5 will provide
- # such an API
- def fk_on_trigger_schedules?
- connection.foreign_keys(:ci_trigger_schedules).include?("ci_triggers")
- end
-end
diff --git a/db/migrate/20170425114731_add_pipeline_schedule_id_to_pipelines.rb b/db/migrate/20170425114731_add_pipeline_schedule_id_to_pipelines.rb
deleted file mode 100644
index da16d89febc..00000000000
--- a/db/migrate/20170425114731_add_pipeline_schedule_id_to_pipelines.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-class AddPipelineScheduleIdToPipelines < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def change
- add_column :ci_pipelines, :pipeline_schedule_id, :integer
- end
-end
diff --git a/db/migrate/20170426175636_fill_missing_uuid_on_application_settings.rb b/db/migrate/20170426175636_fill_missing_uuid_on_application_settings.rb
deleted file mode 100644
index eeeb216f32c..00000000000
--- a/db/migrate/20170426175636_fill_missing_uuid_on_application_settings.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-class FillMissingUuidOnApplicationSettings < ActiveRecord::Migration[4.2]
- DOWNTIME = false
-
- def up
- execute("UPDATE application_settings SET uuid = #{quote(SecureRandom.uuid)} WHERE uuid is NULL")
- end
-
- def down
- end
-end
diff --git a/db/migrate/20170426181740_add_index_on_ci_runners_contacted_at.rb b/db/migrate/20170426181740_add_index_on_ci_runners_contacted_at.rb
deleted file mode 100644
index e14b2eb4c8a..00000000000
--- a/db/migrate/20170426181740_add_index_on_ci_runners_contacted_at.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class AddIndexOnCiRunnersContactedAt < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- add_concurrent_index :ci_runners, :contacted_at
- end
-
- def down
- remove_concurrent_index :ci_runners, :contacted_at if index_exists?(:ci_runners, :contacted_at)
- end
-end
diff --git a/db/migrate/20170427103502_create_web_hook_logs.rb b/db/migrate/20170427103502_create_web_hook_logs.rb
deleted file mode 100644
index a7a061e7bae..00000000000
--- a/db/migrate/20170427103502_create_web_hook_logs.rb
+++ /dev/null
@@ -1,22 +0,0 @@
-# rubocop:disable all
-class CreateWebHookLogs < ActiveRecord::Migration[4.2]
- DOWNTIME = false
-
- def change
- create_table :web_hook_logs do |t|
- t.references :web_hook, null: false, index: true, foreign_key: { on_delete: :cascade }
-
- t.string :trigger
- t.string :url
- t.text :request_headers
- t.text :request_data
- t.text :response_headers
- t.text :response_body
- t.string :response_status
- t.float :execution_duration
- t.string :internal_error_message
-
- t.timestamps null: false
- end
- end
-end
diff --git a/db/migrate/20170427215854_create_redirect_routes.rb b/db/migrate/20170427215854_create_redirect_routes.rb
deleted file mode 100644
index 069c9b39d37..00000000000
--- a/db/migrate/20170427215854_create_redirect_routes.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-# rubocop:disable Migration/Timestamps
-class CreateRedirectRoutes < ActiveRecord::Migration[4.2]
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- def change
- create_table :redirect_routes do |t|
- t.integer :source_id, null: false
- t.string :source_type, null: false
- t.string :path, null: false
-
- t.timestamps null: false
- end
- end
-end
diff --git a/db/migrate/20170428064307_add_column_delete_error_to_projects.rb b/db/migrate/20170428064307_add_column_delete_error_to_projects.rb
deleted file mode 100644
index bef0373309c..00000000000
--- a/db/migrate/20170428064307_add_column_delete_error_to_projects.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-class AddColumnDeleteErrorToProjects < ActiveRecord::Migration[4.2]
- DOWNTIME = false
-
- def change
- add_column :projects, :delete_error, :text
- end
-end
diff --git a/db/migrate/20170502065653_make_auto_cancel_pending_pipelines_on_by_default.rb b/db/migrate/20170502065653_make_auto_cancel_pending_pipelines_on_by_default.rb
deleted file mode 100644
index e51a790de4d..00000000000
--- a/db/migrate/20170502065653_make_auto_cancel_pending_pipelines_on_by_default.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-class MakeAutoCancelPendingPipelinesOnByDefault < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def up
- change_column_default(:projects, :auto_cancel_pending_pipelines, 1)
- end
-
- def down
- change_column_default(:projects, :auto_cancel_pending_pipelines, 0)
- end
-end
diff --git a/db/migrate/20170502091007_markdown_cache_limits_to_mysql.rb b/db/migrate/20170502091007_markdown_cache_limits_to_mysql.rb
deleted file mode 100644
index 1c5d4997d40..00000000000
--- a/db/migrate/20170502091007_markdown_cache_limits_to_mysql.rb
+++ /dev/null
@@ -1 +0,0 @@
-require_relative 'markdown_cache_limits_to_mysql'
diff --git a/db/migrate/20170502135553_create_index_ci_pipelines_auto_canceled_by_id.rb b/db/migrate/20170502135553_create_index_ci_pipelines_auto_canceled_by_id.rb
deleted file mode 100644
index 7acae645c7b..00000000000
--- a/db/migrate/20170502135553_create_index_ci_pipelines_auto_canceled_by_id.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-class CreateIndexCiPipelinesAutoCanceledById < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- # MySQL would already have the index
- unless index_exists?(:ci_pipelines, :auto_canceled_by_id)
- add_concurrent_index(:ci_pipelines, :auto_canceled_by_id)
- end
- end
-
- def down
- # We cannot remove index for MySQL because it's needed for foreign key
- if Gitlab::Database.postgresql?
- remove_concurrent_index(:ci_pipelines, :auto_canceled_by_id)
- end
- end
-end
diff --git a/db/migrate/20170502140503_create_index_ci_builds_auto_canceled_by_id.rb b/db/migrate/20170502140503_create_index_ci_builds_auto_canceled_by_id.rb
deleted file mode 100644
index f5148f6fdb8..00000000000
--- a/db/migrate/20170502140503_create_index_ci_builds_auto_canceled_by_id.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-class CreateIndexCiBuildsAutoCanceledById < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- # MySQL would already have the index
- unless index_exists?(:ci_builds, :auto_canceled_by_id)
- add_concurrent_index(:ci_builds, :auto_canceled_by_id)
- end
- end
-
- def down
- # We cannot remove index for MySQL because it's needed for foreign key
- if Gitlab::Database.postgresql?
- remove_concurrent_index(:ci_builds, :auto_canceled_by_id)
- end
- end
-end
diff --git a/db/migrate/20170503004125_add_last_repository_updated_at_to_projects.rb b/db/migrate/20170503004125_add_last_repository_updated_at_to_projects.rb
deleted file mode 100644
index 303250ff3b0..00000000000
--- a/db/migrate/20170503004125_add_last_repository_updated_at_to_projects.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-# rubocop:disable Migration/Datetime
-class AddLastRepositoryUpdatedAtToProjects < ActiveRecord::Migration[4.2]
- DOWNTIME = false
-
- def change
- add_column :projects, :last_repository_updated_at, :datetime
- end
-end
diff --git a/db/migrate/20170503004425_add_index_to_last_repository_updated_at_on_projects.rb b/db/migrate/20170503004425_add_index_to_last_repository_updated_at_on_projects.rb
deleted file mode 100644
index ae54cfb39f5..00000000000
--- a/db/migrate/20170503004425_add_index_to_last_repository_updated_at_on_projects.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-class AddIndexToLastRepositoryUpdatedAtOnProjects < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- add_concurrent_index(:projects, :last_repository_updated_at)
- end
-
- def down
- remove_concurrent_index(:projects, :last_repository_updated_at) if index_exists?(:projects, :last_repository_updated_at)
- end
-end
diff --git a/db/migrate/20170503004426_add_retried_to_ci_build.rb b/db/migrate/20170503004426_add_retried_to_ci_build.rb
deleted file mode 100644
index ff2e0ba64c5..00000000000
--- a/db/migrate/20170503004426_add_retried_to_ci_build.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-class AddRetriedToCiBuild < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def change
- add_column(:ci_builds, :retried, :boolean)
- end
-end
diff --git a/db/migrate/20170503021915_add_last_edited_at_and_last_edited_by_id_to_issues.rb b/db/migrate/20170503021915_add_last_edited_at_and_last_edited_by_id_to_issues.rb
deleted file mode 100644
index ef527bb8007..00000000000
--- a/db/migrate/20170503021915_add_last_edited_at_and_last_edited_by_id_to_issues.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-# rubocop:disable Migration/Datetime
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class AddLastEditedAtAndLastEditedByIdToIssues < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- def change
- add_column :issues, :last_edited_at, :timestamp
- add_column :issues, :last_edited_by_id, :integer
- end
-end
diff --git a/db/migrate/20170503022548_add_last_edited_at_and_last_edited_by_id_to_merge_requests.rb b/db/migrate/20170503022548_add_last_edited_at_and_last_edited_by_id_to_merge_requests.rb
deleted file mode 100644
index 19b8a9d66e7..00000000000
--- a/db/migrate/20170503022548_add_last_edited_at_and_last_edited_by_id_to_merge_requests.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-# rubocop:disable Migration/Datetime
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class AddLastEditedAtAndLastEditedByIdToMergeRequests < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- def change
- add_column :merge_requests, :last_edited_at, :timestamp
- add_column :merge_requests, :last_edited_by_id, :integer
- end
-end
diff --git a/db/migrate/20170503023315_add_repository_update_events_to_web_hooks.rb b/db/migrate/20170503023315_add_repository_update_events_to_web_hooks.rb
deleted file mode 100644
index 4824c404ec7..00000000000
--- a/db/migrate/20170503023315_add_repository_update_events_to_web_hooks.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-class AddRepositoryUpdateEventsToWebHooks < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- add_column_with_default :web_hooks, :repository_update_events, :boolean, default: false, allow_null: false
- end
-
- def down
- remove_column :web_hooks, :repository_update_events
- end
-end
diff --git a/db/migrate/20170503114228_add_description_to_snippets.rb b/db/migrate/20170503114228_add_description_to_snippets.rb
deleted file mode 100644
index 78151ed9ff6..00000000000
--- a/db/migrate/20170503114228_add_description_to_snippets.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-class AddDescriptionToSnippets < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def change
- add_column :snippets, :description, :text
- add_column :snippets, :description_html, :text
- end
-end
diff --git a/db/migrate/20170503140201_reschedule_project_authorizations.rb b/db/migrate/20170503140201_reschedule_project_authorizations.rb
deleted file mode 100644
index aa940bed2d3..00000000000
--- a/db/migrate/20170503140201_reschedule_project_authorizations.rb
+++ /dev/null
@@ -1,44 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class RescheduleProjectAuthorizations < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- class User < ActiveRecord::Base
- self.table_name = 'users'
- end
-
- def up
- offset = 0
- batch = 5000
- start = Time.now
-
- loop do
- relation = User.where('id > ?', offset)
- user_ids = relation.limit(batch).reorder(id: :asc).pluck(:id)
-
- break if user_ids.empty?
-
- offset = user_ids.last
-
- # This will schedule each batch 5 minutes after the previous batch was
- # scheduled. This smears out the load over time, instead of immediately
- # scheduling a million jobs.
- Sidekiq::Client.push_bulk(
- 'queue' => 'authorized_projects',
- 'args' => user_ids.zip,
- 'class' => 'AuthorizedProjectsWorker',
- 'at' => start.to_i
- )
-
- start += 5.minutes
- end
- end
-
- def down
- end
-end
diff --git a/db/migrate/20170503140202_turn_nested_groups_into_regular_groups_for_mysql.rb b/db/migrate/20170503140202_turn_nested_groups_into_regular_groups_for_mysql.rb
deleted file mode 100644
index 65b2c6a57be..00000000000
--- a/db/migrate/20170503140202_turn_nested_groups_into_regular_groups_for_mysql.rb
+++ /dev/null
@@ -1,116 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-# This migration depends on code external to it. For example, it relies on
-# updating a namespace to also rename directories (uploads, GitLab pages, etc).
-# The alternative is to copy hundreds of lines of code into this migration,
-# adjust them where needed, etc; something which doesn't work well at all.
-class TurnNestedGroupsIntoRegularGroupsForMysql < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- def run_migration?
- Gitlab::Database.mysql?
- end
-
- def up
- return unless run_migration?
-
- # For all sub-groups we need to give the right people access. We do this as
- # follows:
- #
- # 1. Get all the ancestors for the current namespace
- # 2. Get all the members of these namespaces, along with their higher access
- # level
- # 3. Give these members access to the current namespace
- Namespace.unscoped.where('parent_id IS NOT NULL').find_each do |namespace|
- rows = []
- existing = namespace.members.pluck(:user_id)
-
- all_members_for(namespace).each do |member|
- next if existing.include?(member[:user_id])
-
- rows << {
- access_level: member[:access_level],
- source_id: namespace.id,
- source_type: 'Namespace',
- user_id: member[:user_id],
- notification_level: 3, # global
- type: 'GroupMember',
- created_at: Time.current,
- updated_at: Time.current
- }
- end
-
- bulk_insert_members(rows)
-
- namespace.update!(parent_id: nil, path: new_path_for(namespace))
- end
- end
-
- def down
- # There is no way to go back from regular groups to nested groups.
- end
-
- # Generates a new (unique) path for a namespace.
- def new_path_for(namespace)
- counter = 1
- base = namespace.full_path.tr('/', '-')
- new_path = base
-
- while Namespace.unscoped.where(path: new_path).exists?
- new_path = base + "-#{counter}"
- counter += 1
- end
-
- new_path
- end
-
- # Returns an Array containing all the ancestors of the current namespace.
- #
- # This method is not particularly efficient, but it's probably still faster
- # than using the "routes" table. Most importantly of all, it _only_ depends
- # on the namespaces table and the "parent_id" column.
- def ancestors_for(namespace)
- ancestors = []
- current = namespace
-
- while current&.parent_id
- # We're using find_by(id: ...) here to deal with cases where the
- # parent_id may point to a missing row.
- current = Namespace.unscoped.select([:id, :parent_id])
- .find_by(id: current.parent_id)
-
- ancestors << current.id if current
- end
-
- ancestors
- end
-
- # Returns a relation containing all the members that have access to any of
- # the current namespace's parent namespaces.
- def all_members_for(namespace)
- Member
- .unscoped
- .select(['user_id', 'MAX(access_level) AS access_level'])
- .where(source_type: 'Namespace', source_id: ancestors_for(namespace))
- .group(:user_id)
- end
-
- def bulk_insert_members(rows)
- return if rows.empty?
-
- keys = rows.first.keys
-
- tuples = rows.map do |row|
- row.map { |(_, value)| connection.quote(value) }
- end
-
- execute <<-EOF.strip_heredoc
- INSERT INTO members (#{keys.join(', ')})
- VALUES #{tuples.map { |tuple| "(#{tuple.join(', ')})" }.join(', ')}
- EOF
- end
-end
diff --git a/db/migrate/20170503184421_add_index_to_redirect_routes.rb b/db/migrate/20170503184421_add_index_to_redirect_routes.rb
deleted file mode 100644
index 6320d4bbc99..00000000000
--- a/db/migrate/20170503184421_add_index_to_redirect_routes.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class AddIndexToRedirectRoutes < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- add_concurrent_index(:redirect_routes, :path, unique: true)
- add_concurrent_index(:redirect_routes, [:source_type, :source_id])
- end
-
- def down
- remove_concurrent_index(:redirect_routes, :path) if index_exists?(:redirect_routes, :path)
- remove_concurrent_index(:redirect_routes, [:source_type, :source_id]) if index_exists?(:redirect_routes, [:source_type, :source_id])
- end
-end
diff --git a/db/migrate/20170503185032_index_redirect_routes_path_for_like.rb b/db/migrate/20170503185032_index_redirect_routes_path_for_like.rb
deleted file mode 100644
index 5d06fd0511c..00000000000
--- a/db/migrate/20170503185032_index_redirect_routes_path_for_like.rb
+++ /dev/null
@@ -1,28 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class IndexRedirectRoutesPathForLike < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- INDEX_NAME = 'index_redirect_routes_on_path_text_pattern_ops'
-
- disable_ddl_transaction!
-
- def up
- return unless Gitlab::Database.postgresql?
-
- unless index_exists?(:redirect_routes, :path, name: INDEX_NAME)
- execute("CREATE INDEX CONCURRENTLY #{INDEX_NAME} ON redirect_routes (path varchar_pattern_ops);")
- end
- end
-
- def down
- return unless Gitlab::Database.postgresql?
- return unless index_exists?(:redirect_routes, :path, name: INDEX_NAME)
-
- remove_concurrent_index_by_name(:redirect_routes, INDEX_NAME)
- end
-end
diff --git a/db/migrate/20170504102911_add_clientside_sentry_to_application_settings.rb b/db/migrate/20170504102911_add_clientside_sentry_to_application_settings.rb
deleted file mode 100644
index 4659f694020..00000000000
--- a/db/migrate/20170504102911_add_clientside_sentry_to_application_settings.rb
+++ /dev/null
@@ -1,33 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class AddClientsideSentryToApplicationSettings < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- # When a migration requires downtime you **must** uncomment the following
- # constant and define a short and easy to understand explanation as to why the
- # migration requires downtime.
- # DOWNTIME_REASON = ''
-
- # When using "add_concurrent_index" or "remove_concurrent_index" methods make sure
- # that either of them is the _only_ method called in the migration,
- # any other changes should go in a separate migration.
- # This ensures that upon failure _only_ the index creation or removing fails
- # and can be retried or reverted easily.
- #
- # To disable transactions uncomment the following line and remove these
- # comments:
- disable_ddl_transaction!
-
- def up
- add_column_with_default :application_settings, :clientside_sentry_enabled, :boolean, default: false
- add_column :application_settings, :clientside_sentry_dsn, :string
- end
-
- def down
- remove_columns :application_settings, :clientside_sentry_enabled, :clientside_sentry_dsn
- end
-end
diff --git a/db/migrate/20170504182103_add_index_project_group_links_group_id.rb b/db/migrate/20170504182103_add_index_project_group_links_group_id.rb
deleted file mode 100644
index 5b1c14e66dd..00000000000
--- a/db/migrate/20170504182103_add_index_project_group_links_group_id.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class AddIndexProjectGroupLinksGroupId < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- add_concurrent_index :project_group_links, :group_id
- end
-
- def down
- remove_concurrent_index :project_group_links, :group_id
- end
-end
diff --git a/db/migrate/20170506085040_add_index_to_pipeline_pipeline_schedule_id.rb b/db/migrate/20170506085040_add_index_to_pipeline_pipeline_schedule_id.rb
deleted file mode 100644
index 9d8cc8a83a2..00000000000
--- a/db/migrate/20170506085040_add_index_to_pipeline_pipeline_schedule_id.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-class AddIndexToPipelinePipelineScheduleId < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- unless index_exists?(:ci_pipelines, :pipeline_schedule_id)
- add_concurrent_index(:ci_pipelines, :pipeline_schedule_id)
- end
- end
-
- def down
- if index_exists?(:ci_pipelines, :pipeline_schedule_id)
- remove_concurrent_index(:ci_pipelines, :pipeline_schedule_id)
- end
- end
-end
diff --git a/db/migrate/20170506091344_add_foreign_key_to_pipeline_schedules.rb b/db/migrate/20170506091344_add_foreign_key_to_pipeline_schedules.rb
deleted file mode 100644
index 244e41e2f07..00000000000
--- a/db/migrate/20170506091344_add_foreign_key_to_pipeline_schedules.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-class AddForeignKeyToPipelineSchedules < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- add_concurrent_foreign_key :ci_pipeline_schedules, :projects, column: :project_id
- end
-
- def down
- remove_foreign_key :ci_pipeline_schedules, :projects
- end
-end
diff --git a/db/migrate/20170506185517_add_foreign_key_pipeline_schedules_and_pipelines.rb b/db/migrate/20170506185517_add_foreign_key_pipeline_schedules_and_pipelines.rb
deleted file mode 100644
index 50364cac259..00000000000
--- a/db/migrate/20170506185517_add_foreign_key_pipeline_schedules_and_pipelines.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-class AddForeignKeyPipelineSchedulesAndPipelines < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- on_delete =
- if Gitlab::Database.mysql?
- :nullify
- else
- 'SET NULL'
- end
-
- add_concurrent_foreign_key :ci_pipelines, :ci_pipeline_schedules,
- column: :pipeline_schedule_id, on_delete: on_delete
- end
-
- def down
- remove_foreign_key :ci_pipelines, column: :pipeline_schedule_id
- end
-end
diff --git a/db/migrate/20170507205316_add_head_pipeline_id_to_merge_requests.rb b/db/migrate/20170507205316_add_head_pipeline_id_to_merge_requests.rb
deleted file mode 100644
index adfe6559084..00000000000
--- a/db/migrate/20170507205316_add_head_pipeline_id_to_merge_requests.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-class AddHeadPipelineIdToMergeRequests < ActiveRecord::Migration[4.2]
- DOWNTIME = false
-
- def change
- add_column :merge_requests, :head_pipeline_id, :integer
- end
-end
diff --git a/db/migrate/20170508153950_add_not_null_contraints_to_ci_variables.rb b/db/migrate/20170508153950_add_not_null_contraints_to_ci_variables.rb
deleted file mode 100644
index 2a0c7132bfd..00000000000
--- a/db/migrate/20170508153950_add_not_null_contraints_to_ci_variables.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-class AddNotNullContraintsToCiVariables < ActiveRecord::Migration[4.2]
- DOWNTIME = false
-
- def up
- change_column(:ci_variables, :key, :string, null: false)
- change_column(:ci_variables, :project_id, :integer, null: false)
- end
-
- def down
- # no op
- end
-end
diff --git a/db/migrate/20170508190732_add_foreign_key_to_ci_variables.rb b/db/migrate/20170508190732_add_foreign_key_to_ci_variables.rb
deleted file mode 100644
index 305366b2171..00000000000
--- a/db/migrate/20170508190732_add_foreign_key_to_ci_variables.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-class AddForeignKeyToCiVariables < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- execute <<~SQL
- DELETE FROM ci_variables
- WHERE NOT EXISTS (
- SELECT true
- FROM projects
- WHERE projects.id = ci_variables.project_id
- )
- SQL
-
- add_concurrent_foreign_key(:ci_variables, :projects, column: :project_id)
- end
-
- def down
- remove_foreign_key(:ci_variables, column: :project_id)
- end
-end
diff --git a/db/migrate/20170511082759_rename_web_hooks_build_events_to_job_events.rb b/db/migrate/20170511082759_rename_web_hooks_build_events_to_job_events.rb
deleted file mode 100644
index 3a44057d948..00000000000
--- a/db/migrate/20170511082759_rename_web_hooks_build_events_to_job_events.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class RenameWebHooksBuildEventsToJobEvents < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- rename_column_concurrently :web_hooks, :build_events, :job_events
- end
-
- def down
- cleanup_concurrent_column_rename :web_hooks, :job_events, :build_events
- end
-end
diff --git a/db/migrate/20170511083824_rename_services_build_events_to_job_events.rb b/db/migrate/20170511083824_rename_services_build_events_to_job_events.rb
deleted file mode 100644
index 713adde76ef..00000000000
--- a/db/migrate/20170511083824_rename_services_build_events_to_job_events.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class RenameServicesBuildEventsToJobEvents < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- rename_column_concurrently :services, :build_events, :job_events
- end
-
- def down
- cleanup_concurrent_column_rename :services, :job_events, :build_events
- end
-end
diff --git a/db/migrate/20170516153305_migrate_assignee_to_separate_table.rb b/db/migrate/20170516153305_migrate_assignee_to_separate_table.rb
deleted file mode 100644
index 0ed45775421..00000000000
--- a/db/migrate/20170516153305_migrate_assignee_to_separate_table.rb
+++ /dev/null
@@ -1,83 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class MigrateAssigneeToSeparateTable < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- # When a migration requires downtime you **must** uncomment the following
- # constant and define a short and easy to understand explanation as to why the
- # migration requires downtime.
- # DOWNTIME_REASON = ''
-
- # When using the methods "add_concurrent_index", "remove_concurrent_index" or
- # "add_column_with_default" you must disable the use of transactions
- # as these methods can not run in an existing transaction.
- # When using "add_concurrent_index" or "remove_concurrent_index" methods make sure
- # that either of them is the _only_ method called in the migration,
- # any other changes should go in a separate migration.
- # This ensures that upon failure _only_ the index creation or removing fails
- # and can be retried or reverted easily.
- #
- # To disable transactions uncomment the following line and remove these
- # comments:
- # disable_ddl_transaction!
-
- def up
- drop_table(:issue_assignees) if table_exists?(:issue_assignees)
-
- if Gitlab::Database.mysql?
- execute <<-EOF
- CREATE TABLE issue_assignees AS
- SELECT assignee_id AS user_id, id AS issue_id FROM issues WHERE assignee_id IS NOT NULL
- EOF
- else
- ActiveRecord::Base.transaction do
- execute('LOCK TABLE issues IN EXCLUSIVE MODE')
-
- execute <<-EOF
- CREATE TABLE issue_assignees AS
- SELECT assignee_id AS user_id, id AS issue_id FROM issues WHERE assignee_id IS NOT NULL
- EOF
-
- execute <<-EOF
- CREATE OR REPLACE FUNCTION replicate_assignee_id()
- RETURNS trigger AS
- $BODY$
- BEGIN
- if OLD IS NOT NULL AND OLD.assignee_id IS NOT NULL THEN
- DELETE FROM issue_assignees WHERE issue_id = OLD.id;
- END IF;
-
- if NEW.assignee_id IS NOT NULL THEN
- INSERT INTO issue_assignees (user_id, issue_id) VALUES (NEW.assignee_id, NEW.id);
- END IF;
-
- RETURN NEW;
- END;
- $BODY$
- LANGUAGE 'plpgsql'
- VOLATILE;
-
- CREATE TRIGGER replicate_assignee_id
- BEFORE INSERT OR UPDATE OF assignee_id
- ON issues
- FOR EACH ROW EXECUTE PROCEDURE replicate_assignee_id();
- EOF
- end
- end
- end
-
- def down
- drop_table(:issue_assignees) if table_exists?(:issue_assignees)
-
- if Gitlab::Database.postgresql?
- execute <<-EOF
- DROP TRIGGER IF EXISTS replicate_assignee_id ON issues;
- DROP FUNCTION IF EXISTS replicate_assignee_id();
- EOF
- end
- end
-end
diff --git a/db/migrate/20170516183131_add_indices_to_issue_assignees.rb b/db/migrate/20170516183131_add_indices_to_issue_assignees.rb
deleted file mode 100644
index 6877fe9ff98..00000000000
--- a/db/migrate/20170516183131_add_indices_to_issue_assignees.rb
+++ /dev/null
@@ -1,41 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class AddIndicesToIssueAssignees < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- # When a migration requires downtime you **must** uncomment the following
- # constant and define a short and easy to understand explanation as to why the
- # migration requires downtime.
- # DOWNTIME_REASON = ''
-
- # When using the methods "add_concurrent_index", "remove_concurrent_index" or
- # "add_column_with_default" you must disable the use of transactions
- # as these methods can not run in an existing transaction.
- # When using "add_concurrent_index" or "remove_concurrent_index" methods make sure
- # that either of them is the _only_ method called in the migration,
- # any other changes should go in a separate migration.
- # This ensures that upon failure _only_ the index creation or removing fails
- # and can be retried or reverted easily.
- #
- # To disable transactions uncomment the following line and remove these
- # comments:
- disable_ddl_transaction!
-
- def up
- add_concurrent_index :issue_assignees, [:issue_id, :user_id], unique: true, name: 'index_issue_assignees_on_issue_id_and_user_id'
- add_concurrent_index :issue_assignees, :user_id, name: 'index_issue_assignees_on_user_id'
- add_concurrent_foreign_key :issue_assignees, :users, column: :user_id, on_delete: :cascade
- add_concurrent_foreign_key :issue_assignees, :issues, column: :issue_id, on_delete: :cascade
- end
-
- def down
- remove_foreign_key :issue_assignees, column: :user_id
- remove_foreign_key :issue_assignees, column: :issue_id
- remove_concurrent_index :issue_assignees, [:issue_id, :user_id] if index_exists?(:issue_assignees, [:issue_id, :user_id])
- remove_concurrent_index :issue_assignees, :user_id if index_exists?(:issue_assignees, :user_id)
- end
-end
diff --git a/db/migrate/20170519102115_add_prometheus_settings_to_metrics_settings.rb b/db/migrate/20170519102115_add_prometheus_settings_to_metrics_settings.rb
deleted file mode 100644
index 9c8f58104bd..00000000000
--- a/db/migrate/20170519102115_add_prometheus_settings_to_metrics_settings.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-class AddPrometheusSettingsToMetricsSettings < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- disable_ddl_transaction!
-
- DOWNTIME = false
-
- def up
- add_column_with_default(:application_settings, :prometheus_metrics_enabled, :boolean,
- default: false, allow_null: false)
- end
-
- def down
- remove_column(:application_settings, :prometheus_metrics_enabled)
- end
-end
diff --git a/db/migrate/20170521184006_add_change_position_to_notes.rb b/db/migrate/20170521184006_add_change_position_to_notes.rb
deleted file mode 100644
index f0ca3a2a9ea..00000000000
--- a/db/migrate/20170521184006_add_change_position_to_notes.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class AddChangePositionToNotes < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- def change
- add_column :notes, :change_position, :text
- end
-end
diff --git a/db/migrate/20170523091700_add_rss_token_to_users.rb b/db/migrate/20170523091700_add_rss_token_to_users.rb
deleted file mode 100644
index e1bcd9b3fee..00000000000
--- a/db/migrate/20170523091700_add_rss_token_to_users.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-class AddRssTokenToUsers < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- add_column :users, :rss_token, :string
-
- add_concurrent_index :users, :rss_token
- end
-
- def down
- remove_concurrent_index :users, :rss_token if index_exists? :users, :rss_token
-
- remove_column :users, :rss_token
- end
-end
diff --git a/db/migrate/20170523121229_create_conversational_development_index_metrics.rb b/db/migrate/20170523121229_create_conversational_development_index_metrics.rb
deleted file mode 100644
index 5f8c0d07e3c..00000000000
--- a/db/migrate/20170523121229_create_conversational_development_index_metrics.rb
+++ /dev/null
@@ -1,40 +0,0 @@
-# rubocop:disable Migration/Timestamps
-class CreateConversationalDevelopmentIndexMetrics < ActiveRecord::Migration[4.2]
- DOWNTIME = false
-
- def change
- create_table :conversational_development_index_metrics do |t|
- t.float :leader_issues, null: false
- t.float :instance_issues, null: false
-
- t.float :leader_notes, null: false
- t.float :instance_notes, null: false
-
- t.float :leader_milestones, null: false
- t.float :instance_milestones, null: false
-
- t.float :leader_boards, null: false
- t.float :instance_boards, null: false
-
- t.float :leader_merge_requests, null: false
- t.float :instance_merge_requests, null: false
-
- t.float :leader_ci_pipelines, null: false
- t.float :instance_ci_pipelines, null: false
-
- t.float :leader_environments, null: false
- t.float :instance_environments, null: false
-
- t.float :leader_deployments, null: false
- t.float :instance_deployments, null: false
-
- t.float :leader_projects_prometheus_active, null: false
- t.float :instance_projects_prometheus_active, null: false
-
- t.float :leader_service_desk_issues, null: false
- t.float :instance_service_desk_issues, null: false
-
- t.timestamps null: false
- end
- end
-end
diff --git a/db/migrate/20170524125940_add_source_to_ci_pipeline.rb b/db/migrate/20170524125940_add_source_to_ci_pipeline.rb
deleted file mode 100644
index 81358e7ce3d..00000000000
--- a/db/migrate/20170524125940_add_source_to_ci_pipeline.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-class AddSourceToCiPipeline < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def change
- add_column :ci_pipelines, :source, :integer
- end
-end
diff --git a/db/migrate/20170524161101_add_protected_to_ci_variables.rb b/db/migrate/20170524161101_add_protected_to_ci_variables.rb
deleted file mode 100644
index 6125ea5d5a8..00000000000
--- a/db/migrate/20170524161101_add_protected_to_ci_variables.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-class AddProtectedToCiVariables < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- add_column_with_default(:ci_variables, :protected, :boolean, default: false)
- end
-
- def down
- remove_column(:ci_variables, :protected)
- end
-end
diff --git a/db/migrate/20170525130346_create_group_variables_table.rb b/db/migrate/20170525130346_create_group_variables_table.rb
deleted file mode 100644
index 6eae7eff7bd..00000000000
--- a/db/migrate/20170525130346_create_group_variables_table.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-class CreateGroupVariablesTable < ActiveRecord::Migration[4.2]
- DOWNTIME = false
-
- def up
- create_table :ci_group_variables do |t|
- t.string :key, null: false
- t.text :value
- t.text :encrypted_value
- t.string :encrypted_value_salt
- t.string :encrypted_value_iv
- t.integer :group_id, null: false
- t.boolean :protected, default: false, null: false
-
- t.timestamps_with_timezone null: false
- end
-
- add_index :ci_group_variables, [:group_id, :key], unique: true
- end
-
- def down
- drop_table :ci_group_variables
- end
-end
diff --git a/db/migrate/20170525130758_add_foreign_key_to_group_variables.rb b/db/migrate/20170525130758_add_foreign_key_to_group_variables.rb
deleted file mode 100644
index f1f51a1dda3..00000000000
--- a/db/migrate/20170525130758_add_foreign_key_to_group_variables.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-class AddForeignKeyToGroupVariables < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- add_concurrent_foreign_key :ci_group_variables, :namespaces, column: :group_id
- end
-
- def down
- remove_foreign_key :ci_group_variables, column: :group_id
- end
-end
diff --git a/db/migrate/20170525132202_create_pipeline_stages.rb b/db/migrate/20170525132202_create_pipeline_stages.rb
deleted file mode 100644
index 0a6400fde90..00000000000
--- a/db/migrate/20170525132202_create_pipeline_stages.rb
+++ /dev/null
@@ -1,26 +0,0 @@
-# rubocop:disable Migration/Timestamps
-class CreatePipelineStages < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- create_table :ci_stages do |t|
- t.integer :project_id
- t.integer :pipeline_id
- t.timestamps null: true
- t.string :name
- end
-
- add_concurrent_foreign_key :ci_stages, :projects, column: :project_id, on_delete: :cascade
- add_concurrent_foreign_key :ci_stages, :ci_pipelines, column: :pipeline_id, on_delete: :cascade
- add_concurrent_index :ci_stages, :project_id
- add_concurrent_index :ci_stages, :pipeline_id
- end
-
- def down
- drop_table :ci_stages
- end
-end
diff --git a/db/migrate/20170525174156_create_feature_tables.rb b/db/migrate/20170525174156_create_feature_tables.rb
deleted file mode 100644
index e1eaaff8d35..00000000000
--- a/db/migrate/20170525174156_create_feature_tables.rb
+++ /dev/null
@@ -1,26 +0,0 @@
-class CreateFeatureTables < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def self.up
- create_table :features do |t|
- t.string :key, null: false
- t.timestamps null: false
- end
- add_index :features, :key, unique: true
-
- create_table :feature_gates do |t|
- t.string :feature_key, null: false
- t.string :key, null: false
- t.string :value
- t.timestamps null: false
- end
- add_index :feature_gates, [:feature_key, :key, :value], unique: true
- end
-
- def self.down
- drop_table :feature_gates
- drop_table :features
- end
-end
diff --git a/db/migrate/20170526185602_add_stage_id_to_ci_builds.rb b/db/migrate/20170526185602_add_stage_id_to_ci_builds.rb
deleted file mode 100644
index 6958557d118..00000000000
--- a/db/migrate/20170526185602_add_stage_id_to_ci_builds.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-class AddStageIdToCiBuilds < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def up
- add_column :ci_builds, :stage_id, :integer
- end
-
- def down
- remove_column :ci_builds, :stage_id, :integer
- end
-end
diff --git a/db/migrate/20170530130129_project_foreign_keys_with_cascading_deletes.rb b/db/migrate/20170530130129_project_foreign_keys_with_cascading_deletes.rb
deleted file mode 100644
index b4658bc4017..00000000000
--- a/db/migrate/20170530130129_project_foreign_keys_with_cascading_deletes.rb
+++ /dev/null
@@ -1,198 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class ProjectForeignKeysWithCascadingDeletes < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- CONCURRENCY = 4
-
- disable_ddl_transaction!
-
- # The tables/columns for which to remove orphans and add foreign keys. Order
- # matters as some tables/columns should be processed before others.
- TABLES = [
- [:boards, :projects, :project_id],
- [:lists, :labels, :label_id],
- [:lists, :boards, :board_id],
- [:services, :projects, :project_id],
- [:forked_project_links, :projects, :forked_to_project_id],
- [:merge_requests, :projects, :target_project_id],
- [:labels, :projects, :project_id],
- [:issues, :projects, :project_id],
- [:events, :projects, :project_id],
- [:milestones, :projects, :project_id],
- [:notes, :projects, :project_id],
- [:snippets, :projects, :project_id],
- [:web_hooks, :projects, :project_id],
- [:protected_branch_merge_access_levels, :protected_branches, :protected_branch_id],
- [:protected_branch_push_access_levels, :protected_branches, :protected_branch_id],
- [:protected_branches, :projects, :project_id],
- [:protected_tags, :projects, :project_id],
- [:deploy_keys_projects, :projects, :project_id],
- [:users_star_projects, :projects, :project_id],
- [:releases, :projects, :project_id],
- [:project_group_links, :projects, :project_id],
- [:pages_domains, :projects, :project_id],
- [:todos, :projects, :project_id],
- [:project_import_data, :projects, :project_id],
- [:project_features, :projects, :project_id],
- [:ci_builds, :projects, :project_id],
- [:ci_pipelines, :projects, :project_id],
- [:ci_runner_projects, :projects, :project_id],
- [:ci_triggers, :projects, :project_id],
- [:environments, :projects, :project_id],
- [:deployments, :projects, :project_id]
- ]
-
- def up
- # These existing foreign keys don't have an "ON DELETE CASCADE" clause.
- remove_foreign_key_without_error(:boards, :project_id)
- remove_foreign_key_without_error(:lists, :label_id)
- remove_foreign_key_without_error(:lists, :board_id)
- remove_foreign_key_without_error(:protected_branch_merge_access_levels,
- :protected_branch_id)
-
- remove_foreign_key_without_error(:protected_branch_push_access_levels,
- :protected_branch_id)
-
- remove_orphaned_rows
- add_foreign_keys
-
- # These columns are not indexed yet, meaning a cascading delete would take
- # forever.
- add_index_if_not_exists(:project_group_links, :project_id)
- add_index_if_not_exists(:pages_domains, :project_id)
- end
-
- def down
- TABLES.each do |(source, _, column)|
- remove_foreign_key_without_error(source, column)
- end
-
- add_foreign_key_if_not_exists(:boards, :projects, column: :project_id)
- add_foreign_key_if_not_exists(:lists, :labels, column: :label_id)
- add_foreign_key_if_not_exists(:lists, :boards, column: :board_id)
-
- add_foreign_key_if_not_exists(:protected_branch_merge_access_levels,
- :protected_branches,
- column: :protected_branch_id)
-
- add_foreign_key_if_not_exists(:protected_branch_push_access_levels,
- :protected_branches,
- column: :protected_branch_id)
-
- remove_index_without_error(:project_group_links, :project_id)
- remove_index_without_error(:pages_domains, :project_id)
- end
-
- def add_foreign_keys
- TABLES.each do |(source, target, column)|
- add_foreign_key_if_not_exists(source, target, column: column)
- end
- end
-
- # Removes orphans from various tables concurrently.
- def remove_orphaned_rows
- Gitlab::Database.with_connection_pool(CONCURRENCY) do |pool|
- queues = queues_for_rows(TABLES)
-
- threads = queues.map do |queue|
- Thread.new do
- pool.with_connection do |connection|
- Thread.current[:foreign_key_connection] = connection
-
- # Disables statement timeouts for the current connection. This is
- # necessary as removing of orphaned data might otherwise exceed the
- # statement timeout.
- disable_statement_timeout do
- remove_orphans(*queue.pop) until queue.empty?
-
- steal_from_queues(queues - [queue])
- end
- end
- end
- end
-
- threads.each(&:join)
- end
- end
-
- def steal_from_queues(queues)
- loop do
- stolen = false
-
- queues.each do |queue|
- # Stealing is racy so it's possible a pop might be called on an
- # already-empty queue.
-
- remove_orphans(*queue.pop(true))
- stolen = true
- rescue ThreadError
- end
-
- break unless stolen
- end
- end
-
- def remove_orphans(source, target, column)
- quoted_source = quote_table_name(source)
- quoted_target = quote_table_name(target)
- quoted_column = quote_column_name(column)
-
- execute <<-EOF.strip_heredoc
- DELETE FROM #{quoted_source}
- WHERE NOT EXISTS (
- SELECT true
- FROM #{quoted_target}
- WHERE #{quoted_target}.id = #{quoted_source}.#{quoted_column}
- )
- AND #{quoted_source}.#{quoted_column} IS NOT NULL
- EOF
- end
-
- def add_foreign_key_if_not_exists(source, target, column:)
- return if foreign_key_exists?(source, target, column: column)
-
- add_concurrent_foreign_key(source, target, column: column)
- end
-
- def add_index_if_not_exists(table, column)
- return if index_exists?(table, column)
-
- add_concurrent_index(table, column)
- end
-
- def remove_foreign_key_without_error(table, column)
- remove_foreign_key(table, column: column)
- rescue ArgumentError
- end
-
- def remove_index_without_error(table, column)
- remove_concurrent_index(table, column)
- rescue ArgumentError
- end
-
- def connection
- # Rails memoizes connection objects, but this causes them to be shared
- # amongst threads; we don't want that.
- Thread.current[:foreign_key_connection] || ActiveRecord::Base.connection
- end
-
- def queues_for_rows(rows)
- queues = Array.new(CONCURRENCY) { Queue.new }
- slice_size = rows.length / CONCURRENCY
-
- # Divide all the tuples as evenly as possible amongst the queues.
- rows.each_slice(slice_size).each_with_index do |slice, index|
- bucket = index % CONCURRENCY
-
- slice.each do |row|
- queues[bucket] << row
- end
- end
-
- queues
- end
-end
diff --git a/db/migrate/20170531180233_add_authorized_keys_enabled_to_application_settings.rb b/db/migrate/20170531180233_add_authorized_keys_enabled_to_application_settings.rb
deleted file mode 100644
index f440609ff8a..00000000000
--- a/db/migrate/20170531180233_add_authorized_keys_enabled_to_application_settings.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class AddAuthorizedKeysEnabledToApplicationSettings < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- add_column_with_default :application_settings, :authorized_keys_enabled, :boolean, default: true, allow_null: false
- end
-
- def down
- remove_column :application_settings, :authorized_keys_enabled
- end
-end
diff --git a/db/migrate/20170531202042_rename_users_ldap_email_to_external_email.rb b/db/migrate/20170531202042_rename_users_ldap_email_to_external_email.rb
deleted file mode 100644
index 7b1a7644555..00000000000
--- a/db/migrate/20170531202042_rename_users_ldap_email_to_external_email.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-class RenameUsersLdapEmailToExternalEmail < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- # rubocop:disable Migration/UpdateLargeTable
- rename_column_concurrently :users, :ldap_email, :external_email
- end
-
- def down
- cleanup_concurrent_column_rename :users, :external_email, :ldap_email
- end
-end
diff --git a/db/migrate/20170601163708_add_artifacts_store_to_ci_build.rb b/db/migrate/20170601163708_add_artifacts_store_to_ci_build.rb
deleted file mode 100644
index 4c9ac821b20..00000000000
--- a/db/migrate/20170601163708_add_artifacts_store_to_ci_build.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-class AddArtifactsStoreToCiBuild < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def change
- add_column(:ci_builds, :artifacts_file_store, :integer)
- add_column(:ci_builds, :artifacts_metadata_store, :integer)
- end
-end
diff --git a/db/migrate/20170602154736_add_help_page_hide_commercial_content_to_application_settings.rb b/db/migrate/20170602154736_add_help_page_hide_commercial_content_to_application_settings.rb
deleted file mode 100644
index ff9e188d7a8..00000000000
--- a/db/migrate/20170602154736_add_help_page_hide_commercial_content_to_application_settings.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-# rubocop:disable Migration/SaferBooleanColumn
-class AddHelpPageHideCommercialContentToApplicationSettings < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def change
- add_column :application_settings, :help_page_hide_commercial_content, :boolean, default: false
- end
-end
diff --git a/db/migrate/20170602154813_add_help_page_support_url_to_application_settings.rb b/db/migrate/20170602154813_add_help_page_support_url_to_application_settings.rb
deleted file mode 100644
index 388e130ab88..00000000000
--- a/db/migrate/20170602154813_add_help_page_support_url_to_application_settings.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-class AddHelpPageSupportUrlToApplicationSettings < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def change
- add_column :application_settings, :help_page_support_url, :string
- end
-end
diff --git a/db/migrate/20170603200744_add_email_provider_to_users.rb b/db/migrate/20170603200744_add_email_provider_to_users.rb
deleted file mode 100644
index ad6e813d31b..00000000000
--- a/db/migrate/20170603200744_add_email_provider_to_users.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-class AddEmailProviderToUsers < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def change
- add_column :users, :email_provider, :string
- end
-end
diff --git a/db/migrate/20170606154216_add_notification_setting_columns.rb b/db/migrate/20170606154216_add_notification_setting_columns.rb
deleted file mode 100644
index 3b9493e6b49..00000000000
--- a/db/migrate/20170606154216_add_notification_setting_columns.rb
+++ /dev/null
@@ -1,26 +0,0 @@
-class AddNotificationSettingColumns < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- COLUMNS = [
- :new_note,
- :new_issue,
- :reopen_issue,
- :close_issue,
- :reassign_issue,
- :new_merge_request,
- :reopen_merge_request,
- :close_merge_request,
- :reassign_merge_request,
- :merge_merge_request,
- :failed_pipeline,
- :success_pipeline
- ]
-
- def change
- COLUMNS.each do |column|
- add_column(:notification_settings, column, :boolean)
- end
- end
-end
diff --git a/db/migrate/20170608152747_prepare_events_table_for_push_events_migration.rb b/db/migrate/20170608152747_prepare_events_table_for_push_events_migration.rb
deleted file mode 100644
index 851af7f7bf6..00000000000
--- a/db/migrate/20170608152747_prepare_events_table_for_push_events_migration.rb
+++ /dev/null
@@ -1,51 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class PrepareEventsTableForPushEventsMigration < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- # The order of these columns is deliberate and results in the following
- # columns and sizes:
- #
- # * id (4 bytes)
- # * project_id (4 bytes)
- # * author_id (4 bytes)
- # * target_id (4 bytes)
- # * created_at (8 bytes)
- # * updated_at (8 bytes)
- # * action (2 bytes)
- # * target_type (variable)
- #
- # Unfortunately we can't make the "id" column a bigint/bigserial as Rails 4
- # does not support this properly.
- create_table :events_for_migration do |t|
- t.references :project,
- index: true,
- foreign_key: { on_delete: :cascade }
-
- t.integer :author_id, index: true, null: false
- t.integer :target_id
-
- t.timestamps_with_timezone null: false
-
- t.integer :action, null: false, limit: 2, index: true
- t.string :target_type
-
- t.index %i[target_type target_id]
- end
-
- # t.references doesn't like it when the column name doesn't make the table
- # name so we have to add the foreign key separately.
- add_concurrent_foreign_key(:events_for_migration, :users, column: :author_id)
- end
-
- def down
- drop_table :events_for_migration
- end
-end
diff --git a/db/migrate/20170608152748_create_push_event_payloads_tables.rb b/db/migrate/20170608152748_create_push_event_payloads_tables.rb
deleted file mode 100644
index 292d9e3ca06..00000000000
--- a/db/migrate/20170608152748_create_push_event_payloads_tables.rb
+++ /dev/null
@@ -1,46 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class CreatePushEventPayloadsTables < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- create_table :push_event_payloads, id: false do |t|
- t.bigint :commit_count, null: false
-
- t.integer :event_id, null: false
- t.integer :action, null: false, limit: 2
- t.integer :ref_type, null: false, limit: 2
-
- t.binary :commit_from
- t.binary :commit_to
-
- t.text :ref
- t.string :commit_title, limit: 70
-
- t.index :event_id, unique: true
- end
-
- # We're adding a foreign key to the _shadow_ table, and this is deliberate.
- # By using the shadow table we don't have to recreate/revalidate this
- # foreign key after swapping the "events_for_migration" and "events" tables.
- #
- # The "events_for_migration" table has a foreign key to "projects.id"
- # ensuring that project removals also remove events from the shadow table
- # (and thus also from this table).
- add_concurrent_foreign_key(
- :push_event_payloads,
- :events_for_migration,
- column: :event_id
- )
- end
-
- def down
- drop_table :push_event_payloads
- end
-end
diff --git a/db/migrate/20170608171156_create_merge_request_diff_files.rb b/db/migrate/20170608171156_create_merge_request_diff_files.rb
deleted file mode 100644
index 94b518455ee..00000000000
--- a/db/migrate/20170608171156_create_merge_request_diff_files.rb
+++ /dev/null
@@ -1,22 +0,0 @@
-class CreateMergeRequestDiffFiles < ActiveRecord::Migration[4.2]
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def change
- create_table :merge_request_diff_files, id: false do |t|
- t.belongs_to :merge_request_diff, null: false, foreign_key: { on_delete: :cascade }
- t.integer :relative_order, null: false
- t.boolean :new_file, null: false
- t.boolean :renamed_file, null: false
- t.boolean :deleted_file, null: false
- t.boolean :too_large, null: false
- t.string :a_mode, null: false
- t.string :b_mode, null: false
- t.text :new_path, null: false
- t.text :old_path, null: false
- t.text :diff, null: false
- t.index [:merge_request_diff_id, :relative_order], name: 'index_merge_request_diff_files_on_mr_diff_id_and_order', unique: true
- end
- end
-end
diff --git a/db/migrate/20170613154149_create_gpg_signatures.rb b/db/migrate/20170613154149_create_gpg_signatures.rb
deleted file mode 100644
index 181d35fe7af..00000000000
--- a/db/migrate/20170613154149_create_gpg_signatures.rb
+++ /dev/null
@@ -1,25 +0,0 @@
-class CreateGpgSignatures < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def change
- create_table :gpg_signatures do |t|
- t.timestamps_with_timezone null: false
-
- t.references :project, index: true, foreign_key: { on_delete: :cascade }
- t.references :gpg_key, index: true, foreign_key: { on_delete: :nullify }
-
- t.boolean :valid_signature
-
- t.binary :commit_sha
- t.binary :gpg_key_primary_keyid
-
- t.text :gpg_key_user_name
- t.text :gpg_key_user_email
-
- 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/20170614115405_merge_request_diff_file_limits_to_mysql.rb b/db/migrate/20170614115405_merge_request_diff_file_limits_to_mysql.rb
deleted file mode 100644
index 4c1cf08aa06..00000000000
--- a/db/migrate/20170614115405_merge_request_diff_file_limits_to_mysql.rb
+++ /dev/null
@@ -1 +0,0 @@
-require_relative 'merge_request_diff_file_limits_to_mysql'
diff --git a/db/migrate/20170616133147_create_merge_request_diff_commits.rb b/db/migrate/20170616133147_create_merge_request_diff_commits.rb
deleted file mode 100644
index 5e148affba2..00000000000
--- a/db/migrate/20170616133147_create_merge_request_diff_commits.rb
+++ /dev/null
@@ -1,20 +0,0 @@
-class CreateMergeRequestDiffCommits < ActiveRecord::Migration[4.2]
- DOWNTIME = false
-
- def change
- create_table :merge_request_diff_commits, id: false do |t|
- t.datetime_with_timezone :authored_date
- t.datetime_with_timezone :committed_date
- t.belongs_to :merge_request_diff, null: false, foreign_key: { on_delete: :cascade }
- t.integer :relative_order, null: false
- t.binary :sha, null: false, limit: 20
- t.text :author_name
- t.text :author_email
- t.text :committer_name
- t.text :committer_email
- t.text :message
-
- t.index [:merge_request_diff_id, :relative_order], name: 'index_merge_request_diff_commits_on_mr_diff_id_and_order', unique: true
- end
- end
-end
diff --git a/db/migrate/20170619144837_add_index_for_head_pipeline_merge_request.rb b/db/migrate/20170619144837_add_index_for_head_pipeline_merge_request.rb
deleted file mode 100644
index f97c8a14b8d..00000000000
--- a/db/migrate/20170619144837_add_index_for_head_pipeline_merge_request.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-class AddIndexForHeadPipelineMergeRequest < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- add_concurrent_index :merge_requests, :head_pipeline_id
- end
-
- def down
- remove_concurrent_index :merge_requests, :head_pipeline_id if index_exists?(:merge_requests, :head_pipeline_id)
- end
-end
diff --git a/db/migrate/20170620064728_create_ci_pipeline_schedule_variables.rb b/db/migrate/20170620064728_create_ci_pipeline_schedule_variables.rb
deleted file mode 100644
index 74f3603505b..00000000000
--- a/db/migrate/20170620064728_create_ci_pipeline_schedule_variables.rb
+++ /dev/null
@@ -1,25 +0,0 @@
-class CreateCiPipelineScheduleVariables < ActiveRecord::Migration[4.2]
- DOWNTIME = false
-
- def up
- create_table :ci_pipeline_schedule_variables do |t|
- t.string :key, null: false
- t.text :value
- t.text :encrypted_value
- t.string :encrypted_value_salt
- t.string :encrypted_value_iv
- t.integer :pipeline_schedule_id, null: false
-
- t.timestamps_with_timezone null: true
- end
-
- add_index :ci_pipeline_schedule_variables,
- [:pipeline_schedule_id, :key],
- name: "index_ci_pipeline_schedule_variables_on_schedule_id_and_key",
- unique: true
- end
-
- def down
- drop_table :ci_pipeline_schedule_variables
- end
-end
diff --git a/db/migrate/20170620065449_add_foreign_key_to_ci_pipeline_schedule_variables.rb b/db/migrate/20170620065449_add_foreign_key_to_ci_pipeline_schedule_variables.rb
deleted file mode 100644
index f6de19aeaf2..00000000000
--- a/db/migrate/20170620065449_add_foreign_key_to_ci_pipeline_schedule_variables.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-class AddForeignKeyToCiPipelineScheduleVariables < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- add_concurrent_foreign_key(:ci_pipeline_schedule_variables, :ci_pipeline_schedules, column: :pipeline_schedule_id)
- end
-
- def down
- remove_foreign_key(:ci_pipeline_schedule_variables, column: :pipeline_schedule_id)
- end
-end
diff --git a/db/migrate/20170622130029_correct_protected_branches_foreign_keys.rb b/db/migrate/20170622130029_correct_protected_branches_foreign_keys.rb
deleted file mode 100644
index c4ba3ec2cc0..00000000000
--- a/db/migrate/20170622130029_correct_protected_branches_foreign_keys.rb
+++ /dev/null
@@ -1,40 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class CorrectProtectedBranchesForeignKeys < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- remove_foreign_key_without_error(:protected_branch_push_access_levels,
- column: :protected_branch_id)
-
- execute <<-EOF
- DELETE FROM protected_branch_push_access_levels
- WHERE NOT EXISTS (
- SELECT true
- FROM protected_branches
- WHERE protected_branch_push_access_levels.protected_branch_id = protected_branches.id
- )
- AND protected_branch_id IS NOT NULL
- EOF
-
- add_concurrent_foreign_key(:protected_branch_push_access_levels,
- :protected_branches,
- column: :protected_branch_id)
- end
-
- def down
- # Previously there was a foreign key without a CASCADING DELETE, so we'll
- # just leave the foreign key in place.
- end
-
- def remove_foreign_key_without_error(*args)
- remove_foreign_key(*args)
- rescue ArgumentError
- end
-end
diff --git a/db/migrate/20170622132212_add_foreign_key_for_merge_request_diffs.rb b/db/migrate/20170622132212_add_foreign_key_for_merge_request_diffs.rb
deleted file mode 100644
index b826f67ff39..00000000000
--- a/db/migrate/20170622132212_add_foreign_key_for_merge_request_diffs.rb
+++ /dev/null
@@ -1,30 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class AddForeignKeyForMergeRequestDiffs < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- execute <<-EOF
- DELETE FROM merge_request_diffs
- WHERE NOT EXISTS (
- SELECT true
- FROM merge_requests
- WHERE merge_requests.id = merge_request_diffs.merge_request_id
- )
- EOF
-
- add_concurrent_foreign_key(:merge_request_diffs,
- :merge_requests,
- column: :merge_request_id)
- end
-
- def down
- remove_foreign_key(:merge_request_diffs, column: :merge_request_id)
- end
-end
diff --git a/db/migrate/20170622135451_rename_duplicated_variable_key.rb b/db/migrate/20170622135451_rename_duplicated_variable_key.rb
deleted file mode 100644
index 06a9529ae79..00000000000
--- a/db/migrate/20170622135451_rename_duplicated_variable_key.rb
+++ /dev/null
@@ -1,38 +0,0 @@
-class RenameDuplicatedVariableKey < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- execute(<<~SQL)
- UPDATE ci_variables
- SET #{key} = CONCAT(#{key}, #{underscore}, id)
- WHERE id IN (
- SELECT *
- FROM ( -- MySQL requires an extra layer
- SELECT dup.id
- FROM ci_variables dup
- INNER JOIN (SELECT max(id) AS id, #{key}, project_id
- FROM ci_variables tmp
- GROUP BY #{key}, project_id) var
- USING (#{key}, project_id) where dup.id <> var.id
- ) dummy
- )
- SQL
- end
-
- def down
- # noop
- end
-
- def key
- # key needs to be quoted in MySQL
- quote_column_name('key')
- end
-
- def underscore
- quote('_')
- end
-end
diff --git a/db/migrate/20170622135628_add_environment_scope_to_ci_variables.rb b/db/migrate/20170622135628_add_environment_scope_to_ci_variables.rb
deleted file mode 100644
index 8fbb2ab57d5..00000000000
--- a/db/migrate/20170622135628_add_environment_scope_to_ci_variables.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-class AddEnvironmentScopeToCiVariables < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- add_column_with_default(:ci_variables, :environment_scope, :string, default: '*')
- end
-
- def down
- remove_column(:ci_variables, :environment_scope)
- end
-end
diff --git a/db/migrate/20170622135728_add_unique_constraint_to_ci_variables.rb b/db/migrate/20170622135728_add_unique_constraint_to_ci_variables.rb
deleted file mode 100644
index 240f55766d3..00000000000
--- a/db/migrate/20170622135728_add_unique_constraint_to_ci_variables.rb
+++ /dev/null
@@ -1,35 +0,0 @@
-class AddUniqueConstraintToCiVariables < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
- INDEX_NAME = 'index_ci_variables_on_project_id_and_key_and_environment_scope'
-
- disable_ddl_transaction!
-
- def up
- unless this_index_exists?
- add_concurrent_index(:ci_variables, columns, name: INDEX_NAME, unique: true)
- end
- end
-
- def down
- if this_index_exists?
- if Gitlab::Database.mysql? && !index_exists?(:ci_variables, :project_id)
- # Need to add this index for MySQL project_id foreign key constraint
- add_concurrent_index(:ci_variables, :project_id)
- end
-
- remove_concurrent_index(:ci_variables, columns, name: INDEX_NAME)
- end
- end
-
- private
-
- def this_index_exists?
- index_exists?(:ci_variables, columns, name: INDEX_NAME)
- end
-
- def columns
- @columns ||= [:project_id, :key, :environment_scope]
- end
-end
diff --git a/db/migrate/20170622162730_add_ref_fetched_to_merge_request.rb b/db/migrate/20170622162730_add_ref_fetched_to_merge_request.rb
deleted file mode 100644
index 4715ff7a715..00000000000
--- a/db/migrate/20170622162730_add_ref_fetched_to_merge_request.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-class AddRefFetchedToMergeRequest < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def change
- add_column :merge_requests, :ref_fetched, :boolean
- end
-end
diff --git a/db/migrate/20170623080805_remove_ci_variables_project_id_index.rb b/db/migrate/20170623080805_remove_ci_variables_project_id_index.rb
deleted file mode 100644
index 861dbd2ee14..00000000000
--- a/db/migrate/20170623080805_remove_ci_variables_project_id_index.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-class RemoveCiVariablesProjectIdIndex < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- if index_exists?(:ci_variables, :project_id)
- remove_concurrent_index(:ci_variables, :project_id)
- end
- end
-
- def down
- unless index_exists?(:ci_variables, :project_id)
- add_concurrent_index(:ci_variables, :project_id)
- end
- end
-end
diff --git a/db/migrate/20170629171610_rename_application_settings_signin_enabled_to_password_authentication_enabled.rb b/db/migrate/20170629171610_rename_application_settings_signin_enabled_to_password_authentication_enabled.rb
deleted file mode 100644
index 1651a47ebec..00000000000
--- a/db/migrate/20170629171610_rename_application_settings_signin_enabled_to_password_authentication_enabled.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-class RenameApplicationSettingsSigninEnabledToPasswordAuthenticationEnabled < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- rename_column_concurrently :application_settings, :signin_enabled, :password_authentication_enabled
- end
-
- def down
- cleanup_concurrent_column_rename :application_settings, :password_authentication_enabled, :signin_enabled
- end
-end
diff --git a/db/migrate/20170703102400_add_stage_id_foreign_key_to_builds.rb b/db/migrate/20170703102400_add_stage_id_foreign_key_to_builds.rb
deleted file mode 100644
index 36ac360fb0b..00000000000
--- a/db/migrate/20170703102400_add_stage_id_foreign_key_to_builds.rb
+++ /dev/null
@@ -1,27 +0,0 @@
-class AddStageIdForeignKeyToBuilds < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- unless index_exists?(:ci_builds, :stage_id)
- add_concurrent_index(:ci_builds, :stage_id)
- end
-
- unless foreign_key_exists?(:ci_builds, :ci_stages, column: :stage_id)
- add_concurrent_foreign_key(:ci_builds, :ci_stages, column: :stage_id, on_delete: :cascade)
- end
- end
-
- def down
- if foreign_key_exists?(:ci_builds, column: :stage_id)
- remove_foreign_key(:ci_builds, column: :stage_id)
- end
-
- if index_exists?(:ci_builds, :stage_id)
- remove_concurrent_index(:ci_builds, :stage_id)
- end
- end
-end
diff --git a/db/migrate/20170706151212_add_performance_bar_allowed_group_id_to_application_settings.rb b/db/migrate/20170706151212_add_performance_bar_allowed_group_id_to_application_settings.rb
deleted file mode 100644
index 61416f74b63..00000000000
--- a/db/migrate/20170706151212_add_performance_bar_allowed_group_id_to_application_settings.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-class AddPerformanceBarAllowedGroupIdToApplicationSettings < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def change
- add_column :application_settings, :performance_bar_allowed_group_id, :integer
- end
-end
diff --git a/db/migrate/20170707183807_add_group_id_to_milestones.rb b/db/migrate/20170707183807_add_group_id_to_milestones.rb
deleted file mode 100644
index e778a30192f..00000000000
--- a/db/migrate/20170707183807_add_group_id_to_milestones.rb
+++ /dev/null
@@ -1,20 +0,0 @@
-class AddGroupIdToMilestones < ActiveRecord::Migration[4.2]
- DOWNTIME = false
-
- def up
- return if column_exists? :milestones, :group_id
-
- change_column_null :milestones, :project_id, true
-
- add_column :milestones, :group_id, :integer
- end
-
- def down
- # We cannot rollback project_id not null constraint if there are records
- # with null values.
- execute "DELETE from milestones WHERE project_id IS NULL"
-
- remove_column :milestones, :group_id
- change_column :milestones, :project_id, :integer, null: false
- end
-end
diff --git a/db/migrate/20170707184243_add_group_milestone_id_indexes.rb b/db/migrate/20170707184243_add_group_milestone_id_indexes.rb
deleted file mode 100644
index 545ee070194..00000000000
--- a/db/migrate/20170707184243_add_group_milestone_id_indexes.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-class AddGroupMilestoneIdIndexes < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- disable_ddl_transaction!
-
- DOWNTIME = false
-
- def up
- return if index_exists?(:milestones, :group_id)
-
- add_concurrent_foreign_key :milestones, :namespaces, column: :group_id, on_delete: :cascade
-
- add_concurrent_index :milestones, :group_id
- end
-
- def down
- remove_foreign_key :milestones, column: :group_id
-
- remove_concurrent_index :milestones, :group_id
- end
-end
diff --git a/db/migrate/20170707184244_remove_wrong_versions_from_schema_versions.rb b/db/migrate/20170707184244_remove_wrong_versions_from_schema_versions.rb
deleted file mode 100644
index f99206c7f78..00000000000
--- a/db/migrate/20170707184244_remove_wrong_versions_from_schema_versions.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-class RemoveWrongVersionsFromSchemaVersions < ActiveRecord::Migration[4.2]
- DOWNTIME = false
-
- def up
- execute("DELETE FROM schema_migrations WHERE version IN ('20170723183807', '20170724184243')")
- end
-
- def down
- end
-end
diff --git a/db/migrate/20170710083355_clean_stage_id_reference_migration.rb b/db/migrate/20170710083355_clean_stage_id_reference_migration.rb
deleted file mode 100644
index d33c6f53b15..00000000000
--- a/db/migrate/20170710083355_clean_stage_id_reference_migration.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-class CleanStageIdReferenceMigration < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- ##
- # `MigrateStageIdReferenceInBackground` background migration cleanup.
- #
- def up
- Gitlab::BackgroundMigration.steal('MigrateBuildStageIdReference')
- end
-
- def down
- # noop
- end
-end
diff --git a/db/migrate/20170711145320_add_status_to_ci_stages.rb b/db/migrate/20170711145320_add_status_to_ci_stages.rb
deleted file mode 100644
index 3ea7b750882..00000000000
--- a/db/migrate/20170711145320_add_status_to_ci_stages.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-class AddStatusToCiStages < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def change
- add_column :ci_stages, :status, :integer
- end
-end
diff --git a/db/migrate/20170713104829_add_foreign_key_to_merge_requests.rb b/db/migrate/20170713104829_add_foreign_key_to_merge_requests.rb
deleted file mode 100644
index 908b122c659..00000000000
--- a/db/migrate/20170713104829_add_foreign_key_to_merge_requests.rb
+++ /dev/null
@@ -1,37 +0,0 @@
-class AddForeignKeyToMergeRequests < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- class MergeRequest < ActiveRecord::Base
- self.table_name = 'merge_requests'
- include ::EachBatch
- end
-
- def up
- scope = <<-SQL.strip_heredoc
- head_pipeline_id IS NOT NULL
- AND NOT EXISTS (
- SELECT 1 FROM ci_pipelines
- WHERE ci_pipelines.id = merge_requests.head_pipeline_id
- )
- SQL
-
- MergeRequest.where(scope).each_batch(of: 1000) do |merge_requests|
- merge_requests.update_all(head_pipeline_id: nil)
- end
-
- unless foreign_key_exists?(:merge_requests, column: :head_pipeline_id)
- add_concurrent_foreign_key(:merge_requests, :ci_pipelines,
- column: :head_pipeline_id, on_delete: :nullify)
- end
- end
-
- def down
- if foreign_key_exists?(:merge_requests, column: :head_pipeline_id)
- remove_foreign_key(:merge_requests, column: :head_pipeline_id)
- end
- end
-end
diff --git a/db/migrate/20170717074009_move_system_upload_folder.rb b/db/migrate/20170717074009_move_system_upload_folder.rb
deleted file mode 100644
index 6c57a751c8d..00000000000
--- a/db/migrate/20170717074009_move_system_upload_folder.rb
+++ /dev/null
@@ -1,70 +0,0 @@
-class MoveSystemUploadFolder < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
- disable_ddl_transaction!
-
- DOWNTIME = false
-
- def up
- unless file_storage?
- say 'Using object storage, no need to move.'
- return
- end
-
- unless File.directory?(old_directory)
- say "#{old_directory} doesn't exist, no need to move it."
- return
- end
-
- if File.directory?(new_directory)
- say "#{new_directory} already exists. No need to redo the move."
- return
- end
-
- FileUtils.mkdir_p(File.join(base_directory, '-'))
-
- say "Moving #{old_directory} -> #{new_directory}"
- FileUtils.mv(old_directory, new_directory)
- FileUtils.ln_s(new_directory, old_directory)
- end
-
- def down
- unless file_storage?
- say 'Using object storage, no need to move.'
- return
- end
-
- unless File.directory?(new_directory)
- say "#{new_directory} doesn't exist, no need to move it."
- return
- end
-
- if !File.symlink?(old_directory) && File.directory?(old_directory)
- say "#{old_directory} already exists and is not a symlink, no need to revert."
- return
- end
-
- if File.symlink?(old_directory)
- say "Removing #{old_directory} -> #{new_directory} symlink"
- FileUtils.rm(old_directory)
- end
-
- say "Moving #{new_directory} -> #{old_directory}"
- FileUtils.mv(new_directory, old_directory)
- end
-
- def new_directory
- File.join(base_directory, '-', 'system')
- end
-
- def old_directory
- File.join(base_directory, 'system')
- end
-
- def base_directory
- File.join(Rails.root, 'public', 'uploads')
- end
-
- def file_storage?
- CarrierWave::Uploader::Base.storage == CarrierWave::Storage::File
- end
-end
diff --git a/db/migrate/20170717200542_add_trusted_column_to_oauth_applications.rb b/db/migrate/20170717200542_add_trusted_column_to_oauth_applications.rb
deleted file mode 100644
index d9ae86f6c52..00000000000
--- a/db/migrate/20170717200542_add_trusted_column_to_oauth_applications.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-class AddTrustedColumnToOauthApplications < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- add_column_with_default(:oauth_applications, :trusted, :boolean, default: false)
- end
-
- def down
- remove_column(:oauth_applications, :trusted)
- end
-end
diff --git a/db/migrate/20170720111708_add_lock_version_to_ci_stages.rb b/db/migrate/20170720111708_add_lock_version_to_ci_stages.rb
deleted file mode 100644
index a5caca7e80c..00000000000
--- a/db/migrate/20170720111708_add_lock_version_to_ci_stages.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-class AddLockVersionToCiStages < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def change
- add_column :ci_stages, :lock_version, :integer
- end
-end
diff --git a/db/migrate/20170720122741_create_user_custom_attributes.rb b/db/migrate/20170720122741_create_user_custom_attributes.rb
deleted file mode 100644
index 0e6f37d7317..00000000000
--- a/db/migrate/20170720122741_create_user_custom_attributes.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-class CreateUserCustomAttributes < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def change
- create_table :user_custom_attributes do |t|
- t.timestamps_with_timezone null: false
- t.references :user, null: false, foreign_key: { on_delete: :cascade }
- t.string :key, null: false
- t.string :value, null: false
-
- t.index [:user_id, :key], unique: true
- t.index [:key, :value]
- end
- end
-end
diff --git a/db/migrate/20170720130522_create_ci_pipeline_variables.rb b/db/migrate/20170720130522_create_ci_pipeline_variables.rb
deleted file mode 100644
index 4f162d46cf5..00000000000
--- a/db/migrate/20170720130522_create_ci_pipeline_variables.rb
+++ /dev/null
@@ -1,20 +0,0 @@
-class CreateCiPipelineVariables < ActiveRecord::Migration[4.2]
- DOWNTIME = false
-
- def up
- create_table :ci_pipeline_variables do |t|
- t.string :key, null: false
- t.text :value
- t.text :encrypted_value
- t.string :encrypted_value_salt
- t.string :encrypted_value_iv
- t.integer :pipeline_id, null: false
- end
-
- add_index :ci_pipeline_variables, [:pipeline_id, :key], unique: true
- end
-
- def down
- drop_table :ci_pipeline_variables
- end
-end
diff --git a/db/migrate/20170720130749_add_foreign_key_to_ci_pipeline_variables.rb b/db/migrate/20170720130749_add_foreign_key_to_ci_pipeline_variables.rb
deleted file mode 100644
index df9350d9ad5..00000000000
--- a/db/migrate/20170720130749_add_foreign_key_to_ci_pipeline_variables.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-class AddForeignKeyToCiPipelineVariables < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- add_concurrent_foreign_key(:ci_pipeline_variables, :ci_pipelines, column: :pipeline_id)
- end
-
- def down
- remove_foreign_key(:ci_pipeline_variables, column: :pipeline_id)
- end
-end
diff --git a/db/migrate/20170724214302_add_lower_path_index_to_redirect_routes.rb b/db/migrate/20170724214302_add_lower_path_index_to_redirect_routes.rb
deleted file mode 100644
index 1a6516f8777..00000000000
--- a/db/migrate/20170724214302_add_lower_path_index_to_redirect_routes.rb
+++ /dev/null
@@ -1,35 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class AddLowerPathIndexToRedirectRoutes < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
- INDEX_NAME = 'index_on_redirect_routes_lower_path'
-
- disable_ddl_transaction!
-
- def up
- return unless Gitlab::Database.postgresql?
-
- execute "CREATE INDEX CONCURRENTLY #{INDEX_NAME} ON redirect_routes (LOWER(path));"
- end
-
- def down
- return unless Gitlab::Database.postgresql?
-
- # Why not use remove_concurrent_index_by_name?
- #
- # `index_exists?` doesn't work on this index. Perhaps this is related to the
- # fact that the index doesn't show up in the schema. And apparently it isn't
- # trivial to write a query that checks for an index. BUT there is a
- # convenient `IF EXISTS` parameter for `DROP INDEX`.
- if supports_drop_index_concurrently?
- disable_statement_timeout do
- execute "DROP INDEX CONCURRENTLY IF EXISTS #{INDEX_NAME};"
- end
- else
- execute "DROP INDEX IF EXISTS #{INDEX_NAME};"
- end
- end
-end
diff --git a/db/migrate/20170725145659_add_binary_to_merge_request_diff_files.rb b/db/migrate/20170725145659_add_binary_to_merge_request_diff_files.rb
deleted file mode 100644
index c7d377547e4..00000000000
--- a/db/migrate/20170725145659_add_binary_to_merge_request_diff_files.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-class AddBinaryToMergeRequestDiffFiles < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def change
- add_column :merge_request_diff_files, :binary, :boolean
- end
-end
diff --git a/db/migrate/20170727123534_add_index_on_events_project_id_id.rb b/db/migrate/20170727123534_add_index_on_events_project_id_id.rb
deleted file mode 100644
index 076b8ee87b2..00000000000
--- a/db/migrate/20170727123534_add_index_on_events_project_id_id.rb
+++ /dev/null
@@ -1,37 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class AddIndexOnEventsProjectIdId < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- COLUMNS = %i[project_id id].freeze
- TABLES = %i[events events_for_migration].freeze
-
- disable_ddl_transaction!
-
- def up
- TABLES.each do |table|
- add_concurrent_index(table, COLUMNS) unless index_exists?(table, COLUMNS)
-
- # We remove the index _after_ adding the new one since MySQL doesn't let
- # you remove an index when a foreign key exists for the same column.
- if index_exists?(table, :project_id)
- remove_concurrent_index(table, :project_id)
- end
- end
- end
-
- def down
- TABLES.each do |table|
- unless index_exists?(table, :project_id)
- add_concurrent_index(table, :project_id)
- end
-
- unless index_exists?(table, COLUMNS)
- remove_concurrent_index(table, COLUMNS)
- end
- end
- end
-end
diff --git a/db/migrate/20170731175128_add_percentages_to_conv_dev.rb b/db/migrate/20170731175128_add_percentages_to_conv_dev.rb
deleted file mode 100644
index 522e99c0751..00000000000
--- a/db/migrate/20170731175128_add_percentages_to_conv_dev.rb
+++ /dev/null
@@ -1,32 +0,0 @@
-class AddPercentagesToConvDev < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
- disable_ddl_transaction!
-
- DOWNTIME = false
-
- def up
- add_column_with_default :conversational_development_index_metrics, :percentage_boards, :float, allow_null: false, default: 0
- add_column_with_default :conversational_development_index_metrics, :percentage_ci_pipelines, :float, allow_null: false, default: 0
- add_column_with_default :conversational_development_index_metrics, :percentage_deployments, :float, allow_null: false, default: 0
- add_column_with_default :conversational_development_index_metrics, :percentage_environments, :float, allow_null: false, default: 0
- add_column_with_default :conversational_development_index_metrics, :percentage_issues, :float, allow_null: false, default: 0
- add_column_with_default :conversational_development_index_metrics, :percentage_merge_requests, :float, allow_null: false, default: 0
- add_column_with_default :conversational_development_index_metrics, :percentage_milestones, :float, allow_null: false, default: 0
- add_column_with_default :conversational_development_index_metrics, :percentage_notes, :float, allow_null: false, default: 0
- add_column_with_default :conversational_development_index_metrics, :percentage_projects_prometheus_active, :float, allow_null: false, default: 0
- add_column_with_default :conversational_development_index_metrics, :percentage_service_desk_issues, :float, allow_null: false, default: 0
- end
-
- def down
- remove_column :conversational_development_index_metrics, :percentage_boards
- remove_column :conversational_development_index_metrics, :percentage_ci_pipelines
- remove_column :conversational_development_index_metrics, :percentage_deployments
- remove_column :conversational_development_index_metrics, :percentage_environments
- remove_column :conversational_development_index_metrics, :percentage_issues
- remove_column :conversational_development_index_metrics, :percentage_merge_requests
- remove_column :conversational_development_index_metrics, :percentage_milestones
- remove_column :conversational_development_index_metrics, :percentage_notes
- remove_column :conversational_development_index_metrics, :percentage_projects_prometheus_active
- remove_column :conversational_development_index_metrics, :percentage_service_desk_issues
- end
-end
diff --git a/db/migrate/20170731183033_add_merge_jid_to_merge_requests.rb b/db/migrate/20170731183033_add_merge_jid_to_merge_requests.rb
deleted file mode 100644
index 3c677f3bc2d..00000000000
--- a/db/migrate/20170731183033_add_merge_jid_to_merge_requests.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-class AddMergeJidToMergeRequests < ActiveRecord::Migration[4.2]
- DOWNTIME = false
-
- def change
- add_column :merge_requests, :merge_jid, :string
- end
-end
diff --git a/db/migrate/20170802013652_add_storage_fields_to_project.rb b/db/migrate/20170802013652_add_storage_fields_to_project.rb
deleted file mode 100644
index d6672b9b3af..00000000000
--- a/db/migrate/20170802013652_add_storage_fields_to_project.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class AddStorageFieldsToProject < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def up
- add_column :projects, :storage_version, :integer, limit: 2
- end
-
- def down
- remove_column :projects, :storage_version
- end
-end
diff --git a/db/migrate/20170803130232_reorganise_issues_indexes_for_faster_sorting.rb b/db/migrate/20170803130232_reorganise_issues_indexes_for_faster_sorting.rb
deleted file mode 100644
index e92b5f28685..00000000000
--- a/db/migrate/20170803130232_reorganise_issues_indexes_for_faster_sorting.rb
+++ /dev/null
@@ -1,43 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class ReorganiseIssuesIndexesForFasterSorting < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- REMOVE_INDEX_COLUMNS = %i[project_id created_at due_date updated_at].freeze
-
- ADD_INDEX_COLUMNS = [
- %i[project_id created_at id state],
- %i[project_id due_date id state],
- %i[project_id updated_at id state]
- ].freeze
-
- TABLE = :issues
-
- def up
- add_indexes(ADD_INDEX_COLUMNS)
- remove_indexes(REMOVE_INDEX_COLUMNS)
- end
-
- def down
- add_indexes(REMOVE_INDEX_COLUMNS)
- remove_indexes(ADD_INDEX_COLUMNS)
- end
-
- def add_indexes(columns)
- columns.each do |column|
- add_concurrent_index(TABLE, column) unless index_exists?(TABLE, column)
- end
- end
-
- def remove_indexes(columns)
- columns.each do |column|
- remove_concurrent_index(TABLE, column) if index_exists?(TABLE, column)
- end
- end
-end
diff --git a/db/migrate/20170807071105_add_hashed_storage_to_settings.rb b/db/migrate/20170807071105_add_hashed_storage_to_settings.rb
deleted file mode 100644
index cfb89743127..00000000000
--- a/db/migrate/20170807071105_add_hashed_storage_to_settings.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class AddHashedStorageToSettings < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- add_column_with_default :application_settings, :hashed_storage_enabled, :boolean, default: false
- end
-
- def down
- remove_columns :application_settings, :hashed_storage_enabled
- end
-end
diff --git a/db/migrate/20170809133343_add_broadcast_messages_index.rb b/db/migrate/20170809133343_add_broadcast_messages_index.rb
deleted file mode 100644
index bcbc6c9f7d2..00000000000
--- a/db/migrate/20170809133343_add_broadcast_messages_index.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class AddBroadcastMessagesIndex < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- COLUMNS = %i[starts_at ends_at id].freeze
-
- def up
- add_concurrent_index :broadcast_messages, COLUMNS
- end
-
- def down
- remove_concurrent_index :broadcast_messages, COLUMNS
- end
-end
diff --git a/db/migrate/20170809134534_add_broadcast_message_not_null_constraints.rb b/db/migrate/20170809134534_add_broadcast_message_not_null_constraints.rb
deleted file mode 100644
index fd8cdbb95aa..00000000000
--- a/db/migrate/20170809134534_add_broadcast_message_not_null_constraints.rb
+++ /dev/null
@@ -1,29 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class AddBroadcastMessageNotNullConstraints < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- COLUMNS = %i[starts_at ends_at created_at updated_at message_html]
-
- class BroadcastMessage < ActiveRecord::Base
- self.table_name = 'broadcast_messages'
- end
-
- def up
- COLUMNS.each do |column|
- BroadcastMessage.where(column => nil).delete_all
-
- change_column_null :broadcast_messages, column, false
- end
- end
-
- def down
- COLUMNS.each do |column|
- change_column_null :broadcast_messages, column, true
- end
- end
-end
diff --git a/db/migrate/20170809142252_cleanup_appearances_schema.rb b/db/migrate/20170809142252_cleanup_appearances_schema.rb
deleted file mode 100644
index 4c5d6a6d75d..00000000000
--- a/db/migrate/20170809142252_cleanup_appearances_schema.rb
+++ /dev/null
@@ -1,33 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class CleanupAppearancesSchema < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- NOT_NULL_COLUMNS = %i[title description created_at updated_at]
-
- TIME_COLUMNS = %i[created_at updated_at]
-
- def up
- NOT_NULL_COLUMNS.each do |column|
- change_column_null :appearances, column, false
- end
-
- TIME_COLUMNS.each do |column|
- change_column :appearances, column, :datetime_with_timezone
- end
- end
-
- def down
- NOT_NULL_COLUMNS.each do |column|
- change_column_null :appearances, column, true
- end
-
- TIME_COLUMNS.each do |column|
- change_column :appearances, column, :datetime # rubocop: disable Migration/Datetime
- end
- end
-end
diff --git a/db/migrate/20170809161910_add_project_export_enabled_to_application_settings.rb b/db/migrate/20170809161910_add_project_export_enabled_to_application_settings.rb
deleted file mode 100644
index 9dd520de264..00000000000
--- a/db/migrate/20170809161910_add_project_export_enabled_to_application_settings.rb
+++ /dev/null
@@ -1,14 +0,0 @@
-class AddProjectExportEnabledToApplicationSettings < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
- disable_ddl_transaction!
-
- DOWNTIME = false
-
- def up
- add_column_with_default(:application_settings, :project_export_enabled, :boolean, default: true)
- end
-
- def down
- remove_column(:application_settings, :project_export_enabled)
- end
-end
diff --git a/db/migrate/20170815221154_add_discussion_locked_to_issuable.rb b/db/migrate/20170815221154_add_discussion_locked_to_issuable.rb
deleted file mode 100644
index 1444ca480b3..00000000000
--- a/db/migrate/20170815221154_add_discussion_locked_to_issuable.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-class AddDiscussionLockedToIssuable < ActiveRecord::Migration[4.2]
- DOWNTIME = false
-
- def up
- add_column(:merge_requests, :discussion_locked, :boolean)
- add_column(:issues, :discussion_locked, :boolean)
- end
-
- def down
- remove_column(:merge_requests, :discussion_locked)
- remove_column(:issues, :discussion_locked)
- end
-end
diff --git a/db/migrate/20170816133938_add_access_level_to_ci_runners.rb b/db/migrate/20170816133938_add_access_level_to_ci_runners.rb
deleted file mode 100644
index 5a1ea9514d1..00000000000
--- a/db/migrate/20170816133938_add_access_level_to_ci_runners.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-class AddAccessLevelToCiRunners < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- add_column_with_default(:ci_runners, :access_level, :integer,
- default: Ci::Runner.access_levels['not_protected'])
- end
-
- def down
- remove_column(:ci_runners, :access_level)
- end
-end
diff --git a/db/migrate/20170816133940_add_protected_to_ci_builds.rb b/db/migrate/20170816133940_add_protected_to_ci_builds.rb
deleted file mode 100644
index 13e1be0d89c..00000000000
--- a/db/migrate/20170816133940_add_protected_to_ci_builds.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-class AddProtectedToCiBuilds < ActiveRecord::Migration[4.2]
- DOWNTIME = false
-
- def change
- add_column :ci_builds, :protected, :boolean
- end
-end
diff --git a/db/migrate/20170816143940_add_protected_to_ci_pipelines.rb b/db/migrate/20170816143940_add_protected_to_ci_pipelines.rb
deleted file mode 100644
index aefaf4a487b..00000000000
--- a/db/migrate/20170816143940_add_protected_to_ci_pipelines.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-class AddProtectedToCiPipelines < ActiveRecord::Migration[4.2]
- DOWNTIME = false
-
- def change
- add_column :ci_pipelines, :protected, :boolean
- end
-end
diff --git a/db/migrate/20170816153940_add_index_on_ci_builds_protected.rb b/db/migrate/20170816153940_add_index_on_ci_builds_protected.rb
deleted file mode 100644
index fbe5fe31ae8..00000000000
--- a/db/migrate/20170816153940_add_index_on_ci_builds_protected.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-class AddIndexOnCiBuildsProtected < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- add_concurrent_index :ci_builds, :protected
- end
-
- def down
- remove_concurrent_index :ci_builds, :protected if index_exists?(:ci_builds, :protected)
- end
-end
diff --git a/db/migrate/20170816234252_add_theme_id_to_users.rb b/db/migrate/20170816234252_add_theme_id_to_users.rb
deleted file mode 100644
index bd04445cac6..00000000000
--- a/db/migrate/20170816234252_add_theme_id_to_users.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class AddThemeIdToUsers < ActiveRecord::Migration[4.2]
- DOWNTIME = false
-
- def change
- add_column :users, :theme_id, :integer, limit: 2
- end
-end
diff --git a/db/migrate/20170817123339_add_verification_status_to_gpg_signatures.rb b/db/migrate/20170817123339_add_verification_status_to_gpg_signatures.rb
deleted file mode 100644
index c7d81dc005a..00000000000
--- a/db/migrate/20170817123339_add_verification_status_to_gpg_signatures.rb
+++ /dev/null
@@ -1,20 +0,0 @@
-class AddVerificationStatusToGpgSignatures < ActiveRecord::Migration[4.2]
- DOWNTIME = false
-
- include Gitlab::Database::MigrationHelpers
- disable_ddl_transaction!
-
- def up
- # First we remove all signatures because we need to re-verify them all
- # again anyway (because of the updated verification logic).
- #
- # This makes adding the column with default values faster
- truncate(:gpg_signatures)
-
- add_column_with_default(:gpg_signatures, :verification_status, :smallint, default: 0)
- end
-
- def down
- remove_column(:gpg_signatures, :verification_status)
- end
-end
diff --git a/db/migrate/20170820100558_correct_protected_tags_foreign_keys.rb b/db/migrate/20170820100558_correct_protected_tags_foreign_keys.rb
deleted file mode 100644
index 82e05885b0e..00000000000
--- a/db/migrate/20170820100558_correct_protected_tags_foreign_keys.rb
+++ /dev/null
@@ -1,35 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class CorrectProtectedTagsForeignKeys < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- remove_foreign_key_without_error(:protected_tag_create_access_levels,
- column: :protected_tag_id)
-
- execute <<-EOF
- DELETE FROM protected_tag_create_access_levels
- WHERE NOT EXISTS (
- SELECT true
- FROM protected_tags
- WHERE protected_tag_create_access_levels.protected_tag_id = protected_tags.id
- )
- AND protected_tag_id IS NOT NULL
- EOF
-
- add_concurrent_foreign_key(:protected_tag_create_access_levels,
- :protected_tags,
- column: :protected_tag_id)
- end
-
- def down
- # Previously there was a foreign key without a CASCADING DELETE, so we'll
- # just leave the foreign key in place.
- end
-end
diff --git a/db/migrate/20170820120108_create_user_synced_attributes_metadata.rb b/db/migrate/20170820120108_create_user_synced_attributes_metadata.rb
deleted file mode 100644
index 131dcf7ac25..00000000000
--- a/db/migrate/20170820120108_create_user_synced_attributes_metadata.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-class CreateUserSyncedAttributesMetadata < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def change
- create_table :user_synced_attributes_metadata do |t|
- t.boolean :name_synced, default: false
- t.boolean :email_synced, default: false
- t.boolean :location_synced, default: false
- t.references :user, null: false, index: { unique: true }, foreign_key: { on_delete: :cascade }
- t.string :provider
- end
- end
-end
diff --git a/db/migrate/20170824101926_add_auto_devops_enabled_to_application_settings.rb b/db/migrate/20170824101926_add_auto_devops_enabled_to_application_settings.rb
deleted file mode 100644
index f7c0aeab8f9..00000000000
--- a/db/migrate/20170824101926_add_auto_devops_enabled_to_application_settings.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-class AddAutoDevopsEnabledToApplicationSettings < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- add_column_with_default(:application_settings, :auto_devops_enabled, :boolean, default: false)
- end
-
- def down
- remove_column(:application_settings, :auto_devops_enabled, :boolean)
- end
-end
diff --git a/db/migrate/20170824162758_allow_appearances_description_html_null.rb b/db/migrate/20170824162758_allow_appearances_description_html_null.rb
deleted file mode 100644
index 6efa3452796..00000000000
--- a/db/migrate/20170824162758_allow_appearances_description_html_null.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class AllowAppearancesDescriptionHtmlNull < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- def up
- change_column_null :appearances, :description_html, true
- end
-
- def down
- # This column should not have a `NOT NULL` class, so we don't want to revert
- # back to re-adding it.
- end
-end
diff --git a/db/migrate/20170825015534_add_file_store_to_lfs_objects.rb b/db/migrate/20170825015534_add_file_store_to_lfs_objects.rb
deleted file mode 100644
index be543ffc983..00000000000
--- a/db/migrate/20170825015534_add_file_store_to_lfs_objects.rb
+++ /dev/null
@@ -1,31 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class AddFileStoreToLfsObjects < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- # When a migration requires downtime you **must** uncomment the following
- # constant and define a short and easy to understand explanation as to why the
- # migration requires downtime.
- # DOWNTIME_REASON = ''
-
- # When using the methods "add_concurrent_index", "remove_concurrent_index" or
- # "add_column_with_default" you must disable the use of transactions
- # as these methods can not run in an existing transaction.
- # When using "add_concurrent_index" or "remove_concurrent_index" methods make sure
- # that either of them is the _only_ method called in the migration,
- # any other changes should go in a separate migration.
- # This ensures that upon failure _only_ the index creation or removing fails
- # and can be retried or reverted easily.
- #
- # To disable transactions uncomment the following line and remove these
- # comments:
- # disable_ddl_transaction!
-
- def change
- add_column(:lfs_objects, :file_store, :integer)
- end
-end
diff --git a/db/migrate/20170825104051_migrate_issues_to_ghost_user.rb b/db/migrate/20170825104051_migrate_issues_to_ghost_user.rb
deleted file mode 100644
index b1adccc9c5c..00000000000
--- a/db/migrate/20170825104051_migrate_issues_to_ghost_user.rb
+++ /dev/null
@@ -1,37 +0,0 @@
-class MigrateIssuesToGhostUser < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- class User < ActiveRecord::Base
- self.table_name = 'users'
- end
-
- class Issue < ActiveRecord::Base
- self.table_name = 'issues'
-
- include ::EachBatch
- end
-
- def reset_column_in_migration_models
- ActiveRecord::Base.clear_cache!
-
- ::User.reset_column_information
- ::Namespace.reset_column_information
- end
-
- def up
- reset_column_in_migration_models
-
- # we use the model method because rewriting it is too complicated and would require copying multiple methods
- ghost_id = ::User.ghost.id
-
- Issue.where('NOT EXISTS (?)', User.unscoped.select(1).where('issues.author_id = users.id')).each_batch do |relation|
- relation.update_all(author_id: ghost_id)
- end
- end
-
- def down
- end
-end
diff --git a/db/migrate/20170825154015_resolve_outdated_diff_discussions.rb b/db/migrate/20170825154015_resolve_outdated_diff_discussions.rb
deleted file mode 100644
index 1aed21f10a0..00000000000
--- a/db/migrate/20170825154015_resolve_outdated_diff_discussions.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-class ResolveOutdatedDiffDiscussions < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def change
- add_column(:projects, :resolve_outdated_diff_discussions, :boolean)
- 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
deleted file mode 100644
index e2061b5600a..00000000000
--- a/db/migrate/20170827123848_add_index_on_merge_request_diff_commit_sha.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-# rubocop:disable RemoveIndex
-
-class AddIndexOnMergeRequestDiffCommitSha < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- add_concurrent_index :merge_request_diff_commits, :sha, length: mysql_compatible_index_length
- end
-
- def down
- remove_index :merge_request_diff_commits, :sha if index_exists? :merge_request_diff_commits, :sha
- end
-end
diff --git a/db/migrate/20170828093725_create_project_auto_dev_ops.rb b/db/migrate/20170828093725_create_project_auto_dev_ops.rb
deleted file mode 100644
index ea895dc14c1..00000000000
--- a/db/migrate/20170828093725_create_project_auto_dev_ops.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-class CreateProjectAutoDevOps < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def up
- create_table :project_auto_devops do |t|
- t.belongs_to :project, null: false, index: { unique: true }, foreign_key: { on_delete: :cascade }
- t.datetime_with_timezone :created_at, null: false
- t.datetime_with_timezone :updated_at, null: false
- t.boolean :enabled, default: nil, null: true
- t.string :domain
- end
- end
-
- def down
- drop_table(:project_auto_devops)
- end
-end
diff --git a/db/migrate/20170828135939_migrate_user_external_mail_data.rb b/db/migrate/20170828135939_migrate_user_external_mail_data.rb
deleted file mode 100644
index 9ee4a4598bf..00000000000
--- a/db/migrate/20170828135939_migrate_user_external_mail_data.rb
+++ /dev/null
@@ -1,57 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class MigrateUserExternalMailData < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- class User < ActiveRecord::Base
- self.table_name = 'users'
-
- include EachBatch
- end
-
- class UserSyncedAttributesMetadata < ActiveRecord::Base
- self.table_name = 'user_synced_attributes_metadata'
-
- include EachBatch
- end
-
- def up
- User.each_batch do |batch|
- start_id, end_id = batch.pluck('MIN(id), MAX(id)').first
-
- execute <<-EOF
- INSERT INTO user_synced_attributes_metadata (user_id, provider, email_synced)
- SELECT id, email_provider, external_email
- FROM users
- WHERE external_email = TRUE
- AND NOT EXISTS (
- SELECT true
- FROM user_synced_attributes_metadata
- WHERE user_id = users.id
- AND (provider = users.email_provider OR (provider IS NULL AND users.email_provider IS NULL))
- )
- AND id BETWEEN #{start_id} AND #{end_id}
- EOF
- end
- end
-
- def down
- UserSyncedAttributesMetadata.each_batch do |batch|
- start_id, end_id = batch.pluck('MIN(id), MAX(id)').first
-
- execute <<-EOF
- UPDATE users
- SET users.email_provider = metadata.provider, users.external_email = metadata.email_synced
- FROM user_synced_attributes_metadata as metadata, users
- WHERE metadata.email_synced = TRUE
- AND metadata.user_id = users.id
- AND id BETWEEN #{start_id} AND #{end_id}
- EOF
- end
- end
-end
diff --git a/db/migrate/20170830125940_add_failure_reason_to_ci_builds.rb b/db/migrate/20170830125940_add_failure_reason_to_ci_builds.rb
deleted file mode 100644
index 44f709868ca..00000000000
--- a/db/migrate/20170830125940_add_failure_reason_to_ci_builds.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-class AddFailureReasonToCiBuilds < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def change
- add_column :ci_builds, :failure_reason, :integer
- end
-end
diff --git a/db/migrate/20170830130119_steal_remaining_event_migration_jobs.rb b/db/migrate/20170830130119_steal_remaining_event_migration_jobs.rb
deleted file mode 100644
index bcc34d56d2d..00000000000
--- a/db/migrate/20170830130119_steal_remaining_event_migration_jobs.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class StealRemainingEventMigrationJobs < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- Gitlab::BackgroundMigration.steal('MigrateEventsToPushEventPayloads')
- end
-
- def down
- end
-end
diff --git a/db/migrate/20170830131015_swap_event_migration_tables.rb b/db/migrate/20170830131015_swap_event_migration_tables.rb
deleted file mode 100644
index fb3b2472ffe..00000000000
--- a/db/migrate/20170830131015_swap_event_migration_tables.rb
+++ /dev/null
@@ -1,47 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class SwapEventMigrationTables < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- class Event < ActiveRecord::Base
- self.table_name = 'events'
- end
-
- def up
- rename_tables
- end
-
- def down
- rename_tables
- end
-
- def rename_tables
- rename_table :events, :events_old
- rename_table :events_for_migration, :events
- rename_table :events_old, :events_for_migration
-
- # Once swapped we need to reset the primary key of the new "events" table to
- # make sure that data created starts with the right value. This isn't
- # necessary for events_for_migration since we replicate existing primary key
- # values to it.
- if Gitlab::Database.postgresql?
- reset_primary_key_for_postgresql
- else
- reset_primary_key_for_mysql
- end
- end
-
- def reset_primary_key_for_postgresql
- reset_pk_sequence!(Event.table_name)
- end
-
- def reset_primary_key_for_mysql
- amount = Event.pluck('COALESCE(MAX(id), 1)').first
-
- execute "ALTER TABLE #{Event.table_name} AUTO_INCREMENT = #{amount}"
- end
-end
diff --git a/db/migrate/20170831092813_add_config_source_to_pipelines.rb b/db/migrate/20170831092813_add_config_source_to_pipelines.rb
deleted file mode 100644
index ba1f73f0e68..00000000000
--- a/db/migrate/20170831092813_add_config_source_to_pipelines.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-class AddConfigSourceToPipelines < ActiveRecord::Migration[4.2]
- DOWNTIME = false
-
- def change
- add_column(:ci_pipelines, :config_source, :integer, allow_null: true)
- end
-end
diff --git a/db/migrate/20170901071411_add_foreign_key_to_issue_author.rb b/db/migrate/20170901071411_add_foreign_key_to_issue_author.rb
deleted file mode 100644
index 00d0b0f2c7f..00000000000
--- a/db/migrate/20170901071411_add_foreign_key_to_issue_author.rb
+++ /dev/null
@@ -1,14 +0,0 @@
-class AddForeignKeyToIssueAuthor < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
- disable_ddl_transaction!
-
- def up
- add_concurrent_foreign_key(:issues, :users, column: :author_id, on_delete: :nullify)
- end
-
- def down
- remove_foreign_key(:issues, column: :author_id)
- end
-end
diff --git a/db/migrate/20170904092148_add_email_confirmation.rb b/db/migrate/20170904092148_add_email_confirmation.rb
deleted file mode 100644
index 8bfb2005936..00000000000
--- a/db/migrate/20170904092148_add_email_confirmation.rb
+++ /dev/null
@@ -1,33 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class AddEmailConfirmation < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- # When a migration requires downtime you **must** uncomment the following
- # constant and define a short and easy to understand explanation as to why the
- # migration requires downtime.
- # DOWNTIME_REASON = ''
-
- # When using the methods "add_concurrent_index", "remove_concurrent_index" or
- # "add_column_with_default" you must disable the use of transactions
- # as these methods can not run in an existing transaction.
- # When using "add_concurrent_index" or "remove_concurrent_index" methods make sure
- # that either of them is the _only_ method called in the migration,
- # any other changes should go in a separate migration.
- # This ensures that upon failure _only_ the index creation or removing fails
- # and can be retried or reverted easily.
- #
- # To disable transactions uncomment the following line and remove these
- # comments:
- # disable_ddl_transaction!
-
- def change
- add_column :emails, :confirmation_token, :string
- add_column :emails, :confirmed_at, :datetime_with_timezone
- add_column :emails, :confirmation_sent_at, :datetime_with_timezone
- end
-end
diff --git a/db/migrate/20170905112933_add_resolved_by_push_to_notes.rb b/db/migrate/20170905112933_add_resolved_by_push_to_notes.rb
deleted file mode 100644
index 1f27ea3c467..00000000000
--- a/db/migrate/20170905112933_add_resolved_by_push_to_notes.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-class AddResolvedByPushToNotes < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def change
- add_column :notes, :resolved_by_push, :boolean
- end
-end
diff --git a/db/migrate/20170906133745_add_runners_token_to_groups.rb b/db/migrate/20170906133745_add_runners_token_to_groups.rb
deleted file mode 100644
index a02160feb83..00000000000
--- a/db/migrate/20170906133745_add_runners_token_to_groups.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-class AddRunnersTokenToGroups < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def change
- add_column :namespaces, :runners_token, :string
- end
-end
diff --git a/db/migrate/20170909090114_add_email_confirmation_index.rb b/db/migrate/20170909090114_add_email_confirmation_index.rb
deleted file mode 100644
index 31c48db2bd2..00000000000
--- a/db/migrate/20170909090114_add_email_confirmation_index.rb
+++ /dev/null
@@ -1,36 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class AddEmailConfirmationIndex < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- # When a migration requires downtime you **must** uncomment the following
- # constant and define a short and easy to understand explanation as to why the
- # migration requires downtime.
- # DOWNTIME_REASON = ''
-
- # When using the methods "add_concurrent_index", "remove_concurrent_index" or
- # "add_column_with_default" you must disable the use of transactions
- # as these methods can not run in an existing transaction.
- # When using "add_concurrent_index" or "remove_concurrent_index" methods make sure
- # that either of them is the _only_ method called in the migration,
- # any other changes should go in a separate migration.
- # This ensures that upon failure _only_ the index creation or removing fails
- # and can be retried or reverted easily.
- #
- # To disable transactions uncomment the following line and remove these
- # comments:
- disable_ddl_transaction!
-
- # Not necessary to remove duplicates, as :confirmation_token is a new column
- def up
- add_concurrent_index :emails, :confirmation_token, unique: true
- end
-
- def down
- remove_concurrent_index :emails, :confirmation_token if index_exists?(:emails, :confirmation_token)
- end
-end
diff --git a/db/migrate/20170909150936_add_spent_at_to_timelogs.rb b/db/migrate/20170909150936_add_spent_at_to_timelogs.rb
deleted file mode 100644
index 3a2c900b445..00000000000
--- a/db/migrate/20170909150936_add_spent_at_to_timelogs.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-class AddSpentAtToTimelogs < ActiveRecord::Migration[4.2]
- DOWNTIME = false
-
- def up
- add_column :timelogs, :spent_at, :datetime_with_timezone
- end
-
- def down
- remove_column :timelogs, :spent_at
- end
-end
diff --git a/db/migrate/20170912113435_clean_stages_statuses_migration.rb b/db/migrate/20170912113435_clean_stages_statuses_migration.rb
deleted file mode 100644
index f2040f819cd..00000000000
--- a/db/migrate/20170912113435_clean_stages_statuses_migration.rb
+++ /dev/null
@@ -1,26 +0,0 @@
-class CleanStagesStatusesMigration < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- class Stage < ActiveRecord::Base
- include ::EachBatch
- self.table_name = 'ci_stages'
- end
-
- def up
- Gitlab::BackgroundMigration.steal('MigrateStageStatus')
-
- Stage.where('status IS NULL').each_batch(of: 50) do |batch|
- range = batch.pluck('MIN(id)', 'MAX(id)').first
-
- Gitlab::BackgroundMigration::MigrateStageStatus.new.perform(*range)
- end
- end
-
- def down
- # noop
- end
-end
diff --git a/db/migrate/20170913131410_environments_project_id_not_null.rb b/db/migrate/20170913131410_environments_project_id_not_null.rb
deleted file mode 100644
index ba66113945b..00000000000
--- a/db/migrate/20170913131410_environments_project_id_not_null.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class EnvironmentsProjectIdNotNull < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def up
- change_column_null :environments, :project_id, false
- end
-
- def down
- change_column_null :environments, :project_id, true
- end
-end
diff --git a/db/migrate/20170914135630_add_index_for_recent_push_events.rb b/db/migrate/20170914135630_add_index_for_recent_push_events.rb
deleted file mode 100644
index ac86185ba50..00000000000
--- a/db/migrate/20170914135630_add_index_for_recent_push_events.rb
+++ /dev/null
@@ -1,40 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class AddIndexForRecentPushEvents < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- add_concurrent_index_if_not_present(
- :merge_requests,
- [:source_project_id, :source_branch]
- )
-
- remove_concurrent_index_if_present(:merge_requests, :source_project_id)
- end
-
- def down
- add_concurrent_index_if_not_present(:merge_requests, :source_project_id)
-
- remove_concurrent_index_if_present(
- :merge_requests,
- [:source_project_id, :source_branch]
- )
- end
-
- def add_concurrent_index_if_not_present(table, columns)
- return if index_exists?(table, columns)
-
- add_concurrent_index(table, columns)
- end
-
- def remove_concurrent_index_if_present(table, columns)
- return unless index_exists?(table, columns)
-
- remove_concurrent_index(table, columns)
- end
-end
diff --git a/db/migrate/20170918072948_create_job_artifacts.rb b/db/migrate/20170918072948_create_job_artifacts.rb
deleted file mode 100644
index 4dd24aaff99..00000000000
--- a/db/migrate/20170918072948_create_job_artifacts.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-class CreateJobArtifacts < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def change
- create_table :ci_job_artifacts do |t|
- t.belongs_to :project, null: false, index: true, foreign_key: { on_delete: :cascade }
- t.integer :job_id, null: false
- t.integer :file_type, null: false
- t.integer :size, limit: 8
-
- t.datetime_with_timezone :created_at, null: false
- t.datetime_with_timezone :updated_at, null: false
- t.datetime_with_timezone :expire_at
-
- t.string :file
-
- t.foreign_key :ci_builds, column: :job_id, on_delete: :cascade
- t.index [:job_id, :file_type], unique: true
- end
- end
-end
diff --git a/db/migrate/20170918072949_add_file_store_job_artifacts.rb b/db/migrate/20170918072949_add_file_store_job_artifacts.rb
deleted file mode 100644
index 3eb355c9305..00000000000
--- a/db/migrate/20170918072949_add_file_store_job_artifacts.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-class AddFileStoreJobArtifacts < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- disable_ddl_transaction!
- DOWNTIME = false
-
- def change
- add_column(:ci_job_artifacts, :file_store, :integer)
- end
-end
diff --git a/db/migrate/20170918111708_create_project_custom_attributes.rb b/db/migrate/20170918111708_create_project_custom_attributes.rb
deleted file mode 100644
index bd6064689ff..00000000000
--- a/db/migrate/20170918111708_create_project_custom_attributes.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-class CreateProjectCustomAttributes < ActiveRecord::Migration[4.2]
- DOWNTIME = false
-
- def change
- create_table :project_custom_attributes do |t|
- t.timestamps_with_timezone null: false
- t.references :project, null: false, foreign_key: { on_delete: :cascade }
- t.string :key, null: false
- t.string :value, null: false
-
- t.index [:project_id, :key], unique: true
- t.index [:key, :value]
- end
- end
-end
diff --git a/db/migrate/20170918140927_create_group_custom_attributes.rb b/db/migrate/20170918140927_create_group_custom_attributes.rb
deleted file mode 100644
index 215a0f16b6f..00000000000
--- a/db/migrate/20170918140927_create_group_custom_attributes.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-class CreateGroupCustomAttributes < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def change
- create_table :group_custom_attributes do |t|
- t.timestamps_with_timezone null: false
- t.references :group, null: false
- t.string :key, null: false
- t.string :value, null: false
-
- t.index [:group_id, :key], unique: true
- t.index [:key, :value]
- end
-
- add_foreign_key :group_custom_attributes, :namespaces, column: :group_id, on_delete: :cascade # rubocop: disable Migration/AddConcurrentForeignKey
- end
-end
diff --git a/db/migrate/20170918222253_reorganize_deployments_indexes.rb b/db/migrate/20170918222253_reorganize_deployments_indexes.rb
deleted file mode 100644
index 480847ac393..00000000000
--- a/db/migrate/20170918222253_reorganize_deployments_indexes.rb
+++ /dev/null
@@ -1,28 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class ReorganizeDeploymentsIndexes < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- add_index_if_not_exists :deployments, [:environment_id, :iid, :project_id]
- remove_index_if_exists :deployments, [:project_id, :environment_id, :iid]
- end
-
- def down
- add_index_if_not_exists :deployments, [:project_id, :environment_id, :iid]
- remove_index_if_exists :deployments, [:environment_id, :iid, :project_id]
- end
-
- def add_index_if_not_exists(table, columns)
- add_concurrent_index(table, columns) unless index_exists?(table, columns)
- end
-
- def remove_index_if_exists(table, columns)
- remove_concurrent_index(table, columns) if index_exists?(table, columns)
- end
-end
diff --git a/db/migrate/20170918223303_add_deployments_index_for_last_deployment.rb b/db/migrate/20170918223303_add_deployments_index_for_last_deployment.rb
deleted file mode 100644
index 8e165ac647d..00000000000
--- a/db/migrate/20170918223303_add_deployments_index_for_last_deployment.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class AddDeploymentsIndexForLastDeployment < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- TO_INDEX = [:deployments, %i[environment_id id]].freeze
-
- def up
- add_concurrent_index(*TO_INDEX)
- end
-
- def down
- remove_concurrent_index(*TO_INDEX)
- end
-end
diff --git a/db/migrate/20170919211300_remove_temporary_ci_builds_index.rb b/db/migrate/20170919211300_remove_temporary_ci_builds_index.rb
deleted file mode 100644
index 23c94a809d4..00000000000
--- a/db/migrate/20170919211300_remove_temporary_ci_builds_index.rb
+++ /dev/null
@@ -1,28 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class RemoveTemporaryCiBuildsIndex < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- # To use create/remove index concurrently
- disable_ddl_transaction!
-
- def up
- return unless index_exists?(:ci_builds, :id, name: 'index_for_ci_builds_retried_migration')
-
- remove_concurrent_index(:ci_builds, :id, name: "index_for_ci_builds_retried_migration")
- end
-
- def down
- # this was a temporary index for a migration that was never
- # present previously so this probably shouldn't be here but it's
- # easier to test the drop if we have a way to create it.
- add_concurrent_index("ci_builds", ["id"],
- name: "index_for_ci_builds_retried_migration",
- where: "(retried IS NULL)",
- using: :btree)
- end
-end
diff --git a/db/migrate/20170921115009_add_project_repository_storage_index.rb b/db/migrate/20170921115009_add_project_repository_storage_index.rb
deleted file mode 100644
index 9e1f5052f28..00000000000
--- a/db/migrate/20170921115009_add_project_repository_storage_index.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-class AddProjectRepositoryStorageIndex < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- add_concurrent_index(*index_spec) unless index_exists?(*index_spec)
- end
-
- def down
- remove_concurrent_index(*index_spec) if index_exists?(*index_spec)
- end
-
- def index_spec
- [:projects, :repository_storage]
- end
-end
diff --git a/db/migrate/20170924094327_create_gcp_clusters.rb b/db/migrate/20170924094327_create_gcp_clusters.rb
deleted file mode 100644
index 43201f75ad7..00000000000
--- a/db/migrate/20170924094327_create_gcp_clusters.rb
+++ /dev/null
@@ -1,45 +0,0 @@
-class CreateGcpClusters < ActiveRecord::Migration[4.2]
- DOWNTIME = false
-
- def change
- create_table :gcp_clusters do |t|
- # Order columns by best align scheme
- t.references :project, null: false, index: { unique: true }, foreign_key: { on_delete: :cascade }
- t.references :user, foreign_key: { on_delete: :nullify }
- t.references :service, foreign_key: { on_delete: :nullify }
- t.integer :status
- t.integer :gcp_cluster_size, null: false
-
- # Timestamps
- t.datetime_with_timezone :created_at, null: false
- t.datetime_with_timezone :updated_at, null: false
-
- # Enable/disable
- t.boolean :enabled, default: true
-
- # General
- t.text :status_reason
-
- # k8s integration specific
- t.string :project_namespace
-
- # Cluster details
- t.string :endpoint
- t.text :ca_cert
- t.text :encrypted_kubernetes_token
- t.string :encrypted_kubernetes_token_iv
- t.string :username
- t.text :encrypted_password
- t.string :encrypted_password_iv
-
- # GKE
- t.string :gcp_project_id, null: false
- t.string :gcp_cluster_zone, null: false
- t.string :gcp_cluster_name, null: false
- t.string :gcp_machine_type
- t.string :gcp_operation_id
- t.text :encrypted_gcp_token
- t.string :encrypted_gcp_token_iv
- end
- end
-end
diff --git a/db/migrate/20170925184228_add_favicon_to_appearances.rb b/db/migrate/20170925184228_add_favicon_to_appearances.rb
deleted file mode 100644
index 1ce750f7e83..00000000000
--- a/db/migrate/20170925184228_add_favicon_to_appearances.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-class AddFaviconToAppearances < ActiveRecord::Migration[4.2]
- DOWNTIME = false
-
- def change
- add_column :appearances, :favicon, :string
- end
-end
diff --git a/db/migrate/20170927095921_add_ci_builds_index_for_jobscontroller.rb b/db/migrate/20170927095921_add_ci_builds_index_for_jobscontroller.rb
deleted file mode 100644
index 3ee9c959fca..00000000000
--- a/db/migrate/20170927095921_add_ci_builds_index_for_jobscontroller.rb
+++ /dev/null
@@ -1,39 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class AddCiBuildsIndexForJobscontroller < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- # When a migration requires downtime you **must** uncomment the following
- # constant and define a short and easy to understand explanation as to why the
- # migration requires downtime.
- # DOWNTIME_REASON = ''
-
- # When using the methods "add_concurrent_index", "remove_concurrent_index" or
- # "add_column_with_default" you must disable the use of transactions
- # as these methods can not run in an existing transaction.
- # When using "add_concurrent_index" or "remove_concurrent_index" methods make sure
- # that either of them is the _only_ method called in the migration,
- # any other changes should go in a separate migration.
- # This ensures that upon failure _only_ the index creation or removing fails
- # and can be retried or reverted easily.
- #
- # To disable transactions uncomment the following line and remove these
- # comments:
- # disable_ddl_transaction!
-
- disable_ddl_transaction!
-
- def up
- add_concurrent_index :ci_builds, [:project_id, :id] unless index_exists? :ci_builds, [:project_id, :id]
- remove_concurrent_index :ci_builds, :project_id if index_exists? :ci_builds, :project_id
- end
-
- def down
- add_concurrent_index :ci_builds, :project_id unless index_exists? :ci_builds, :project_id
- remove_concurrent_index :ci_builds, [:project_id, :id] if index_exists? :ci_builds, [:project_id, :id]
- end
-end
diff --git a/db/migrate/20170927122209_add_partial_index_for_labels_template.rb b/db/migrate/20170927122209_add_partial_index_for_labels_template.rb
deleted file mode 100644
index dd79e024df4..00000000000
--- a/db/migrate/20170927122209_add_partial_index_for_labels_template.rb
+++ /dev/null
@@ -1,45 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class AddPartialIndexForLabelsTemplate < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- # When a migration requires downtime you **must** uncomment the following
- # constant and define a short and easy to understand explanation as to why the
- # migration requires downtime.
- # DOWNTIME_REASON = ''
-
- # When using the methods "add_concurrent_index", "remove_concurrent_index" or
- # "add_column_with_default" you must disable the use of transactions
- # as these methods can not run in an existing transaction.
- # When using "add_concurrent_index" or "remove_concurrent_index" methods make sure
- # that either of them is the _only_ method called in the migration,
- # any other changes should go in a separate migration.
- # This ensures that upon failure _only_ the index creation or removing fails
- # and can be retried or reverted easily.
- #
- # To disable transactions uncomment the following line and remove these
- # comments:
-
- disable_ddl_transaction!
-
- # Note this is a partial index in Postgres but MySQL will ignore the
- # partial index clause. By making it an index on "template" this
- # means the index will still accomplish the same goal of optimizing
- # a query with "where template = true" on MySQL -- it'll just take
- # more space. In this case the number of records with template=true
- # is expected to be very small (small enough to display on a single
- # web page) so it's ok to filter or sort them without the index
- # anyways.
-
- def up
- add_concurrent_index "labels", ["template"], where: "template"
- end
-
- def down
- remove_concurrent_index "labels", ["template"], where: "template"
- end
-end
diff --git a/db/migrate/20170927161718_create_gpg_key_subkeys.rb b/db/migrate/20170927161718_create_gpg_key_subkeys.rb
deleted file mode 100644
index 3b5d452ee12..00000000000
--- a/db/migrate/20170927161718_create_gpg_key_subkeys.rb
+++ /dev/null
@@ -1,25 +0,0 @@
-class CreateGpgKeySubkeys < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def up
- create_table :gpg_key_subkeys do |t|
- t.references :gpg_key, null: false, index: true, foreign_key: { on_delete: :cascade }
-
- t.binary :keyid
- t.binary :fingerprint
-
- 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 }
- end
-
- def down
- remove_reference(:gpg_signatures, :gpg_key_subkey, index: true, foreign_key: true)
-
- drop_table :gpg_key_subkeys
- end
-end
diff --git a/db/migrate/20170928100231_add_composite_index_on_merge_requests_merge_commit_sha.rb b/db/migrate/20170928100231_add_composite_index_on_merge_requests_merge_commit_sha.rb
deleted file mode 100644
index cb16589e8db..00000000000
--- a/db/migrate/20170928100231_add_composite_index_on_merge_requests_merge_commit_sha.rb
+++ /dev/null
@@ -1,33 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class AddCompositeIndexOnMergeRequestsMergeCommitSha < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- # The default index name is too long for PostgreSQL and would thus be
- # truncated.
- INDEX_NAME = 'index_merge_requests_on_tp_id_and_merge_commit_sha_and_id'
-
- COLUMNS = [:target_project_id, :merge_commit_sha, :id]
-
- disable_ddl_transaction!
-
- def up
- return if index_is_present?
-
- add_concurrent_index(:merge_requests, COLUMNS, name: INDEX_NAME)
- end
-
- def down
- return unless index_is_present?
-
- remove_concurrent_index(:merge_requests, COLUMNS, name: INDEX_NAME)
- end
-
- def index_is_present?
- index_exists?(:merge_requests, COLUMNS, name: INDEX_NAME)
- end
-end
diff --git a/db/migrate/20170928124105_create_fork_networks.rb b/db/migrate/20170928124105_create_fork_networks.rb
deleted file mode 100644
index 01f623117f5..00000000000
--- a/db/migrate/20170928124105_create_fork_networks.rb
+++ /dev/null
@@ -1,29 +0,0 @@
-class CreateForkNetworks < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- create_table :fork_networks do |t|
- t.references :root_project,
- references: :projects,
- index: { unique: true }
-
- t.string :deleted_root_project_name
- end
-
- add_concurrent_foreign_key :fork_networks, :projects,
- column: :root_project_id,
- on_delete: :nullify
- end
-
- def down
- if foreign_keys_for(:fork_networks, :root_project_id).any?
- remove_foreign_key :fork_networks, column: :root_project_id
- end
-
- drop_table :fork_networks
- end
-end
diff --git a/db/migrate/20170928133643_create_fork_network_members.rb b/db/migrate/20170928133643_create_fork_network_members.rb
deleted file mode 100644
index e2a6d7b0e8a..00000000000
--- a/db/migrate/20170928133643_create_fork_network_members.rb
+++ /dev/null
@@ -1,27 +0,0 @@
-class CreateForkNetworkMembers < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- create_table :fork_network_members do |t|
- t.references :fork_network, null: false, index: true, foreign_key: { on_delete: :cascade }
- t.references :project, null: false, index: { unique: true }, foreign_key: { on_delete: :cascade }
- t.references :forked_from_project, references: :projects
- end
-
- add_concurrent_foreign_key :fork_network_members, :projects,
- column: :forked_from_project_id,
- on_delete: :nullify
- end
-
- def down
- if foreign_keys_for(:fork_network_members, :forked_from_project_id).any?
- remove_foreign_key :fork_network_members, column: :forked_from_project_id
- end
-
- drop_table :fork_network_members
- end
-end
diff --git a/db/migrate/20170929080234_add_failure_reason_to_pipelines.rb b/db/migrate/20170929080234_add_failure_reason_to_pipelines.rb
deleted file mode 100644
index e000ee27eef..00000000000
--- a/db/migrate/20170929080234_add_failure_reason_to_pipelines.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-class AddFailureReasonToPipelines < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def change
- add_column :ci_pipelines, :failure_reason, :integer
- end
-end
diff --git a/db/migrate/20170929131201_populate_fork_networks.rb b/db/migrate/20170929131201_populate_fork_networks.rb
deleted file mode 100644
index ba4f8ef2531..00000000000
--- a/db/migrate/20170929131201_populate_fork_networks.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class PopulateForkNetworks < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def up
- say 'Fork networks will be populated in 20171205190711 - RescheduleForkNetworkCreationCaller'
- end
-
- def down
- # nothing
- end
-end
diff --git a/db/migrate/20171004121444_make_sure_fast_forward_option_exists.rb b/db/migrate/20171004121444_make_sure_fast_forward_option_exists.rb
deleted file mode 100644
index 9b417de1793..00000000000
--- a/db/migrate/20171004121444_make_sure_fast_forward_option_exists.rb
+++ /dev/null
@@ -1,25 +0,0 @@
-# rubocop:disable all
-class MakeSureFastForwardOptionExists < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- # We had to fix the migration db/migrate/20150827121444_add_fast_forward_option_to_project.rb
- # And this is why it's possible that someone has ran the migrations but does
- # not have the merge_requests_ff_only_enabled column. This migration makes sure it will
- # be added
- unless column_exists?(:projects, :merge_requests_ff_only_enabled)
- add_column_with_default(:projects, :merge_requests_ff_only_enabled, :boolean, default: false)
- end
- end
-
- def down
- if column_exists?(:projects, :merge_requests_ff_only_enabled)
- remove_column(:projects, :merge_requests_ff_only_enabled)
- end
- end
-end
diff --git a/db/migrate/20171006090001_create_ci_build_trace_sections.rb b/db/migrate/20171006090001_create_ci_build_trace_sections.rb
deleted file mode 100644
index a2eca0832f2..00000000000
--- a/db/migrate/20171006090001_create_ci_build_trace_sections.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-class CreateCiBuildTraceSections < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def change
- create_table :ci_build_trace_sections do |t|
- t.references :project, null: false, index: true, foreign_key: { on_delete: :cascade }
- t.datetime_with_timezone :date_start, null: false
- t.datetime_with_timezone :date_end, null: false
- t.integer :byte_start, limit: 8, null: false
- t.integer :byte_end, limit: 8, null: false
- t.integer :build_id, null: false
- t.integer :section_name_id, null: false
- end
-
- add_index :ci_build_trace_sections, [:build_id, :section_name_id], unique: true
- end
-end
diff --git a/db/migrate/20171006090010_add_build_foreign_key_to_ci_build_trace_sections.rb b/db/migrate/20171006090010_add_build_foreign_key_to_ci_build_trace_sections.rb
deleted file mode 100644
index 7b17763ac84..00000000000
--- a/db/migrate/20171006090010_add_build_foreign_key_to_ci_build_trace_sections.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-class AddBuildForeignKeyToCiBuildTraceSections < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- add_concurrent_foreign_key(:ci_build_trace_sections, :ci_builds, column: :build_id)
- end
-
- def down
- remove_foreign_key(:ci_build_trace_sections, column: :build_id)
- end
-end
diff --git a/db/migrate/20171006090100_create_ci_build_trace_section_names.rb b/db/migrate/20171006090100_create_ci_build_trace_section_names.rb
deleted file mode 100644
index 00a38fa59c2..00000000000
--- a/db/migrate/20171006090100_create_ci_build_trace_section_names.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-class CreateCiBuildTraceSectionNames < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def up
- create_table :ci_build_trace_section_names do |t|
- t.references :project, null: false, foreign_key: { on_delete: :cascade }
- t.string :name, null: false
- end
-
- add_index :ci_build_trace_section_names, [:project_id, :name], unique: true
- end
-
- def down
- remove_foreign_key :ci_build_trace_section_names, column: :project_id
- drop_table :ci_build_trace_section_names
- end
-end
diff --git a/db/migrate/20171006091000_add_name_foreign_key_to_ci_build_trace_sections.rb b/db/migrate/20171006091000_add_name_foreign_key_to_ci_build_trace_sections.rb
deleted file mode 100644
index 1342ff013b7..00000000000
--- a/db/migrate/20171006091000_add_name_foreign_key_to_ci_build_trace_sections.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-class AddNameForeignKeyToCiBuildTraceSections < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- add_concurrent_foreign_key(:ci_build_trace_sections, :ci_build_trace_section_names, column: :section_name_id)
- end
-
- def down
- remove_foreign_key(:ci_build_trace_sections, column: :section_name_id)
- end
-end
diff --git a/db/migrate/20171006220837_add_global_rate_limits_to_application_settings.rb b/db/migrate/20171006220837_add_global_rate_limits_to_application_settings.rb
deleted file mode 100644
index 96d76069b35..00000000000
--- a/db/migrate/20171006220837_add_global_rate_limits_to_application_settings.rb
+++ /dev/null
@@ -1,38 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class AddGlobalRateLimitsToApplicationSettings < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- add_column_with_default :application_settings, :throttle_unauthenticated_enabled, :boolean, default: false, allow_null: false
- add_column_with_default :application_settings, :throttle_unauthenticated_requests_per_period, :integer, default: 3600, allow_null: false
- add_column_with_default :application_settings, :throttle_unauthenticated_period_in_seconds, :integer, default: 3600, allow_null: false
-
- add_column_with_default :application_settings, :throttle_authenticated_api_enabled, :boolean, default: false, allow_null: false
- add_column_with_default :application_settings, :throttle_authenticated_api_requests_per_period, :integer, default: 7200, allow_null: false
- add_column_with_default :application_settings, :throttle_authenticated_api_period_in_seconds, :integer, default: 3600, allow_null: false
-
- add_column_with_default :application_settings, :throttle_authenticated_web_enabled, :boolean, default: false, allow_null: false
- add_column_with_default :application_settings, :throttle_authenticated_web_requests_per_period, :integer, default: 7200, allow_null: false
- add_column_with_default :application_settings, :throttle_authenticated_web_period_in_seconds, :integer, default: 3600, allow_null: false
- end
-
- def down
- remove_column :application_settings, :throttle_authenticated_web_period_in_seconds
- remove_column :application_settings, :throttle_authenticated_web_requests_per_period
- remove_column :application_settings, :throttle_authenticated_web_enabled
-
- remove_column :application_settings, :throttle_authenticated_api_period_in_seconds
- remove_column :application_settings, :throttle_authenticated_api_requests_per_period
- remove_column :application_settings, :throttle_authenticated_api_enabled
-
- remove_column :application_settings, :throttle_unauthenticated_period_in_seconds
- remove_column :application_settings, :throttle_unauthenticated_requests_per_period
- remove_column :application_settings, :throttle_unauthenticated_enabled
- end
-end
diff --git a/db/migrate/20171012101043_add_circuit_breaker_properties_to_application_settings.rb b/db/migrate/20171012101043_add_circuit_breaker_properties_to_application_settings.rb
deleted file mode 100644
index 91bba07b4d7..00000000000
--- a/db/migrate/20171012101043_add_circuit_breaker_properties_to_application_settings.rb
+++ /dev/null
@@ -1,27 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class AddCircuitBreakerPropertiesToApplicationSettings < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def change
- add_column :application_settings,
- :circuitbreaker_failure_count_threshold,
- :integer,
- default: 160
- add_column :application_settings,
- :circuitbreaker_failure_wait_time,
- :integer,
- default: 30
- add_column :application_settings,
- :circuitbreaker_failure_reset_time,
- :integer,
- default: 1800
- add_column :application_settings,
- :circuitbreaker_storage_timeout,
- :integer,
- default: 30
- end
-end
diff --git a/db/migrate/20171012125712_migrate_user_authentication_token_to_personal_access_token.rb b/db/migrate/20171012125712_migrate_user_authentication_token_to_personal_access_token.rb
deleted file mode 100644
index 305c12e31f8..00000000000
--- a/db/migrate/20171012125712_migrate_user_authentication_token_to_personal_access_token.rb
+++ /dev/null
@@ -1,78 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class MigrateUserAuthenticationTokenToPersonalAccessToken < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- # disable_ddl_transaction!
-
- TOKEN_NAME = 'Private Token'.freeze
-
- def up
- execute <<~SQL
- INSERT INTO personal_access_tokens (user_id, token, name, created_at, updated_at, scopes)
- SELECT id, authentication_token, '#{TOKEN_NAME}', NOW(), NOW(), '#{%w[api].to_yaml}'
- FROM users
- WHERE authentication_token IS NOT NULL
- AND admin = FALSE
- AND NOT EXISTS (
- SELECT true
- FROM personal_access_tokens
- WHERE user_id = users.id
- AND token = users.authentication_token
- )
- SQL
-
- # Admins also need the `sudo` scope
- execute <<~SQL
- INSERT INTO personal_access_tokens (user_id, token, name, created_at, updated_at, scopes)
- SELECT id, authentication_token, '#{TOKEN_NAME}', NOW(), NOW(), '#{%w[api sudo].to_yaml}'
- FROM users
- WHERE authentication_token IS NOT NULL
- AND admin = TRUE
- AND NOT EXISTS (
- SELECT true
- FROM personal_access_tokens
- WHERE user_id = users.id
- AND token = users.authentication_token
- )
- SQL
- end
-
- def down
- if Gitlab::Database.postgresql?
- execute <<~SQL
- UPDATE users
- SET authentication_token = pats.token
- FROM (
- SELECT user_id, token
- FROM personal_access_tokens
- WHERE name = '#{TOKEN_NAME}'
- ) AS pats
- WHERE id = pats.user_id
- SQL
- else
- execute <<~SQL
- UPDATE users
- INNER JOIN personal_access_tokens AS pats
- ON users.id = pats.user_id
- SET authentication_token = pats.token
- WHERE pats.name = '#{TOKEN_NAME}'
- SQL
- end
-
- execute <<~SQL
- DELETE FROM personal_access_tokens
- WHERE name = '#{TOKEN_NAME}'
- AND EXISTS (
- SELECT true
- FROM users
- WHERE id = personal_access_tokens.user_id
- AND authentication_token = personal_access_tokens.token
- )
- SQL
- end
-end
diff --git a/db/migrate/20171013094327_create_new_clusters_architectures.rb b/db/migrate/20171013094327_create_new_clusters_architectures.rb
deleted file mode 100644
index 98f91e6130f..00000000000
--- a/db/migrate/20171013094327_create_new_clusters_architectures.rb
+++ /dev/null
@@ -1,68 +0,0 @@
-class CreateNewClustersArchitectures < ActiveRecord::Migration[4.2]
- DOWNTIME = false
-
- def change
- create_table :clusters do |t|
- t.references :user, index: true, foreign_key: { on_delete: :nullify }
-
- t.integer :provider_type
- t.integer :platform_type
-
- t.datetime_with_timezone :created_at, null: false
- t.datetime_with_timezone :updated_at, null: false
-
- t.boolean :enabled, index: true, default: true
-
- t.string :name, null: false # If manual, read-write. If gcp, read-only.
- end
-
- create_table :cluster_projects do |t|
- t.references :project, null: false, index: true, foreign_key: { on_delete: :cascade }
- t.references :cluster, null: false, index: true, foreign_key: { on_delete: :cascade }
-
- t.datetime_with_timezone :created_at, null: false
- t.datetime_with_timezone :updated_at, null: false
- end
-
- create_table :cluster_platforms_kubernetes do |t|
- t.references :cluster, null: false, index: { unique: true }, foreign_key: { on_delete: :cascade }
-
- t.datetime_with_timezone :created_at, null: false
- t.datetime_with_timezone :updated_at, null: false
-
- t.text :api_url
- t.text :ca_cert
-
- t.string :namespace
-
- t.string :username
- t.text :encrypted_password
- t.string :encrypted_password_iv
-
- t.text :encrypted_token
- t.string :encrypted_token_iv
- end
-
- create_table :cluster_providers_gcp do |t|
- t.references :cluster, null: false, index: { unique: true }, foreign_key: { on_delete: :cascade }
-
- t.integer :status
- t.integer :num_nodes, null: false
-
- t.datetime_with_timezone :created_at, null: false
- t.datetime_with_timezone :updated_at, null: false
-
- t.text :status_reason
-
- t.string :gcp_project_id, null: false
- t.string :zone, null: false
- t.string :machine_type
- t.string :operation_id
-
- t.string :endpoint
-
- t.text :encrypted_access_token
- t.string :encrypted_access_token_iv
- end
- end
-end
diff --git a/db/migrate/20171017145932_add_new_circuitbreaker_settings_to_application_settings.rb b/db/migrate/20171017145932_add_new_circuitbreaker_settings_to_application_settings.rb
deleted file mode 100644
index 4a0cadea364..00000000000
--- a/db/migrate/20171017145932_add_new_circuitbreaker_settings_to_application_settings.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-class AddNewCircuitbreakerSettingsToApplicationSettings < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def change
- add_column :application_settings,
- :circuitbreaker_access_retries,
- :integer,
- default: 3
- add_column :application_settings,
- :circuitbreaker_backoff_threshold,
- :integer,
- default: 80
- end
-end
diff --git a/db/migrate/20171019141859_fix_dev_timezone_schema.rb b/db/migrate/20171019141859_fix_dev_timezone_schema.rb
deleted file mode 100644
index 68c8b528e17..00000000000
--- a/db/migrate/20171019141859_fix_dev_timezone_schema.rb
+++ /dev/null
@@ -1,25 +0,0 @@
-class FixDevTimezoneSchema < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # The this migrations tries to help solve unwanted changes to `schema.rb`
- # while developing GitLab. Installations created before we started using
- # `datetime_with_timezone` are likely to face this problem. Updating those
- # columns to the new type should help fix this.
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- TIMEZONE_TABLES = %i(appearances ci_group_variables ci_pipeline_schedule_variables events gpg_keys gpg_signatures project_auto_devops)
-
- def up
- return unless Rails.env.development? || Rails.env.test?
-
- TIMEZONE_TABLES.each do |table|
- change_column table, :created_at, :datetime_with_timezone
- change_column table, :updated_at, :datetime_with_timezone
- end
- end
-
- def down
- end
-end
diff --git a/db/migrate/20171025110159_add_latest_merge_request_diff_id_to_merge_requests.rb b/db/migrate/20171025110159_add_latest_merge_request_diff_id_to_merge_requests.rb
deleted file mode 100644
index 1af0cf70958..00000000000
--- a/db/migrate/20171025110159_add_latest_merge_request_diff_id_to_merge_requests.rb
+++ /dev/null
@@ -1,26 +0,0 @@
-class AddLatestMergeRequestDiffIdToMergeRequests < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- add_column :merge_requests, :latest_merge_request_diff_id, :integer
- add_concurrent_index :merge_requests, :latest_merge_request_diff_id
-
- add_concurrent_foreign_key :merge_requests, :merge_request_diffs,
- column: :latest_merge_request_diff_id,
- on_delete: :nullify
- end
-
- def down
- remove_foreign_key :merge_requests, column: :latest_merge_request_diff_id
-
- if index_exists?(:merge_requests, :latest_merge_request_diff_id)
- remove_concurrent_index :merge_requests, :latest_merge_request_diff_id
- end
-
- remove_column :merge_requests, :latest_merge_request_diff_id
- end
-end
diff --git a/db/migrate/20171031100710_create_clusters_kubernetes_helm_apps.rb b/db/migrate/20171031100710_create_clusters_kubernetes_helm_apps.rb
deleted file mode 100644
index 0af05f5c94a..00000000000
--- a/db/migrate/20171031100710_create_clusters_kubernetes_helm_apps.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-class CreateClustersKubernetesHelmApps < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def change
- create_table :clusters_applications_helm do |t|
- t.references :cluster, null: false, unique: true, foreign_key: { on_delete: :cascade }
-
- t.datetime_with_timezone :created_at, null: false
- t.datetime_with_timezone :updated_at, null: false
-
- t.integer :status, null: false
- t.string :version, null: false
- t.text :status_reason
- end
- end
-end
diff --git a/db/migrate/20171101130535_add_gitaly_timeout_properties_to_application_settings.rb b/db/migrate/20171101130535_add_gitaly_timeout_properties_to_application_settings.rb
deleted file mode 100644
index 6d60fdc6132..00000000000
--- a/db/migrate/20171101130535_add_gitaly_timeout_properties_to_application_settings.rb
+++ /dev/null
@@ -1,31 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class AddGitalyTimeoutPropertiesToApplicationSettings < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- add_column_with_default :application_settings,
- :gitaly_timeout_default,
- :integer,
- default: 55
- add_column_with_default :application_settings,
- :gitaly_timeout_medium,
- :integer,
- default: 30
- add_column_with_default :application_settings,
- :gitaly_timeout_fast,
- :integer,
- default: 10
- end
-
- def down
- remove_column :application_settings, :gitaly_timeout_default
- remove_column :application_settings, :gitaly_timeout_medium
- remove_column :application_settings, :gitaly_timeout_fast
- end
-end
diff --git a/db/migrate/20171103000000_set_uploads_path_size_for_mysql.rb b/db/migrate/20171103000000_set_uploads_path_size_for_mysql.rb
deleted file mode 100644
index 93cec87f999..00000000000
--- a/db/migrate/20171103000000_set_uploads_path_size_for_mysql.rb
+++ /dev/null
@@ -1,25 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class SetUploadsPathSizeForMysql < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- def up
- # We need at least 297 at the moment. For more detail on that number, see:
- # https://gitlab.com/gitlab-org/gitlab-ce/issues/40168#what-is-the-expected-correct-behavior
- #
- # Rails + PostgreSQL `string` is equivalent to a `text` field, but
- # Rails + MySQL `string` is `varchar(255)` by default. Also, note that we
- # have an upper limit because with a unique index, MySQL has a max key
- # length of 3072 bytes which seems to correspond to `varchar(1024)`.
- change_column :uploads, :path, :string, limit: 511
- end
-
- def down
- # It was unspecified, which is varchar(255) by default in Rails for MySQL.
- change_column :uploads, :path, :string
- end
-end
diff --git a/db/migrate/20171106101200_create_clusters_kubernetes_ingress_apps.rb b/db/migrate/20171106101200_create_clusters_kubernetes_ingress_apps.rb
deleted file mode 100644
index 770cb94ee18..00000000000
--- a/db/migrate/20171106101200_create_clusters_kubernetes_ingress_apps.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-class CreateClustersKubernetesIngressApps < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def change
- create_table :clusters_applications_ingress do |t|
- t.references :cluster, null: false, unique: true, foreign_key: { on_delete: :cascade }
-
- t.datetime_with_timezone :created_at, null: false
- t.datetime_with_timezone :updated_at, null: false
-
- t.integer :status, null: false
- t.integer :ingress_type, null: false
-
- t.string :version, null: false
- t.string :cluster_ip
- t.text :status_reason
- end
- end
-end
diff --git a/db/migrate/20171106132212_issues_confidential_not_null.rb b/db/migrate/20171106132212_issues_confidential_not_null.rb
deleted file mode 100644
index 444a38c2dc5..00000000000
--- a/db/migrate/20171106132212_issues_confidential_not_null.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class IssuesConfidentialNotNull < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- class Issue < ActiveRecord::Base
- self.table_name = 'issues'
- end
-
- def up
- Issue.where('confidential IS NULL').update_all(confidential: false)
-
- change_column_null :issues, :confidential, false
- end
-
- def down
- # There's no way / point to revert this.
- end
-end
diff --git a/db/migrate/20171106133143_rename_application_settings_password_authentication_enabled_to_password_authentication_enabled_for_web.rb b/db/migrate/20171106133143_rename_application_settings_password_authentication_enabled_to_password_authentication_enabled_for_web.rb
deleted file mode 100644
index 58762a4f852..00000000000
--- a/db/migrate/20171106133143_rename_application_settings_password_authentication_enabled_to_password_authentication_enabled_for_web.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-class RenameApplicationSettingsPasswordAuthenticationEnabledToPasswordAuthenticationEnabledForWeb < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- rename_column_concurrently :application_settings, :password_authentication_enabled, :password_authentication_enabled_for_web
- end
-
- def down
- cleanup_concurrent_column_rename :application_settings, :password_authentication_enabled_for_web, :password_authentication_enabled
- end
-end
diff --git a/db/migrate/20171106133911_add_password_authentication_enabled_for_git_to_application_settings.rb b/db/migrate/20171106133911_add_password_authentication_enabled_for_git_to_application_settings.rb
deleted file mode 100644
index 1f96a0426a1..00000000000
--- a/db/migrate/20171106133911_add_password_authentication_enabled_for_git_to_application_settings.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-class AddPasswordAuthenticationEnabledForGitToApplicationSettings < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def change
- add_column :application_settings, :password_authentication_enabled_for_git, :boolean, default: true, null: false
- end
-end
diff --git a/db/migrate/20171106135924_issues_milestone_id_foreign_key.rb b/db/migrate/20171106135924_issues_milestone_id_foreign_key.rb
deleted file mode 100644
index 1de7d5e768e..00000000000
--- a/db/migrate/20171106135924_issues_milestone_id_foreign_key.rb
+++ /dev/null
@@ -1,39 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class IssuesMilestoneIdForeignKey < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- class Issue < ActiveRecord::Base
- include EachBatch
-
- self.table_name = 'issues'
-
- def self.with_orphaned_milestones
- where('NOT EXISTS (SELECT true FROM milestones WHERE milestones.id = issues.milestone_id)')
- .where('milestone_id IS NOT NULL')
- end
- end
-
- def up
- Issue.with_orphaned_milestones.each_batch(of: 100) do |batch|
- batch.update_all(milestone_id: nil)
- end
-
- add_concurrent_foreign_key(
- :issues,
- :milestones,
- column: :milestone_id,
- on_delete: :nullify
- )
- end
-
- def down
- remove_foreign_key_without_error(:issues, column: :milestone_id)
- end
-end
diff --git a/db/migrate/20171106150657_issues_updated_by_id_foreign_key.rb b/db/migrate/20171106150657_issues_updated_by_id_foreign_key.rb
deleted file mode 100644
index b2992b1ff5d..00000000000
--- a/db/migrate/20171106150657_issues_updated_by_id_foreign_key.rb
+++ /dev/null
@@ -1,45 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class IssuesUpdatedByIdForeignKey < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- class Issue < ActiveRecord::Base
- include EachBatch
-
- self.table_name = 'issues'
-
- def self.with_orphaned_updaters
- where('NOT EXISTS (SELECT true FROM users WHERE users.id = issues.updated_by_id)')
- .where('updated_by_id IS NOT NULL')
- end
- end
-
- def up
- Issue.with_orphaned_updaters.each_batch(of: 100) do |batch|
- batch.update_all(updated_by_id: nil)
- end
-
- # This index is only used for foreign keys, and those in turn will always
- # specify a value. As such we can add a WHERE condition to make the index
- # smaller.
- add_concurrent_index(:issues, :updated_by_id, where: 'updated_by_id IS NOT NULL')
-
- add_concurrent_foreign_key(
- :issues,
- :users,
- column: :updated_by_id,
- on_delete: :nullify
- )
- end
-
- def down
- remove_foreign_key_without_error(:issues, column: :updated_by_id)
- remove_concurrent_index(:issues, :updated_by_id)
- end
-end
diff --git a/db/migrate/20171106151218_issues_moved_to_id_foreign_key.rb b/db/migrate/20171106151218_issues_moved_to_id_foreign_key.rb
deleted file mode 100644
index 66bfb5718dc..00000000000
--- a/db/migrate/20171106151218_issues_moved_to_id_foreign_key.rb
+++ /dev/null
@@ -1,56 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class IssuesMovedToIdForeignKey < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- class Issue < ActiveRecord::Base
- include EachBatch
-
- self.table_name = 'issues'
-
- def self.with_orphaned_moved_to_issues
- if Gitlab::Database.postgresql?
- # Be careful to use a second table here for comparison otherwise we'll null
- # out all rows that don't have id == moved.to_id!
- where('NOT EXISTS (SELECT true FROM issues B WHERE issues.moved_to_id = B.id)')
- .where('moved_to_id IS NOT NULL')
- else
- # MySQL doesn't allow modification of the same table in a subquery,
- # and using a temporary table isn't automatically guaranteed to work
- # due to the MySQL query optimizer. See
- # https://dev.mysql.com/doc/refman/5.7/en/update.html for more
- # details.
- joins('LEFT JOIN issues AS b ON issues.moved_to_id = b.id')
- .where('issues.moved_to_id IS NOT NULL AND b.id IS NULL')
- end
- end
- end
-
- def up
- Issue.with_orphaned_moved_to_issues.each_batch(of: 100) do |batch|
- batch.update_all(moved_to_id: nil)
- end
-
- add_concurrent_foreign_key(
- :issues,
- :issues,
- column: :moved_to_id,
- on_delete: :nullify
- )
-
- # We're using a partial index here so we only index the data we actually
- # care about.
- add_concurrent_index(:issues, :moved_to_id, where: 'moved_to_id IS NOT NULL')
- end
-
- def down
- remove_foreign_key_without_error(:issues, column: :moved_to_id)
- remove_concurrent_index(:issues, :moved_to_id)
- end
-end
diff --git a/db/migrate/20171106155656_turn_issues_due_date_index_to_partial_index.rb b/db/migrate/20171106155656_turn_issues_due_date_index_to_partial_index.rb
deleted file mode 100644
index 58392de5e6b..00000000000
--- a/db/migrate/20171106155656_turn_issues_due_date_index_to_partial_index.rb
+++ /dev/null
@@ -1,35 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class TurnIssuesDueDateIndexToPartialIndex < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- NEW_INDEX_NAME = 'idx_issues_on_project_id_and_due_date_and_id_and_state_partial'
- OLD_INDEX_NAME = 'index_issues_on_project_id_and_due_date_and_id_and_state'
-
- disable_ddl_transaction!
-
- def up
- add_concurrent_index(
- :issues,
- [:project_id, :due_date, :id, :state],
- where: 'due_date IS NOT NULL',
- name: NEW_INDEX_NAME
- )
-
- remove_concurrent_index_by_name(:issues, OLD_INDEX_NAME)
- end
-
- def down
- add_concurrent_index(
- :issues,
- [:project_id, :due_date, :id, :state],
- name: OLD_INDEX_NAME
- )
-
- remove_concurrent_index_by_name(:issues, NEW_INDEX_NAME)
- end
-end
diff --git a/db/migrate/20171106171453_add_timezone_to_issues_closed_at.rb b/db/migrate/20171106171453_add_timezone_to_issues_closed_at.rb
deleted file mode 100644
index c6edc1af6cb..00000000000
--- a/db/migrate/20171106171453_add_timezone_to_issues_closed_at.rb
+++ /dev/null
@@ -1,20 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class AddTimezoneToIssuesClosedAt < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- # rubocop:disable Migration/UpdateLargeTable
- change_column_type_concurrently(:issues, :closed_at, :datetime_with_timezone)
- end
-
- def down
- cleanup_concurrent_column_type_change(:issues, :closed_at)
- end
-end
diff --git a/db/migrate/20171114150259_merge_requests_author_id_foreign_key.rb b/db/migrate/20171114150259_merge_requests_author_id_foreign_key.rb
deleted file mode 100644
index 4ebb6fad059..00000000000
--- a/db/migrate/20171114150259_merge_requests_author_id_foreign_key.rb
+++ /dev/null
@@ -1,43 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class MergeRequestsAuthorIdForeignKey < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- class MergeRequest < ActiveRecord::Base
- include EachBatch
-
- self.table_name = 'merge_requests'
-
- def self.with_orphaned_authors
- where('NOT EXISTS (SELECT true FROM users WHERE merge_requests.author_id = users.id)')
- .where('author_id IS NOT NULL')
- end
- end
-
- def up
- # Replacing the ghost user ID logic would be too complex, hence we don't
- # redefine the User model here.
- ghost_id = User.select(:id).ghost.id
-
- MergeRequest.with_orphaned_authors.each_batch(of: 100) do |batch|
- batch.update_all(author_id: ghost_id)
- end
-
- add_concurrent_foreign_key(
- :merge_requests,
- :users,
- column: :author_id,
- on_delete: :nullify
- )
- end
-
- def down
- remove_foreign_key(:merge_requests, column: :author_id)
- end
-end
diff --git a/db/migrate/20171114160005_merge_requests_assignee_id_foreign_key.rb b/db/migrate/20171114160005_merge_requests_assignee_id_foreign_key.rb
deleted file mode 100644
index 73c177c44f9..00000000000
--- a/db/migrate/20171114160005_merge_requests_assignee_id_foreign_key.rb
+++ /dev/null
@@ -1,39 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class MergeRequestsAssigneeIdForeignKey < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- class MergeRequest < ActiveRecord::Base
- include EachBatch
-
- self.table_name = 'merge_requests'
-
- def self.with_orphaned_assignees
- where('NOT EXISTS (SELECT true FROM users WHERE merge_requests.assignee_id = users.id)')
- .where('assignee_id IS NOT NULL')
- end
- end
-
- def up
- MergeRequest.with_orphaned_assignees.each_batch(of: 100) do |batch|
- batch.update_all(assignee_id: nil)
- end
-
- add_concurrent_foreign_key(
- :merge_requests,
- :users,
- column: :assignee_id,
- on_delete: :nullify
- )
- end
-
- def down
- remove_foreign_key(:merge_requests, column: :assignee_id)
- end
-end
diff --git a/db/migrate/20171114160904_merge_requests_updated_by_id_foreign_key.rb b/db/migrate/20171114160904_merge_requests_updated_by_id_foreign_key.rb
deleted file mode 100644
index 69f9c181c10..00000000000
--- a/db/migrate/20171114160904_merge_requests_updated_by_id_foreign_key.rb
+++ /dev/null
@@ -1,46 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class MergeRequestsUpdatedByIdForeignKey < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- class MergeRequest < ActiveRecord::Base
- include EachBatch
-
- self.table_name = 'merge_requests'
-
- def self.with_orphaned_updaters
- where('NOT EXISTS (SELECT true FROM users WHERE merge_requests.updated_by_id = users.id)')
- .where('updated_by_id IS NOT NULL')
- end
- end
-
- def up
- MergeRequest.with_orphaned_updaters.each_batch(of: 100) do |batch|
- batch.update_all(updated_by_id: nil)
- end
-
- add_concurrent_index(
- :merge_requests,
- :updated_by_id,
- where: 'updated_by_id IS NOT NULL'
- )
-
- add_concurrent_foreign_key(
- :merge_requests,
- :users,
- column: :updated_by_id,
- on_delete: :nullify
- )
- end
-
- def down
- remove_foreign_key_without_error(:merge_requests, column: :updated_by_id)
- remove_concurrent_index(:merge_requests, :updated_by_id)
- end
-end
diff --git a/db/migrate/20171114161720_merge_requests_merge_user_id_foreign_key.rb b/db/migrate/20171114161720_merge_requests_merge_user_id_foreign_key.rb
deleted file mode 100644
index ccd275d5bb4..00000000000
--- a/db/migrate/20171114161720_merge_requests_merge_user_id_foreign_key.rb
+++ /dev/null
@@ -1,46 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class MergeRequestsMergeUserIdForeignKey < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- class MergeRequest < ActiveRecord::Base
- include EachBatch
-
- self.table_name = 'merge_requests'
-
- def self.with_orphaned_mergers
- where('NOT EXISTS (SELECT true FROM users WHERE merge_requests.merge_user_id = users.id)')
- .where('merge_user_id IS NOT NULL')
- end
- end
-
- def up
- MergeRequest.with_orphaned_mergers.each_batch(of: 100) do |batch|
- batch.update_all(merge_user_id: nil)
- end
-
- add_concurrent_index(
- :merge_requests,
- :merge_user_id,
- where: 'merge_user_id IS NOT NULL'
- )
-
- add_concurrent_foreign_key(
- :merge_requests,
- :users,
- column: :merge_user_id,
- on_delete: :nullify
- )
- end
-
- def down
- remove_foreign_key_without_error(:merge_requests, column: :merge_user_id)
- remove_concurrent_index(:merge_requests, :merge_user_id)
- end
-end
diff --git a/db/migrate/20171114161914_merge_requests_source_project_id_foreign_key.rb b/db/migrate/20171114161914_merge_requests_source_project_id_foreign_key.rb
deleted file mode 100644
index 250928a6551..00000000000
--- a/db/migrate/20171114161914_merge_requests_source_project_id_foreign_key.rb
+++ /dev/null
@@ -1,45 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class MergeRequestsSourceProjectIdForeignKey < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- class MergeRequest < ActiveRecord::Base
- include EachBatch
-
- self.table_name = 'merge_requests'
-
- def self.with_orphaned_source_projects
- where('NOT EXISTS (SELECT true FROM projects WHERE merge_requests.source_project_id = projects.id)')
- .where('source_project_id IS NOT NULL')
- end
- end
-
- def up
- # We need to allow NULL values so we can nullify the column when the source
- # project is removed. We _don't_ want to remove the merge request, instead
- # the application will keep them but close them.
- change_column_null(:merge_requests, :source_project_id, true)
-
- MergeRequest.with_orphaned_source_projects.each_batch(of: 100) do |batch|
- batch.update_all(source_project_id: nil)
- end
-
- add_concurrent_foreign_key(
- :merge_requests,
- :projects,
- column: :source_project_id,
- on_delete: :nullify
- )
- end
-
- def down
- remove_foreign_key_without_error(:merge_requests, column: :source_project_id)
- change_column_null(:merge_requests, :source_project_id, false)
- end
-end
diff --git a/db/migrate/20171114162227_merge_requests_milestone_id_foreign_key.rb b/db/migrate/20171114162227_merge_requests_milestone_id_foreign_key.rb
deleted file mode 100644
index cafe0ce0853..00000000000
--- a/db/migrate/20171114162227_merge_requests_milestone_id_foreign_key.rb
+++ /dev/null
@@ -1,39 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class MergeRequestsMilestoneIdForeignKey < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- class MergeRequest < ActiveRecord::Base
- include EachBatch
-
- self.table_name = 'merge_requests'
-
- def self.with_orphaned_milestones
- where('NOT EXISTS (SELECT true FROM milestones WHERE merge_requests.milestone_id = milestones.id)')
- .where('milestone_id IS NOT NULL')
- end
- end
-
- def up
- MergeRequest.with_orphaned_milestones.each_batch(of: 100) do |batch|
- batch.update_all(milestone_id: nil)
- end
-
- add_concurrent_foreign_key(
- :merge_requests,
- :milestones,
- column: :milestone_id,
- on_delete: :nullify
- )
- end
-
- def down
- remove_foreign_key_without_error(:merge_requests, column: :milestone_id)
- end
-end
diff --git a/db/migrate/20171115164540_populate_merge_requests_latest_merge_request_diff_id_take_two.rb b/db/migrate/20171115164540_populate_merge_requests_latest_merge_request_diff_id_take_two.rb
deleted file mode 100644
index 935092ce46a..00000000000
--- a/db/migrate/20171115164540_populate_merge_requests_latest_merge_request_diff_id_take_two.rb
+++ /dev/null
@@ -1,30 +0,0 @@
-# This is identical to the stolen background migration, which already has specs.
-class PopulateMergeRequestsLatestMergeRequestDiffIdTakeTwo < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
- BATCH_SIZE = 1_000
-
- class MergeRequest < ActiveRecord::Base
- self.table_name = 'merge_requests'
-
- include ::EachBatch
- end
-
- disable_ddl_transaction!
-
- def up
- Gitlab::BackgroundMigration.steal('PopulateMergeRequestsLatestMergeRequestDiffId')
-
- update = '
- latest_merge_request_diff_id = (
- SELECT MAX(id)
- FROM merge_request_diffs
- WHERE merge_requests.id = merge_request_diffs.merge_request_id
- )'.squish
-
- MergeRequest.where(latest_merge_request_diff_id: nil).each_batch(of: BATCH_SIZE) do |relation|
- relation.update_all(update)
- end
- end
-end
diff --git a/db/migrate/20171116135628_add_environment_scope_to_clusters.rb b/db/migrate/20171116135628_add_environment_scope_to_clusters.rb
deleted file mode 100644
index 39bb8759cc0..00000000000
--- a/db/migrate/20171116135628_add_environment_scope_to_clusters.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-class AddEnvironmentScopeToClusters < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- add_column_with_default(:clusters, :environment_scope, :string, default: '*')
- end
-
- def down
- remove_column(:clusters, :environment_scope)
- end
-end
diff --git a/db/migrate/20171121144800_ci_pipelines_index_on_project_id_ref_status_id.rb b/db/migrate/20171121144800_ci_pipelines_index_on_project_id_ref_status_id.rb
deleted file mode 100644
index a1dcfc70650..00000000000
--- a/db/migrate/20171121144800_ci_pipelines_index_on_project_id_ref_status_id.rb
+++ /dev/null
@@ -1,35 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class CiPipelinesIndexOnProjectIdRefStatusId < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- TABLE = :ci_pipelines
- OLD_COLUMNS = %i[project_id ref status].freeze
- NEW_COLUMNS = %i[project_id ref status id].freeze
-
- def up
- unless index_exists?(TABLE, NEW_COLUMNS)
- add_concurrent_index(TABLE, NEW_COLUMNS)
- end
-
- if index_exists?(TABLE, OLD_COLUMNS)
- remove_concurrent_index(TABLE, OLD_COLUMNS)
- end
- end
-
- def down
- unless index_exists?(TABLE, OLD_COLUMNS)
- add_concurrent_index(TABLE, OLD_COLUMNS)
- end
-
- if index_exists?(TABLE, NEW_COLUMNS)
- remove_concurrent_index(TABLE, NEW_COLUMNS)
- end
- end
-end
diff --git a/db/migrate/20171122131600_add_new_project_guidelines_to_appearances.rb b/db/migrate/20171122131600_add_new_project_guidelines_to_appearances.rb
deleted file mode 100644
index cbcbb5d988a..00000000000
--- a/db/migrate/20171122131600_add_new_project_guidelines_to_appearances.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-class AddNewProjectGuidelinesToAppearances < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def change
- # Clears the current Appearance cache otherwise it breaks since
- # new_project_guidelines_html would be missing. See
- # https://gitlab.com/gitlab-org/gitlab-ce/issues/41041
- # We're not using Appearance#flush_redis_cache on purpose here.
- Rails.cache.delete('current_appearance')
-
- change_table :appearances do |t|
- t.text :new_project_guidelines
- t.text :new_project_guidelines_html
- end
- end
-end
diff --git a/db/migrate/20171123094802_add_circuitbreaker_check_interval_to_application_settings.rb b/db/migrate/20171123094802_add_circuitbreaker_check_interval_to_application_settings.rb
deleted file mode 100644
index 94360c64926..00000000000
--- a/db/migrate/20171123094802_add_circuitbreaker_check_interval_to_application_settings.rb
+++ /dev/null
@@ -1,20 +0,0 @@
-class AddCircuitbreakerCheckIntervalToApplicationSettings < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- add_column_with_default :application_settings,
- :circuitbreaker_check_interval,
- :integer,
- default: 1
- end
-
- def down
- remove_column :application_settings,
- :circuitbreaker_check_interval
- end
-end
diff --git a/db/migrate/20171124125042_add_default_values_to_merge_request_states.rb b/db/migrate/20171124125042_add_default_values_to_merge_request_states.rb
deleted file mode 100644
index d0d06863777..00000000000
--- a/db/migrate/20171124125042_add_default_values_to_merge_request_states.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class AddDefaultValuesToMergeRequestStates < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- def up
- change_column_default :merge_requests, :state, :opened
- change_column_default :merge_requests, :merge_status, :unchecked
- end
-
- def down
- change_column_default :merge_requests, :state, nil
- change_column_default :merge_requests, :merge_status, nil
- end
-end
diff --git a/db/migrate/20171124125748_populate_missing_merge_request_statuses.rb b/db/migrate/20171124125748_populate_missing_merge_request_statuses.rb
deleted file mode 100644
index 67444f36e24..00000000000
--- a/db/migrate/20171124125748_populate_missing_merge_request_statuses.rb
+++ /dev/null
@@ -1,50 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class PopulateMissingMergeRequestStatuses < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- class MergeRequest < ActiveRecord::Base
- include EachBatch
-
- self.table_name = 'merge_requests'
- end
-
- def up
- say 'Populating missing merge_requests.state values'
-
- # GitLab.com has no rows where "state" is NULL, and technically this should
- # never happen. However it doesn't hurt to be 100% certain.
- MergeRequest.where(state: nil).each_batch do |batch|
- batch.update_all(state: 'opened')
- end
-
- say 'Populating missing merge_requests.merge_status values. ' \
- 'This will take a few minutes...'
-
- # GitLab.com has 66 880 rows where "merge_status" is NULL, dating back all
- # the way to 2011.
- MergeRequest.where(merge_status: nil).each_batch(of: 10_000) do |batch|
- batch.update_all(merge_status: 'unchecked')
-
- # We want to give PostgreSQL some time to vacuum any dead tuples. In
- # production we see it takes roughly 1 minute for a vacuuming run to clear
- # out 10-20k dead tuples, so we'll wait for 90 seconds between every
- # batch.
- sleep(90) if sleep?
- end
- end
-
- def down
- # Reverting this makes no sense.
- end
-
- def sleep?
- Rails.env.staging? || Rails.env.production?
- end
-end
diff --git a/db/migrate/20171124132536_make_merge_request_statuses_not_null.rb b/db/migrate/20171124132536_make_merge_request_statuses_not_null.rb
deleted file mode 100644
index 49b693c5950..00000000000
--- a/db/migrate/20171124132536_make_merge_request_statuses_not_null.rb
+++ /dev/null
@@ -1,14 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class MakeMergeRequestStatusesNotNull < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- def change
- change_column_null :merge_requests, :state, false
- change_column_null :merge_requests, :merge_status, false
- end
-end
diff --git a/db/migrate/20171127151038_add_events_related_columns_to_merge_request_metrics.rb b/db/migrate/20171127151038_add_events_related_columns_to_merge_request_metrics.rb
deleted file mode 100644
index 385de9dd73d..00000000000
--- a/db/migrate/20171127151038_add_events_related_columns_to_merge_request_metrics.rb
+++ /dev/null
@@ -1,37 +0,0 @@
-class AddEventsRelatedColumnsToMergeRequestMetrics < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- change_table :merge_request_metrics do |t|
- t.references :merged_by, references: :users
- t.references :latest_closed_by, references: :users
- end
-
- add_column :merge_request_metrics, :latest_closed_at, :datetime_with_timezone
-
- add_concurrent_foreign_key :merge_request_metrics, :users,
- column: :merged_by_id,
- on_delete: :nullify
-
- add_concurrent_foreign_key :merge_request_metrics, :users,
- column: :latest_closed_by_id,
- on_delete: :nullify
- end
-
- def down
- if foreign_keys_for(:merge_request_metrics, :merged_by_id).any?
- remove_foreign_key :merge_request_metrics, column: :merged_by_id
- end
-
- if foreign_keys_for(:merge_request_metrics, :latest_closed_by_id).any?
- remove_foreign_key :merge_request_metrics, column: :latest_closed_by_id
- end
-
- remove_columns :merge_request_metrics,
- :merged_by_id, :latest_closed_by_id, :latest_closed_at
- end
-end
diff --git a/db/migrate/20171204204233_add_permanent_to_redirect_route.rb b/db/migrate/20171204204233_add_permanent_to_redirect_route.rb
deleted file mode 100644
index bc0658035d6..00000000000
--- a/db/migrate/20171204204233_add_permanent_to_redirect_route.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class AddPermanentToRedirectRoute < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
- disable_ddl_transaction!
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- def up
- add_column(:redirect_routes, :permanent, :boolean)
- end
-
- def down
- remove_column(:redirect_routes, :permanent)
- end
-end
diff --git a/db/migrate/20171206221519_add_permanent_index_to_redirect_route.rb b/db/migrate/20171206221519_add_permanent_index_to_redirect_route.rb
deleted file mode 100644
index ba924c4eecc..00000000000
--- a/db/migrate/20171206221519_add_permanent_index_to_redirect_route.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class AddPermanentIndexToRedirectRoute < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- add_concurrent_index(:redirect_routes, :permanent)
- end
-
- def down
- remove_concurrent_index(:redirect_routes, :permanent) if index_exists?(:redirect_routes, :permanent)
- end
-end
diff --git a/db/migrate/20171207185153_add_merge_request_state_index.rb b/db/migrate/20171207185153_add_merge_request_state_index.rb
deleted file mode 100644
index 167470cf7fe..00000000000
--- a/db/migrate/20171207185153_add_merge_request_state_index.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-class AddMergeRequestStateIndex < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- add_concurrent_index :merge_requests, [:source_project_id, :source_branch],
- where: "state = 'opened'",
- name: 'index_merge_requests_on_source_project_and_branch_state_opened'
- end
-
- def down
- remove_concurrent_index_by_name :merge_requests,
- 'index_merge_requests_on_source_project_and_branch_state_opened'
- end
-end
diff --git a/db/migrate/20171211131502_add_external_classification_authorization_settings_to_appliction_settings.rb b/db/migrate/20171211131502_add_external_classification_authorization_settings_to_appliction_settings.rb
deleted file mode 100644
index a7dec8732fb..00000000000
--- a/db/migrate/20171211131502_add_external_classification_authorization_settings_to_appliction_settings.rb
+++ /dev/null
@@ -1,29 +0,0 @@
-class AddExternalClassificationAuthorizationSettingsToApplictionSettings < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- add_column_with_default :application_settings,
- :external_authorization_service_enabled,
- :boolean,
- default: false
- add_column :application_settings,
- :external_authorization_service_url,
- :string
- add_column :application_settings,
- :external_authorization_service_default_label,
- :string
- end
-
- def down
- remove_column :application_settings,
- :external_authorization_service_default_label
- remove_column :application_settings,
- :external_authorization_service_url
- remove_column :application_settings,
- :external_authorization_service_enabled
- end
-end
diff --git a/db/migrate/20171211145425_add_can_push_to_deploy_keys_projects.rb b/db/migrate/20171211145425_add_can_push_to_deploy_keys_projects.rb
deleted file mode 100644
index 63e86b23aad..00000000000
--- a/db/migrate/20171211145425_add_can_push_to_deploy_keys_projects.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-class AddCanPushToDeployKeysProjects < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
- disable_ddl_transaction!
-
- def up
- add_column_with_default :deploy_keys_projects, :can_push, :boolean, default: false, allow_null: false
- end
-
- def down
- remove_column :deploy_keys_projects, :can_push
- end
-end
diff --git a/db/migrate/20171212203433_create_clusters_applications_prometheus.rb b/db/migrate/20171212203433_create_clusters_applications_prometheus.rb
deleted file mode 100644
index 6eb9fec609e..00000000000
--- a/db/migrate/20171212203433_create_clusters_applications_prometheus.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-class CreateClustersApplicationsPrometheus < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def change
- create_table :clusters_applications_prometheus do |t|
- t.references :cluster, null: false, unique: true, foreign_key: { on_delete: :cascade }
-
- t.integer :status, null: false
- t.string :version, null: false
-
- t.text :status_reason
-
- t.timestamps_with_timezone null: false
- end
- end
-end
diff --git a/db/migrate/20171214144320_add_store_column_to_uploads.rb b/db/migrate/20171214144320_add_store_column_to_uploads.rb
deleted file mode 100644
index 11b3951a3fa..00000000000
--- a/db/migrate/20171214144320_add_store_column_to_uploads.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class AddStoreColumnToUploads < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def change
- add_column(:uploads, :store, :integer)
- end
-end
diff --git a/db/migrate/20171215113714_populate_can_push_from_deploy_keys_projects.rb b/db/migrate/20171215113714_populate_can_push_from_deploy_keys_projects.rb
deleted file mode 100644
index e2d7879b140..00000000000
--- a/db/migrate/20171215113714_populate_can_push_from_deploy_keys_projects.rb
+++ /dev/null
@@ -1,64 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class PopulateCanPushFromDeployKeysProjects < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
- DATABASE_NAME = Gitlab::Database.database_name
-
- disable_ddl_transaction!
-
- class DeploysKeyProject < ActiveRecord::Base
- include EachBatch
-
- self.table_name = 'deploy_keys_projects'
- end
-
- def up
- DeploysKeyProject.each_batch(of: 10_000) do |batch|
- start_id, end_id = batch.pluck('MIN(id), MAX(id)').first
-
- if Gitlab::Database.mysql?
- execute <<-EOF.strip_heredoc
- UPDATE deploy_keys_projects, #{DATABASE_NAME}.keys
- SET deploy_keys_projects.can_push = #{DATABASE_NAME}.keys.can_push
- WHERE deploy_keys_projects.deploy_key_id = #{DATABASE_NAME}.keys.id
- AND deploy_keys_projects.id BETWEEN #{start_id} AND #{end_id}
- EOF
- else
- execute <<-EOF.strip_heredoc
- UPDATE deploy_keys_projects
- SET can_push = keys.can_push
- FROM keys
- WHERE deploy_key_id = keys.id
- AND deploy_keys_projects.id BETWEEN #{start_id} AND #{end_id}
- EOF
- end
- end
- end
-
- def down
- DeploysKeyProject.each_batch(of: 10_000) do |batch|
- start_id, end_id = batch.pluck('MIN(id), MAX(id)').first
-
- if Gitlab::Database.mysql?
- execute <<-EOF.strip_heredoc
- UPDATE deploy_keys_projects, #{DATABASE_NAME}.keys
- SET #{DATABASE_NAME}.keys.can_push = deploy_keys_projects.can_push
- WHERE deploy_keys_projects.deploy_key_id = #{DATABASE_NAME}.keys.id
- AND deploy_keys_projects.id BETWEEN #{start_id} AND #{end_id}
- EOF
- else
- execute <<-EOF.strip_heredoc
- UPDATE keys
- SET can_push = deploy_keys_projects.can_push
- FROM deploy_keys_projects
- WHERE deploy_keys_projects.deploy_key_id = keys.id
- AND deploy_keys_projects.id BETWEEN #{start_id} AND #{end_id}
- EOF
- end
- end
- end
-end
diff --git a/db/migrate/20171216112339_add_foreign_key_for_members.rb b/db/migrate/20171216112339_add_foreign_key_for_members.rb
deleted file mode 100644
index 06c2c5068da..00000000000
--- a/db/migrate/20171216112339_add_foreign_key_for_members.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class AddForeignKeyForMembers < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- add_concurrent_foreign_key(:members,
- :users,
- column: :user_id)
- end
-
- def down
- remove_foreign_key(:members, column: :user_id)
- end
-end
diff --git a/db/migrate/20171218140451_add_external_authorization_service_classification_label_to_projects.rb b/db/migrate/20171218140451_add_external_authorization_service_classification_label_to_projects.rb
deleted file mode 100644
index 7b83580f025..00000000000
--- a/db/migrate/20171218140451_add_external_authorization_service_classification_label_to_projects.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-class AddExternalAuthorizationServiceClassificationLabelToProjects < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def change
- add_column :projects,
- :external_authorization_classification_label,
- :string
- end
-end
diff --git a/db/migrate/20171220191323_add_index_on_namespaces_lower_name.rb b/db/migrate/20171220191323_add_index_on_namespaces_lower_name.rb
deleted file mode 100644
index 7543e435941..00000000000
--- a/db/migrate/20171220191323_add_index_on_namespaces_lower_name.rb
+++ /dev/null
@@ -1,32 +0,0 @@
-class AddIndexOnNamespacesLowerName < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
- DOWNTIME = false
- INDEX_NAME = 'index_on_namespaces_lower_name'
-
- disable_ddl_transaction!
-
- def up
- return unless Gitlab::Database.postgresql?
-
- disable_statement_timeout do
- if Gitlab::Database.version.to_f >= 9.5
- # Allow us to hot-patch the index manually ahead of the migration
- execute "CREATE INDEX CONCURRENTLY IF NOT EXISTS #{INDEX_NAME} ON namespaces (lower(name));"
- else
- execute "CREATE INDEX CONCURRENTLY #{INDEX_NAME} ON namespaces (lower(name));"
- end
- end
- end
-
- def down
- return unless Gitlab::Database.postgresql?
-
- disable_statement_timeout do
- if Gitlab::Database.version.to_f >= 9.2
- execute "DROP INDEX CONCURRENTLY IF EXISTS #{INDEX_NAME};"
- else
- execute "DROP INDEX IF EXISTS #{INDEX_NAME};"
- end
- end
- end
-end
diff --git a/db/migrate/20171222115326_add_confidential_note_events_to_web_hooks.rb b/db/migrate/20171222115326_add_confidential_note_events_to_web_hooks.rb
deleted file mode 100644
index 788a842a3ad..00000000000
--- a/db/migrate/20171222115326_add_confidential_note_events_to_web_hooks.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-class AddConfidentialNoteEventsToWebHooks < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- add_column :web_hooks, :confidential_note_events, :boolean
- end
-
- def down
- remove_column :web_hooks, :confidential_note_events
- end
-end
diff --git a/db/migrate/20171222183504_add_jobs_cache_index_to_project.rb b/db/migrate/20171222183504_add_jobs_cache_index_to_project.rb
deleted file mode 100644
index 78a195c351c..00000000000
--- a/db/migrate/20171222183504_add_jobs_cache_index_to_project.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class AddJobsCacheIndexToProject < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- def change
- add_column :projects, :jobs_cache_index, :integer
- end
-end
diff --git a/db/migrate/20171229225929_change_user_project_limit_not_null_and_remove_default.rb b/db/migrate/20171229225929_change_user_project_limit_not_null_and_remove_default.rb
deleted file mode 100644
index b9efdb8bb8f..00000000000
--- a/db/migrate/20171229225929_change_user_project_limit_not_null_and_remove_default.rb
+++ /dev/null
@@ -1,38 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class ChangeUserProjectLimitNotNullAndRemoveDefault < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- # When a migration requires downtime you **must** uncomment the following
- # constant and define a short and easy to understand explanation as to why the
- # migration requires downtime.
- # DOWNTIME_REASON = ''
-
- # When using the methods "add_concurrent_index", "remove_concurrent_index" or
- # "add_column_with_default" you must disable the use of transactions
- # as these methods can not run in an existing transaction.
- # When using "add_concurrent_index" or "remove_concurrent_index" methods make sure
- # that either of them is the _only_ method called in the migration,
- # any other changes should go in a separate migration.
- # This ensures that upon failure _only_ the index creation or removing fails
- # and can be retried or reverted easily.
- #
- # To disable transactions uncomment the following line and remove these
- # comments:
- # disable_ddl_transaction!
-
- def up
- # Set Users#projects_limit to NOT NULL and remove the default value
- change_column_null :users, :projects_limit, false
- change_column_default :users, :projects_limit, nil
- end
-
- def down
- change_column_null :users, :projects_limit, true
- change_column_default :users, :projects_limit, 10
- end
-end
diff --git a/db/migrate/20171230123729_add_rebase_commit_sha_to_merge_requests_ce.rb b/db/migrate/20171230123729_add_rebase_commit_sha_to_merge_requests_ce.rb
deleted file mode 100644
index 4e1107e1ff5..00000000000
--- a/db/migrate/20171230123729_add_rebase_commit_sha_to_merge_requests_ce.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-class AddRebaseCommitShaToMergeRequestsCe < ActiveRecord::Migration[4.2]
- DOWNTIME = false
-
- def up
- unless column_exists?(:merge_requests, :rebase_commit_sha)
- add_column :merge_requests, :rebase_commit_sha, :string
- end
- end
-
- def down
- if column_exists?(:merge_requests, :rebase_commit_sha)
- remove_column :merge_requests, :rebase_commit_sha
- end
- end
-end
diff --git a/db/migrate/20171230123729_init_schema.rb b/db/migrate/20171230123729_init_schema.rb
new file mode 100644
index 00000000000..ae7541f2475
--- /dev/null
+++ b/db/migrate/20171230123729_init_schema.rb
@@ -0,0 +1,1854 @@
+# frozen_string_literal: true
+
+# rubocop:disable Layout/SpaceInsideHashLiteralBraces
+# rubocop:disable Layout/SpaceAroundOperators
+# rubocop:disable Metrics/AbcSize
+# rubocop:disable Migration/AddConcurrentForeignKey
+# rubocop:disable Style/WordArray
+
+class InitSchema < ActiveRecord::Migration[4.2]
+ DOWNTIME = false
+
+ def up
+ # These are extensions that must be enabled in order to support this database
+ enable_extension "plpgsql"
+ enable_extension "pg_trgm"
+ create_table "abuse_reports", id: :serial do |t|
+ t.integer "reporter_id"
+ t.integer "user_id"
+ t.text "message"
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ t.text "message_html"
+ t.integer "cached_markdown_version"
+ end
+ create_table "appearances", id: :serial do |t|
+ t.string "title", null: false
+ t.text "description", null: false
+ t.string "header_logo"
+ t.string "logo"
+ t.datetime_with_timezone "created_at", null: false
+ t.datetime_with_timezone "updated_at", null: false
+ t.text "description_html"
+ t.integer "cached_markdown_version"
+ t.string "favicon"
+ t.text "new_project_guidelines"
+ t.text "new_project_guidelines_html"
+ end
+ create_table "application_settings", id: :serial do |t|
+ t.integer "default_projects_limit"
+ t.boolean "signup_enabled"
+ t.boolean "gravatar_enabled"
+ t.text "sign_in_text"
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ t.string "home_page_url"
+ t.integer "default_branch_protection", default: 2
+ t.text "restricted_visibility_levels"
+ t.boolean "version_check_enabled", default: true
+ t.integer "max_attachment_size", default: 10, null: false
+ t.integer "default_project_visibility"
+ t.integer "default_snippet_visibility"
+ t.text "domain_whitelist"
+ t.boolean "user_oauth_applications", default: true
+ t.string "after_sign_out_path"
+ t.integer "session_expire_delay", default: 10080, null: false
+ t.text "import_sources"
+ t.text "help_page_text"
+ t.string "admin_notification_email"
+ t.boolean "shared_runners_enabled", default: true, null: false
+ t.integer "max_artifacts_size", default: 100, null: false
+ t.string "runners_registration_token"
+ t.integer "max_pages_size", default: 100, null: false
+ t.boolean "require_two_factor_authentication", default: false
+ t.integer "two_factor_grace_period", default: 48
+ t.boolean "metrics_enabled", default: false
+ t.string "metrics_host", default: "localhost"
+ t.integer "metrics_pool_size", default: 16
+ t.integer "metrics_timeout", default: 10
+ t.integer "metrics_method_call_threshold", default: 10
+ t.boolean "recaptcha_enabled", default: false
+ t.string "recaptcha_site_key"
+ t.string "recaptcha_private_key"
+ t.integer "metrics_port", default: 8089
+ t.boolean "akismet_enabled", default: false
+ t.string "akismet_api_key"
+ t.integer "metrics_sample_interval", default: 15
+ t.boolean "sentry_enabled", default: false
+ t.string "sentry_dsn"
+ t.boolean "email_author_in_body", default: false
+ t.integer "default_group_visibility"
+ t.boolean "repository_checks_enabled", default: false
+ t.text "shared_runners_text"
+ t.integer "metrics_packet_size", default: 1
+ t.text "disabled_oauth_sign_in_sources"
+ t.string "health_check_access_token"
+ t.boolean "send_user_confirmation_email", default: false
+ t.integer "container_registry_token_expire_delay", default: 5
+ t.text "after_sign_up_text"
+ t.boolean "user_default_external", default: false, null: false
+ t.string "repository_storages", default: "default"
+ t.string "enabled_git_access_protocol"
+ t.boolean "domain_blacklist_enabled", default: false
+ t.text "domain_blacklist"
+ t.boolean "usage_ping_enabled", default: true, null: false
+ t.boolean "koding_enabled"
+ t.string "koding_url"
+ t.text "sign_in_text_html"
+ t.text "help_page_text_html"
+ t.text "shared_runners_text_html"
+ t.text "after_sign_up_text_html"
+ t.integer "rsa_key_restriction", default: 0, null: false
+ t.integer "dsa_key_restriction", default: 0, null: false
+ t.integer "ecdsa_key_restriction", default: 0, null: false
+ t.integer "ed25519_key_restriction", default: 0, null: false
+ t.boolean "housekeeping_enabled", default: true, null: false
+ t.boolean "housekeeping_bitmaps_enabled", default: true, null: false
+ 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"
+ t.integer "terminal_max_session_time", default: 0, null: false
+ t.integer "unique_ips_limit_per_user"
+ t.integer "unique_ips_limit_time_window"
+ t.boolean "unique_ips_limit_enabled", default: false, null: false
+ t.string "default_artifacts_expire_in", default: "0", null: false
+ t.string "uuid"
+ t.decimal "polling_interval_multiplier", default: "1.0", null: false
+ t.integer "cached_markdown_version"
+ t.boolean "clientside_sentry_enabled", default: false, null: false
+ t.string "clientside_sentry_dsn"
+ t.boolean "prometheus_metrics_enabled", default: false, null: false
+ t.boolean "authorized_keys_enabled", default: true, null: false
+ t.boolean "help_page_hide_commercial_content", default: false
+ t.string "help_page_support_url"
+ t.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 "throttle_unauthenticated_enabled", default: false, null: false
+ t.integer "throttle_unauthenticated_requests_per_period", default: 3600, null: false
+ t.integer "throttle_unauthenticated_period_in_seconds", default: 3600, null: false
+ t.boolean "throttle_authenticated_api_enabled", default: false, null: false
+ t.integer "throttle_authenticated_api_requests_per_period", default: 7200, null: false
+ t.integer "throttle_authenticated_api_period_in_seconds", default: 3600, null: false
+ t.boolean "throttle_authenticated_web_enabled", default: false, null: false
+ t.integer "throttle_authenticated_web_requests_per_period", default: 7200, null: false
+ t.integer "throttle_authenticated_web_period_in_seconds", default: 3600, null: false
+ t.integer "circuitbreaker_failure_count_threshold", default: 3
+ t.integer "circuitbreaker_failure_reset_time", default: 1800
+ t.integer "circuitbreaker_storage_timeout", default: 15
+ t.integer "circuitbreaker_access_retries", default: 3
+ t.integer "gitaly_timeout_default", default: 55, null: false
+ t.integer "gitaly_timeout_medium", default: 30, null: false
+ t.integer "gitaly_timeout_fast", default: 10, null: false
+ t.boolean "password_authentication_enabled_for_web"
+ t.boolean "password_authentication_enabled_for_git", default: true, null: false
+ t.integer "circuitbreaker_check_interval", default: 1, null: false
+ t.boolean "external_authorization_service_enabled", default: false, null: false
+ t.string "external_authorization_service_url"
+ t.string "external_authorization_service_default_label"
+ end
+ create_table "audit_events", id: :serial do |t|
+ t.integer "author_id", null: false
+ t.string "type", null: false
+ t.integer "entity_id", null: false
+ t.string "entity_type", null: false
+ t.text "details"
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ t.index ["entity_id", "entity_type"], name: "index_audit_events_on_entity_id_and_entity_type", using: :btree
+ end
+ create_table "award_emoji", id: :serial do |t|
+ t.string "name"
+ t.integer "user_id"
+ t.string "awardable_type"
+ t.integer "awardable_id"
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ t.index ["awardable_type", "awardable_id"], name: "index_award_emoji_on_awardable_type_and_awardable_id", using: :btree
+ t.index ["user_id", "name"], name: "index_award_emoji_on_user_id_and_name", using: :btree
+ end
+ create_table "boards", id: :serial do |t|
+ t.integer "project_id", null: false
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ t.index ["project_id"], name: "index_boards_on_project_id", using: :btree
+ end
+ create_table "broadcast_messages", id: :serial do |t|
+ t.text "message", null: false
+ t.datetime "starts_at", null: false
+ t.datetime "ends_at", null: false
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ t.string "color"
+ t.string "font"
+ t.text "message_html", null: false
+ t.integer "cached_markdown_version"
+ t.index ["starts_at", "ends_at", "id"], name: "index_broadcast_messages_on_starts_at_and_ends_at_and_id", using: :btree
+ end
+ create_table "chat_names", id: :serial do |t|
+ t.integer "user_id", null: false
+ t.integer "service_id", null: false
+ t.string "team_id", null: false
+ t.string "team_domain"
+ t.string "chat_id", null: false
+ t.string "chat_name"
+ t.datetime "last_used_at"
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ t.index ["service_id", "team_id", "chat_id"], name: "index_chat_names_on_service_id_and_team_id_and_chat_id", unique: true, using: :btree
+ t.index ["user_id", "service_id"], name: "index_chat_names_on_user_id_and_service_id", unique: true, using: :btree
+ end
+ create_table "chat_teams", id: :serial do |t|
+ t.integer "namespace_id", null: false
+ t.string "team_id"
+ t.string "name"
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ t.index ["namespace_id"], name: "index_chat_teams_on_namespace_id", unique: true, using: :btree
+ end
+ create_table "ci_build_trace_section_names", id: :serial do |t|
+ t.integer "project_id", null: false
+ t.string "name", null: false
+ t.index ["project_id", "name"], name: "index_ci_build_trace_section_names_on_project_id_and_name", unique: true, using: :btree
+ end
+ create_table "ci_build_trace_sections", id: :serial do |t|
+ t.integer "project_id", null: false
+ t.datetime_with_timezone "date_start", null: false
+ t.datetime_with_timezone "date_end", null: false
+ t.bigint "byte_start", null: false
+ t.bigint "byte_end", null: false
+ t.integer "build_id", null: false
+ t.integer "section_name_id", null: false
+ t.index ["build_id", "section_name_id"], name: "index_ci_build_trace_sections_on_build_id_and_section_name_id", unique: true, using: :btree
+ t.index ["project_id"], name: "index_ci_build_trace_sections_on_project_id", using: :btree
+ end
+ create_table "ci_builds", id: :serial do |t|
+ t.string "status"
+ t.datetime "finished_at"
+ t.text "trace"
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ t.datetime "started_at"
+ t.integer "runner_id"
+ t.float "coverage"
+ t.integer "commit_id"
+ t.text "commands"
+ t.string "name"
+ t.text "options"
+ t.boolean "allow_failure", default: false, null: false
+ t.string "stage"
+ t.integer "trigger_request_id"
+ t.integer "stage_idx"
+ t.boolean "tag"
+ t.string "ref"
+ t.integer "user_id"
+ t.string "type"
+ t.string "target_url"
+ t.string "description"
+ t.text "artifacts_file"
+ t.integer "project_id"
+ t.text "artifacts_metadata"
+ t.integer "erased_by_id"
+ t.datetime "erased_at"
+ t.datetime "artifacts_expire_at"
+ t.string "environment"
+ t.bigint "artifacts_size"
+ t.string "when"
+ t.text "yaml_variables"
+ t.datetime "queued_at"
+ t.string "token"
+ t.integer "lock_version"
+ t.string "coverage_regex"
+ t.integer "auto_canceled_by_id"
+ t.boolean "retried"
+ t.integer "stage_id"
+ t.integer "artifacts_file_store"
+ t.integer "artifacts_metadata_store"
+ t.boolean "protected"
+ t.integer "failure_reason"
+ t.index ["auto_canceled_by_id"], name: "index_ci_builds_on_auto_canceled_by_id", using: :btree
+ t.index ["commit_id", "stage_idx", "created_at"], name: "index_ci_builds_on_commit_id_and_stage_idx_and_created_at", using: :btree
+ t.index ["commit_id", "status", "type"], name: "index_ci_builds_on_commit_id_and_status_and_type", using: :btree
+ t.index ["commit_id", "type", "name", "ref"], name: "index_ci_builds_on_commit_id_and_type_and_name_and_ref", using: :btree
+ t.index ["commit_id", "type", "ref"], name: "index_ci_builds_on_commit_id_and_type_and_ref", using: :btree
+ t.index ["project_id", "id"], name: "index_ci_builds_on_project_id_and_id", using: :btree
+ t.index ["protected"], name: "index_ci_builds_on_protected", using: :btree
+ t.index ["runner_id"], name: "index_ci_builds_on_runner_id", using: :btree
+ t.index ["stage_id"], name: "index_ci_builds_on_stage_id", using: :btree
+ t.index ["status", "type", "runner_id"], name: "index_ci_builds_on_status_and_type_and_runner_id", using: :btree
+ t.index ["status"], name: "index_ci_builds_on_status", using: :btree
+ t.index ["token"], name: "index_ci_builds_on_token", unique: true, using: :btree
+ t.index ["updated_at"], name: "index_ci_builds_on_updated_at", using: :btree
+ t.index ["user_id"], name: "index_ci_builds_on_user_id", using: :btree
+ end
+ create_table "ci_group_variables", id: :serial do |t|
+ t.string "key", null: false
+ t.text "value"
+ t.text "encrypted_value"
+ t.string "encrypted_value_salt"
+ t.string "encrypted_value_iv"
+ t.integer "group_id", null: false
+ t.boolean "protected", default: false, null: false
+ t.datetime_with_timezone "created_at", null: false
+ t.datetime_with_timezone "updated_at", null: false
+ t.index ["group_id", "key"], name: "index_ci_group_variables_on_group_id_and_key", unique: true, using: :btree
+ end
+ create_table "ci_job_artifacts", id: :serial do |t|
+ t.integer "project_id", null: false
+ t.integer "job_id", null: false
+ t.integer "file_type", null: false
+ t.bigint "size"
+ t.datetime_with_timezone "created_at", null: false
+ t.datetime_with_timezone "updated_at", null: false
+ t.datetime_with_timezone "expire_at"
+ t.string "file"
+ t.integer "file_store"
+ t.index ["job_id", "file_type"], name: "index_ci_job_artifacts_on_job_id_and_file_type", unique: true, using: :btree
+ t.index ["project_id"], name: "index_ci_job_artifacts_on_project_id", using: :btree
+ end
+ create_table "ci_pipeline_schedule_variables", id: :serial do |t|
+ t.string "key", null: false
+ t.text "value"
+ t.text "encrypted_value"
+ t.string "encrypted_value_salt"
+ t.string "encrypted_value_iv"
+ t.integer "pipeline_schedule_id", null: false
+ t.datetime_with_timezone "created_at"
+ t.datetime_with_timezone "updated_at"
+ t.index ["pipeline_schedule_id", "key"], name: "index_ci_pipeline_schedule_variables_on_schedule_id_and_key", unique: true, using: :btree
+ end
+ create_table "ci_pipeline_schedules", id: :serial do |t|
+ t.string "description"
+ t.string "ref"
+ t.string "cron"
+ t.string "cron_timezone"
+ t.datetime "next_run_at"
+ t.integer "project_id"
+ t.integer "owner_id"
+ t.boolean "active", default: true
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ t.index ["next_run_at", "active"], name: "index_ci_pipeline_schedules_on_next_run_at_and_active", using: :btree
+ t.index ["project_id"], name: "index_ci_pipeline_schedules_on_project_id", using: :btree
+ end
+ create_table "ci_pipeline_variables", id: :serial do |t|
+ t.string "key", null: false
+ t.text "value"
+ t.text "encrypted_value"
+ t.string "encrypted_value_salt"
+ t.string "encrypted_value_iv"
+ t.integer "pipeline_id", null: false
+ t.index ["pipeline_id", "key"], name: "index_ci_pipeline_variables_on_pipeline_id_and_key", unique: true, using: :btree
+ end
+ create_table "ci_pipelines", id: :serial do |t|
+ t.string "ref"
+ t.string "sha"
+ t.string "before_sha"
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ t.boolean "tag", default: false
+ t.text "yaml_errors"
+ t.datetime "committed_at"
+ t.integer "project_id"
+ t.string "status"
+ t.datetime "started_at"
+ t.datetime "finished_at"
+ t.integer "duration"
+ t.integer "user_id"
+ t.integer "lock_version"
+ t.integer "auto_canceled_by_id"
+ t.integer "pipeline_schedule_id"
+ t.integer "source"
+ t.boolean "protected"
+ t.integer "config_source"
+ t.integer "failure_reason"
+ t.index ["auto_canceled_by_id"], name: "index_ci_pipelines_on_auto_canceled_by_id", using: :btree
+ t.index ["pipeline_schedule_id"], name: "index_ci_pipelines_on_pipeline_schedule_id", using: :btree
+ t.index ["project_id", "ref", "status", "id"], name: "index_ci_pipelines_on_project_id_and_ref_and_status_and_id", using: :btree
+ t.index ["project_id", "sha"], name: "index_ci_pipelines_on_project_id_and_sha", using: :btree
+ t.index ["project_id"], name: "index_ci_pipelines_on_project_id", using: :btree
+ t.index ["status"], name: "index_ci_pipelines_on_status", using: :btree
+ t.index ["user_id"], name: "index_ci_pipelines_on_user_id", using: :btree
+ end
+ create_table "ci_runner_namespaces", id: :serial do |t|
+ t.integer "runner_id"
+ t.integer "namespace_id"
+ t.index ["namespace_id"], name: "index_ci_runner_namespaces_on_namespace_id", using: :btree
+ t.index ["runner_id", "namespace_id"], name: "index_ci_runner_namespaces_on_runner_id_and_namespace_id", unique: true, using: :btree
+ end
+ create_table "ci_runner_projects", id: :serial do |t|
+ t.integer "runner_id", null: false
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ t.integer "project_id"
+ t.index ["project_id"], name: "index_ci_runner_projects_on_project_id", using: :btree
+ t.index ["runner_id"], name: "index_ci_runner_projects_on_runner_id", using: :btree
+ end
+ create_table "ci_runners", id: :serial do |t|
+ t.string "token"
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ t.string "description"
+ t.datetime "contacted_at"
+ t.boolean "active", default: true, null: false
+ t.boolean "is_shared", default: false
+ t.string "name"
+ t.string "version"
+ t.string "revision"
+ t.string "platform"
+ t.string "architecture"
+ t.boolean "run_untagged", default: true, null: false
+ t.boolean "locked", default: false, null: false
+ t.integer "access_level", default: 0, null: false
+ t.index ["contacted_at"], name: "index_ci_runners_on_contacted_at", using: :btree
+ t.index ["is_shared"], name: "index_ci_runners_on_is_shared", using: :btree
+ t.index ["locked"], name: "index_ci_runners_on_locked", using: :btree
+ t.index ["token"], name: "index_ci_runners_on_token", using: :btree
+ end
+ create_table "ci_stages", id: :serial do |t|
+ t.integer "project_id"
+ t.integer "pipeline_id"
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ t.string "name"
+ t.integer "status"
+ t.integer "lock_version"
+ t.index ["pipeline_id", "name"], name: "index_ci_stages_on_pipeline_id_and_name", using: :btree
+ t.index ["pipeline_id"], name: "index_ci_stages_on_pipeline_id", using: :btree
+ t.index ["project_id"], name: "index_ci_stages_on_project_id", using: :btree
+ end
+ create_table "ci_trigger_requests", id: :serial do |t|
+ t.integer "trigger_id", null: false
+ t.text "variables"
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ t.integer "commit_id"
+ t.index ["commit_id"], name: "index_ci_trigger_requests_on_commit_id", using: :btree
+ end
+ create_table "ci_triggers", id: :serial do |t|
+ t.string "token"
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ t.integer "project_id"
+ t.integer "owner_id"
+ t.string "description"
+ t.string "ref"
+ t.index ["project_id"], name: "index_ci_triggers_on_project_id", using: :btree
+ end
+ create_table "ci_variables", id: :serial do |t|
+ t.string "key", null: false
+ t.text "value"
+ t.text "encrypted_value"
+ t.string "encrypted_value_salt"
+ t.string "encrypted_value_iv"
+ t.integer "project_id", null: false
+ t.boolean "protected", default: false, null: false
+ t.string "environment_scope", default: "*", null: false
+ t.index ["project_id", "key", "environment_scope"], name: "index_ci_variables_on_project_id_and_key_and_environment_scope", unique: true, using: :btree
+ end
+ create_table "cluster_platforms_kubernetes", id: :serial do |t|
+ t.integer "cluster_id", null: false
+ t.datetime_with_timezone "created_at", null: false
+ t.datetime_with_timezone "updated_at", null: false
+ t.text "api_url"
+ t.text "ca_cert"
+ t.string "namespace"
+ t.string "username"
+ t.text "encrypted_password"
+ t.string "encrypted_password_iv"
+ t.text "encrypted_token"
+ t.string "encrypted_token_iv"
+ t.index ["cluster_id"], name: "index_cluster_platforms_kubernetes_on_cluster_id", unique: true, using: :btree
+ end
+ create_table "cluster_projects", id: :serial do |t|
+ t.integer "project_id", null: false
+ t.integer "cluster_id", null: false
+ t.datetime_with_timezone "created_at", null: false
+ t.datetime_with_timezone "updated_at", null: false
+ t.index ["cluster_id"], name: "index_cluster_projects_on_cluster_id", using: :btree
+ t.index ["project_id"], name: "index_cluster_projects_on_project_id", using: :btree
+ end
+ create_table "cluster_providers_gcp", id: :serial do |t|
+ t.integer "cluster_id", null: false
+ t.integer "status"
+ t.integer "num_nodes", null: false
+ t.datetime_with_timezone "created_at", null: false
+ t.datetime_with_timezone "updated_at", null: false
+ t.text "status_reason"
+ t.string "gcp_project_id", null: false
+ t.string "zone", null: false
+ t.string "machine_type"
+ t.string "operation_id"
+ t.string "endpoint"
+ t.text "encrypted_access_token"
+ t.string "encrypted_access_token_iv"
+ t.index ["cluster_id"], name: "index_cluster_providers_gcp_on_cluster_id", unique: true, using: :btree
+ end
+ create_table "clusters", id: :serial do |t|
+ t.integer "user_id"
+ t.integer "provider_type"
+ t.integer "platform_type"
+ t.datetime_with_timezone "created_at", null: false
+ t.datetime_with_timezone "updated_at", null: false
+ t.boolean "enabled", default: true
+ t.string "name", null: false
+ t.string "environment_scope", default: "*", null: false
+ t.index ["enabled"], name: "index_clusters_on_enabled", using: :btree
+ t.index ["user_id"], name: "index_clusters_on_user_id", using: :btree
+ end
+ create_table "clusters_applications_helm", id: :serial do |t|
+ t.integer "cluster_id", null: false
+ t.datetime_with_timezone "created_at", null: false
+ t.datetime_with_timezone "updated_at", null: false
+ t.integer "status", null: false
+ t.string "version", null: false
+ t.text "status_reason"
+ end
+ create_table "clusters_applications_ingress", id: :serial do |t|
+ t.integer "cluster_id", null: false
+ t.datetime_with_timezone "created_at", null: false
+ t.datetime_with_timezone "updated_at", null: false
+ t.integer "status", null: false
+ t.integer "ingress_type", null: false
+ t.string "version", null: false
+ t.string "cluster_ip"
+ t.text "status_reason"
+ end
+ create_table "clusters_applications_prometheus", id: :serial do |t|
+ t.integer "cluster_id", null: false
+ t.integer "status", null: false
+ t.string "version", null: false
+ t.text "status_reason"
+ t.datetime_with_timezone "created_at", null: false
+ t.datetime_with_timezone "updated_at", null: false
+ end
+ create_table "container_repositories", id: :serial do |t|
+ t.integer "project_id", null: false
+ t.string "name", null: false
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ t.index ["project_id", "name"], name: "index_container_repositories_on_project_id_and_name", unique: true, using: :btree
+ t.index ["project_id"], name: "index_container_repositories_on_project_id", using: :btree
+ end
+ create_table "conversational_development_index_metrics", id: :serial do |t|
+ t.float "leader_issues", null: false
+ t.float "instance_issues", null: false
+ t.float "leader_notes", null: false
+ t.float "instance_notes", null: false
+ t.float "leader_milestones", null: false
+ t.float "instance_milestones", null: false
+ t.float "leader_boards", null: false
+ t.float "instance_boards", null: false
+ t.float "leader_merge_requests", null: false
+ t.float "instance_merge_requests", null: false
+ t.float "leader_ci_pipelines", null: false
+ t.float "instance_ci_pipelines", null: false
+ t.float "leader_environments", null: false
+ t.float "instance_environments", null: false
+ t.float "leader_deployments", null: false
+ t.float "instance_deployments", null: false
+ t.float "leader_projects_prometheus_active", null: false
+ t.float "instance_projects_prometheus_active", null: false
+ t.float "leader_service_desk_issues", null: false
+ t.float "instance_service_desk_issues", null: false
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ t.float "percentage_boards", default: 0.0, null: false
+ t.float "percentage_ci_pipelines", default: 0.0, null: false
+ t.float "percentage_deployments", default: 0.0, null: false
+ t.float "percentage_environments", default: 0.0, null: false
+ t.float "percentage_issues", default: 0.0, null: false
+ t.float "percentage_merge_requests", default: 0.0, null: false
+ t.float "percentage_milestones", default: 0.0, null: false
+ t.float "percentage_notes", default: 0.0, null: false
+ t.float "percentage_projects_prometheus_active", default: 0.0, null: false
+ t.float "percentage_service_desk_issues", default: 0.0, null: false
+ end
+ create_table "deploy_keys_projects", id: :serial do |t|
+ t.integer "deploy_key_id", null: false
+ t.integer "project_id", null: false
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ t.boolean "can_push", default: false, null: false
+ t.index ["project_id"], name: "index_deploy_keys_projects_on_project_id", using: :btree
+ end
+ create_table "deployments", id: :serial do |t|
+ t.integer "iid", null: false
+ t.integer "project_id", null: false
+ t.integer "environment_id", null: false
+ t.string "ref", null: false
+ t.boolean "tag", null: false
+ t.string "sha", null: false
+ t.integer "user_id"
+ t.integer "deployable_id"
+ t.string "deployable_type"
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ t.string "on_stop"
+ t.index ["created_at"], name: "index_deployments_on_created_at", using: :btree
+ t.index ["environment_id", "id"], name: "index_deployments_on_environment_id_and_id", using: :btree
+ t.index ["environment_id", "iid", "project_id"], name: "index_deployments_on_environment_id_and_iid_and_project_id", using: :btree
+ t.index ["project_id", "iid"], name: "index_deployments_on_project_id_and_iid", unique: true, using: :btree
+ end
+ create_table "emails", id: :serial do |t|
+ t.integer "user_id", null: false
+ t.string "email", null: false
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ t.string "confirmation_token"
+ t.datetime_with_timezone "confirmed_at"
+ t.datetime_with_timezone "confirmation_sent_at"
+ t.index ["confirmation_token"], name: "index_emails_on_confirmation_token", unique: true, using: :btree
+ t.index ["email"], name: "index_emails_on_email", unique: true, using: :btree
+ t.index ["user_id"], name: "index_emails_on_user_id", using: :btree
+ end
+ create_table "environments", id: :serial do |t|
+ t.integer "project_id", null: false
+ t.string "name", null: false
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ t.string "external_url"
+ t.string "environment_type"
+ t.string "state", default: "available", null: false
+ t.string "slug", null: false
+ t.index ["project_id", "name"], name: "index_environments_on_project_id_and_name", unique: true, using: :btree
+ t.index ["project_id", "slug"], name: "index_environments_on_project_id_and_slug", unique: true, using: :btree
+ end
+ create_table "events", id: :serial do |t|
+ t.integer "project_id"
+ t.integer "author_id", null: false
+ t.integer "target_id"
+ t.datetime_with_timezone "created_at", null: false
+ t.datetime_with_timezone "updated_at", null: false
+ t.integer "action", limit: 2, null: false
+ t.string "target_type"
+ t.index ["action"], name: "index_events_on_action", using: :btree
+ t.index ["author_id"], name: "index_events_on_author_id", using: :btree
+ t.index ["project_id", "id"], name: "index_events_on_project_id_and_id", using: :btree
+ t.index ["target_type", "target_id"], name: "index_events_on_target_type_and_target_id", using: :btree
+ end
+ create_table "feature_gates", id: :serial do |t|
+ t.string "feature_key", null: false
+ t.string "key", null: false
+ t.string "value"
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ t.index ["feature_key", "key", "value"], name: "index_feature_gates_on_feature_key_and_key_and_value", unique: true, using: :btree
+ end
+ create_table "features", id: :serial do |t|
+ t.string "key", null: false
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ t.index ["key"], name: "index_features_on_key", unique: true, using: :btree
+ end
+ create_table "fork_network_members", id: :serial do |t|
+ t.integer "fork_network_id", null: false
+ t.integer "project_id", null: false
+ t.integer "forked_from_project_id"
+ t.index ["fork_network_id"], name: "index_fork_network_members_on_fork_network_id", using: :btree
+ t.index ["project_id"], name: "index_fork_network_members_on_project_id", unique: true, using: :btree
+ end
+ create_table "fork_networks", id: :serial do |t|
+ t.integer "root_project_id"
+ t.string "deleted_root_project_name"
+ t.index ["root_project_id"], name: "index_fork_networks_on_root_project_id", unique: true, using: :btree
+ end
+ create_table "forked_project_links", id: :serial do |t|
+ t.integer "forked_to_project_id", null: false
+ t.integer "forked_from_project_id", null: false
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ t.index ["forked_to_project_id"], name: "index_forked_project_links_on_forked_to_project_id", unique: true, using: :btree
+ end
+ create_table "gcp_clusters", id: :serial do |t|
+ t.integer "project_id", null: false
+ t.integer "user_id"
+ t.integer "service_id"
+ t.integer "status"
+ t.integer "gcp_cluster_size", null: false
+ t.datetime_with_timezone "created_at", null: false
+ t.datetime_with_timezone "updated_at", null: false
+ t.boolean "enabled", default: true
+ t.text "status_reason"
+ t.string "project_namespace"
+ t.string "endpoint"
+ t.text "ca_cert"
+ t.text "encrypted_kubernetes_token"
+ t.string "encrypted_kubernetes_token_iv"
+ t.string "username"
+ t.text "encrypted_password"
+ t.string "encrypted_password_iv"
+ t.string "gcp_project_id", null: false
+ t.string "gcp_cluster_zone", null: false
+ t.string "gcp_cluster_name", null: false
+ t.string "gcp_machine_type"
+ t.string "gcp_operation_id"
+ t.text "encrypted_gcp_token"
+ t.string "encrypted_gcp_token_iv"
+ t.index ["project_id"], name: "index_gcp_clusters_on_project_id", unique: true, using: :btree
+ end
+ create_table "gpg_key_subkeys", id: :serial do |t|
+ t.integer "gpg_key_id", null: false
+ t.binary "keyid"
+ t.binary "fingerprint"
+ t.index ["fingerprint"], name: "index_gpg_key_subkeys_on_fingerprint", unique: true, using: :btree
+ t.index ["gpg_key_id"], name: "index_gpg_key_subkeys_on_gpg_key_id", using: :btree
+ t.index ["keyid"], name: "index_gpg_key_subkeys_on_keyid", unique: true, using: :btree
+ end
+ create_table "gpg_keys", id: :serial do |t|
+ t.datetime_with_timezone "created_at", null: false
+ t.datetime_with_timezone "updated_at", null: false
+ t.integer "user_id"
+ t.binary "primary_keyid"
+ t.binary "fingerprint"
+ t.text "key"
+ t.index ["fingerprint"], name: "index_gpg_keys_on_fingerprint", unique: true, using: :btree
+ t.index ["primary_keyid"], name: "index_gpg_keys_on_primary_keyid", unique: true, using: :btree
+ t.index ["user_id"], name: "index_gpg_keys_on_user_id", using: :btree
+ end
+ create_table "gpg_signatures", id: :serial do |t|
+ t.datetime_with_timezone "created_at", null: false
+ t.datetime_with_timezone "updated_at", null: false
+ t.integer "project_id"
+ t.integer "gpg_key_id"
+ t.binary "commit_sha"
+ t.binary "gpg_key_primary_keyid"
+ t.text "gpg_key_user_name"
+ t.text "gpg_key_user_email"
+ t.integer "verification_status", limit: 2, default: 0, null: false
+ t.integer "gpg_key_subkey_id"
+ t.index ["commit_sha"], name: "index_gpg_signatures_on_commit_sha", unique: true, using: :btree
+ t.index ["gpg_key_id"], name: "index_gpg_signatures_on_gpg_key_id", using: :btree
+ t.index ["gpg_key_primary_keyid"], name: "index_gpg_signatures_on_gpg_key_primary_keyid", using: :btree
+ t.index ["gpg_key_subkey_id"], name: "index_gpg_signatures_on_gpg_key_subkey_id", using: :btree
+ t.index ["project_id"], name: "index_gpg_signatures_on_project_id", using: :btree
+ end
+ create_table "group_custom_attributes", id: :serial do |t|
+ t.datetime_with_timezone "created_at", null: false
+ t.datetime_with_timezone "updated_at", null: false
+ t.integer "group_id", null: false
+ t.string "key", null: false
+ t.string "value", null: false
+ t.index ["group_id", "key"], name: "index_group_custom_attributes_on_group_id_and_key", unique: true, using: :btree
+ t.index ["key", "value"], name: "index_group_custom_attributes_on_key_and_value", using: :btree
+ end
+ create_table "identities", id: :serial do |t|
+ t.string "extern_uid"
+ t.string "provider"
+ t.integer "user_id"
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ t.index ["user_id"], name: "index_identities_on_user_id", using: :btree
+ end
+ create_table "issue_assignees", id: false do |t|
+ t.integer "user_id", null: false
+ t.integer "issue_id", null: false
+ t.index ["issue_id", "user_id"], name: "index_issue_assignees_on_issue_id_and_user_id", unique: true, using: :btree
+ t.index ["user_id"], name: "index_issue_assignees_on_user_id", using: :btree
+ end
+ create_table "issue_metrics", id: :serial do |t|
+ t.integer "issue_id", null: false
+ t.datetime "first_mentioned_in_commit_at"
+ t.datetime "first_associated_with_milestone_at"
+ t.datetime "first_added_to_board_at"
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ t.index ["issue_id"], name: "index_issue_metrics", using: :btree
+ end
+ create_table "issues", id: :serial do |t|
+ t.string "title"
+ t.integer "author_id"
+ t.integer "project_id"
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ t.text "description"
+ t.integer "milestone_id"
+ t.string "state"
+ t.integer "iid"
+ t.integer "updated_by_id"
+ t.boolean "confidential", default: false, null: false
+ t.date "due_date"
+ t.integer "moved_to_id"
+ t.integer "lock_version"
+ t.text "title_html"
+ t.text "description_html"
+ t.integer "time_estimate"
+ t.integer "relative_position"
+ t.integer "cached_markdown_version"
+ t.datetime "last_edited_at"
+ t.integer "last_edited_by_id"
+ t.boolean "discussion_locked"
+ t.datetime_with_timezone "closed_at"
+ t.index ["author_id"], name: "index_issues_on_author_id", using: :btree
+ t.index ["confidential"], name: "index_issues_on_confidential", using: :btree
+ t.index ["description"], name: "index_issues_on_description_trigram", using: :gin, opclasses: {"description"=>"gin_trgm_ops"}
+ t.index ["milestone_id"], name: "index_issues_on_milestone_id", using: :btree
+ t.index ["moved_to_id"], name: "index_issues_on_moved_to_id", where: "(moved_to_id IS NOT NULL)", using: :btree
+ t.index ["project_id", "created_at", "id", "state"], name: "index_issues_on_project_id_and_created_at_and_id_and_state", using: :btree
+ t.index ["project_id", "due_date", "id", "state"], name: "idx_issues_on_project_id_and_due_date_and_id_and_state_partial", where: "(due_date IS NOT NULL)", using: :btree
+ t.index ["project_id", "iid"], name: "index_issues_on_project_id_and_iid", unique: true, using: :btree
+ t.index ["project_id", "updated_at", "id", "state"], name: "index_issues_on_project_id_and_updated_at_and_id_and_state", using: :btree
+ t.index ["relative_position"], name: "index_issues_on_relative_position", using: :btree
+ t.index ["state"], name: "index_issues_on_state", using: :btree
+ t.index ["title"], name: "index_issues_on_title_trigram", using: :gin, opclasses: {"title"=>"gin_trgm_ops"}
+ t.index ["updated_by_id"], name: "index_issues_on_updated_by_id", where: "(updated_by_id IS NOT NULL)", using: :btree
+ end
+ create_table "keys", id: :serial do |t|
+ t.integer "user_id"
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ t.text "key"
+ t.string "title"
+ t.string "type"
+ t.string "fingerprint"
+ t.boolean "public", default: false, null: false
+ t.datetime "last_used_at"
+ t.index ["fingerprint"], name: "index_keys_on_fingerprint", unique: true, using: :btree
+ t.index ["user_id"], name: "index_keys_on_user_id", using: :btree
+ end
+ create_table "label_links", id: :serial do |t|
+ t.integer "label_id"
+ t.integer "target_id"
+ t.string "target_type"
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ t.index ["label_id"], name: "index_label_links_on_label_id", using: :btree
+ t.index ["target_id", "target_type"], name: "index_label_links_on_target_id_and_target_type", using: :btree
+ end
+ create_table "label_priorities", id: :serial do |t|
+ t.integer "project_id", null: false
+ t.integer "label_id", null: false
+ t.integer "priority", null: false
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ t.index ["priority"], name: "index_label_priorities_on_priority", using: :btree
+ t.index ["project_id", "label_id"], name: "index_label_priorities_on_project_id_and_label_id", unique: true, using: :btree
+ end
+ create_table "labels", id: :serial do |t|
+ t.string "title"
+ t.string "color"
+ t.integer "project_id"
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ t.boolean "template", default: false
+ t.string "description"
+ t.text "description_html"
+ t.string "type"
+ t.integer "group_id"
+ t.integer "cached_markdown_version"
+ t.index ["group_id", "project_id", "title"], name: "index_labels_on_group_id_and_project_id_and_title", unique: true, using: :btree
+ t.index ["project_id"], name: "index_labels_on_project_id", using: :btree
+ t.index ["template"], name: "index_labels_on_template", where: "template", using: :btree
+ t.index ["title"], name: "index_labels_on_title", using: :btree
+ t.index ["type", "project_id"], name: "index_labels_on_type_and_project_id", using: :btree
+ end
+ create_table "lfs_objects", id: :serial do |t|
+ t.string "oid", null: false
+ t.bigint "size", null: false
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ t.string "file"
+ t.integer "file_store"
+ t.index ["oid"], name: "index_lfs_objects_on_oid", unique: true, using: :btree
+ end
+ create_table "lfs_objects_projects", id: :serial do |t|
+ t.integer "lfs_object_id", null: false
+ t.integer "project_id", null: false
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ t.index ["project_id"], name: "index_lfs_objects_projects_on_project_id", using: :btree
+ end
+ create_table "lists", id: :serial do |t|
+ t.integer "board_id", null: false
+ t.integer "label_id"
+ t.integer "list_type", default: 1, null: false
+ t.integer "position"
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ t.index ["board_id", "label_id"], name: "index_lists_on_board_id_and_label_id", unique: true, using: :btree
+ t.index ["label_id"], name: "index_lists_on_label_id", using: :btree
+ end
+ create_table "members", id: :serial do |t|
+ t.integer "access_level", null: false
+ t.integer "source_id", null: false
+ t.string "source_type", null: false
+ t.integer "user_id"
+ t.integer "notification_level", null: false
+ t.string "type"
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ t.integer "created_by_id"
+ t.string "invite_email"
+ t.string "invite_token"
+ t.datetime "invite_accepted_at"
+ t.datetime "requested_at"
+ t.date "expires_at"
+ t.index ["access_level"], name: "index_members_on_access_level", using: :btree
+ t.index ["invite_token"], name: "index_members_on_invite_token", unique: true, using: :btree
+ t.index ["requested_at"], name: "index_members_on_requested_at", using: :btree
+ t.index ["source_id", "source_type"], name: "index_members_on_source_id_and_source_type", using: :btree
+ t.index ["user_id"], name: "index_members_on_user_id", using: :btree
+ end
+ create_table "merge_request_diff_commits", id: false do |t|
+ t.datetime_with_timezone "authored_date"
+ t.datetime_with_timezone "committed_date"
+ t.integer "merge_request_diff_id", null: false
+ t.integer "relative_order", null: false
+ t.binary "sha", null: false
+ t.text "author_name"
+ t.text "author_email"
+ t.text "committer_name"
+ t.text "committer_email"
+ t.text "message"
+ t.index ["merge_request_diff_id", "relative_order"], name: "index_merge_request_diff_commits_on_mr_diff_id_and_order", unique: true, using: :btree
+ t.index ["sha"], name: "index_merge_request_diff_commits_on_sha", using: :btree
+ end
+ create_table "merge_request_diff_files", id: false do |t|
+ t.integer "merge_request_diff_id", null: false
+ t.integer "relative_order", null: false
+ t.boolean "new_file", null: false
+ t.boolean "renamed_file", null: false
+ t.boolean "deleted_file", null: false
+ t.boolean "too_large", null: false
+ t.string "a_mode", null: false
+ t.string "b_mode", null: false
+ t.text "new_path", null: false
+ t.text "old_path", null: false
+ t.text "diff", null: false
+ t.boolean "binary"
+ t.index ["merge_request_diff_id", "relative_order"], name: "index_merge_request_diff_files_on_mr_diff_id_and_order", unique: true, using: :btree
+ end
+ create_table "merge_request_diffs", id: :serial do |t|
+ t.string "state"
+ t.integer "merge_request_id", null: false
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ t.string "base_commit_sha"
+ t.string "real_size"
+ t.string "head_commit_sha"
+ t.string "start_commit_sha"
+ t.index ["merge_request_id", "id"], name: "index_merge_request_diffs_on_merge_request_id_and_id", using: :btree
+ end
+ create_table "merge_request_metrics", id: :serial do |t|
+ t.integer "merge_request_id", null: false
+ t.datetime "latest_build_started_at"
+ t.datetime "latest_build_finished_at"
+ t.datetime "first_deployed_to_production_at"
+ t.datetime "merged_at"
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ t.integer "pipeline_id"
+ t.integer "merged_by_id"
+ t.integer "latest_closed_by_id"
+ t.datetime_with_timezone "latest_closed_at"
+ t.index ["first_deployed_to_production_at"], name: "index_merge_request_metrics_on_first_deployed_to_production_at", using: :btree
+ t.index ["merge_request_id"], name: "index_merge_request_metrics", using: :btree
+ t.index ["pipeline_id"], name: "index_merge_request_metrics_on_pipeline_id", using: :btree
+ end
+ create_table "merge_requests", id: :serial do |t|
+ t.string "target_branch", null: false
+ t.string "source_branch", null: false
+ t.integer "source_project_id"
+ t.integer "author_id"
+ t.integer "assignee_id"
+ t.string "title"
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ t.integer "milestone_id"
+ t.string "state", default: "opened", null: false
+ t.string "merge_status", default: "unchecked", null: false
+ t.integer "target_project_id", null: false
+ t.integer "iid"
+ t.text "description"
+ t.integer "updated_by_id"
+ t.text "merge_error"
+ t.text "merge_params"
+ t.boolean "merge_when_pipeline_succeeds", default: false, null: false
+ t.integer "merge_user_id"
+ t.string "merge_commit_sha"
+ t.string "rebase_commit_sha"
+ t.string "in_progress_merge_commit_sha"
+ t.integer "lock_version"
+ t.text "title_html"
+ t.text "description_html"
+ t.integer "time_estimate"
+ t.integer "cached_markdown_version"
+ t.datetime "last_edited_at"
+ t.integer "last_edited_by_id"
+ t.integer "head_pipeline_id"
+ t.string "merge_jid"
+ t.boolean "discussion_locked"
+ t.integer "latest_merge_request_diff_id"
+ t.index ["assignee_id"], name: "index_merge_requests_on_assignee_id", using: :btree
+ t.index ["author_id"], name: "index_merge_requests_on_author_id", using: :btree
+ t.index ["created_at"], name: "index_merge_requests_on_created_at", using: :btree
+ t.index ["description"], name: "index_merge_requests_on_description_trigram", using: :gin, opclasses: {"description"=>"gin_trgm_ops"}
+ t.index ["head_pipeline_id"], name: "index_merge_requests_on_head_pipeline_id", using: :btree
+ t.index ["latest_merge_request_diff_id"], name: "index_merge_requests_on_latest_merge_request_diff_id", using: :btree
+ t.index ["merge_user_id"], name: "index_merge_requests_on_merge_user_id", where: "(merge_user_id IS NOT NULL)", using: :btree
+ t.index ["milestone_id"], name: "index_merge_requests_on_milestone_id", using: :btree
+ t.index ["source_branch"], name: "index_merge_requests_on_source_branch", using: :btree
+ t.index ["source_project_id", "source_branch"], name: "index_merge_requests_on_source_project_and_branch_state_opened", where: "((state)::text = 'opened'::text)", using: :btree
+ t.index ["source_project_id", "source_branch"], name: "index_merge_requests_on_source_project_id_and_source_branch", using: :btree
+ t.index ["target_branch"], name: "index_merge_requests_on_target_branch", using: :btree
+ t.index ["target_project_id", "iid"], name: "index_merge_requests_on_target_project_id_and_iid", unique: true, using: :btree
+ t.index ["target_project_id", "merge_commit_sha", "id"], name: "index_merge_requests_on_tp_id_and_merge_commit_sha_and_id", using: :btree
+ t.index ["title"], name: "index_merge_requests_on_title", using: :btree
+ t.index ["title"], name: "index_merge_requests_on_title_trigram", using: :gin, opclasses: {"title"=>"gin_trgm_ops"}
+ t.index ["updated_by_id"], name: "index_merge_requests_on_updated_by_id", where: "(updated_by_id IS NOT NULL)", using: :btree
+ end
+ create_table "merge_requests_closing_issues", id: :serial do |t|
+ t.integer "merge_request_id", null: false
+ t.integer "issue_id", null: false
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ t.index ["issue_id"], name: "index_merge_requests_closing_issues_on_issue_id", using: :btree
+ t.index ["merge_request_id"], name: "index_merge_requests_closing_issues_on_merge_request_id", using: :btree
+ end
+ create_table "milestones", id: :serial do |t|
+ t.string "title", null: false
+ t.integer "project_id"
+ t.text "description"
+ t.date "due_date"
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ t.string "state"
+ t.integer "iid"
+ t.text "title_html"
+ t.text "description_html"
+ t.date "start_date"
+ t.integer "cached_markdown_version"
+ t.integer "group_id"
+ t.index ["description"], name: "index_milestones_on_description_trigram", using: :gin, opclasses: {"description"=>"gin_trgm_ops"}
+ t.index ["due_date"], name: "index_milestones_on_due_date", using: :btree
+ t.index ["group_id"], name: "index_milestones_on_group_id", using: :btree
+ t.index ["project_id", "iid"], name: "index_milestones_on_project_id_and_iid", unique: true, using: :btree
+ t.index ["title"], name: "index_milestones_on_title", using: :btree
+ t.index ["title"], name: "index_milestones_on_title_trigram", using: :gin, opclasses: {"title"=>"gin_trgm_ops"}
+ end
+ create_table "namespaces", id: :serial do |t|
+ t.string "name", null: false
+ t.string "path", null: false
+ t.integer "owner_id"
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ t.string "type"
+ t.string "description", default: "", null: false
+ t.string "avatar"
+ t.boolean "share_with_group_lock", default: false
+ t.integer "visibility_level", default: 20, null: false
+ t.boolean "request_access_enabled", default: false, null: false
+ t.text "description_html"
+ t.boolean "lfs_enabled"
+ t.integer "parent_id"
+ t.boolean "require_two_factor_authentication", default: false, null: false
+ t.integer "two_factor_grace_period", default: 48, null: false
+ t.integer "cached_markdown_version"
+ t.string "runners_token"
+ t.index ["created_at"], name: "index_namespaces_on_created_at", using: :btree
+ t.index ["name", "parent_id"], name: "index_namespaces_on_name_and_parent_id", unique: true, using: :btree
+ t.index ["name"], name: "index_namespaces_on_name_trigram", using: :gin, opclasses: {"name"=>"gin_trgm_ops"}
+ t.index ["owner_id"], name: "index_namespaces_on_owner_id", using: :btree
+ t.index ["parent_id", "id"], name: "index_namespaces_on_parent_id_and_id", unique: true, using: :btree
+ t.index ["path"], name: "index_namespaces_on_path", using: :btree
+ t.index ["path"], name: "index_namespaces_on_path_trigram", using: :gin, opclasses: {"path"=>"gin_trgm_ops"}
+ t.index ["require_two_factor_authentication"], name: "index_namespaces_on_require_two_factor_authentication", using: :btree
+ t.index ["type"], name: "index_namespaces_on_type", using: :btree
+ end
+ create_table "notes", id: :serial do |t|
+ t.text "note"
+ t.string "noteable_type"
+ t.integer "author_id"
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ t.integer "project_id"
+ t.string "attachment"
+ t.string "line_code"
+ t.string "commit_id"
+ t.integer "noteable_id"
+ t.boolean "system", default: false, null: false
+ t.text "st_diff"
+ t.integer "updated_by_id"
+ t.string "type"
+ t.text "position"
+ t.text "original_position"
+ t.datetime "resolved_at"
+ t.integer "resolved_by_id"
+ t.string "discussion_id"
+ t.text "note_html"
+ t.integer "cached_markdown_version"
+ t.text "change_position"
+ t.boolean "resolved_by_push"
+ t.index ["author_id"], name: "index_notes_on_author_id", using: :btree
+ t.index ["commit_id"], name: "index_notes_on_commit_id", using: :btree
+ t.index ["created_at"], name: "index_notes_on_created_at", using: :btree
+ t.index ["discussion_id"], name: "index_notes_on_discussion_id", using: :btree
+ t.index ["line_code"], name: "index_notes_on_line_code", using: :btree
+ t.index ["note"], name: "index_notes_on_note_trigram", using: :gin, opclasses: {"note"=>"gin_trgm_ops"}
+ t.index ["noteable_id", "noteable_type"], name: "index_notes_on_noteable_id_and_noteable_type", using: :btree
+ t.index ["noteable_type"], name: "index_notes_on_noteable_type", using: :btree
+ t.index ["project_id", "noteable_type"], name: "index_notes_on_project_id_and_noteable_type", using: :btree
+ t.index ["updated_at"], name: "index_notes_on_updated_at", using: :btree
+ end
+ create_table "notification_settings", id: :serial do |t|
+ t.integer "user_id", null: false
+ t.string "source_type"
+ t.integer "source_id"
+ t.integer "level", default: 0, null: false
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ t.boolean "new_note"
+ t.boolean "new_issue"
+ t.boolean "reopen_issue"
+ t.boolean "close_issue"
+ t.boolean "reassign_issue"
+ t.boolean "new_merge_request"
+ t.boolean "reopen_merge_request"
+ t.boolean "close_merge_request"
+ t.boolean "reassign_merge_request"
+ t.boolean "merge_merge_request"
+ t.boolean "failed_pipeline"
+ t.boolean "success_pipeline"
+ t.index ["source_id", "source_type"], name: "index_notification_settings_on_source_id_and_source_type", using: :btree
+ t.index ["user_id", "source_id", "source_type"], name: "index_notifications_on_user_id_and_source_id_and_source_type", unique: true, using: :btree
+ t.index ["user_id"], name: "index_notification_settings_on_user_id", using: :btree
+ end
+ create_table "oauth_access_grants", id: :serial do |t|
+ t.integer "resource_owner_id", null: false
+ t.integer "application_id", null: false
+ t.string "token", null: false
+ t.integer "expires_in", null: false
+ t.text "redirect_uri", null: false
+ t.datetime "created_at", null: false
+ t.datetime "revoked_at"
+ t.string "scopes"
+ t.index ["token"], name: "index_oauth_access_grants_on_token", unique: true, using: :btree
+ end
+ create_table "oauth_access_tokens", id: :serial do |t|
+ t.integer "resource_owner_id"
+ t.integer "application_id"
+ t.string "token", null: false
+ t.string "refresh_token"
+ t.integer "expires_in"
+ t.datetime "revoked_at"
+ t.datetime "created_at", null: false
+ t.string "scopes"
+ t.index ["refresh_token"], name: "index_oauth_access_tokens_on_refresh_token", unique: true, using: :btree
+ t.index ["resource_owner_id"], name: "index_oauth_access_tokens_on_resource_owner_id", using: :btree
+ t.index ["token"], name: "index_oauth_access_tokens_on_token", unique: true, using: :btree
+ end
+ create_table "oauth_applications", id: :serial do |t|
+ t.string "name", null: false
+ t.string "uid", null: false
+ t.string "secret", null: false
+ t.text "redirect_uri", null: false
+ t.string "scopes", default: "", null: false
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ t.integer "owner_id"
+ t.string "owner_type"
+ t.boolean "trusted", default: false, null: false
+ t.index ["owner_id", "owner_type"], name: "index_oauth_applications_on_owner_id_and_owner_type", using: :btree
+ t.index ["uid"], name: "index_oauth_applications_on_uid", unique: true, using: :btree
+ end
+ create_table "oauth_openid_requests", id: :serial do |t|
+ t.integer "access_grant_id", null: false
+ t.string "nonce", null: false
+ end
+ create_table "pages_domains", id: :serial do |t|
+ t.integer "project_id"
+ t.text "certificate"
+ t.text "encrypted_key"
+ t.string "encrypted_key_iv"
+ t.string "encrypted_key_salt"
+ t.string "domain"
+ t.index ["domain"], name: "index_pages_domains_on_domain", unique: true, using: :btree
+ t.index ["project_id"], name: "index_pages_domains_on_project_id", using: :btree
+ end
+ create_table "personal_access_tokens", id: :serial do |t|
+ t.integer "user_id", null: false
+ t.string "token", null: false
+ t.string "name", null: false
+ t.boolean "revoked", default: false
+ t.date "expires_at"
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ t.string "scopes", default: "--- []\n", null: false
+ t.boolean "impersonation", default: false, null: false
+ t.index ["token"], name: "index_personal_access_tokens_on_token", unique: true, using: :btree
+ t.index ["user_id"], name: "index_personal_access_tokens_on_user_id", using: :btree
+ end
+ create_table "project_authorizations", id: false do |t|
+ t.integer "user_id"
+ t.integer "project_id"
+ t.integer "access_level"
+ t.index ["project_id"], name: "index_project_authorizations_on_project_id", using: :btree
+ t.index ["user_id", "project_id", "access_level"], name: "index_project_authorizations_on_user_id_project_id_access_level", unique: true, using: :btree
+ end
+ create_table "project_auto_devops", id: :serial do |t|
+ t.integer "project_id", null: false
+ t.datetime_with_timezone "created_at", null: false
+ t.datetime_with_timezone "updated_at", null: false
+ t.boolean "enabled"
+ t.string "domain"
+ t.index ["project_id"], name: "index_project_auto_devops_on_project_id", unique: true, using: :btree
+ end
+ create_table "project_custom_attributes", id: :serial do |t|
+ t.datetime_with_timezone "created_at", null: false
+ t.datetime_with_timezone "updated_at", null: false
+ t.integer "project_id", null: false
+ t.string "key", null: false
+ t.string "value", null: false
+ t.index ["key", "value"], name: "index_project_custom_attributes_on_key_and_value", using: :btree
+ t.index ["project_id", "key"], name: "index_project_custom_attributes_on_project_id_and_key", unique: true, using: :btree
+ end
+ create_table "project_features", id: :serial do |t|
+ t.integer "project_id"
+ t.integer "merge_requests_access_level"
+ t.integer "issues_access_level"
+ t.integer "wiki_access_level"
+ t.integer "snippets_access_level"
+ t.integer "builds_access_level"
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ t.integer "repository_access_level", default: 20, null: false
+ t.index ["project_id"], name: "index_project_features_on_project_id", using: :btree
+ end
+ create_table "project_group_links", id: :serial do |t|
+ t.integer "project_id", null: false
+ t.integer "group_id", null: false
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ t.integer "group_access", default: 30, null: false
+ t.date "expires_at"
+ t.index ["group_id"], name: "index_project_group_links_on_group_id", using: :btree
+ t.index ["project_id"], name: "index_project_group_links_on_project_id", using: :btree
+ end
+ create_table "project_import_data", id: :serial do |t|
+ t.integer "project_id"
+ t.text "data"
+ t.text "encrypted_credentials"
+ t.string "encrypted_credentials_iv"
+ t.string "encrypted_credentials_salt"
+ t.index ["project_id"], name: "index_project_import_data_on_project_id", using: :btree
+ end
+ create_table "project_statistics", id: :serial do |t|
+ t.integer "project_id", null: false
+ t.integer "namespace_id", null: false
+ t.bigint "commit_count", default: 0, null: false
+ t.bigint "storage_size", default: 0, null: false
+ t.bigint "repository_size", default: 0, null: false
+ t.bigint "lfs_objects_size", default: 0, null: false
+ t.bigint "build_artifacts_size", default: 0, null: false
+ t.index ["namespace_id"], name: "index_project_statistics_on_namespace_id", using: :btree
+ t.index ["project_id"], name: "index_project_statistics_on_project_id", unique: true, using: :btree
+ end
+ create_table "projects", id: :serial do |t|
+ t.string "name"
+ t.string "path"
+ t.text "description"
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ t.integer "creator_id"
+ t.integer "namespace_id"
+ t.datetime "last_activity_at"
+ t.string "import_url"
+ t.integer "visibility_level", default: 0, null: false
+ t.boolean "archived", default: false, null: false
+ t.string "avatar"
+ t.string "import_status"
+ t.integer "star_count", default: 0, null: false
+ t.boolean "merge_requests_rebase_enabled", default: false, null: false
+ t.string "import_type"
+ t.string "import_source"
+ t.boolean "merge_requests_ff_only_enabled", default: false, null: false
+ t.text "import_error"
+ t.integer "ci_id"
+ t.boolean "shared_runners_enabled", default: true, null: false
+ t.string "runners_token"
+ t.string "build_coverage_regex"
+ t.boolean "build_allow_git_fetch", default: true, null: false
+ t.integer "build_timeout", default: 3600, null: false
+ t.boolean "pending_delete", default: false
+ t.boolean "public_builds", default: true, null: false
+ t.boolean "last_repository_check_failed"
+ t.datetime "last_repository_check_at"
+ t.boolean "container_registry_enabled"
+ t.boolean "only_allow_merge_if_pipeline_succeeds", default: false, null: false
+ t.boolean "has_external_issue_tracker"
+ t.string "repository_storage", default: "default", null: false
+ t.boolean "repository_read_only"
+ t.boolean "request_access_enabled", default: false, null: false
+ t.boolean "has_external_wiki"
+ t.string "ci_config_path"
+ t.boolean "lfs_enabled"
+ t.text "description_html"
+ t.boolean "only_allow_merge_if_all_discussions_are_resolved"
+ t.boolean "printing_merge_request_link_enabled", default: true, null: false
+ t.integer "auto_cancel_pending_pipelines", default: 1, null: false
+ t.string "import_jid"
+ t.integer "cached_markdown_version"
+ t.text "delete_error"
+ t.datetime "last_repository_updated_at"
+ t.integer "storage_version", limit: 2
+ t.boolean "resolve_outdated_diff_discussions"
+ t.string "external_authorization_classification_label"
+ t.integer "jobs_cache_index"
+ t.index ["ci_id"], name: "index_projects_on_ci_id", using: :btree
+ t.index ["created_at"], name: "index_projects_on_created_at", using: :btree
+ t.index ["creator_id"], name: "index_projects_on_creator_id", using: :btree
+ t.index ["description"], name: "index_projects_on_description_trigram", using: :gin, opclasses: {"description"=>"gin_trgm_ops"}
+ t.index ["last_activity_at"], name: "index_projects_on_last_activity_at", using: :btree
+ t.index ["last_repository_check_failed"], name: "index_projects_on_last_repository_check_failed", using: :btree
+ t.index ["last_repository_updated_at"], name: "index_projects_on_last_repository_updated_at", using: :btree
+ t.index ["name"], name: "index_projects_on_name_trigram", using: :gin, opclasses: {"name"=>"gin_trgm_ops"}
+ t.index ["namespace_id"], name: "index_projects_on_namespace_id", using: :btree
+ t.index ["path"], name: "index_projects_on_path", using: :btree
+ t.index ["path"], name: "index_projects_on_path_trigram", using: :gin, opclasses: {"path"=>"gin_trgm_ops"}
+ t.index ["pending_delete"], name: "index_projects_on_pending_delete", using: :btree
+ t.index ["repository_storage"], name: "index_projects_on_repository_storage", using: :btree
+ t.index ["runners_token"], name: "index_projects_on_runners_token", using: :btree
+ t.index ["star_count"], name: "index_projects_on_star_count", using: :btree
+ t.index ["visibility_level"], name: "index_projects_on_visibility_level", using: :btree
+ end
+ create_table "protected_branch_merge_access_levels", id: :serial do |t|
+ t.integer "protected_branch_id", null: false
+ t.integer "access_level", default: 40, null: false
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ t.index ["protected_branch_id"], name: "index_protected_branch_merge_access", using: :btree
+ end
+ create_table "protected_branch_push_access_levels", id: :serial do |t|
+ t.integer "protected_branch_id", null: false
+ t.integer "access_level", default: 40, null: false
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ t.index ["protected_branch_id"], name: "index_protected_branch_push_access", using: :btree
+ end
+ create_table "protected_branches", id: :serial do |t|
+ t.integer "project_id", null: false
+ t.string "name", null: false
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ t.index ["project_id"], name: "index_protected_branches_on_project_id", using: :btree
+ end
+ create_table "protected_tag_create_access_levels", id: :serial do |t|
+ t.integer "protected_tag_id", null: false
+ t.integer "access_level", default: 40
+ t.integer "user_id"
+ t.integer "group_id"
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ t.index ["protected_tag_id"], name: "index_protected_tag_create_access", using: :btree
+ t.index ["user_id"], name: "index_protected_tag_create_access_levels_on_user_id", using: :btree
+ end
+ create_table "protected_tags", id: :serial do |t|
+ t.integer "project_id", null: false
+ t.string "name", null: false
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ t.index ["project_id"], name: "index_protected_tags_on_project_id", using: :btree
+ end
+ create_table "push_event_payloads", id: false do |t|
+ t.bigint "commit_count", null: false
+ t.integer "event_id", null: false
+ t.integer "action", limit: 2, null: false
+ t.integer "ref_type", limit: 2, null: false
+ t.binary "commit_from"
+ t.binary "commit_to"
+ t.text "ref"
+ t.string "commit_title", limit: 70
+ t.index ["event_id"], name: "index_push_event_payloads_on_event_id", unique: true, using: :btree
+ end
+ create_table "redirect_routes", id: :serial do |t|
+ t.integer "source_id", null: false
+ t.string "source_type", null: false
+ t.string "path", null: false
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ t.boolean "permanent"
+ t.index ["path"], name: "index_redirect_routes_on_path", unique: true, using: :btree
+ t.index ["path"], name: "index_redirect_routes_on_path_text_pattern_ops", using: :btree, opclasses: {"path"=>"varchar_pattern_ops"}
+ t.index ["permanent"], name: "index_redirect_routes_on_permanent", using: :btree
+ t.index ["source_type", "source_id"], name: "index_redirect_routes_on_source_type_and_source_id", using: :btree
+ end
+ create_table "releases", id: :serial do |t|
+ t.string "tag"
+ t.text "description"
+ t.integer "project_id"
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ t.text "description_html"
+ t.integer "cached_markdown_version"
+ t.index ["project_id", "tag"], name: "index_releases_on_project_id_and_tag", using: :btree
+ t.index ["project_id"], name: "index_releases_on_project_id", using: :btree
+ end
+ create_table "routes", id: :serial do |t|
+ t.integer "source_id", null: false
+ t.string "source_type", null: false
+ t.string "path", null: false
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ t.string "name"
+ t.index ["path"], name: "index_routes_on_path", unique: true, using: :btree
+ t.index ["path"], name: "index_routes_on_path_text_pattern_ops", using: :btree, opclasses: {"path"=>"varchar_pattern_ops"}
+ t.index ["source_type", "source_id"], name: "index_routes_on_source_type_and_source_id", unique: true, using: :btree
+ end
+ create_table "sent_notifications", id: :serial do |t|
+ t.integer "project_id"
+ t.string "noteable_type"
+ t.integer "noteable_id"
+ t.integer "recipient_id"
+ t.string "commit_id"
+ t.string "reply_key", null: false
+ t.string "line_code"
+ t.string "note_type"
+ t.text "position"
+ t.string "in_reply_to_discussion_id"
+ t.index ["reply_key"], name: "index_sent_notifications_on_reply_key", unique: true, using: :btree
+ end
+ create_table "services", id: :serial do |t|
+ t.string "type"
+ t.string "title"
+ t.integer "project_id"
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ t.boolean "active", default: false, null: false
+ t.text "properties"
+ t.boolean "template", default: false
+ t.boolean "push_events", default: true
+ t.boolean "issues_events", default: true
+ t.boolean "merge_requests_events", default: true
+ t.boolean "tag_push_events", default: true
+ t.boolean "note_events", default: true, null: false
+ t.string "category", default: "common", null: false
+ t.boolean "default", default: false
+ t.boolean "wiki_page_events", default: true
+ t.boolean "pipeline_events", default: false, null: false
+ t.boolean "confidential_issues_events", default: true, null: false
+ t.boolean "commit_events", default: true, null: false
+ t.boolean "job_events", default: false, null: false
+ t.index ["project_id"], name: "index_services_on_project_id", using: :btree
+ t.index ["template"], name: "index_services_on_template", using: :btree
+ end
+ create_table "snippets", id: :serial do |t|
+ t.string "title"
+ t.text "content"
+ t.integer "author_id", null: false
+ t.integer "project_id"
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ t.string "file_name"
+ t.string "type"
+ t.integer "visibility_level", default: 0, null: false
+ t.text "title_html"
+ t.text "content_html"
+ t.integer "cached_markdown_version"
+ t.text "description"
+ t.text "description_html"
+ t.index ["author_id"], name: "index_snippets_on_author_id", using: :btree
+ t.index ["file_name"], name: "index_snippets_on_file_name_trigram", using: :gin, opclasses: {"file_name"=>"gin_trgm_ops"}
+ t.index ["project_id"], name: "index_snippets_on_project_id", using: :btree
+ t.index ["title"], name: "index_snippets_on_title_trigram", using: :gin, opclasses: {"title"=>"gin_trgm_ops"}
+ t.index ["updated_at"], name: "index_snippets_on_updated_at", using: :btree
+ t.index ["visibility_level"], name: "index_snippets_on_visibility_level", using: :btree
+ end
+ create_table "spam_logs", id: :serial do |t|
+ t.integer "user_id"
+ t.string "source_ip"
+ t.string "user_agent"
+ t.boolean "via_api"
+ t.string "noteable_type"
+ t.string "title"
+ t.text "description"
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ t.boolean "submitted_as_ham", default: false, null: false
+ t.boolean "recaptcha_verified", default: false, null: false
+ end
+ create_table "subscriptions", id: :serial do |t|
+ t.integer "user_id"
+ t.string "subscribable_type"
+ t.integer "subscribable_id"
+ t.boolean "subscribed"
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ t.integer "project_id"
+ t.index ["subscribable_id", "subscribable_type", "user_id", "project_id"], name: "index_subscriptions_on_subscribable_and_user_id_and_project_id", unique: true, using: :btree
+ end
+ create_table "system_note_metadata", id: :serial do |t|
+ t.integer "note_id", null: false
+ t.integer "commit_count"
+ t.string "action"
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ t.index ["note_id"], name: "index_system_note_metadata_on_note_id", unique: true, using: :btree
+ end
+ create_table "taggings", id: :serial do |t|
+ t.integer "tag_id"
+ t.integer "taggable_id"
+ t.string "taggable_type"
+ t.integer "tagger_id"
+ t.string "tagger_type"
+ t.string "context"
+ t.datetime "created_at"
+ t.index ["tag_id", "taggable_id", "taggable_type", "context", "tagger_id", "tagger_type"], name: "taggings_idx", unique: true, using: :btree
+ t.index ["taggable_id", "taggable_type", "context"], name: "index_taggings_on_taggable_id_and_taggable_type_and_context", using: :btree
+ end
+ create_table "tags", id: :serial do |t|
+ t.string "name"
+ t.integer "taggings_count", default: 0
+ t.index ["name"], name: "index_tags_on_name", unique: true, using: :btree
+ end
+ create_table "timelogs", id: :serial do |t|
+ t.integer "time_spent", null: false
+ t.integer "user_id"
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ t.integer "issue_id"
+ t.integer "merge_request_id"
+ t.datetime_with_timezone "spent_at"
+ t.index ["issue_id"], name: "index_timelogs_on_issue_id", using: :btree
+ t.index ["merge_request_id"], name: "index_timelogs_on_merge_request_id", using: :btree
+ t.index ["user_id"], name: "index_timelogs_on_user_id", using: :btree
+ end
+ create_table "todos", id: :serial do |t|
+ t.integer "user_id", null: false
+ t.integer "project_id", null: false
+ t.string "target_type", null: false
+ t.integer "target_id"
+ t.integer "author_id"
+ t.integer "action", null: false
+ t.string "state", null: false
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ t.integer "note_id"
+ t.string "commit_id"
+ t.index ["author_id"], name: "index_todos_on_author_id", using: :btree
+ t.index ["commit_id"], name: "index_todos_on_commit_id", using: :btree
+ t.index ["note_id"], name: "index_todos_on_note_id", using: :btree
+ t.index ["project_id"], name: "index_todos_on_project_id", using: :btree
+ t.index ["target_type", "target_id"], name: "index_todos_on_target_type_and_target_id", using: :btree
+ t.index ["user_id"], name: "index_todos_on_user_id", using: :btree
+ end
+ create_table "trending_projects", id: :serial do |t|
+ t.integer "project_id", null: false
+ t.index ["project_id"], name: "index_trending_projects_on_project_id", using: :btree
+ end
+ create_table "u2f_registrations", id: :serial do |t|
+ t.text "certificate"
+ t.string "key_handle"
+ t.string "public_key"
+ t.integer "counter"
+ t.integer "user_id"
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ t.string "name"
+ t.index ["key_handle"], name: "index_u2f_registrations_on_key_handle", using: :btree
+ t.index ["user_id"], name: "index_u2f_registrations_on_user_id", using: :btree
+ end
+ create_table "uploads", id: :serial do |t|
+ t.bigint "size", null: false
+ t.string "path", limit: 511, null: false
+ t.string "checksum", limit: 64
+ t.string "model_type"
+ t.integer "model_id"
+ t.string "uploader", null: false
+ t.datetime "created_at", null: false
+ t.integer "store"
+ t.index ["checksum"], name: "index_uploads_on_checksum", using: :btree
+ t.index ["model_id", "model_type"], name: "index_uploads_on_model_id_and_model_type", using: :btree
+ t.index ["path"], name: "index_uploads_on_path", using: :btree
+ end
+ create_table "user_agent_details", id: :serial do |t|
+ t.string "user_agent", null: false
+ t.string "ip_address", null: false
+ t.integer "subject_id", null: false
+ t.string "subject_type", null: false
+ t.boolean "submitted", default: false, null: false
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ t.index ["subject_id", "subject_type"], name: "index_user_agent_details_on_subject_id_and_subject_type", using: :btree
+ end
+ create_table "user_custom_attributes", id: :serial do |t|
+ t.datetime_with_timezone "created_at", null: false
+ t.datetime_with_timezone "updated_at", null: false
+ t.integer "user_id", null: false
+ t.string "key", null: false
+ t.string "value", null: false
+ t.index ["key", "value"], name: "index_user_custom_attributes_on_key_and_value", using: :btree
+ t.index ["user_id", "key"], name: "index_user_custom_attributes_on_user_id_and_key", unique: true, using: :btree
+ end
+ create_table "user_synced_attributes_metadata", id: :serial do |t|
+ t.boolean "name_synced", default: false
+ t.boolean "email_synced", default: false
+ t.boolean "location_synced", default: false
+ t.integer "user_id", null: false
+ t.string "provider"
+ t.index ["user_id"], name: "index_user_synced_attributes_metadata_on_user_id", unique: true, using: :btree
+ end
+ create_table "users", id: :serial do |t|
+ t.string "email", default: "", null: false
+ t.string "encrypted_password", default: "", null: false
+ t.string "reset_password_token"
+ t.datetime "reset_password_sent_at"
+ t.datetime "remember_created_at"
+ t.integer "sign_in_count", default: 0
+ t.datetime "current_sign_in_at"
+ t.datetime "last_sign_in_at"
+ t.string "current_sign_in_ip"
+ t.string "last_sign_in_ip"
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ t.string "name"
+ t.boolean "admin", default: false, null: false
+ t.integer "projects_limit", null: false
+ t.string "skype", default: "", null: false
+ t.string "linkedin", default: "", null: false
+ t.string "twitter", default: "", null: false
+ t.string "bio"
+ t.integer "failed_attempts", default: 0
+ t.datetime "locked_at"
+ t.string "username"
+ t.boolean "can_create_group", default: true, null: false
+ t.boolean "can_create_team", default: true, null: false
+ t.string "state"
+ t.integer "color_scheme_id", default: 1, null: false
+ t.datetime "password_expires_at"
+ t.integer "created_by_id"
+ t.datetime "last_credential_check_at"
+ t.string "avatar"
+ t.string "confirmation_token"
+ t.datetime "confirmed_at"
+ t.datetime "confirmation_sent_at"
+ t.string "unconfirmed_email"
+ t.boolean "hide_no_ssh_key", default: false
+ t.string "website_url", default: "", null: false
+ t.string "notification_email"
+ t.boolean "hide_no_password", default: false
+ t.boolean "password_automatically_set", default: false
+ t.string "location"
+ t.string "encrypted_otp_secret"
+ t.string "encrypted_otp_secret_iv"
+ t.string "encrypted_otp_secret_salt"
+ t.boolean "otp_required_for_login", default: false, null: false
+ t.text "otp_backup_codes"
+ t.string "public_email", default: "", null: false
+ t.integer "dashboard", default: 0
+ t.integer "project_view", default: 0
+ t.integer "consumed_timestep"
+ t.integer "layout", default: 0
+ t.boolean "hide_project_limit", default: false
+ t.string "unlock_token"
+ t.datetime "otp_grace_period_started_at"
+ t.boolean "external", default: false
+ t.string "incoming_email_token"
+ t.string "organization"
+ t.boolean "require_two_factor_authentication_from_group", default: false, null: false
+ t.integer "two_factor_grace_period", default: 48, null: false
+ t.boolean "ghost"
+ t.date "last_activity_on"
+ t.boolean "notified_of_own_activity"
+ t.string "preferred_language"
+ t.string "rss_token"
+ t.integer "theme_id", limit: 2
+ t.index ["admin"], name: "index_users_on_admin", using: :btree
+ t.index ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true, using: :btree
+ t.index ["created_at"], name: "index_users_on_created_at", using: :btree
+ t.index ["email"], name: "index_users_on_email", unique: true, using: :btree
+ t.index ["email"], name: "index_users_on_email_trigram", using: :gin, opclasses: {"email"=>"gin_trgm_ops"}
+ t.index ["ghost"], name: "index_users_on_ghost", using: :btree
+ t.index ["incoming_email_token"], name: "index_users_on_incoming_email_token", using: :btree
+ t.index ["name"], name: "index_users_on_name", using: :btree
+ t.index ["name"], name: "index_users_on_name_trigram", using: :gin, opclasses: {"name"=>"gin_trgm_ops"}
+ t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, using: :btree
+ t.index ["rss_token"], name: "index_users_on_rss_token", using: :btree
+ t.index ["state"], name: "index_users_on_state", using: :btree
+ t.index ["username"], name: "index_users_on_username", using: :btree
+ t.index ["username"], name: "index_users_on_username_trigram", using: :gin, opclasses: {"username"=>"gin_trgm_ops"}
+ end
+ create_table "users_star_projects", id: :serial do |t|
+ t.integer "project_id", null: false
+ t.integer "user_id", null: false
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ t.index ["project_id"], name: "index_users_star_projects_on_project_id", using: :btree
+ t.index ["user_id", "project_id"], name: "index_users_star_projects_on_user_id_and_project_id", unique: true, using: :btree
+ end
+ create_table "web_hook_logs", id: :serial do |t|
+ t.integer "web_hook_id", null: false
+ t.string "trigger"
+ t.string "url"
+ t.text "request_headers"
+ t.text "request_data"
+ t.text "response_headers"
+ t.text "response_body"
+ t.string "response_status"
+ t.float "execution_duration"
+ t.string "internal_error_message"
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ t.index ["web_hook_id"], name: "index_web_hook_logs_on_web_hook_id", using: :btree
+ end
+ create_table "web_hooks", id: :serial do |t|
+ t.string "url", limit: 2000
+ t.integer "project_id"
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ t.string "type", default: "ProjectHook"
+ t.integer "service_id"
+ t.boolean "push_events", default: true, null: false
+ t.boolean "issues_events", default: false, null: false
+ t.boolean "merge_requests_events", default: false, null: false
+ t.boolean "tag_push_events", default: false
+ t.boolean "note_events", default: false, null: false
+ t.boolean "enable_ssl_verification", default: true
+ t.boolean "wiki_page_events", default: false, null: false
+ t.string "token"
+ t.boolean "pipeline_events", default: false, null: false
+ t.boolean "confidential_issues_events", default: false, null: false
+ t.boolean "repository_update_events", default: false, null: false
+ t.boolean "job_events", default: false, null: false
+ t.boolean "confidential_note_events"
+ t.index ["project_id"], name: "index_web_hooks_on_project_id", using: :btree
+ t.index ["type"], name: "index_web_hooks_on_type", using: :btree
+ end
+ add_foreign_key "boards", "projects", name: "fk_f15266b5f9", on_delete: :cascade
+ add_foreign_key "chat_teams", "namespaces", on_delete: :cascade
+ add_foreign_key "ci_build_trace_section_names", "projects", on_delete: :cascade
+ add_foreign_key "ci_build_trace_sections", "ci_build_trace_section_names", column: "section_name_id", name: "fk_264e112c66", on_delete: :cascade
+ add_foreign_key "ci_build_trace_sections", "ci_builds", column: "build_id", name: "fk_4ebe41f502", on_delete: :cascade
+ add_foreign_key "ci_build_trace_sections", "projects", on_delete: :cascade
+ add_foreign_key "ci_builds", "ci_pipelines", column: "auto_canceled_by_id", name: "fk_a2141b1522", on_delete: :nullify
+ add_foreign_key "ci_builds", "ci_stages", column: "stage_id", name: "fk_3a9eaa254d", on_delete: :cascade
+ add_foreign_key "ci_builds", "projects", name: "fk_befce0568a", on_delete: :cascade
+ add_foreign_key "ci_group_variables", "namespaces", column: "group_id", name: "fk_33ae4d58d8", on_delete: :cascade
+ add_foreign_key "ci_job_artifacts", "ci_builds", column: "job_id", on_delete: :cascade
+ add_foreign_key "ci_job_artifacts", "projects", on_delete: :cascade
+ add_foreign_key "ci_pipeline_schedule_variables", "ci_pipeline_schedules", column: "pipeline_schedule_id", name: "fk_41c35fda51", on_delete: :cascade
+ add_foreign_key "ci_pipeline_schedules", "projects", name: "fk_8ead60fcc4", on_delete: :cascade
+ add_foreign_key "ci_pipeline_schedules", "users", column: "owner_id", name: "fk_9ea99f58d2", on_delete: :nullify
+ add_foreign_key "ci_pipeline_variables", "ci_pipelines", column: "pipeline_id", name: "fk_f29c5f4380", on_delete: :cascade
+ add_foreign_key "ci_pipelines", "ci_pipeline_schedules", column: "pipeline_schedule_id", name: "fk_3d34ab2e06", on_delete: :nullify
+ add_foreign_key "ci_pipelines", "ci_pipelines", column: "auto_canceled_by_id", name: "fk_262d4c2d19", on_delete: :nullify
+ add_foreign_key "ci_pipelines", "projects", name: "fk_86635dbd80", on_delete: :cascade
+ add_foreign_key "ci_runner_namespaces", "ci_runners", column: "runner_id", on_delete: :cascade
+ add_foreign_key "ci_runner_namespaces", "namespaces", on_delete: :cascade
+ add_foreign_key "ci_runner_projects", "projects", name: "fk_4478a6f1e4", on_delete: :cascade
+ add_foreign_key "ci_stages", "ci_pipelines", column: "pipeline_id", name: "fk_fb57e6cc56", on_delete: :cascade
+ add_foreign_key "ci_stages", "projects", name: "fk_2360681d1d", on_delete: :cascade
+ add_foreign_key "ci_trigger_requests", "ci_triggers", column: "trigger_id", name: "fk_b8ec8b7245", on_delete: :cascade
+ add_foreign_key "ci_triggers", "projects", name: "fk_e3e63f966e", on_delete: :cascade
+ add_foreign_key "ci_triggers", "users", column: "owner_id", name: "fk_e8e10d1964", on_delete: :cascade
+ add_foreign_key "ci_variables", "projects", name: "fk_ada5eb64b3", on_delete: :cascade
+ add_foreign_key "cluster_platforms_kubernetes", "clusters", on_delete: :cascade
+ add_foreign_key "cluster_projects", "clusters", on_delete: :cascade
+ add_foreign_key "cluster_projects", "projects", on_delete: :cascade
+ add_foreign_key "cluster_providers_gcp", "clusters", on_delete: :cascade
+ add_foreign_key "clusters", "users", on_delete: :nullify
+ add_foreign_key "clusters_applications_helm", "clusters", on_delete: :cascade
+ add_foreign_key "clusters_applications_ingress", "clusters", on_delete: :cascade
+ add_foreign_key "clusters_applications_prometheus", "clusters", on_delete: :cascade
+ add_foreign_key "container_repositories", "projects"
+ add_foreign_key "deploy_keys_projects", "projects", name: "fk_58a901ca7e", on_delete: :cascade
+ add_foreign_key "deployments", "projects", name: "fk_b9a3851b82", on_delete: :cascade
+ add_foreign_key "environments", "projects", name: "fk_d1c8c1da6a", on_delete: :cascade
+ add_foreign_key "events", "projects", on_delete: :cascade
+ add_foreign_key "events", "users", column: "author_id", name: "fk_edfd187b6f", on_delete: :cascade
+ add_foreign_key "fork_network_members", "fork_networks", on_delete: :cascade
+ add_foreign_key "fork_network_members", "projects", column: "forked_from_project_id", name: "fk_b01280dae4", on_delete: :nullify
+ add_foreign_key "fork_network_members", "projects", on_delete: :cascade
+ add_foreign_key "fork_networks", "projects", column: "root_project_id", name: "fk_e7b436b2b5", on_delete: :nullify
+ add_foreign_key "forked_project_links", "projects", column: "forked_to_project_id", name: "fk_434510edb0", on_delete: :cascade
+ add_foreign_key "gcp_clusters", "projects", on_delete: :cascade
+ add_foreign_key "gcp_clusters", "services", on_delete: :nullify
+ add_foreign_key "gcp_clusters", "users", on_delete: :nullify
+ add_foreign_key "gpg_key_subkeys", "gpg_keys", on_delete: :cascade
+ add_foreign_key "gpg_keys", "users", on_delete: :cascade
+ add_foreign_key "gpg_signatures", "gpg_key_subkeys", on_delete: :nullify
+ add_foreign_key "gpg_signatures", "gpg_keys", on_delete: :nullify
+ add_foreign_key "gpg_signatures", "projects", on_delete: :cascade
+ add_foreign_key "group_custom_attributes", "namespaces", column: "group_id", on_delete: :cascade
+ add_foreign_key "issue_assignees", "issues", name: "fk_b7d881734a", on_delete: :cascade
+ add_foreign_key "issue_assignees", "users", name: "fk_5e0c8d9154", on_delete: :cascade
+ add_foreign_key "issue_metrics", "issues", on_delete: :cascade
+ add_foreign_key "issues", "issues", column: "moved_to_id", name: "fk_a194299be1", on_delete: :nullify
+ add_foreign_key "issues", "milestones", name: "fk_96b1dd429c", on_delete: :nullify
+ add_foreign_key "issues", "projects", name: "fk_899c8f3231", on_delete: :cascade
+ add_foreign_key "issues", "users", column: "author_id", name: "fk_05f1e72feb", on_delete: :nullify
+ add_foreign_key "issues", "users", column: "updated_by_id", name: "fk_ffed080f01", on_delete: :nullify
+ add_foreign_key "label_priorities", "labels", on_delete: :cascade
+ add_foreign_key "label_priorities", "projects", on_delete: :cascade
+ add_foreign_key "labels", "namespaces", column: "group_id", on_delete: :cascade
+ add_foreign_key "labels", "projects", name: "fk_7de4989a69", on_delete: :cascade
+ add_foreign_key "lists", "boards", name: "fk_0d3f677137", on_delete: :cascade
+ add_foreign_key "lists", "labels", name: "fk_7a5553d60f", on_delete: :cascade
+ add_foreign_key "members", "users", name: "fk_2e88fb7ce9", on_delete: :cascade
+ add_foreign_key "merge_request_diff_commits", "merge_request_diffs", on_delete: :cascade
+ add_foreign_key "merge_request_diff_files", "merge_request_diffs", on_delete: :cascade
+ add_foreign_key "merge_request_diffs", "merge_requests", name: "fk_8483f3258f", on_delete: :cascade
+ add_foreign_key "merge_request_metrics", "ci_pipelines", column: "pipeline_id", on_delete: :cascade
+ add_foreign_key "merge_request_metrics", "merge_requests", on_delete: :cascade
+ add_foreign_key "merge_request_metrics", "users", column: "latest_closed_by_id", name: "fk_ae440388cc", on_delete: :nullify
+ add_foreign_key "merge_request_metrics", "users", column: "merged_by_id", name: "fk_7f28d925f3", on_delete: :nullify
+ add_foreign_key "merge_requests", "ci_pipelines", column: "head_pipeline_id", name: "fk_fd82eae0b9", on_delete: :nullify
+ add_foreign_key "merge_requests", "merge_request_diffs", column: "latest_merge_request_diff_id", name: "fk_06067f5644", on_delete: :nullify
+ add_foreign_key "merge_requests", "milestones", name: "fk_6a5165a692", on_delete: :nullify
+ add_foreign_key "merge_requests", "projects", column: "source_project_id", name: "fk_3308fe130c", on_delete: :nullify
+ add_foreign_key "merge_requests", "projects", column: "target_project_id", name: "fk_a6963e8447", on_delete: :cascade
+ add_foreign_key "merge_requests", "users", column: "assignee_id", name: "fk_6149611a04", on_delete: :nullify
+ add_foreign_key "merge_requests", "users", column: "author_id", name: "fk_e719a85f8a", on_delete: :nullify
+ add_foreign_key "merge_requests", "users", column: "merge_user_id", name: "fk_ad525e1f87", on_delete: :nullify
+ add_foreign_key "merge_requests", "users", column: "updated_by_id", name: "fk_641731faff", on_delete: :nullify
+ add_foreign_key "merge_requests_closing_issues", "issues", on_delete: :cascade
+ add_foreign_key "merge_requests_closing_issues", "merge_requests", on_delete: :cascade
+ add_foreign_key "milestones", "namespaces", column: "group_id", name: "fk_95650a40d4", on_delete: :cascade
+ add_foreign_key "milestones", "projects", name: "fk_9bd0a0c791", on_delete: :cascade
+ add_foreign_key "notes", "projects", name: "fk_99e097b079", on_delete: :cascade
+ add_foreign_key "oauth_openid_requests", "oauth_access_grants", column: "access_grant_id", name: "fk_oauth_openid_requests_oauth_access_grants_access_grant_id"
+ add_foreign_key "pages_domains", "projects", name: "fk_ea2f6dfc6f", on_delete: :cascade
+ add_foreign_key "personal_access_tokens", "users"
+ add_foreign_key "project_authorizations", "projects", on_delete: :cascade
+ add_foreign_key "project_authorizations", "users", on_delete: :cascade
+ add_foreign_key "project_auto_devops", "projects", on_delete: :cascade
+ add_foreign_key "project_custom_attributes", "projects", on_delete: :cascade
+ add_foreign_key "project_features", "projects", name: "fk_18513d9b92", on_delete: :cascade
+ add_foreign_key "project_group_links", "projects", name: "fk_daa8cee94c", on_delete: :cascade
+ add_foreign_key "project_import_data", "projects", name: "fk_ffb9ee3a10", on_delete: :cascade
+ add_foreign_key "project_statistics", "projects", on_delete: :cascade
+ add_foreign_key "protected_branch_merge_access_levels", "protected_branches", name: "fk_8a3072ccb3", on_delete: :cascade
+ add_foreign_key "protected_branch_push_access_levels", "protected_branches", name: "fk_9ffc86a3d9", on_delete: :cascade
+ add_foreign_key "protected_branches", "projects", name: "fk_7a9c6d93e7", on_delete: :cascade
+ add_foreign_key "protected_tag_create_access_levels", "namespaces", column: "group_id"
+ add_foreign_key "protected_tag_create_access_levels", "protected_tags", name: "fk_f7dfda8c51", on_delete: :cascade
+ add_foreign_key "protected_tag_create_access_levels", "users"
+ add_foreign_key "protected_tags", "projects", name: "fk_8e4af87648", on_delete: :cascade
+ add_foreign_key "push_event_payloads", "events", name: "fk_36c74129da", on_delete: :cascade
+ add_foreign_key "releases", "projects", name: "fk_47fe2a0596", on_delete: :cascade
+ add_foreign_key "services", "projects", name: "fk_71cce407f9", on_delete: :cascade
+ add_foreign_key "snippets", "projects", name: "fk_be41fd4bb7", on_delete: :cascade
+ add_foreign_key "subscriptions", "projects", on_delete: :cascade
+ add_foreign_key "system_note_metadata", "notes", name: "fk_d83a918cb1", on_delete: :cascade
+ add_foreign_key "timelogs", "issues", name: "fk_timelogs_issues_issue_id", on_delete: :cascade
+ add_foreign_key "timelogs", "merge_requests", name: "fk_timelogs_merge_requests_merge_request_id", on_delete: :cascade
+ add_foreign_key "todos", "projects", name: "fk_45054f9c45", on_delete: :cascade
+ add_foreign_key "trending_projects", "projects", on_delete: :cascade
+ add_foreign_key "u2f_registrations", "users"
+ add_foreign_key "user_custom_attributes", "users", on_delete: :cascade
+ add_foreign_key "user_synced_attributes_metadata", "users", on_delete: :cascade
+ add_foreign_key "users_star_projects", "projects", name: "fk_22cd27ddfc", on_delete: :cascade
+ add_foreign_key "web_hook_logs", "web_hooks", on_delete: :cascade
+ add_foreign_key "web_hooks", "projects", name: "fk_0c8ca6d9d1", on_delete: :cascade
+ end
+
+ def down
+ raise ActiveRecord::IrreversibleMigration, "The initial migration is not revertable"
+ end
+end
diff --git a/db/migrate/20190613044655_add_username_to_deploy_tokens.rb b/db/migrate/20190613044655_add_username_to_deploy_tokens.rb
new file mode 100644
index 00000000000..793553afe35
--- /dev/null
+++ b/db/migrate/20190613044655_add_username_to_deploy_tokens.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+class AddUsernameToDeployTokens < ActiveRecord::Migration[5.1]
+ DOWNTIME = false
+
+ def change
+ add_column :deploy_tokens, :username, :string
+ end
+end
diff --git a/db/migrate/20190617123615_add_grafana_to_settings.rb b/db/migrate/20190617123615_add_grafana_to_settings.rb
new file mode 100644
index 00000000000..f9c6f4d883e
--- /dev/null
+++ b/db/migrate/20190617123615_add_grafana_to_settings.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+class AddGrafanaToSettings < ActiveRecord::Migration[5.1]
+ include Gitlab::Database::MigrationHelpers
+
+ disable_ddl_transaction!
+
+ DOWNTIME = false
+
+ def up
+ add_column_with_default(:application_settings, :grafana_enabled, :boolean,
+ default: false, allow_null: false)
+ end
+
+ def down
+ remove_column(:application_settings, :grafana_enabled)
+ end
+end
diff --git a/db/migrate/20190621022810_add_last_ci_minutes_usage_notification_level_to_namespaces.rb b/db/migrate/20190621022810_add_last_ci_minutes_usage_notification_level_to_namespaces.rb
new file mode 100644
index 00000000000..1611340284c
--- /dev/null
+++ b/db/migrate/20190621022810_add_last_ci_minutes_usage_notification_level_to_namespaces.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+class AddLastCiMinutesUsageNotificationLevelToNamespaces < ActiveRecord::Migration[5.1]
+ DOWNTIME = false
+
+ def change
+ add_column :namespaces, :last_ci_minutes_usage_notification_level, :integer
+ end
+end
diff --git a/db/migrate/20190621151636_add_merge_request_rebase_jid.rb b/db/migrate/20190621151636_add_merge_request_rebase_jid.rb
new file mode 100644
index 00000000000..1fed5690ead
--- /dev/null
+++ b/db/migrate/20190621151636_add_merge_request_rebase_jid.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+class AddMergeRequestRebaseJid < ActiveRecord::Migration[5.1]
+ DOWNTIME = false
+
+ def change
+ add_column :merge_requests, :rebase_jid, :string
+ end
+end
diff --git a/db/migrate/20190624123615_add_grafana_url_to_settings.rb b/db/migrate/20190624123615_add_grafana_url_to_settings.rb
new file mode 100644
index 00000000000..61efe64a7a1
--- /dev/null
+++ b/db/migrate/20190624123615_add_grafana_url_to_settings.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+class AddGrafanaUrlToSettings < ActiveRecord::Migration[5.1]
+ include Gitlab::Database::MigrationHelpers
+
+ disable_ddl_transaction!
+
+ DOWNTIME = false
+
+ def up
+ add_column_with_default(:application_settings, :grafana_url, :string,
+ default: '/-/grafana', allow_null: false)
+ end
+
+ def down
+ remove_column(:application_settings, :grafana_url)
+ end
+end
diff --git a/db/migrate/20190625115224_add_description_to_services.rb b/db/migrate/20190625115224_add_description_to_services.rb
new file mode 100644
index 00000000000..d5ef3900462
--- /dev/null
+++ b/db/migrate/20190625115224_add_description_to_services.rb
@@ -0,0 +1,14 @@
+# frozen_string_literal: true
+
+# See http://doc.gitlab.com/ce/development/migration_style_guide.html
+# for more information on how to write migrations for GitLab.
+
+class AddDescriptionToServices < ActiveRecord::Migration[5.1]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ def change
+ add_column :services, :description, :string, limit: 500
+ end
+end
diff --git a/db/migrate/20190628145246_add_strategies_to_operations_feature_flag_scopes.rb b/db/migrate/20190628145246_add_strategies_to_operations_feature_flag_scopes.rb
new file mode 100644
index 00000000000..ed1f16ee69a
--- /dev/null
+++ b/db/migrate/20190628145246_add_strategies_to_operations_feature_flag_scopes.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+class AddStrategiesToOperationsFeatureFlagScopes < ActiveRecord::Migration[5.1]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def up
+ add_column_with_default :operations_feature_flag_scopes, :strategies, :jsonb, default: [{ name: "default", parameters: {} }]
+ end
+
+ def down
+ remove_column(:operations_feature_flag_scopes, :strategies)
+ end
+end
diff --git a/db/migrate/20190628185000_add_released_at_to_releases_table.rb b/db/migrate/20190628185000_add_released_at_to_releases_table.rb
new file mode 100644
index 00000000000..ae55aa434d9
--- /dev/null
+++ b/db/migrate/20190628185000_add_released_at_to_releases_table.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+class AddReleasedAtToReleasesTable < ActiveRecord::Migration[5.1]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ def change
+ add_column(:releases, :released_at, :datetime_with_timezone)
+ end
+end
diff --git a/db/migrate/20190628185004_backfill_and_add_not_null_constraint_to_released_at_column_on_releases_table.rb b/db/migrate/20190628185004_backfill_and_add_not_null_constraint_to_released_at_column_on_releases_table.rb
new file mode 100644
index 00000000000..1e5d3e8f235
--- /dev/null
+++ b/db/migrate/20190628185004_backfill_and_add_not_null_constraint_to_released_at_column_on_releases_table.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+class BackfillAndAddNotNullConstraintToReleasedAtColumnOnReleasesTable < ActiveRecord::Migration[5.1]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def up
+ update_column_in_batches(:releases, :released_at, Arel.sql('created_at'))
+ change_column_null(:releases, :released_at, false)
+ end
+
+ def down
+ change_column_null(:releases, :released_at, true)
+ end
+end
diff --git a/db/migrate/20190703130053_remove_gitaly_feature_flags.rb b/db/migrate/20190703130053_remove_gitaly_feature_flags.rb
new file mode 100644
index 00000000000..13ac10a5e21
--- /dev/null
+++ b/db/migrate/20190703130053_remove_gitaly_feature_flags.rb
@@ -0,0 +1,48 @@
+# frozen_string_literal: true
+
+class RemoveGitalyFeatureFlags < ActiveRecord::Migration[5.1]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ FEATURES = %w[
+ gitaly_batch_lfs_pointers gitaly_blame gitaly_blob_get_all_lfs_pointers gitaly_blob_get_new_lfs_pointers
+ gitaly_branch_names gitaly_branch_names_contains_sha gitaly_branches gitaly_bundle_to_disk
+ gitaly_calculate_checksum gitaly_can_be_merged gitaly_cherry_pick gitaly_commit_count
+ gitaly_commit_deltas gitaly_commit_languages gitaly_commit_messages gitaly_commit_patch
+ gitaly_commit_raw_diffs gitaly_commit_stats gitaly_commit_tree_entry gitaly_commits_between
+ gitaly_commits_by_message gitaly_conflicts_list_conflict_files gitaly_conflicts_resolve_conflicts gitaly_count_commits
+ gitaly_count_diverging_commits_no_max gitaly_create_branch gitaly_create_repo_from_bundle gitaly_create_repository
+ gitaly_delete_branch gitaly_delete_refs gitaly_delta_islands gitaly_deny_disk_acces
+ gitaly_diff_between gitaly_extract_commit_signature gitaly_fetch_ref gitaly_fetch_remote
+ gitaly_fetch_source_branch gitaly_filter_shas_with_signature gitaly_filter_shas_with_signatures gitaly_find_all_commits
+ gitaly_find_branch gitaly_find_commit gitaly_find_commits gitaly_find_ref_name
+ gitaly_force_push gitaly_fork_repository gitaly_garbage_collect gitaly_get_info_attributes
+ gitaly_git_blob_load_all_data gitaly_git_blob_raw gitaly_git_fsck gitaly_go-find-all-tags
+ gitaly_has_local_branches gitaly_import_repository gitaly_is_ancestor gitaly_last_commit_for_path
+ gitaly_license_short_name gitaly_list_blobs_by_sha_path gitaly_list_commits_by_oid gitaly_local_branches
+ gitaly_ls_files gitaly_merge_base gitaly_merged_branch_names gitaly_new_commits
+ gitaly_operation_user_add_tag gitaly_operation_user_commit_file gitaly_operation_user_commit_files gitaly_operation_user_create_branch
+ gitaly_operation_user_delete_branch gitaly_operation_user_delete_tag gitaly_operation_user_ff_branch gitaly_operation_user_merge_branch
+ gitaly_post_receive_pack gitaly_post_upload_pack gitaly_project_raw_show gitaly_raw_changes_between
+ gitaly_rebase gitaly_rebase_in_progress gitaly_ref_delete_refs gitaly_ref_exists
+ gitaly_ref_exists_branch gitaly_ref_exists_branches gitaly_ref_find_all_remote_branches gitaly_remote_add_remote
+ gitaly_remote_fetch_internal_remote gitaly_remote_remove_remote gitaly_remote_update_remote_mirror gitaly_remove_namespace
+ gitaly_repack_full gitaly_repack_incremental gitaly_repository_cleanup gitaly_repository_exists
+ gitaly_repository_size gitaly_root_ref gitaly_search_files_by_content gitaly_search_files_by_name
+ gitaly_squash gitaly_squash_in_progress gitaly_ssh_receive_pack gitaly_ssh_upload_pack
+ gitaly_submodule_url_for gitaly_tag_messages gitaly_tag_names gitaly_tag_names_contains_sha
+ gitaly_tags gitaly_tree_entries gitaly_wiki_delete_page gitaly_wiki_find_file
+ gitaly_wiki_find_page gitaly_wiki_get_all_pages gitaly_wiki_page_formatted_data gitaly_wiki_page_versions
+ gitaly_wiki_update_page gitaly_wiki_write_page gitaly_workhorse_archive gitaly_workhorse_raw_show
+ gitaly_workhorse_send_git_diff gitaly_workhorse_send_git_patch gitaly_write_config gitaly_write_ref
+ ]
+
+ class Feature < ActiveRecord::Base
+ self.table_name = 'features'
+ end
+
+ def up
+ Feature.where(key: FEATURES).delete_all
+ end
+end
diff --git a/db/post_migrate/20160824121037_change_personal_access_tokens_default_back_to_empty_array.rb b/db/post_migrate/20160824121037_change_personal_access_tokens_default_back_to_empty_array.rb
deleted file mode 100644
index 099814d7556..00000000000
--- a/db/post_migrate/20160824121037_change_personal_access_tokens_default_back_to_empty_array.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-# The default needs to be `[]`, but all existing access tokens need to have `scopes` set to `['api']`.
-# It's easier to achieve this by adding the column with the `['api']` default (regular migration), and
-# then changing the default to `[]` (in this post-migration).
-#
-# Details: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/5951#note_19721973
-
-class ChangePersonalAccessTokensDefaultBackToEmptyArray < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def up
- change_column_default :personal_access_tokens, :scopes, [].to_yaml
- end
-
- def down
- change_column_default :personal_access_tokens, :scopes, ['api'].to_yaml
- end
-end
diff --git a/db/post_migrate/20161011222551_remove_inactive_jira_service_properties.rb b/db/post_migrate/20161011222551_remove_inactive_jira_service_properties.rb
deleted file mode 100644
index bf3aee99418..00000000000
--- a/db/post_migrate/20161011222551_remove_inactive_jira_service_properties.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-class RemoveInactiveJiraServiceProperties < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = true
- DOWNTIME_REASON = "Removes all inactive jira_service properties"
-
- def up
- execute("UPDATE services SET properties = '{}' WHERE services.type = 'JiraService' and services.active = false")
- end
-end
diff --git a/db/post_migrate/20161109150329_fix_project_records_with_invalid_visibility.rb b/db/post_migrate/20161109150329_fix_project_records_with_invalid_visibility.rb
deleted file mode 100644
index 6d9c7e4ed72..00000000000
--- a/db/post_migrate/20161109150329_fix_project_records_with_invalid_visibility.rb
+++ /dev/null
@@ -1,49 +0,0 @@
-class FixProjectRecordsWithInvalidVisibility < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- BATCH_SIZE = 500
- DOWNTIME = false
-
- # This migration is idempotent and there's no sense in throwing away the
- # partial result if it's interrupted
- disable_ddl_transaction!
-
- def up
- projects = Arel::Table.new(:projects)
- namespaces = Arel::Table.new(:namespaces)
-
- finder_sql =
- projects
- .join(namespaces, Arel::Nodes::InnerJoin)
- .on(projects[:namespace_id].eq(namespaces[:id]))
- .where(projects[:visibility_level].gt(namespaces[:visibility_level]))
- .project(projects[:id], namespaces[:visibility_level])
- .take(BATCH_SIZE)
- .to_sql
-
- # Update matching rows in batches. Each batch can cause up to 3 UPDATE
- # statements, in addition to the SELECT: one per visibility_level
- loop do
- to_update = connection.exec_query(finder_sql)
- break if to_update.rows.count == 0
-
- # row[0] is projects.id, row[1] is namespaces.visibility_level
- updates = to_update.rows.each_with_object(Hash.new {|h, k| h[k] = [] }) do |row, obj|
- obj[row[1]] << row[0]
- end
-
- updates.each do |visibility_level, project_ids|
- updater = Arel::UpdateManager.new
- .table(projects)
- .set(projects[:visibility_level] => visibility_level)
- .where(projects[:id].in(project_ids))
-
- ActiveRecord::Base.connection.exec_update(updater.to_sql, self.class.name, [])
- end
- end
- end
-
- def down
- # no-op
- end
-end
diff --git a/db/post_migrate/20161128170531_drop_user_activities_table.rb b/db/post_migrate/20161128170531_drop_user_activities_table.rb
deleted file mode 100644
index d8b1e0731f3..00000000000
--- a/db/post_migrate/20161128170531_drop_user_activities_table.rb
+++ /dev/null
@@ -1,33 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-class DropUserActivitiesTable < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- # When using the methods "add_concurrent_index" or "add_column_with_default"
- # you must disable the use of transactions as these methods can not run in an
- # existing transaction. When using "add_concurrent_index" make sure that this
- # method is the _only_ method called in the migration, any other changes
- # should go in a separate migration. This ensures that upon failure _only_ the
- # index creation fails and can be retried or reverted easily.
- #
- # To disable transactions uncomment the following line and remove these
- # comments:
- # disable_ddl_transaction!
-
- def up
- drop_table :user_activities if table_exists?(:user_activities)
- end
-
- def down
- unless table_exists?(:user_activities)
- create_table "user_activities", force: :cascade do |t|
- t.integer "user_id"
- t.datetime "last_activity_at", null: false
- end
-
- add_index "user_activities", ["user_id"], name: "index_user_activities_on_user_id", unique: true, using: :btree
- end
- end
-end
diff --git a/db/post_migrate/20161221140236_remove_unneeded_services.rb b/db/post_migrate/20161221140236_remove_unneeded_services.rb
deleted file mode 100644
index 31f24263877..00000000000
--- a/db/post_migrate/20161221140236_remove_unneeded_services.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-class RemoveUnneededServices < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def up
- disable_statement_timeout
-
- execute("DELETE FROM services WHERE active = false AND properties = '{}';")
- end
-
- def down
- # noop
- end
-end
diff --git a/db/post_migrate/20161221153951_rename_reserved_project_names.rb b/db/post_migrate/20161221153951_rename_reserved_project_names.rb
deleted file mode 100644
index 32579256299..00000000000
--- a/db/post_migrate/20161221153951_rename_reserved_project_names.rb
+++ /dev/null
@@ -1,137 +0,0 @@
-class RenameReservedProjectNames < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- THREAD_COUNT = 8
-
- KNOWN_PATHS = %w(.well-known
- all
- blame
- blob
- commits
- create
- create_dir
- edit
- files
- find_file
- groups
- hooks
- issues
- logs_tree
- merge_requests
- new
- preview
- projects
- raw
- repository
- robots.txt
- s
- snippets
- teams
- tree
- u
- unsubscribes
- update
- users
- wikis).freeze
-
- def up
- queues = Array.new(THREAD_COUNT) { Queue.new }
- start = false
-
- threads = Array.new(THREAD_COUNT) do |index|
- Thread.new do
- queue = queues[index]
-
- # Wait until we have input to process.
- until start; end
-
- rename_projects(queue.pop) until queue.empty?
- end
- end
-
- enum = queues.each
-
- reserved_projects.each_slice(100) do |slice|
- begin
- queue = enum.next
- rescue StopIteration
- enum.rewind
- retry
- end
-
- queue << slice
- end
-
- start = true
-
- threads.each(&:join)
- end
-
- def down
- # nothing to do here
- end
-
- private
-
- def reserved_projects
- Project.unscoped
- .includes(:namespace)
- .where('EXISTS (SELECT 1 FROM namespaces WHERE projects.namespace_id = namespaces.id)')
- .where('projects.path' => KNOWN_PATHS)
- end
-
- def route_exists?(full_path)
- quoted_path = ActiveRecord::Base.connection.quote_string(full_path)
-
- ActiveRecord::Base.connection
- .select_all("SELECT id, path FROM routes WHERE path = '#{quoted_path}'").present?
- end
-
- # Adds number to the end of the path that is not taken by other route
- def rename_path(namespace_path, path_was)
- counter = 0
- path = "#{path_was}#{counter}"
-
- while route_exists?("#{namespace_path}/#{path}")
- counter += 1
- path = "#{path_was}#{counter}"
- end
-
- path
- end
-
- def rename_projects(projects)
- projects.each do |project|
- id = project.id
- path_was = project.path
- namespace_path = project.namespace.path
- path = rename_path(namespace_path, path_was)
-
- begin
- # Because project path update is quite complex operation we can't safely
- # copy-paste all code from GitLab. As exception we use Rails code here
- if rename_project_row(project, path)
- after_rename_service(project, path_was, namespace_path).execute
- end
- rescue Exception => e # rubocop: disable Lint/RescueException
- Rails.logger.error "Exception when renaming project #{id}: #{e.message}"
- end
- end
- end
-
- def rename_project_row(project, path)
- project.respond_to?(:update_attributes) &&
- project.update(path: path) &&
- defined?(Projects::AfterRenameService)
- end
-
- def after_rename_service(project, path_was, namespace_path)
- AfterRenameService.new(
- project,
- path_before: path_was,
- full_path_before: "#{namespace_path}/#{path_was}"
- ).execute
- end
-end
diff --git a/db/post_migrate/20170104150317_requeue_pending_delete_projects.rb b/db/post_migrate/20170104150317_requeue_pending_delete_projects.rb
deleted file mode 100644
index f567accb051..00000000000
--- a/db/post_migrate/20170104150317_requeue_pending_delete_projects.rb
+++ /dev/null
@@ -1,49 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class RequeuePendingDeleteProjects < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def up
- admin = User.find_by(admin: true)
- return unless admin
-
- @offset = 0
-
- loop do
- ids = pending_delete_batch
-
- break if ids.rows.count.zero?
-
- args = ids.map { |id| [id['id'], admin.id, {}] }
-
- Sidekiq::Client.push_bulk('class' => "ProjectDestroyWorker", 'args' => args)
-
- @offset += 1
- end
- end
-
- def down
- # noop
- end
-
- private
-
- def pending_delete_batch
- connection.exec_query(find_batch)
- end
-
- BATCH_SIZE = 5000
-
- def find_batch
- projects = Arel::Table.new(:projects)
- projects.project(projects[:id])
- .where(projects[:pending_delete].eq(true))
- .where(projects[:namespace_id].not_eq(nil))
- .skip(@offset * BATCH_SIZE)
- .take(BATCH_SIZE)
- .to_sql
- end
-end
diff --git a/db/post_migrate/20170106142508_fill_authorized_projects.rb b/db/post_migrate/20170106142508_fill_authorized_projects.rb
deleted file mode 100644
index 1f1dd0f47f0..00000000000
--- a/db/post_migrate/20170106142508_fill_authorized_projects.rb
+++ /dev/null
@@ -1,30 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class FillAuthorizedProjects < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- class User < ActiveRecord::Base
- self.table_name = 'users'
- end
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- # We're not inserting any data so we don't need to start a transaction.
- disable_ddl_transaction!
-
- def up
- relation = User.select(:id)
- .where('authorized_projects_populated IS NOT TRUE')
-
- relation.find_in_batches(batch_size: 1_000) do |rows|
- args = rows.map { |row| [row.id] }
-
- Sidekiq::Client.push_bulk('class' => 'AuthorizedProjectsWorker', 'args' => args)
- end
- end
-
- def down
- end
-end
diff --git a/db/post_migrate/20170106172224_remove_project_authorizations_id_column.rb b/db/post_migrate/20170106172224_remove_project_authorizations_id_column.rb
deleted file mode 100644
index 893af23465a..00000000000
--- a/db/post_migrate/20170106172224_remove_project_authorizations_id_column.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class RemoveProjectAuthorizationsIdColumn < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def change
- remove_column :project_authorizations, :id, :primary_key
- end
-end
diff --git a/db/post_migrate/20170131214021_reset_users_authorized_projects_populated.rb b/db/post_migrate/20170131214021_reset_users_authorized_projects_populated.rb
deleted file mode 100644
index 055a14ad729..00000000000
--- a/db/post_migrate/20170131214021_reset_users_authorized_projects_populated.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-# rubocop:disable Migration/UpdateLargeTable
-# rubocop:disable Migration/UpdateColumnInBatches
-class ResetUsersAuthorizedProjectsPopulated < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- # This ensures we don't lock all users for the duration of the migration.
- update_column_in_batches(:users, :authorized_projects_populated, nil)
- end
-
- def down
- # noop
- end
-end
diff --git a/db/post_migrate/20170206040400_remove_inactive_default_email_services.rb b/db/post_migrate/20170206040400_remove_inactive_default_email_services.rb
deleted file mode 100644
index f221dac8e20..00000000000
--- a/db/post_migrate/20170206040400_remove_inactive_default_email_services.rb
+++ /dev/null
@@ -1,41 +0,0 @@
-class RemoveInactiveDefaultEmailServices < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- Gitlab::Database.with_connection_pool(2) do |pool|
- threads = []
-
- threads << Thread.new do
- pool.with_connection do |connection|
- connection.execute <<-SQL.strip_heredoc
- DELETE FROM services
- WHERE type = 'BuildsEmailService'
- AND active IS FALSE
- AND properties = '{"notify_only_broken_builds":true}';
- SQL
- end
- end
-
- threads << Thread.new do
- pool.with_connection do |connection|
- connection.execute <<-SQL.strip_heredoc
- DELETE FROM services
- WHERE type = 'PipelinesEmailService'
- AND active IS FALSE
- AND properties = '{"notify_only_broken_pipelines":true}';
- SQL
- end
- end
-
- threads.each(&:join)
- end
- end
-
- def down
- # Nothing can be done to restore the records
- end
-end
diff --git a/db/post_migrate/20170206101007_remove_trackable_columns_from_timelogs.rb b/db/post_migrate/20170206101007_remove_trackable_columns_from_timelogs.rb
deleted file mode 100644
index 14f5d0d4add..00000000000
--- a/db/post_migrate/20170206101007_remove_trackable_columns_from_timelogs.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class RemoveTrackableColumnsFromTimelogs < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- # When using the methods "add_concurrent_index" or "add_column_with_default"
- # you must disable the use of transactions as these methods can not run in an
- # existing transaction. When using "add_concurrent_index" make sure that this
- # method is the _only_ method called in the migration, any other changes
- # should go in a separate migration. This ensures that upon failure _only_ the
- # index creation fails and can be retried or reverted easily.
- #
- # To disable transactions uncomment the following line and remove these
- # comments:
- # disable_ddl_transaction!
-
- def change
- remove_column :timelogs, :trackable_id, :integer
- remove_column :timelogs, :trackable_type, :string
- end
-end
diff --git a/db/post_migrate/20170206101030_validate_foreign_keys_on_timelogs.rb b/db/post_migrate/20170206101030_validate_foreign_keys_on_timelogs.rb
deleted file mode 100644
index b5a5c0f06c7..00000000000
--- a/db/post_migrate/20170206101030_validate_foreign_keys_on_timelogs.rb
+++ /dev/null
@@ -1,32 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class ValidateForeignKeysOnTimelogs < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- # When using the methods "add_concurrent_index" or "add_column_with_default"
- # you must disable the use of transactions as these methods can not run in an
- # existing transaction. When using "add_concurrent_index" make sure that this
- # method is the _only_ method called in the migration, any other changes
- # should go in a separate migration. This ensures that upon failure _only_ the
- # index creation fails and can be retried or reverted easily.
- #
- # To disable transactions uncomment the following line and remove these
- # comments:
- disable_ddl_transaction!
-
- def up
- if Gitlab::Database.postgresql?
- execute <<-EOF
- ALTER TABLE timelogs VALIDATE CONSTRAINT "fk_timelogs_issues_issue_id";
- ALTER TABLE timelogs VALIDATE CONSTRAINT "fk_timelogs_merge_requests_merge_request_id";
- EOF
- end
- end
-
- def down
- # noop
- end
-end
diff --git a/db/post_migrate/20170209140523_validate_foreign_keys_on_oauth_openid_requests.rb b/db/post_migrate/20170209140523_validate_foreign_keys_on_oauth_openid_requests.rb
deleted file mode 100644
index 81ac4cf1373..00000000000
--- a/db/post_migrate/20170209140523_validate_foreign_keys_on_oauth_openid_requests.rb
+++ /dev/null
@@ -1,20 +0,0 @@
-class ValidateForeignKeysOnOauthOpenidRequests < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- if Gitlab::Database.postgresql?
- execute %q{
- ALTER TABLE "oauth_openid_requests"
- VALIDATE CONSTRAINT "fk_oauth_openid_requests_oauth_access_grants_access_grant_id";
- }
- end
- end
-
- def down
- # noop
- end
-end
diff --git a/db/post_migrate/20170211073944_disable_invalid_service_templates.rb b/db/post_migrate/20170211073944_disable_invalid_service_templates.rb
deleted file mode 100644
index 31234e5b086..00000000000
--- a/db/post_migrate/20170211073944_disable_invalid_service_templates.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-class DisableInvalidServiceTemplates < ActiveRecord::Migration[4.2]
- DOWNTIME = false
-
- class Service < ActiveRecord::Base
- self.inheritance_column = nil
- end
-
- def up
- Service.where(template: true, active: true).each do |template|
- template.update(active: false) unless template.valid?
- end
- end
-end
diff --git a/db/post_migrate/20170214111112_delete_deprecated_gitlab_ci_service.rb b/db/post_migrate/20170214111112_delete_deprecated_gitlab_ci_service.rb
deleted file mode 100644
index c273060f8b0..00000000000
--- a/db/post_migrate/20170214111112_delete_deprecated_gitlab_ci_service.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-class DeleteDeprecatedGitlabCiService < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def up
- disable_statement_timeout
-
- execute("DELETE FROM services WHERE type = 'GitlabCiService';")
- end
-
- def down
- # noop
- end
-end
diff --git a/db/post_migrate/20170215200045_remove_theme_id_from_users.rb b/db/post_migrate/20170215200045_remove_theme_id_from_users.rb
deleted file mode 100644
index 937fe3f57af..00000000000
--- a/db/post_migrate/20170215200045_remove_theme_id_from_users.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-class RemoveThemeIdFromUsers < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def change
- remove_column :users, :theme_id, :integer
- end
-end
diff --git a/db/post_migrate/20170301205640_migrate_build_events_to_pipeline_events.rb b/db/post_migrate/20170301205640_migrate_build_events_to_pipeline_events.rb
deleted file mode 100644
index c2d28d79491..00000000000
--- a/db/post_migrate/20170301205640_migrate_build_events_to_pipeline_events.rb
+++ /dev/null
@@ -1,86 +0,0 @@
-class MigrateBuildEventsToPipelineEvents < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def up
- Gitlab::Database.with_connection_pool(2) do |pool|
- threads = []
-
- threads << Thread.new do
- pool.with_connection do |connection|
- Thread.current[:foreign_key_connection] = connection
-
- execute(<<-SQL.strip_heredoc)
- UPDATE services
- SET properties = replace(properties,
- 'notify_only_broken_builds',
- 'notify_only_broken_pipelines')
- , pipeline_events = #{true_value}
- , build_events = #{false_value}
- WHERE type IN
- ('SlackService', 'MattermostService', 'HipchatService')
- AND build_events = #{true_value};
- SQL
- end
- end
-
- threads << Thread.new do
- pool.with_connection do |connection|
- Thread.current[:foreign_key_connection] = connection
-
- execute(update_pipeline_services_sql)
- end
- end
-
- threads.each(&:join)
- end
- end
-
- def down
- # Don't bother to migrate the data back
- end
-
- def connection
- # Rails memoizes connection objects, but this causes them to be shared
- # amongst threads; we don't want that.
- Thread.current[:foreign_key_connection] || ActiveRecord::Base.connection
- end
-
- private
-
- def update_pipeline_services_sql
- if Gitlab::Database.postgresql?
- <<-SQL
- UPDATE services
- SET type = 'PipelinesEmailService'
- , properties = replace(properties,
- 'notify_only_broken_builds',
- 'notify_only_broken_pipelines')
- , pipeline_events = #{true_value}
- , build_events = #{false_value}
- WHERE type = 'BuildsEmailService'
- AND
- (SELECT 1 FROM services pipeline_services
- WHERE pipeline_services.project_id = services.project_id
- AND pipeline_services.type = 'PipelinesEmailService' LIMIT 1)
- IS NULL;
- SQL
- else
- <<-SQL
- UPDATE services build_services
- LEFT OUTER JOIN services pipeline_services
- ON build_services.project_id = pipeline_services.project_id
- AND pipeline_services.type = 'PipelinesEmailService'
- SET build_services.type = 'PipelinesEmailService'
- , build_services.properties = replace(build_services.properties,
- 'notify_only_broken_builds',
- 'notify_only_broken_pipelines')
- , build_services.pipeline_events = #{true_value}
- , build_services.build_events = #{false_value}
- WHERE build_services.type = 'BuildsEmailService'
- AND pipeline_services.id IS NULL;
- SQL
- end.strip_heredoc
- end
-end
diff --git a/db/post_migrate/20170306170512_migrate_legacy_manual_actions.rb b/db/post_migrate/20170306170512_migrate_legacy_manual_actions.rb
deleted file mode 100644
index aa12e8ac3da..00000000000
--- a/db/post_migrate/20170306170512_migrate_legacy_manual_actions.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-class MigrateLegacyManualActions < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def up
- disable_statement_timeout
-
- execute <<-EOS
- UPDATE ci_builds SET status = 'manual', allow_failure = true
- WHERE ci_builds.when = 'manual' AND ci_builds.status = 'skipped';
- EOS
- end
-
- def down
- disable_statement_timeout
-
- execute <<-EOS
- UPDATE ci_builds SET status = 'skipped', allow_failure = false
- WHERE ci_builds.when = 'manual' AND ci_builds.status = 'manual';
- EOS
- end
-end
diff --git a/db/post_migrate/20170309171644_reset_relative_position_for_issue.rb b/db/post_migrate/20170309171644_reset_relative_position_for_issue.rb
deleted file mode 100644
index 2cf4cf61d8f..00000000000
--- a/db/post_migrate/20170309171644_reset_relative_position_for_issue.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-# rubocop:disable Migration/UpdateLargeTable
-# rubocop:disable Migration/UpdateColumnInBatches
-class ResetRelativePositionForIssue < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- update_column_in_batches(:issues, :relative_position, nil) do |table, query|
- query.where(table[:relative_position].not_eq(nil))
- end
- end
-
- def down
- # noop
- end
-end
diff --git a/db/post_migrate/20170313133418_rename_more_reserved_project_names.rb b/db/post_migrate/20170313133418_rename_more_reserved_project_names.rb
deleted file mode 100644
index 85c97e3687e..00000000000
--- a/db/post_migrate/20170313133418_rename_more_reserved_project_names.rb
+++ /dev/null
@@ -1,79 +0,0 @@
-class RenameMoreReservedProjectNames < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- KNOWN_PATHS = %w(artifacts graphs refs badges).freeze
-
- def up
- reserved_projects.each_slice(100) do |slice|
- rename_projects(slice)
- end
- end
-
- def down
- # nothing to do here
- end
-
- private
-
- def reserved_projects
- Project.unscoped
- .includes(:namespace)
- .where('EXISTS (SELECT 1 FROM namespaces WHERE projects.namespace_id = namespaces.id)')
- .where('projects.path' => KNOWN_PATHS)
- end
-
- def route_exists?(full_path)
- quoted_path = ActiveRecord::Base.connection.quote_string(full_path)
-
- ActiveRecord::Base.connection
- .select_all("SELECT id, path FROM routes WHERE path = '#{quoted_path}'").present?
- end
-
- # Adds number to the end of the path that is not taken by other route
- def rename_path(namespace_path, path_was)
- counter = 0
- path = "#{path_was}#{counter}"
-
- while route_exists?("#{namespace_path}/#{path}")
- counter += 1
- path = "#{path_was}#{counter}"
- end
-
- path
- end
-
- def rename_projects(projects)
- projects.each do |project|
- id = project.id
- path_was = project.path
- namespace_path = project.namespace.path
- path = rename_path(namespace_path, path_was)
-
- begin
- # Because project path update is quite complex operation we can't safely
- # copy-paste all code from GitLab. As exception we use Rails code here
- if rename_project_row(project, path)
- after_rename_service(project, path_was, namespace_path).execute
- end
- rescue Exception => e # rubocop: disable Lint/RescueException
- Rails.logger.error "Exception when renaming project #{id}: #{e.message}"
- end
- end
- end
-
- def rename_project_row(project, path)
- project.respond_to?(:update_attributes) &&
- project.update(path: path) &&
- defined?(Projects::AfterRenameService)
- end
-
- def after_rename_service(project, path_was, namespace_path)
- AfterRenameService.new(
- project,
- path_before: path_was,
- full_path_before: "#{namespace_path}/#{path_was}"
- ).execute
- end
-end
diff --git a/db/post_migrate/20170317162059_update_upload_paths_to_system.rb b/db/post_migrate/20170317162059_update_upload_paths_to_system.rb
deleted file mode 100644
index 99cdca465e2..00000000000
--- a/db/post_migrate/20170317162059_update_upload_paths_to_system.rb
+++ /dev/null
@@ -1,57 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class UpdateUploadPathsToSystem < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
- AFFECTED_MODELS = %w(User Project Note Namespace Appearance)
-
- disable_ddl_transaction!
-
- def up
- update_column_in_batches(:uploads, :path, replace_sql(arel_table[:path], base_directory, new_upload_dir)) do |_table, query|
- query.where(uploads_to_switch_to_new_path)
- end
- end
-
- def down
- update_column_in_batches(:uploads, :path, replace_sql(arel_table[:path], new_upload_dir, base_directory)) do |_table, query|
- query.where(uploads_to_switch_to_old_path)
- end
- end
-
- # "SELECT \"uploads\".* FROM \"uploads\" WHERE \"uploads\".\"model_type\" IN ('User', 'Project', 'Note', 'Namespace', 'Appearance') AND (\"uploads\".\"path\" ILIKE 'uploads/%' AND NOT (\"uploads\".\"path\" ILIKE 'uploads/system/%'))"
- def uploads_to_switch_to_new_path
- affected_uploads.and(starting_with_base_directory).and(starting_with_new_upload_directory.not)
- end
-
- # "SELECT \"uploads\".* FROM \"uploads\" WHERE \"uploads\".\"model_type\" IN ('User', 'Project', 'Note', 'Namespace', 'Appearance') AND (\"uploads\".\"path\" ILIKE 'uploads/%' AND \"uploads\".\"path\" ILIKE 'uploads/system/%')"
- def uploads_to_switch_to_old_path
- affected_uploads.and(starting_with_new_upload_directory)
- end
-
- def starting_with_base_directory
- arel_table[:path].matches("#{base_directory}/%")
- end
-
- def starting_with_new_upload_directory
- arel_table[:path].matches("#{new_upload_dir}/%")
- end
-
- def affected_uploads
- arel_table[:model_type].in(AFFECTED_MODELS)
- end
-
- def base_directory
- "uploads"
- end
-
- def new_upload_dir
- File.join(base_directory, "-", "system")
- end
-
- def arel_table
- Arel::Table.new(:uploads)
- end
-end
diff --git a/db/post_migrate/20170324160416_migrate_user_activities_to_users_last_activity_on.rb b/db/post_migrate/20170324160416_migrate_user_activities_to_users_last_activity_on.rb
deleted file mode 100644
index 61a5c364b2f..00000000000
--- a/db/post_migrate/20170324160416_migrate_user_activities_to_users_last_activity_on.rb
+++ /dev/null
@@ -1,88 +0,0 @@
-# rubocop:disable Migration/UpdateLargeTable
-class MigrateUserActivitiesToUsersLastActivityOn < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- disable_ddl_transaction!
-
- DOWNTIME = false
- USER_ACTIVITY_SET_KEY = 'user/activities'.freeze
- ACTIVITIES_PER_PAGE = 100
- TIME_WHEN_ACTIVITY_SET_WAS_INTRODUCED = Time.utc(2016, 12, 1)
-
- def up
- return if activities_count(TIME_WHEN_ACTIVITY_SET_WAS_INTRODUCED, Time.now).zero?
-
- day = Time.at(activities(TIME_WHEN_ACTIVITY_SET_WAS_INTRODUCED, Time.now).first.second)
-
- transaction do
- while day <= Time.now.utc.tomorrow
- persist_last_activity_on(day: day)
- day = day.tomorrow
- end
- end
- end
-
- def down
- # This ensures we don't lock all users for the duration of the migration.
- update_column_in_batches(:users, :last_activity_on, nil) do |table, query|
- query.where(table[:last_activity_on].not_eq(nil))
- end
- end
-
- private
-
- def persist_last_activity_on(day:, page: 1)
- activities_count = activities_count(day.at_beginning_of_day, day.at_end_of_day)
-
- return if activities_count.zero?
-
- activities = activities(day.at_beginning_of_day, day.at_end_of_day, page: page)
-
- update_sql =
- Arel::UpdateManager.new
- .table(users_table)
- .set(users_table[:last_activity_on] => day.to_date)
- .where(users_table[:username].in(activities.map(&:first)))
- .to_sql
-
- connection.exec_update(update_sql, self.class.name, [])
-
- unless last_page?(page, activities_count)
- persist_last_activity_on(day: day, page: page + 1)
- end
- end
-
- def users_table
- @users_table ||= Arel::Table.new(:users)
- end
-
- def activities(from, to, page: 1)
- Gitlab::Redis::SharedState.with do |redis|
- redis.zrangebyscore(USER_ACTIVITY_SET_KEY, from.to_i, to.to_i,
- with_scores: true,
- limit: limit(page))
- end
- end
-
- def activities_count(from, to)
- Gitlab::Redis::SharedState.with do |redis|
- redis.zcount(USER_ACTIVITY_SET_KEY, from.to_i, to.to_i)
- end
- end
-
- def limit(page)
- [offset(page), ACTIVITIES_PER_PAGE]
- end
-
- def total_pages(count)
- (count.to_f / ACTIVITIES_PER_PAGE).ceil
- end
-
- def last_page?(page, count)
- page >= total_pages(count)
- end
-
- def offset(page)
- (page - 1) * ACTIVITIES_PER_PAGE
- end
-end
diff --git a/db/post_migrate/20170404170532_remove_notes_original_discussion_id.rb b/db/post_migrate/20170404170532_remove_notes_original_discussion_id.rb
deleted file mode 100644
index 334742f04e4..00000000000
--- a/db/post_migrate/20170404170532_remove_notes_original_discussion_id.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class RemoveNotesOriginalDiscussionId < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- # When using the methods "add_concurrent_index" or "add_column_with_default"
- # you must disable the use of transactions as these methods can not run in an
- # existing transaction. When using "add_concurrent_index" make sure that this
- # method is the _only_ method called in the migration, any other changes
- # should go in a separate migration. This ensures that upon failure _only_ the
- # index creation fails and can be retried or reverted easily.
- #
- # To disable transactions uncomment the following line and remove these
- # comments:
- # disable_ddl_transaction!
-
- def change
- remove_column :notes, :original_discussion_id, :string
- end
-end
diff --git a/db/post_migrate/20170406111121_clean_upload_symlinks.rb b/db/post_migrate/20170406111121_clean_upload_symlinks.rb
deleted file mode 100644
index 5fec00aa198..00000000000
--- a/db/post_migrate/20170406111121_clean_upload_symlinks.rb
+++ /dev/null
@@ -1,53 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class CleanUploadSymlinks < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
- disable_ddl_transaction!
-
- DOWNTIME = false
- DIRECTORIES_TO_MOVE = %w(user project note group appearance)
-
- def up
- return unless file_storage?
-
- DIRECTORIES_TO_MOVE.each do |dir|
- symlink_location = File.join(old_upload_dir, dir)
- next unless File.symlink?(symlink_location)
-
- say "removing symlink: #{symlink_location}"
- FileUtils.rm(symlink_location)
- end
- end
-
- def down
- return unless file_storage?
-
- DIRECTORIES_TO_MOVE.each do |dir|
- symlink = File.join(old_upload_dir, dir)
- destination = File.join(new_upload_dir, dir)
-
- next if File.directory?(symlink)
- next unless File.directory?(destination)
-
- say "Creating symlink #{symlink} -> #{destination}"
- FileUtils.ln_s(destination, symlink)
- end
- end
-
- def file_storage?
- CarrierWave::Uploader::Base.storage == CarrierWave::Storage::File
- end
-
- def base_directory
- Rails.root
- end
-
- def old_upload_dir
- File.join(base_directory, "public", "uploads")
- end
-
- def new_upload_dir
- File.join(base_directory, "public", "uploads", "-", "system")
- end
-end
diff --git a/db/post_migrate/20170406142253_migrate_user_project_view.rb b/db/post_migrate/20170406142253_migrate_user_project_view.rb
deleted file mode 100644
index 3601baba787..00000000000
--- a/db/post_migrate/20170406142253_migrate_user_project_view.rb
+++ /dev/null
@@ -1,22 +0,0 @@
-# rubocop:disable Migration/UpdateLargeTable
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class MigrateUserProjectView < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- update_column_in_batches(:users, :project_view, 2) do |table, query|
- query.where(table[:project_view].eq(0))
- end
- end
-
- def down
- # Nothing can be done to restore old values
- end
-end
diff --git a/db/post_migrate/20170408033905_remove_old_cache_directories.rb b/db/post_migrate/20170408033905_remove_old_cache_directories.rb
deleted file mode 100644
index 22bc5b9db7b..00000000000
--- a/db/post_migrate/20170408033905_remove_old_cache_directories.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-# Remove all files from old custom carrierwave's cache directories.
-# See https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/9466
-
-class RemoveOldCacheDirectories < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- # FileUploader cache.
- FileUtils.rm_rf(Dir[Rails.root.join('public', 'uploads', 'tmp', '*')])
- end
-
- def down
- # Old cache is not supposed to be recoverable.
- # So the down method is empty.
- end
-end
diff --git a/db/post_migrate/20170412174900_rename_reserved_dynamic_paths.rb b/db/post_migrate/20170412174900_rename_reserved_dynamic_paths.rb
deleted file mode 100644
index c9ff91b0401..00000000000
--- a/db/post_migrate/20170412174900_rename_reserved_dynamic_paths.rb
+++ /dev/null
@@ -1,62 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class RenameReservedDynamicPaths < ActiveRecord::Migration[4.2]
- include Gitlab::Database::RenameReservedPathsMigration::V1
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- DISALLOWED_ROOT_PATHS = %w[
- -
- abuse_reports
- api
- autocomplete
- explore
- health_check
- import
- invites
- jwt
- koding
- member
- notification_settings
- oauth
- sent_notifications
- unicorn_test
- uploads
- users
- ]
-
- DISALLOWED_WILDCARD_PATHS = %w[
- environments/folders
- gitlab-lfs/objects
- info/lfs/objects
- ]
-
- DISSALLOWED_GROUP_PATHS = %w[
- activity
- analytics
- audit_events
- avatar
- group_members
- hooks
- labels
- ldap
- ldap_group_links
- milestones
- notification_setting
- pipeline_quota
- subgroups
- ]
-
- def up
- rename_root_paths(DISALLOWED_ROOT_PATHS)
- rename_wildcard_paths(DISALLOWED_WILDCARD_PATHS)
- rename_child_paths(DISSALLOWED_GROUP_PATHS)
- end
-
- def down
- # nothing to do
- end
-end
diff --git a/db/post_migrate/20170425121605_migrate_trigger_schedules_to_pipeline_schedules.rb b/db/post_migrate/20170425121605_migrate_trigger_schedules_to_pipeline_schedules.rb
deleted file mode 100644
index 99ded277277..00000000000
--- a/db/post_migrate/20170425121605_migrate_trigger_schedules_to_pipeline_schedules.rb
+++ /dev/null
@@ -1,48 +0,0 @@
-class MigrateTriggerSchedulesToPipelineSchedules < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def up
- connection.execute <<~SQL
- DELETE FROM ci_trigger_schedules WHERE NOT EXISTS
- (SELECT true FROM projects
- WHERE ci_trigger_schedules.project_id = projects.id
- )
- SQL
-
- connection.execute <<-SQL
- INSERT INTO ci_pipeline_schedules (
- project_id,
- created_at,
- updated_at,
- deleted_at,
- cron,
- cron_timezone,
- next_run_at,
- ref,
- active,
- owner_id,
- description
- )
- SELECT
- ci_trigger_schedules.project_id,
- ci_trigger_schedules.created_at,
- ci_trigger_schedules.updated_at,
- ci_trigger_schedules.deleted_at,
- ci_trigger_schedules.cron,
- ci_trigger_schedules.cron_timezone,
- ci_trigger_schedules.next_run_at,
- ci_trigger_schedules.ref,
- ci_trigger_schedules.active,
- ci_triggers.owner_id,
- ci_triggers.description
- FROM ci_trigger_schedules
- INNER JOIN ci_triggers ON ci_trigger_schedules.trigger_id=ci_triggers.id;
- SQL
- end
-
- def down
- # no op as the data has been removed
- end
-end
diff --git a/db/post_migrate/20170425130047_drop_ci_trigger_schedules_table.rb b/db/post_migrate/20170425130047_drop_ci_trigger_schedules_table.rb
deleted file mode 100644
index 9d515aca8b4..00000000000
--- a/db/post_migrate/20170425130047_drop_ci_trigger_schedules_table.rb
+++ /dev/null
@@ -1,32 +0,0 @@
-class DropCiTriggerSchedulesTable < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- drop_table :ci_trigger_schedules
- end
-
- def down
- create_table "ci_trigger_schedules", force: :cascade do |t|
- t.integer "project_id"
- t.integer "trigger_id", null: false
- t.datetime "deleted_at"
- t.datetime "created_at"
- t.datetime "updated_at"
- t.string "cron"
- t.string "cron_timezone"
- t.datetime "next_run_at"
- t.string "ref"
- t.boolean "active"
- end
-
- add_index "ci_trigger_schedules", %w(active next_run_at), name: "index_ci_trigger_schedules_on_active_and_next_run_at", using: :btree
- add_index "ci_trigger_schedules", ["project_id"], name: "index_ci_trigger_schedules_on_project_id", using: :btree
- add_index "ci_trigger_schedules", ["next_run_at"], name: "index_ci_trigger_schedules_on_next_run_at"
-
- add_concurrent_foreign_key "ci_trigger_schedules", "ci_triggers", column: :trigger_id, on_delete: :cascade
- end
-end
diff --git a/db/post_migrate/20170502070007_enable_auto_cancel_pending_pipelines_for_all.rb b/db/post_migrate/20170502070007_enable_auto_cancel_pending_pipelines_for_all.rb
deleted file mode 100644
index 4d091d7f275..00000000000
--- a/db/post_migrate/20170502070007_enable_auto_cancel_pending_pipelines_for_all.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-# rubocop:disable Migration/UpdateLargeTable
-# rubocop:disable Migration/UpdateColumnInBatches
-class EnableAutoCancelPendingPipelinesForAll < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- disable_ddl_transaction!
-
- DOWNTIME = false
-
- def up
- disable_statement_timeout do
- update_column_in_batches(:projects, :auto_cancel_pending_pipelines, 1)
- end
- end
-
- def down
- # Nothing we can do!
- end
-end
diff --git a/db/post_migrate/20170503004427_update_retried_for_ci_build.rb b/db/post_migrate/20170503004427_update_retried_for_ci_build.rb
deleted file mode 100644
index 596f8593308..00000000000
--- a/db/post_migrate/20170503004427_update_retried_for_ci_build.rb
+++ /dev/null
@@ -1,69 +0,0 @@
-# rubocop:disable Migration/UpdateLargeTable
-class UpdateRetriedForCiBuild < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- if Gitlab::Database.mysql?
- up_mysql
- else
- disable_statement_timeout do
- up_postgres
- end
- end
- end
-
- def down
- end
-
- private
-
- def up_mysql
- # This is a trick to overcome MySQL limitation:
- # Mysql2::Error: Table 'ci_builds' is specified twice, both as a target for 'UPDATE' and as a separate source for data
- # However, this leads to create a temporary table from `max(ci_builds.id)` which is slow and do full database update
- execute <<-SQL.strip_heredoc
- UPDATE ci_builds SET retried=
- (id NOT IN (
- SELECT * FROM (SELECT MAX(ci_builds.id) FROM ci_builds GROUP BY commit_id, name) AS latest_jobs
- ))
- WHERE retried IS NULL
- SQL
- end
-
- def up_postgres
- with_temporary_partial_index do
- latest_id = <<-SQL.strip_heredoc
- SELECT MAX(ci_builds2.id)
- FROM ci_builds ci_builds2
- WHERE ci_builds.commit_id=ci_builds2.commit_id
- AND ci_builds.name=ci_builds2.name
- SQL
-
- # This is slow update as it does single-row query
- # This is designed to be run as idle, or a post deployment migration
- is_retried = Arel.sql("((#{latest_id}) != ci_builds.id)")
-
- update_column_in_batches(:ci_builds, :retried, is_retried) do |table, query|
- query.where(table[:retried].eq(nil))
- end
- end
- end
-
- def with_temporary_partial_index
- if Gitlab::Database.postgresql?
- unless index_exists?(:ci_builds, :id, name: :index_for_ci_builds_retried_migration)
- execute 'CREATE INDEX CONCURRENTLY index_for_ci_builds_retried_migration ON ci_builds (id) WHERE retried IS NULL;'
- end
- end
-
- yield
-
- if Gitlab::Database.postgresql? && index_exists?(:ci_builds, :id, name: :index_for_ci_builds_retried_migration)
- execute 'DROP INDEX CONCURRENTLY index_for_ci_builds_retried_migration'
- end
- end
-end
diff --git a/db/post_migrate/20170503120310_remove_users_authorized_projects_populated.rb b/db/post_migrate/20170503120310_remove_users_authorized_projects_populated.rb
deleted file mode 100644
index 891ce44f60a..00000000000
--- a/db/post_migrate/20170503120310_remove_users_authorized_projects_populated.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class RemoveUsersAuthorizedProjectsPopulated < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def change
- remove_column :users, :authorized_projects_populated, :boolean
- end
-end
diff --git a/db/post_migrate/20170508170547_add_head_pipeline_for_each_merge_request.rb b/db/post_migrate/20170508170547_add_head_pipeline_for_each_merge_request.rb
deleted file mode 100644
index 6e7365f4c56..00000000000
--- a/db/post_migrate/20170508170547_add_head_pipeline_for_each_merge_request.rb
+++ /dev/null
@@ -1,28 +0,0 @@
-# rubocop:disable Migration/UpdateLargeTable
-class AddHeadPipelineForEachMergeRequest < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- pipelines = Arel::Table.new(:ci_pipelines)
- merge_requests = Arel::Table.new(:merge_requests)
-
- disable_statement_timeout do
- head_id = pipelines
- .project(Arel::Nodes::NamedFunction.new('max', [pipelines[:id]]))
- .from(pipelines)
- .where(pipelines[:ref].eq(merge_requests[:source_branch]))
- .where(pipelines[:project_id].eq(merge_requests[:source_project_id]))
-
- sub_query = Arel::Nodes::SqlLiteral.new(Arel::Nodes::Grouping.new(head_id).to_sql)
-
- update_column_in_batches(:merge_requests, :head_pipeline_id, sub_query)
- end
- end
-
- def down
- end
-end
diff --git a/db/post_migrate/20170510101043_add_foreign_key_on_pipeline_schedule_owner.rb b/db/post_migrate/20170510101043_add_foreign_key_on_pipeline_schedule_owner.rb
deleted file mode 100644
index 85586aecd54..00000000000
--- a/db/post_migrate/20170510101043_add_foreign_key_on_pipeline_schedule_owner.rb
+++ /dev/null
@@ -1,35 +0,0 @@
-class AddForeignKeyOnPipelineScheduleOwner < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- execute <<-SQL
- UPDATE ci_pipeline_schedules
- SET owner_id = NULL
- WHERE NOT EXISTS (
- SELECT true
- FROM users
- WHERE ci_pipeline_schedules.owner_id = users.id
- )
- SQL
-
- add_concurrent_foreign_key(:ci_pipeline_schedules, :users, column: :owner_id, on_delete: on_delete)
- end
-
- def down
- remove_foreign_key(:ci_pipeline_schedules, column: :owner_id)
- end
-
- private
-
- def on_delete
- if Gitlab::Database.mysql?
- :nullify
- else
- 'SET NULL'
- end
- end
-end
diff --git a/db/post_migrate/20170511100900_cleanup_rename_web_hooks_build_events_to_job_events.rb b/db/post_migrate/20170511100900_cleanup_rename_web_hooks_build_events_to_job_events.rb
deleted file mode 100644
index b4a3db65607..00000000000
--- a/db/post_migrate/20170511100900_cleanup_rename_web_hooks_build_events_to_job_events.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class CleanupRenameWebHooksBuildEventsToJobEvents < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- cleanup_concurrent_column_rename :web_hooks, :build_events, :job_events
- end
-
- def down
- rename_column_concurrently :web_hooks, :job_events, :build_events
- end
-end
diff --git a/db/post_migrate/20170511101000_cleanup_rename_services_build_events_to_job_events.rb b/db/post_migrate/20170511101000_cleanup_rename_services_build_events_to_job_events.rb
deleted file mode 100644
index 65342747321..00000000000
--- a/db/post_migrate/20170511101000_cleanup_rename_services_build_events_to_job_events.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class CleanupRenameServicesBuildEventsToJobEvents < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- cleanup_concurrent_column_rename :services, :build_events, :job_events
- end
-
- def down
- rename_column_concurrently :services, :job_events, :build_events
- end
-end
diff --git a/db/post_migrate/20170516165238_cleanup_trigger_for_issues.rb b/db/post_migrate/20170516165238_cleanup_trigger_for_issues.rb
deleted file mode 100644
index affeba52250..00000000000
--- a/db/post_migrate/20170516165238_cleanup_trigger_for_issues.rb
+++ /dev/null
@@ -1,39 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class CleanupTriggerForIssues < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- # When a migration requires downtime you **must** uncomment the following
- # constant and define a short and easy to understand explanation as to why the
- # migration requires downtime.
- # DOWNTIME_REASON = ''
-
- # When using the methods "add_concurrent_index", "remove_concurrent_index" or
- # "add_column_with_default" you must disable the use of transactions
- # as these methods can not run in an existing transaction.
- # When using "add_concurrent_index" or "remove_concurrent_index" methods make sure
- # that either of them is the _only_ method called in the migration,
- # any other changes should go in a separate migration.
- # This ensures that upon failure _only_ the index creation or removing fails
- # and can be retried or reverted easily.
- #
- # To disable transactions uncomment the following line and remove these
- # comments:
- disable_ddl_transaction!
-
- def up
- if Gitlab::Database.postgresql?
- execute <<-EOF
- DROP TRIGGER IF EXISTS replicate_assignee_id ON issues;
- DROP FUNCTION IF EXISTS replicate_assignee_id();
- EOF
- end
- end
-
- def down
- end
-end
diff --git a/db/post_migrate/20170516181025_add_constraints_to_issue_assignees_table.rb b/db/post_migrate/20170516181025_add_constraints_to_issue_assignees_table.rb
deleted file mode 100644
index 03456a31b0d..00000000000
--- a/db/post_migrate/20170516181025_add_constraints_to_issue_assignees_table.rb
+++ /dev/null
@@ -1,37 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class AddConstraintsToIssueAssigneesTable < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- # When a migration requires downtime you **must** uncomment the following
- # constant and define a short and easy to understand explanation as to why the
- # migration requires downtime.
- # DOWNTIME_REASON = ''
-
- # When using the methods "add_concurrent_index", "remove_concurrent_index" or
- # "add_column_with_default" you must disable the use of transactions
- # as these methods can not run in an existing transaction.
- # When using "add_concurrent_index" or "remove_concurrent_index" methods make sure
- # that either of them is the _only_ method called in the migration,
- # any other changes should go in a separate migration.
- # This ensures that upon failure _only_ the index creation or removing fails
- # and can be retried or reverted easily.
- #
- # To disable transactions uncomment the following line and remove these
- # comments:
- # disable_ddl_transaction!
-
- def up
- change_column_null :issue_assignees, :issue_id, false
- change_column_null :issue_assignees, :user_id, false
- end
-
- def down
- change_column_null :issue_assignees, :issue_id, true
- change_column_null :issue_assignees, :user_id, true
- end
-end
diff --git a/db/post_migrate/20170518200835_rename_users_with_renamed_namespace.rb b/db/post_migrate/20170518200835_rename_users_with_renamed_namespace.rb
deleted file mode 100644
index 4ba78727cc3..00000000000
--- a/db/post_migrate/20170518200835_rename_users_with_renamed_namespace.rb
+++ /dev/null
@@ -1,51 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class RenameUsersWithRenamedNamespace < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
- DISALLOWED_ROOT_PATHS = %w[
- abuse_reports
- api
- autocomplete
- explore
- health_check
- import
- invites
- jwt
- koding
- member
- notification_settings
- oauth
- sent_notifications
- unicorn_test
- uploads
- users
- ]
-
- def up
- DISALLOWED_ROOT_PATHS.each do |path|
- users = Arel::Table.new(:users)
- namespaces = Arel::Table.new(:namespaces)
- predicate = namespaces[:owner_id].eq(users[:id])
- .and(namespaces[:type].eq(nil))
- .and(users[:username].matches(path))
-
- update_sql = if Gitlab::Database.postgresql?
- "UPDATE users SET username = namespaces.path "\
- "FROM namespaces WHERE #{predicate.to_sql}"
- else
- "UPDATE users INNER JOIN namespaces "\
- "ON namespaces.owner_id = users.id "\
- "SET username = namespaces.path "\
- "WHERE #{predicate.to_sql}"
- end
-
- connection.execute(update_sql)
- end
- end
-
- def down
- end
-end
diff --git a/db/post_migrate/20170518231126_fix_wrongly_renamed_routes.rb b/db/post_migrate/20170518231126_fix_wrongly_renamed_routes.rb
deleted file mode 100644
index 28a2a2e01bf..00000000000
--- a/db/post_migrate/20170518231126_fix_wrongly_renamed_routes.rb
+++ /dev/null
@@ -1,105 +0,0 @@
-# rubocop:disable Migration/UpdateLargeTable
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class FixWronglyRenamedRoutes < ActiveRecord::Migration[4.2]
- include Gitlab::Database::RenameReservedPathsMigration::V1
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- DISALLOWED_ROOT_PATHS = %w[
- -
- abuse_reports
- api
- autocomplete
- explore
- health_check
- import
- invites
- jwt
- koding
- member
- notification_settings
- oauth
- sent_notifications
- unicorn_test
- uploads
- users
- ]
-
- FIXED_PATHS = DISALLOWED_ROOT_PATHS.map { |p| "#{p}0" }
-
- class Route < Gitlab::Database::RenameReservedPathsMigration::V1::MigrationClasses::Route
- self.table_name = 'routes'
- end
-
- def routes
- @routes ||= Route.arel_table
- end
-
- def namespaces
- @namespaces ||= Arel::Table.new(:namespaces)
- end
-
- def wildcard_collection(collection)
- collection.map { |word| "#{word}%" }
- end
-
- # The routes that got incorrectly renamed before, still have a namespace that
- # contains the correct path.
- # This query fetches all rows from the `routes` table that meet the following
- # conditions using `api` as an example:
- # - route.path ILIKE `api0%`
- # - route.source_type = `Namespace`
- # - namespace.parent_id IS NULL
- # - namespace.path ILIKE `api%`
- # - NOT(namespace.path ILIKE `api0%`)
- # This gives us all root-routes, that were renamed, but their namespace was not.
- #
- def wrongly_renamed
- Route.joins("INNER JOIN namespaces ON routes.source_id = namespaces.id")
- .where(
- routes[:source_type].eq('Namespace')
- .and(namespaces[:parent_id].eq(nil))
- )
- .where(namespaces[:path].matches_any(wildcard_collection(DISALLOWED_ROOT_PATHS)))
- .where.not(namespaces[:path].matches_any(wildcard_collection(FIXED_PATHS)))
- .where(routes[:path].matches_any(wildcard_collection(FIXED_PATHS)))
- end
-
- # Using the query above, we just fetch the `route.path` & the `namespace.path`
- # `route.path` is the part of the route that is now incorrect
- # `namespace.path` is what it should be
- # We can use `route.path` to find all the namespaces that need to be fixed
- # And we can use `namespace.path` to apply the correct name.
- #
- def paths_and_corrections
- connection.select_all(
- wrongly_renamed.select(routes[:path], namespaces[:path].as('namespace_path')).to_sql
- )
- end
-
- # This can be used to limit the `update_in_batches` call to all routes for a
- # single namespace, note the `/` that's what went wrong in the initial migration.
- #
- def routes_in_namespace_query(namespace)
- routes[:path].matches_any([namespace, "#{namespace}/%"])
- end
-
- def up
- paths_and_corrections.each do |root_namespace|
- wrong_path = root_namespace['path']
- correct_path = root_namespace['namespace_path']
- replace_statement = replace_sql(Route.arel_table[:path], wrong_path, correct_path)
-
- update_column_in_batches(:routes, :path, replace_statement) do |table, query|
- query.where(routes_in_namespace_query(wrong_path))
- end
- end
- end
-
- def down
- end
-end
diff --git a/db/post_migrate/20170523073948_remove_assignee_id_from_issue.rb b/db/post_migrate/20170523073948_remove_assignee_id_from_issue.rb
deleted file mode 100644
index d75bbb2f612..00000000000
--- a/db/post_migrate/20170523073948_remove_assignee_id_from_issue.rb
+++ /dev/null
@@ -1,48 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class RemoveAssigneeIdFromIssue < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- # When a migration requires downtime you **must** uncomment the following
- # constant and define a short and easy to understand explanation as to why the
- # migration requires downtime.
- # DOWNTIME_REASON = ''
-
- # When using the methods "add_concurrent_index", "remove_concurrent_index" or
- # "add_column_with_default" you must disable the use of transactions
- # as these methods can not run in an existing transaction.
- # When using "add_concurrent_index" or "remove_concurrent_index" methods make sure
- # that either of them is the _only_ method called in the migration,
- # any other changes should go in a separate migration.
- # This ensures that upon failure _only_ the index creation or removing fails
- # and can be retried or reverted easily.
- #
- # To disable transactions uncomment the following line and remove these
- # comments:
- disable_ddl_transaction!
-
- class Issue < ActiveRecord::Base
- self.table_name = 'issues'
-
- include ::EachBatch
- end
-
- def up
- remove_column :issues, :assignee_id
- end
-
- def down
- add_column :issues, :assignee_id, :integer
- add_concurrent_index :issues, :assignee_id
-
- update_value = Arel.sql('(SELECT user_id FROM issue_assignees WHERE issue_assignees.issue_id = issues.id LIMIT 1)')
-
- # This is only used in the down step, so we can ignore the RuboCop warning
- # about large tables, as this is very unlikely to be run on GitLab.com
- update_column_in_batches(:issues, :assignee_id, update_value) # rubocop:disable Migration/UpdateLargeTable
- end
-end
diff --git a/db/post_migrate/20170523083112_migrate_old_artifacts.rb b/db/post_migrate/20170523083112_migrate_old_artifacts.rb
deleted file mode 100644
index 55e155c7619..00000000000
--- a/db/post_migrate/20170523083112_migrate_old_artifacts.rb
+++ /dev/null
@@ -1,72 +0,0 @@
-class MigrateOldArtifacts < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- # This uses special heuristic to find potential candidates for data migration
- # Read more about this here: https://gitlab.com/gitlab-org/gitlab-ce/issues/32036#note_30422345
-
- def up
- builds_with_artifacts.find_each do |build|
- build.migrate_artifacts!
- end
- end
-
- def down
- end
-
- private
-
- def builds_with_artifacts
- Build.with_artifacts
- .joins('JOIN projects ON projects.id = ci_builds.project_id')
- .where('ci_builds.id < ?', min_id)
- .where('projects.ci_id IS NOT NULL')
- .select('id', 'created_at', 'project_id', 'projects.ci_id AS ci_id')
- end
-
- def min_id
- Build.joins('JOIN projects ON projects.id = ci_builds.project_id')
- .where('projects.ci_id IS NULL')
- .pluck('coalesce(min(ci_builds.id), 0)')
- .first
- end
-
- class Build < ActiveRecord::Base
- self.table_name = 'ci_builds'
-
- scope :with_artifacts, -> { where.not(artifacts_file: [nil, '']) }
-
- def migrate_artifacts!
- return unless File.exist?(source_artifacts_path)
- return if File.exist?(target_artifacts_path)
-
- ensure_target_path
-
- FileUtils.move(source_artifacts_path, target_artifacts_path)
- end
-
- private
-
- def source_artifacts_path
- @source_artifacts_path ||=
- File.join(Gitlab.config.artifacts.path,
- created_at.utc.strftime('%Y_%m'),
- ci_id.to_s, id.to_s)
- end
-
- def target_artifacts_path
- @target_artifacts_path ||=
- File.join(Gitlab.config.artifacts.path,
- created_at.utc.strftime('%Y_%m'),
- project_id.to_s, id.to_s)
- end
-
- def ensure_target_path
- directory = File.dirname(target_artifacts_path)
- FileUtils.mkdir_p(directory) unless Dir.exist?(directory)
- end
- end
-end
diff --git a/db/post_migrate/20170525140254_rename_all_reserved_paths_again.rb b/db/post_migrate/20170525140254_rename_all_reserved_paths_again.rb
deleted file mode 100644
index 59b8daaffdf..00000000000
--- a/db/post_migrate/20170525140254_rename_all_reserved_paths_again.rb
+++ /dev/null
@@ -1,102 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class RenameAllReservedPathsAgain < ActiveRecord::Migration[4.2]
- include Gitlab::Database::RenameReservedPathsMigration::V1
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- TOP_LEVEL_ROUTES = %w[
- -
- .well-known
- abuse_reports
- admin
- api
- assets
- autocomplete
- ci
- dashboard
- explore
- files
- groups
- health_check
- help
- import
- invites
- jwt
- koding
- notification_settings
- oauth
- profile
- projects
- public
- robots.txt
- s
- search
- sent_notifications
- snippets
- u
- unicorn_test
- unsubscribes
- uploads
- users
- ].freeze
-
- PROJECT_WILDCARD_ROUTES = %w[
- badges
- blame
- blob
- builds
- commits
- create
- create_dir
- edit
- environments/folders
- files
- find_file
- gitlab-lfs/objects
- info/lfs/objects
- new
- preview
- raw
- refs
- tree
- update
- wikis
- ].freeze
-
- GROUP_ROUTES = %w[
- activity
- analytics
- audit_events
- avatar
- edit
- group_members
- hooks
- issues
- labels
- ldap
- ldap_group_links
- merge_requests
- milestones
- notification_setting
- pipeline_quota
- projects
- ].freeze
-
- def up
- disable_statement_timeout do
- TOP_LEVEL_ROUTES.each { |route| rename_root_paths(route) }
- PROJECT_WILDCARD_ROUTES.each { |route| rename_wildcard_paths(route) }
- GROUP_ROUTES.each { |route| rename_child_paths(route) }
- end
- end
-
- def down
- disable_statement_timeout do
- revert_renames
- end
- end
-end
diff --git a/db/post_migrate/20170526185842_migrate_pipeline_stages.rb b/db/post_migrate/20170526185842_migrate_pipeline_stages.rb
deleted file mode 100644
index 53743fc16e6..00000000000
--- a/db/post_migrate/20170526185842_migrate_pipeline_stages.rb
+++ /dev/null
@@ -1,22 +0,0 @@
-class MigratePipelineStages < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- disable_statement_timeout do
- execute <<-SQL.strip_heredoc
- INSERT INTO ci_stages (project_id, pipeline_id, name)
- SELECT project_id, commit_id, stage FROM ci_builds
- WHERE stage IS NOT NULL
- AND stage_id IS NULL
- AND EXISTS (SELECT 1 FROM projects WHERE projects.id = ci_builds.project_id)
- AND EXISTS (SELECT 1 FROM ci_pipelines WHERE ci_pipelines.id = ci_builds.commit_id)
- GROUP BY project_id, commit_id, stage
- ORDER BY MAX(stage_idx)
- SQL
- end
- end
-end
diff --git a/db/post_migrate/20170526185858_create_index_in_pipeline_stages.rb b/db/post_migrate/20170526185858_create_index_in_pipeline_stages.rb
deleted file mode 100644
index dc7b1d6d026..00000000000
--- a/db/post_migrate/20170526185858_create_index_in_pipeline_stages.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-class CreateIndexInPipelineStages < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- add_concurrent_index(:ci_stages, [:pipeline_id, :name])
- end
-
- def down
- remove_concurrent_index(:ci_stages, [:pipeline_id, :name])
- end
-end
diff --git a/db/post_migrate/20170526185901_remove_stage_id_index_from_builds.rb b/db/post_migrate/20170526185901_remove_stage_id_index_from_builds.rb
deleted file mode 100644
index de473e7bb91..00000000000
--- a/db/post_migrate/20170526185901_remove_stage_id_index_from_builds.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-class RemoveStageIdIndexFromBuilds < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- if index_exists?(:ci_builds, :stage_id)
- remove_foreign_key(:ci_builds, column: :stage_id)
- remove_concurrent_index(:ci_builds, :stage_id)
- end
- end
-
- def down
- # noop
- end
-end
diff --git a/db/post_migrate/20170526185921_migrate_build_stage_reference.rb b/db/post_migrate/20170526185921_migrate_build_stage_reference.rb
deleted file mode 100644
index a9b392314fa..00000000000
--- a/db/post_migrate/20170526185921_migrate_build_stage_reference.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-class MigrateBuildStageReference < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- ##
- # This is an empty migration, content has been moved to a new one:
- # post migrate 20170526190000 MigrateBuildStageReferenceAgain
- #
- # See gitlab-org/gitlab-ce!12337 for more details.
-
- def up
- # noop
- end
-
- def down
- # noop
- end
-end
diff --git a/db/post_migrate/20170526190000_migrate_build_stage_reference_again.rb b/db/post_migrate/20170526190000_migrate_build_stage_reference_again.rb
deleted file mode 100644
index 01b6cf3a158..00000000000
--- a/db/post_migrate/20170526190000_migrate_build_stage_reference_again.rb
+++ /dev/null
@@ -1,28 +0,0 @@
-# rubocop:disable Migration/UpdateLargeTable
-class MigrateBuildStageReferenceAgain < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- stage_id = Arel.sql <<-SQL.strip_heredoc
- (SELECT id FROM ci_stages
- WHERE ci_stages.pipeline_id = ci_builds.commit_id
- AND ci_stages.name = ci_builds.stage)
- SQL
-
- disable_statement_timeout do
- update_column_in_batches(:ci_builds, :stage_id, stage_id) do |table, query|
- query.where(table[:stage_id].eq(nil))
- end
- end
- end
-
- def down
- disable_statement_timeout do
- update_column_in_batches(:ci_builds, :stage_id, nil)
- end
- end
-end
diff --git a/db/post_migrate/20170531203055_cleanup_users_ldap_email_rename.rb b/db/post_migrate/20170531203055_cleanup_users_ldap_email_rename.rb
deleted file mode 100644
index 3d75c7e3eaf..00000000000
--- a/db/post_migrate/20170531203055_cleanup_users_ldap_email_rename.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-class CleanupUsersLdapEmailRename < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- cleanup_concurrent_column_rename :users, :ldap_email, :external_email
- end
-
- def down
- # rubocop:disable Migration/UpdateLargeTable
- rename_column_concurrently :users, :external_email, :ldap_email
- end
-end
diff --git a/db/post_migrate/20170606202615_move_appearance_to_system_dir.rb b/db/post_migrate/20170606202615_move_appearance_to_system_dir.rb
deleted file mode 100644
index fb9ac8d6daf..00000000000
--- a/db/post_migrate/20170606202615_move_appearance_to_system_dir.rb
+++ /dev/null
@@ -1,57 +0,0 @@
-class MoveAppearanceToSystemDir < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
- disable_ddl_transaction!
-
- DOWNTIME = false
- DIRECTORY_TO_MOVE = 'appearance'.freeze
-
- def up
- source = File.join(old_upload_dir, DIRECTORY_TO_MOVE)
- destination = File.join(new_upload_dir, DIRECTORY_TO_MOVE)
-
- move_directory(source, destination)
- end
-
- def down
- source = File.join(new_upload_dir, DIRECTORY_TO_MOVE)
- destination = File.join(old_upload_dir, DIRECTORY_TO_MOVE)
-
- move_directory(source, destination)
- end
-
- def move_directory(source, destination)
- unless file_storage?
- say 'Not using file storage, skipping'
- return
- end
-
- unless File.directory?(source)
- say "#{source} did not exist, skipping"
- return
- end
-
- if File.directory?(destination)
- say "#{destination} already existed, skipping"
- return
- end
-
- say "Moving #{source} -> #{destination}"
- FileUtils.mv(source, destination)
- end
-
- def file_storage?
- CarrierWave::Uploader::Base.storage == CarrierWave::Storage::File
- end
-
- def base_directory
- Rails.root
- end
-
- def old_upload_dir
- File.join(base_directory, "public", "uploads")
- end
-
- def new_upload_dir
- File.join(base_directory, "public", "uploads", "-", "system")
- end
-end
diff --git a/db/post_migrate/20170607121233_convert_custom_notification_settings_to_columns.rb b/db/post_migrate/20170607121233_convert_custom_notification_settings_to_columns.rb
deleted file mode 100644
index 8ff26130cba..00000000000
--- a/db/post_migrate/20170607121233_convert_custom_notification_settings_to_columns.rb
+++ /dev/null
@@ -1,55 +0,0 @@
-class ConvertCustomNotificationSettingsToColumns < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- class NotificationSetting < ActiveRecord::Base
- self.table_name = 'notification_settings'
-
- store :events, coder: JSON
- end
-
- EMAIL_EVENTS = [
- :new_note,
- :new_issue,
- :reopen_issue,
- :close_issue,
- :reassign_issue,
- :new_merge_request,
- :reopen_merge_request,
- :close_merge_request,
- :reassign_merge_request,
- :merge_merge_request,
- :failed_pipeline,
- :success_pipeline
- ]
-
- # We only need to migrate (up or down) rows where at least one of these
- # settings is set.
- def up
- NotificationSetting.where("events LIKE '%true%'").find_each do |notification_setting|
- EMAIL_EVENTS.each do |event|
- notification_setting[event] = notification_setting.events[event]
- end
-
- notification_setting[:events] = nil
- notification_setting.save!
- end
- end
-
- def down
- NotificationSetting.where(EMAIL_EVENTS.join(' OR ')).find_each do |notification_setting|
- events = {}
-
- EMAIL_EVENTS.each do |event|
- events[event] = !!notification_setting.public_send(event)
- notification_setting[event] = nil
- end
-
- notification_setting[:events] = events
- notification_setting.save!
- end
- end
-end
diff --git a/db/post_migrate/20170609183112_remove_position_from_issuables.rb b/db/post_migrate/20170609183112_remove_position_from_issuables.rb
deleted file mode 100644
index edad0a502b4..00000000000
--- a/db/post_migrate/20170609183112_remove_position_from_issuables.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-class RemovePositionFromIssuables < ActiveRecord::Migration[4.2]
- DOWNTIME = false
-
- def change
- remove_column :issues, :position, :integer
- remove_column :merge_requests, :position, :integer
- end
-end
diff --git a/db/post_migrate/20170612071012_move_personal_snippets_files.rb b/db/post_migrate/20170612071012_move_personal_snippets_files.rb
deleted file mode 100644
index d32d92637fa..00000000000
--- a/db/post_migrate/20170612071012_move_personal_snippets_files.rb
+++ /dev/null
@@ -1,92 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-class MovePersonalSnippetsFiles < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
- disable_ddl_transaction!
-
- DOWNTIME = false
-
- def up
- return unless file_storage?
-
- @source_relative_location = File.join('/uploads', 'personal_snippet')
- @destination_relative_location = File.join('/uploads', '-', 'system', 'personal_snippet')
-
- move_personal_snippet_files
- end
-
- def down
- return unless file_storage?
-
- @source_relative_location = File.join('/uploads', '-', 'system', 'personal_snippet')
- @destination_relative_location = File.join('/uploads', 'personal_snippet')
-
- move_personal_snippet_files
- end
-
- def move_personal_snippet_files
- query = "SELECT uploads.path, uploads.model_id, snippets.description FROM uploads "\
- "INNER JOIN snippets ON snippets.id = uploads.model_id WHERE uploader = 'PersonalFileUploader'"
- select_all(query).each do |upload|
- secret = upload['path'].split('/')[0]
- file_name = upload['path'].split('/')[1]
-
- next unless move_file(upload['model_id'], secret, file_name)
-
- update_markdown(upload['model_id'], secret, file_name, upload['description'])
- end
- end
-
- def move_file(snippet_id, secret, file_name)
- source_dir = File.join(base_directory, @source_relative_location, snippet_id.to_s, secret)
- destination_dir = File.join(base_directory, @destination_relative_location, snippet_id.to_s, secret)
-
- source_file_path = File.join(source_dir, file_name)
- destination_file_path = File.join(destination_dir, file_name)
-
- unless File.exist?(source_file_path)
- say "Source file `#{source_file_path}` doesn't exist. Skipping."
- return
- end
-
- say "Moving file #{source_file_path} -> #{destination_file_path}"
-
- FileUtils.mkdir_p(destination_dir)
- FileUtils.move(source_file_path, destination_file_path)
-
- true
- end
-
- def update_markdown(snippet_id, secret, file_name, description)
- source_markdown_path = File.join(@source_relative_location, snippet_id.to_s, secret, file_name)
- destination_markdown_path = File.join(@destination_relative_location, snippet_id.to_s, secret, file_name)
-
- source_markdown = "](#{source_markdown_path})"
- destination_markdown = "](#{destination_markdown_path})"
-
- if description.present?
- description = description.gsub(source_markdown, destination_markdown)
- quoted_description = quote_string(description)
-
- execute("UPDATE snippets SET description = '#{quoted_description}', description_html = NULL "\
- "WHERE id = #{snippet_id}")
- end
-
- query = "SELECT id, note FROM notes WHERE noteable_id = #{snippet_id} "\
- "AND noteable_type = 'Snippet' AND note IS NOT NULL"
- select_all(query).each do |note|
- text = note['note'].gsub(source_markdown, destination_markdown)
- quoted_text = quote_string(text)
-
- execute("UPDATE notes SET note = '#{quoted_text}', note_html = NULL WHERE id = #{note['id']}")
- end
- end
-
- def base_directory
- File.join(Rails.root, 'public')
- end
-
- def file_storage?
- CarrierWave::Uploader::Base.storage == CarrierWave::Storage::File
- end
-end
diff --git a/db/post_migrate/20170613111224_clean_appearance_symlinks.rb b/db/post_migrate/20170613111224_clean_appearance_symlinks.rb
deleted file mode 100644
index 14511bff3db..00000000000
--- a/db/post_migrate/20170613111224_clean_appearance_symlinks.rb
+++ /dev/null
@@ -1,53 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class CleanAppearanceSymlinks < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
- disable_ddl_transaction!
-
- DOWNTIME = false
-
- def up
- return unless file_storage?
-
- symlink_location = File.join(old_upload_dir, dir)
-
- return unless File.symlink?(symlink_location)
-
- say "removing symlink: #{symlink_location}"
- FileUtils.rm(symlink_location)
- end
-
- def down
- return unless file_storage?
-
- symlink = File.join(old_upload_dir, dir)
- destination = File.join(new_upload_dir, dir)
-
- return if File.directory?(symlink)
- return unless File.directory?(destination)
-
- say "Creating symlink #{symlink} -> #{destination}"
- FileUtils.ln_s(destination, symlink)
- end
-
- def file_storage?
- CarrierWave::Uploader::Base.storage == CarrierWave::Storage::File
- end
-
- def dir
- 'appearance'
- end
-
- def base_directory
- Rails.root
- end
-
- def old_upload_dir
- File.join(base_directory, "public", "uploads")
- end
-
- def new_upload_dir
- File.join(base_directory, "public", "uploads", "system")
- end
-end
diff --git a/db/post_migrate/20170621102400_add_stage_id_index_to_builds.rb b/db/post_migrate/20170621102400_add_stage_id_index_to_builds.rb
deleted file mode 100644
index cca9b488547..00000000000
--- a/db/post_migrate/20170621102400_add_stage_id_index_to_builds.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-class AddStageIdIndexToBuilds < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- ##
- # Improved in 20170703102400_add_stage_id_foreign_key_to_builds.rb
- #
-
- def up
- # noop
- end
-
- def down
- # noop
- end
-end
diff --git a/db/post_migrate/20170627101016_schedule_event_migrations.rb b/db/post_migrate/20170627101016_schedule_event_migrations.rb
deleted file mode 100644
index f026a86bc0f..00000000000
--- a/db/post_migrate/20170627101016_schedule_event_migrations.rb
+++ /dev/null
@@ -1,40 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class ScheduleEventMigrations < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
- BUFFER_SIZE = 1000
-
- disable_ddl_transaction!
-
- class Event < ActiveRecord::Base
- include EachBatch
-
- self.table_name = 'events'
- end
-
- def up
- jobs = []
-
- Event.each_batch(of: 1000) do |relation|
- min, max = relation.pluck('MIN(id), MAX(id)').first
-
- if jobs.length == BUFFER_SIZE
- # We push multiple jobs at a time to reduce the time spent in
- # Sidekiq/Redis operations. We're using this buffer based approach so we
- # don't need to run additional queries for every range.
- BackgroundMigrationWorker.bulk_perform_async(jobs)
- jobs.clear
- end
-
- jobs << ['MigrateEventsToPushEventPayloads', [min, max]]
- end
-
- BackgroundMigrationWorker.bulk_perform_async(jobs) unless jobs.empty?
- end
-
- def down
- end
-end
diff --git a/db/post_migrate/20170628080858_migrate_stage_id_reference_in_background.rb b/db/post_migrate/20170628080858_migrate_stage_id_reference_in_background.rb
deleted file mode 100644
index 36aac3df071..00000000000
--- a/db/post_migrate/20170628080858_migrate_stage_id_reference_in_background.rb
+++ /dev/null
@@ -1,33 +0,0 @@
-class MigrateStageIdReferenceInBackground < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
- BATCH_SIZE = 10000
- RANGE_SIZE = 1000
- MIGRATION = 'MigrateBuildStageIdReference'.freeze
-
- disable_ddl_transaction!
-
- class Build < ActiveRecord::Base
- self.table_name = 'ci_builds'
- include ::EachBatch
- end
-
- ##
- # It will take around 3 days to process 20M ci_builds.
- #
- def up
- Build.where(stage_id: nil).each_batch(of: BATCH_SIZE) do |relation, index|
- relation.each_batch(of: RANGE_SIZE) do |relation|
- range = relation.pluck('MIN(id)', 'MAX(id)').first
-
- BackgroundMigrationWorker
- .perform_in(index * 2.minutes, MIGRATION, range)
- end
- end
- end
-
- def down
- # noop
- end
-end
diff --git a/db/post_migrate/20170629180131_cleanup_application_settings_signin_enabled_rename.rb b/db/post_migrate/20170629180131_cleanup_application_settings_signin_enabled_rename.rb
deleted file mode 100644
index 87268fb4b31..00000000000
--- a/db/post_migrate/20170629180131_cleanup_application_settings_signin_enabled_rename.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-class CleanupApplicationSettingsSigninEnabledRename < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- cleanup_concurrent_column_rename :application_settings, :signin_enabled, :password_authentication_enabled
- end
-
- def down
- rename_column_concurrently :application_settings, :password_authentication_enabled, :signin_enabled
- end
-end
diff --git a/db/post_migrate/20170711145558_migrate_stages_statuses.rb b/db/post_migrate/20170711145558_migrate_stages_statuses.rb
deleted file mode 100644
index 8ba69ea4dce..00000000000
--- a/db/post_migrate/20170711145558_migrate_stages_statuses.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-class MigrateStagesStatuses < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- BATCH_SIZE = 10000
- RANGE_SIZE = 100
- MIGRATION = 'MigrateStageStatus'.freeze
-
- class Stage < ActiveRecord::Base
- self.table_name = 'ci_stages'
- include ::EachBatch
- end
-
- def up
- Stage.where(status: nil).each_batch(of: BATCH_SIZE) do |relation, index|
- relation.each_batch(of: RANGE_SIZE) do |batch|
- range = batch.pluck('MIN(id)', 'MAX(id)').first
- delay = index * 5.minutes
-
- BackgroundMigrationWorker.perform_in(delay, MIGRATION, range)
- end
- end
- end
-
- def down
- disable_statement_timeout do
- # rubocop:disable Migration/UpdateLargeTable
- update_column_in_batches(:ci_stages, :status, nil)
- end
- end
-end
diff --git a/db/post_migrate/20170717111152_cleanup_move_system_upload_folder_symlink.rb b/db/post_migrate/20170717111152_cleanup_move_system_upload_folder_symlink.rb
deleted file mode 100644
index 392c4f71532..00000000000
--- a/db/post_migrate/20170717111152_cleanup_move_system_upload_folder_symlink.rb
+++ /dev/null
@@ -1,40 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class CleanupMoveSystemUploadFolderSymlink < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- if File.symlink?(old_directory)
- say "Removing #{old_directory} -> #{new_directory} symlink"
- FileUtils.rm(old_directory)
- else
- say "Symlink #{old_directory} non existent, nothing to do."
- end
- end
-
- def down
- if File.directory?(new_directory)
- say "Symlinking #{old_directory} -> #{new_directory}"
- FileUtils.ln_s(new_directory, old_directory) unless File.exist?(old_directory)
- else
- say "#{new_directory} doesn't exist, skipping."
- end
- end
-
- def new_directory
- File.join(base_directory, '-', 'system')
- end
-
- def old_directory
- File.join(base_directory, 'system')
- end
-
- def base_directory
- File.join(Rails.root, 'public', 'uploads')
- end
-end
diff --git a/db/post_migrate/20170717150329_enqueue_migrate_system_uploads_to_new_folder.rb b/db/post_migrate/20170717150329_enqueue_migrate_system_uploads_to_new_folder.rb
deleted file mode 100644
index fdd990ae2e5..00000000000
--- a/db/post_migrate/20170717150329_enqueue_migrate_system_uploads_to_new_folder.rb
+++ /dev/null
@@ -1,20 +0,0 @@
-class EnqueueMigrateSystemUploadsToNewFolder < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- OLD_FOLDER = 'uploads/system/'
- NEW_FOLDER = 'uploads/-/system/'
-
- disable_ddl_transaction!
-
- def up
- BackgroundMigrationWorker.perform_async('MigrateSystemUploadsToNewFolder',
- [OLD_FOLDER, NEW_FOLDER])
- end
-
- def down
- BackgroundMigrationWorker.perform_async('MigrateSystemUploadsToNewFolder',
- [NEW_FOLDER, OLD_FOLDER])
- end
-end
diff --git a/db/post_migrate/20170719150301_merge_issuable_reopened_into_opened_state.rb b/db/post_migrate/20170719150301_merge_issuable_reopened_into_opened_state.rb
deleted file mode 100644
index 7af1d04f0cc..00000000000
--- a/db/post_migrate/20170719150301_merge_issuable_reopened_into_opened_state.rb
+++ /dev/null
@@ -1,32 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class MergeIssuableReopenedIntoOpenedState < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- class Issue < ActiveRecord::Base
- self.table_name = 'issues'
-
- include EachBatch
- end
-
- class MergeRequest < ActiveRecord::Base
- self.table_name = 'merge_requests'
-
- include EachBatch
- end
-
- def up
- [Issue, MergeRequest].each do |model|
- say "Changing #{model.table_name}.state from 'reopened' to 'opened'"
-
- model.where(state: 'reopened').each_batch do |batch|
- batch.update_all(state: 'opened')
- end
- end
- end
-end
diff --git a/db/post_migrate/20170728101014_remove_events_from_notification_settings.rb b/db/post_migrate/20170728101014_remove_events_from_notification_settings.rb
deleted file mode 100644
index f1b0a1daec5..00000000000
--- a/db/post_migrate/20170728101014_remove_events_from_notification_settings.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-class RemoveEventsFromNotificationSettings < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def change
- remove_column :notification_settings, :events, :text
- end
-end
diff --git a/db/post_migrate/20170803090603_calculate_conv_dev_index_percentages.rb b/db/post_migrate/20170803090603_calculate_conv_dev_index_percentages.rb
deleted file mode 100644
index a148586ca89..00000000000
--- a/db/post_migrate/20170803090603_calculate_conv_dev_index_percentages.rb
+++ /dev/null
@@ -1,30 +0,0 @@
-class CalculateConvDevIndexPercentages < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
- DOWNTIME = false
-
- class ConversationalDevelopmentIndexMetric < ActiveRecord::Base
- self.table_name = 'conversational_development_index_metrics'
-
- METRICS = %w[boards ci_pipelines deployments environments issues merge_requests milestones notes
- projects_prometheus_active service_desk_issues]
- end
-
- def up
- ConversationalDevelopmentIndexMetric.find_each do |conv_dev_index|
- update = []
-
- ConversationalDevelopmentIndexMetric::METRICS.each do |metric|
- instance_score = conv_dev_index["instance_#{metric}"].to_f
- leader_score = conv_dev_index["leader_#{metric}"].to_f
-
- percentage = leader_score.zero? ? 0.0 : (instance_score / leader_score) * 100
- update << "percentage_#{metric} = '#{percentage}'"
- end
-
- execute("UPDATE conversational_development_index_metrics SET #{update.join(',')} WHERE id = #{conv_dev_index.id}")
- end
- end
-
- def down
- end
-end
diff --git a/db/post_migrate/20170807160457_remove_locked_at_column_from_merge_requests.rb b/db/post_migrate/20170807160457_remove_locked_at_column_from_merge_requests.rb
deleted file mode 100644
index 6dc49211e5a..00000000000
--- a/db/post_migrate/20170807160457_remove_locked_at_column_from_merge_requests.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-class RemoveLockedAtColumnFromMergeRequests < ActiveRecord::Migration[4.2]
- DOWNTIME = false
-
- def up
- remove_column :merge_requests, :locked_at
- end
-
- def down
- add_column :merge_requests, :locked_at, :datetime_with_timezone
- end
-end
diff --git a/db/post_migrate/20170807190736_move_personal_snippet_files_into_correct_folder.rb b/db/post_migrate/20170807190736_move_personal_snippet_files_into_correct_folder.rb
deleted file mode 100644
index 8341ac39c25..00000000000
--- a/db/post_migrate/20170807190736_move_personal_snippet_files_into_correct_folder.rb
+++ /dev/null
@@ -1,29 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class MovePersonalSnippetFilesIntoCorrectFolder < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
- disable_ddl_transaction!
-
- DOWNTIME = false
- NEW_DIRECTORY = File.join('/uploads', '-', 'system', 'personal_snippet')
- OLD_DIRECTORY = File.join('/uploads', 'system', 'personal_snippet')
-
- def up
- return unless file_storage?
-
- BackgroundMigrationWorker.perform_async('MovePersonalSnippetFiles',
- [OLD_DIRECTORY, NEW_DIRECTORY])
- end
-
- def down
- return unless file_storage?
-
- BackgroundMigrationWorker.perform_async('MovePersonalSnippetFiles',
- [NEW_DIRECTORY, OLD_DIRECTORY])
- end
-
- def file_storage?
- CarrierWave::Uploader::Base.storage == CarrierWave::Storage::File
- end
-end
diff --git a/db/post_migrate/20170815060945_remove_duplicate_mr_events.rb b/db/post_migrate/20170815060945_remove_duplicate_mr_events.rb
deleted file mode 100644
index fdc126b8fd6..00000000000
--- a/db/post_migrate/20170815060945_remove_duplicate_mr_events.rb
+++ /dev/null
@@ -1,26 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class RemoveDuplicateMrEvents < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
- DOWNTIME = false
-
- class Event < ActiveRecord::Base
- self.table_name = 'events'
- end
-
- def up
- base_condition = "action = 1 AND target_type = 'MergeRequest' AND created_at > '2017-08-13'"
- Event.select('target_id, count(*)')
- .where(base_condition)
- .group('target_id').having('count(*) > 1').each do |event|
- duplicates = Event.where("#{base_condition} AND target_id = #{event.target_id}").pluck(:id)
- duplicates.shift
-
- Event.where(id: duplicates).delete_all
- end
- end
-
- def down
- end
-end
diff --git a/db/post_migrate/20170816102555_cleanup_nonexisting_namespace_pending_delete_projects.rb b/db/post_migrate/20170816102555_cleanup_nonexisting_namespace_pending_delete_projects.rb
deleted file mode 100644
index 27656fd926d..00000000000
--- a/db/post_migrate/20170816102555_cleanup_nonexisting_namespace_pending_delete_projects.rb
+++ /dev/null
@@ -1,54 +0,0 @@
-# Follow up of CleanupNamespacelessPendingDeleteProjects and it cleans
-# all projects with `pending_delete = true` and for which the
-# namespace no longer exists.
-class CleanupNonexistingNamespacePendingDeleteProjects < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- class Project < ActiveRecord::Base
- self.table_name = 'projects'
-
- include ::EachBatch
- end
-
- class Namespace < ActiveRecord::Base
- self.table_name = 'namespaces'
- end
-
- def up
- find_projects.each_batch do |batch|
- args = batch.pluck(:id).map { |id| [id] }
-
- NamespacelessProjectDestroyWorker.bulk_perform_async(args)
- end
- end
-
- def down
- # NOOP
- end
-
- private
-
- def find_projects
- projects = Project.arel_table
- namespaces = Namespace.arel_table
-
- namespace_query = namespaces.project(1)
- .where(namespaces[:id].eq(projects[:namespace_id]))
- .exists.not
-
- # SELECT "projects"."id"
- # FROM "projects"
- # WHERE "projects"."pending_delete" = 't'
- # AND (NOT (EXISTS
- # (SELECT 1
- # FROM "namespaces"
- # WHERE "namespaces"."id" = "projects"."namespace_id")))
- Project.where(projects[:pending_delete].eq(true))
- .where(namespace_query)
- .select(:id)
- end
-end
diff --git a/db/post_migrate/20170822101017_migrate_pipeline_sidekiq_queues.rb b/db/post_migrate/20170822101017_migrate_pipeline_sidekiq_queues.rb
deleted file mode 100644
index 825bc9250bd..00000000000
--- a/db/post_migrate/20170822101017_migrate_pipeline_sidekiq_queues.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-class MigratePipelineSidekiqQueues < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def up
- sidekiq_queue_migrate 'build', to: 'pipeline_default'
- sidekiq_queue_migrate 'pipeline', to: 'pipeline_default'
- end
-
- def down
- sidekiq_queue_migrate 'pipeline_default', to: 'pipeline'
- sidekiq_queue_migrate 'pipeline_processing', to: 'pipeline'
- sidekiq_queue_migrate 'pipeline_hooks', to: 'pipeline'
- sidekiq_queue_migrate 'pipeline_cache', to: 'pipeline'
- end
-end
diff --git a/db/post_migrate/20170828170502_post_deploy_migrate_user_external_mail_data.rb b/db/post_migrate/20170828170502_post_deploy_migrate_user_external_mail_data.rb
deleted file mode 100644
index 533155aeb7a..00000000000
--- a/db/post_migrate/20170828170502_post_deploy_migrate_user_external_mail_data.rb
+++ /dev/null
@@ -1,57 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class PostDeployMigrateUserExternalMailData < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- class User < ActiveRecord::Base
- self.table_name = 'users'
-
- include EachBatch
- end
-
- class UserSyncedAttributesMetadata < ActiveRecord::Base
- self.table_name = 'user_synced_attributes_metadata'
-
- include EachBatch
- end
-
- def up
- User.each_batch do |batch|
- start_id, end_id = batch.pluck('MIN(id), MAX(id)').first
-
- execute <<-EOF
- INSERT INTO user_synced_attributes_metadata (user_id, provider, email_synced)
- SELECT id, email_provider, external_email
- FROM users
- WHERE external_email = TRUE
- AND NOT EXISTS (
- SELECT true
- FROM user_synced_attributes_metadata
- WHERE user_id = users.id
- AND (provider = users.email_provider OR (provider IS NULL AND users.email_provider IS NULL))
- )
- AND id BETWEEN #{start_id} AND #{end_id}
- EOF
- end
- end
-
- def down
- UserSyncedAttributesMetadata.each_batch do |batch|
- start_id, end_id = batch.pluck('MIN(id), MAX(id)').first
-
- execute <<-EOF
- UPDATE users
- SET users.email_provider = metadata.provider, users.external_email = metadata.email_synced
- FROM user_synced_attributes_metadata as metadata, users
- WHERE metadata.email_synced = TRUE
- AND metadata.user_id = users.id
- AND id BETWEEN #{start_id} AND #{end_id}
- EOF
- end
- end
-end
diff --git a/db/post_migrate/20170828170513_remove_user_email_provider_column.rb b/db/post_migrate/20170828170513_remove_user_email_provider_column.rb
deleted file mode 100644
index bfc8aede540..00000000000
--- a/db/post_migrate/20170828170513_remove_user_email_provider_column.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class RemoveUserEmailProviderColumn < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def change
- remove_column :users, :email_provider, :string
- end
-end
diff --git a/db/post_migrate/20170828170516_remove_user_external_mail_columns.rb b/db/post_migrate/20170828170516_remove_user_external_mail_columns.rb
deleted file mode 100644
index 0104955e5c8..00000000000
--- a/db/post_migrate/20170828170516_remove_user_external_mail_columns.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class RemoveUserExternalMailColumns < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def change
- remove_column :users, :external_email, :boolean
- end
-end
diff --git a/db/post_migrate/20170830084744_destroy_gpg_signatures.rb b/db/post_migrate/20170830084744_destroy_gpg_signatures.rb
deleted file mode 100644
index 2945eb9fde6..00000000000
--- a/db/post_migrate/20170830084744_destroy_gpg_signatures.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-class DestroyGpgSignatures < ActiveRecord::Migration[4.2]
- DOWNTIME = false
-
- def up
- truncate(:gpg_signatures)
- end
-
- def down
- end
-end
diff --git a/db/post_migrate/20170830150306_drop_events_for_migration_table.rb b/db/post_migrate/20170830150306_drop_events_for_migration_table.rb
deleted file mode 100644
index 3538b52b004..00000000000
--- a/db/post_migrate/20170830150306_drop_events_for_migration_table.rb
+++ /dev/null
@@ -1,47 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class DropEventsForMigrationTable < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- class Event < ActiveRecord::Base
- include EachBatch
- end
-
- def up
- transaction do
- drop_table :events_for_migration
- end
- end
-
- def down
- create_table :events_for_migration do |t|
- t.string :target_type, index: true
- t.integer :target_id, index: true
- t.string :title
- t.text :data
- t.integer :project_id
- t.datetime :created_at, index: true
- t.datetime :updated_at
- t.integer :action, index: true
- t.integer :author_id, index: true
-
- t.index [:project_id, :id]
- end
-
- Event.all.each_batch do |relation|
- start_id, stop_id = relation.pluck('MIN(id), MAX(id)').first
-
- execute <<-EOF.strip_heredoc
- INSERT INTO events_for_migration (target_type, target_id, project_id, created_at, updated_at, action, author_id)
- SELECT target_type, target_id, project_id, created_at, updated_at, action, author_id
- FROM events
- WHERE id BETWEEN #{start_id} AND #{stop_id}
- EOF
- end
- end
-end
diff --git a/db/post_migrate/20170831195038_remove_valid_signature_from_gpg_signatures.rb b/db/post_migrate/20170831195038_remove_valid_signature_from_gpg_signatures.rb
deleted file mode 100644
index 8e264c1ab41..00000000000
--- a/db/post_migrate/20170831195038_remove_valid_signature_from_gpg_signatures.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-class RemoveValidSignatureFromGpgSignatures < ActiveRecord::Migration[4.2]
- DOWNTIME = false
-
- def up
- remove_column :gpg_signatures, :valid_signature
- end
-
- def down
- add_column :gpg_signatures, :valid_signature, :boolean
- end
-end
diff --git a/db/post_migrate/20170907170235_delete_conflicting_redirect_routes.rb b/db/post_migrate/20170907170235_delete_conflicting_redirect_routes.rb
deleted file mode 100644
index 95abf2474dd..00000000000
--- a/db/post_migrate/20170907170235_delete_conflicting_redirect_routes.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class DeleteConflictingRedirectRoutes < ActiveRecord::Migration[4.2]
- def up
- # No-op.
- # See https://gitlab.com/gitlab-com/infrastructure/issues/3460#note_53223252
- end
-
- def down
- # nothing
- end
-end
diff --git a/db/post_migrate/20170913180600_fix_projects_without_project_feature.rb b/db/post_migrate/20170913180600_fix_projects_without_project_feature.rb
deleted file mode 100644
index bbc624ac7c0..00000000000
--- a/db/post_migrate/20170913180600_fix_projects_without_project_feature.rb
+++ /dev/null
@@ -1,33 +0,0 @@
-class FixProjectsWithoutProjectFeature < ActiveRecord::Migration[4.2]
- DOWNTIME = false
-
- def up
- # Deletes corrupted project features
- sql = "DELETE FROM project_features WHERE project_id IS NULL"
- execute(sql)
-
- # Creates missing project features with private visibility
- sql =
- %Q{
- INSERT INTO project_features(project_id, repository_access_level, issues_access_level, merge_requests_access_level, wiki_access_level,
- builds_access_level, snippets_access_level, created_at, updated_at)
- SELECT projects.id as project_id,
- 10 as repository_access_level,
- 10 as issues_access_level,
- 10 as merge_requests_access_level,
- 10 as wiki_access_level,
- 10 as builds_access_level ,
- 10 as snippets_access_level,
- projects.created_at,
- projects.updated_at
- FROM projects
- LEFT OUTER JOIN project_features ON project_features.project_id = projects.id
- WHERE (project_features.id IS NULL)
- }
-
- execute(sql)
- end
-
- def down
- end
-end
diff --git a/db/post_migrate/20170921101004_normalize_ldap_extern_uids.rb b/db/post_migrate/20170921101004_normalize_ldap_extern_uids.rb
deleted file mode 100644
index 9080acee1d6..00000000000
--- a/db/post_migrate/20170921101004_normalize_ldap_extern_uids.rb
+++ /dev/null
@@ -1,29 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class NormalizeLdapExternUids < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
- MIGRATION = 'NormalizeLdapExternUidsRange'.freeze
- DELAY_INTERVAL = 10.seconds
-
- disable_ddl_transaction!
-
- class Identity < ActiveRecord::Base
- include EachBatch
-
- self.table_name = 'identities'
- end
-
- def up
- ldap_identities = Identity.where("provider like 'ldap%'")
-
- if ldap_identities.any?
- queue_background_migration_jobs_by_range_at_intervals(Identity, MIGRATION, DELAY_INTERVAL)
- end
- end
-
- def down
- end
-end
diff --git a/db/post_migrate/20170927112318_update_legacy_diff_notes_type_for_import.rb b/db/post_migrate/20170927112318_update_legacy_diff_notes_type_for_import.rb
deleted file mode 100644
index 83c21c203e0..00000000000
--- a/db/post_migrate/20170927112318_update_legacy_diff_notes_type_for_import.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-# rubocop:disable Migration/UpdateLargeTable
-class UpdateLegacyDiffNotesTypeForImport < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- update_column_in_batches(:notes, :type, 'LegacyDiffNote') do |table, query|
- query.where(table[:type].eq('Github::Import::LegacyDiffNote'))
- end
- end
-
- def down
- end
-end
diff --git a/db/post_migrate/20170927112319_update_notes_type_for_import.rb b/db/post_migrate/20170927112319_update_notes_type_for_import.rb
deleted file mode 100644
index 8c691de3192..00000000000
--- a/db/post_migrate/20170927112319_update_notes_type_for_import.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-# rubocop:disable Migration/UpdateLargeTable
-class UpdateNotesTypeForImport < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- update_column_in_batches(:notes, :type, 'Note') do |table, query|
- query.where(table[:type].eq('Github::Import::Note'))
- end
- end
-
- def down
- end
-end
diff --git a/db/post_migrate/20171012150314_remove_user_authentication_token.rb b/db/post_migrate/20171012150314_remove_user_authentication_token.rb
deleted file mode 100644
index 9313986ce85..00000000000
--- a/db/post_migrate/20171012150314_remove_user_authentication_token.rb
+++ /dev/null
@@ -1,20 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class RemoveUserAuthenticationToken < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- remove_column :users, :authentication_token
- end
-
- def down
- add_column :users, :authentication_token, :string
-
- add_concurrent_index :users, :authentication_token, unique: true
- end
-end
diff --git a/db/post_migrate/20171013104327_migrate_gcp_clusters_to_new_clusters_architectures.rb b/db/post_migrate/20171013104327_migrate_gcp_clusters_to_new_clusters_architectures.rb
deleted file mode 100644
index 9c90aa611a4..00000000000
--- a/db/post_migrate/20171013104327_migrate_gcp_clusters_to_new_clusters_architectures.rb
+++ /dev/null
@@ -1,98 +0,0 @@
-class MigrateGcpClustersToNewClustersArchitectures < ActiveRecord::Migration[4.2]
- DOWNTIME = false
-
- class GcpCluster < ActiveRecord::Base
- self.table_name = 'gcp_clusters'
-
- belongs_to :project, class_name: 'Project'
-
- include EachBatch
- end
-
- class Cluster < ActiveRecord::Base
- self.table_name = 'clusters'
-
- has_many :cluster_projects, class_name: 'ClustersProject'
- has_many :projects, through: :cluster_projects, class_name: 'Project'
- has_one :provider_gcp, class_name: 'ProvidersGcp'
- has_one :platform_kubernetes, class_name: 'PlatformsKubernetes'
-
- accepts_nested_attributes_for :provider_gcp
- accepts_nested_attributes_for :platform_kubernetes
-
- enum platform_type: {
- kubernetes: 1
- }
-
- enum provider_type: {
- user: 0,
- gcp: 1
- }
- end
-
- class Project < ActiveRecord::Base
- self.table_name = 'projects'
-
- has_one :cluster_project, class_name: 'ClustersProject'
- has_one :cluster, through: :cluster_project, class_name: 'Cluster'
- end
-
- class ClustersProject < ActiveRecord::Base
- self.table_name = 'cluster_projects'
-
- belongs_to :cluster, class_name: 'Cluster'
- belongs_to :project, class_name: 'Project'
- end
-
- class ProvidersGcp < ActiveRecord::Base
- self.table_name = 'cluster_providers_gcp'
- end
-
- class PlatformsKubernetes < ActiveRecord::Base
- self.table_name = 'cluster_platforms_kubernetes'
- end
-
- def up
- GcpCluster.all.find_each(batch_size: 1) do |gcp_cluster|
- Cluster.create(
- enabled: gcp_cluster.enabled,
- user_id: gcp_cluster.user_id,
- name: gcp_cluster.gcp_cluster_name,
- provider_type: Cluster.provider_types[:gcp],
- platform_type: Cluster.platform_types[:kubernetes],
- projects: [gcp_cluster.project],
- provider_gcp_attributes: {
- status: gcp_cluster.status,
- status_reason: gcp_cluster.status_reason,
- gcp_project_id: gcp_cluster.gcp_project_id,
- zone: gcp_cluster.gcp_cluster_zone,
- num_nodes: gcp_cluster.gcp_cluster_size,
- machine_type: gcp_cluster.gcp_machine_type,
- operation_id: gcp_cluster.gcp_operation_id,
- endpoint: gcp_cluster.endpoint,
- encrypted_access_token: gcp_cluster.encrypted_gcp_token,
- encrypted_access_token_iv: gcp_cluster.encrypted_gcp_token_iv
- },
- platform_kubernetes_attributes: {
- api_url: api_url(gcp_cluster.endpoint),
- ca_cert: gcp_cluster.ca_cert,
- namespace: gcp_cluster.project_namespace,
- username: gcp_cluster.username,
- encrypted_password: gcp_cluster.encrypted_password,
- encrypted_password_iv: gcp_cluster.encrypted_password_iv,
- encrypted_token: gcp_cluster.encrypted_kubernetes_token,
- encrypted_token_iv: gcp_cluster.encrypted_kubernetes_token_iv
- } )
- end
- end
-
- def down
- execute('DELETE FROM clusters')
- end
-
- private
-
- def api_url(endpoint)
- endpoint ? 'https://' + endpoint : nil
- end
-end
diff --git a/db/post_migrate/20171026082505_schedule_merge_request_latest_merge_request_diff_id_migrations.rb b/db/post_migrate/20171026082505_schedule_merge_request_latest_merge_request_diff_id_migrations.rb
deleted file mode 100644
index 764561de997..00000000000
--- a/db/post_migrate/20171026082505_schedule_merge_request_latest_merge_request_diff_id_migrations.rb
+++ /dev/null
@@ -1,29 +0,0 @@
-class ScheduleMergeRequestLatestMergeRequestDiffIdMigrations < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
- BATCH_SIZE = 50_000
- MIGRATION = 'PopulateMergeRequestsLatestMergeRequestDiffId'
-
- disable_ddl_transaction!
-
- class MergeRequest < ActiveRecord::Base
- self.table_name = 'merge_requests'
-
- include ::EachBatch
- end
-
- # On GitLab.com, we saw that we generated about 500,000 dead tuples over 5 minutes.
- # To keep replication lag from ballooning, we'll aim for 50,000 updates over 5 minutes.
- #
- # Assuming that there are 5 million rows affected (which is more than on
- # GitLab.com), and that each batch of 50,000 rows takes up to 5 minutes, then
- # we can migrate all the rows in 8.5 hours.
- def up
- MergeRequest.where(latest_merge_request_diff_id: nil).each_batch(of: BATCH_SIZE) do |relation, index|
- range = relation.pluck('MIN(id)', 'MAX(id)').first
-
- BackgroundMigrationWorker.perform_in(index * 5.minutes, MIGRATION, range)
- end
- end
-end
diff --git a/db/post_migrate/20171101134435_remove_ref_fetched_from_merge_requests.rb b/db/post_migrate/20171101134435_remove_ref_fetched_from_merge_requests.rb
deleted file mode 100644
index e6a5ffc8649..00000000000
--- a/db/post_migrate/20171101134435_remove_ref_fetched_from_merge_requests.rb
+++ /dev/null
@@ -1,14 +0,0 @@
-class RemoveRefFetchedFromMergeRequests < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- # We don't need to cache this anymore: the refs are now created
- # upon save/update and there is no more use for this flag
- #
- # See https://gitlab.com/gitlab-org/gitlab-ce/issues/36061
- def change
- remove_column :merge_requests, :ref_fetched, :boolean
- end
-end
diff --git a/db/post_migrate/20171103140253_track_untracked_uploads.rb b/db/post_migrate/20171103140253_track_untracked_uploads.rb
deleted file mode 100644
index 6891ef5ba12..00000000000
--- a/db/post_migrate/20171103140253_track_untracked_uploads.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class TrackUntrackedUploads < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- disable_ddl_transaction!
-
- DOWNTIME = false
- MIGRATION = 'PrepareUntrackedUploads'
-
- def up
- BackgroundMigrationWorker.perform_async(MIGRATION)
- end
-
- def down
- if table_exists?(:untracked_files_for_uploads)
- drop_table :untracked_files_for_uploads
- end
- end
-end
diff --git a/db/post_migrate/20171106133144_cleanup_application_settings_password_authentication_enabled_rename.rb b/db/post_migrate/20171106133144_cleanup_application_settings_password_authentication_enabled_rename.rb
deleted file mode 100644
index 4a01bf75f50..00000000000
--- a/db/post_migrate/20171106133144_cleanup_application_settings_password_authentication_enabled_rename.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-class CleanupApplicationSettingsPasswordAuthenticationEnabledRename < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- cleanup_concurrent_column_rename :application_settings, :password_authentication_enabled, :password_authentication_enabled_for_web
- end
-
- def down
- rename_column_concurrently :application_settings, :password_authentication_enabled_for_web, :password_authentication_enabled
- end
-end
diff --git a/db/post_migrate/20171106154015_remove_issues_branch_name.rb b/db/post_migrate/20171106154015_remove_issues_branch_name.rb
deleted file mode 100644
index 4e71aa2f163..00000000000
--- a/db/post_migrate/20171106154015_remove_issues_branch_name.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class RemoveIssuesBranchName < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- # Set this constant to true if this migration requires downtime.
- DOWNTIME = false
-
- def change
- remove_column :issues, :branch_name, :string
- end
-end
diff --git a/db/post_migrate/20171106180641_cleanup_add_timezone_to_issues_closed_at.rb b/db/post_migrate/20171106180641_cleanup_add_timezone_to_issues_closed_at.rb
deleted file mode 100644
index 8187d3971fc..00000000000
--- a/db/post_migrate/20171106180641_cleanup_add_timezone_to_issues_closed_at.rb
+++ /dev/null
@@ -1,20 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class CleanupAddTimezoneToIssuesClosedAt < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- cleanup_concurrent_column_type_change(:issues, :closed_at)
- end
-
- # rubocop:disable Migration/Datetime
- # rubocop:disable Migration/UpdateLargeTable
- def down
- change_column_type_concurrently(:issues, :closed_at, :datetime)
- end
-end
diff --git a/db/post_migrate/20171114104051_remove_empty_fork_networks.rb b/db/post_migrate/20171114104051_remove_empty_fork_networks.rb
deleted file mode 100644
index 76862cccf60..00000000000
--- a/db/post_migrate/20171114104051_remove_empty_fork_networks.rb
+++ /dev/null
@@ -1,36 +0,0 @@
-class RemoveEmptyForkNetworks < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
- BATCH_SIZE = 10_000
-
- class MigrationForkNetwork < ActiveRecord::Base
- include EachBatch
-
- self.table_name = 'fork_networks'
- end
-
- class MigrationForkNetworkMembers < ActiveRecord::Base
- self.table_name = 'fork_network_members'
- end
-
- disable_ddl_transaction!
-
- def up
- say 'Deleting empty ForkNetworks in batches'
-
- has_members = MigrationForkNetworkMembers
- .where('fork_network_members.fork_network_id = fork_networks.id')
- .select(1)
- MigrationForkNetwork.where('NOT EXISTS (?)', has_members)
- .each_batch(of: BATCH_SIZE) do |networks|
- deleted = networks.delete_all
-
- say "Deleted #{deleted} rows in batch"
- end
- end
-
- def down
- # nothing
- end
-end
diff --git a/db/post_migrate/20171121160421_remove_merge_request_diff_st_commits_and_st_diffs.rb b/db/post_migrate/20171121160421_remove_merge_request_diff_st_commits_and_st_diffs.rb
deleted file mode 100644
index 93a97993f1f..00000000000
--- a/db/post_migrate/20171121160421_remove_merge_request_diff_st_commits_and_st_diffs.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-class RemoveMergeRequestDiffStCommitsAndStDiffs < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def change
- remove_column :merge_request_diffs, :st_commits, :text
- remove_column :merge_request_diffs, :st_diffs, :text
- end
-end
diff --git a/db/post_migrate/20171123101020_update_circuitbreaker_defaults.rb b/db/post_migrate/20171123101020_update_circuitbreaker_defaults.rb
deleted file mode 100644
index ae954289291..00000000000
--- a/db/post_migrate/20171123101020_update_circuitbreaker_defaults.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class UpdateCircuitbreakerDefaults < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- class ApplicationSetting < ActiveRecord::Base; end
-
- def up
- change_column_default :application_settings,
- :circuitbreaker_failure_count_threshold,
- 3
- change_column_default :application_settings,
- :circuitbreaker_storage_timeout,
- 15
-
- ApplicationSetting.update_all(circuitbreaker_failure_count_threshold: 3,
- circuitbreaker_storage_timeout: 15)
- end
-
- def down
- change_column_default :application_settings,
- :circuitbreaker_failure_count_threshold,
- 160
- change_column_default :application_settings,
- :circuitbreaker_storage_timeout,
- 30
-
- ApplicationSetting.update_all(circuitbreaker_failure_count_threshold: 160,
- circuitbreaker_storage_timeout: 30)
- end
-end
diff --git a/db/post_migrate/20171123101046_remove_old_circuitbreaker_config.rb b/db/post_migrate/20171123101046_remove_old_circuitbreaker_config.rb
deleted file mode 100644
index 3f2c1b2170a..00000000000
--- a/db/post_migrate/20171123101046_remove_old_circuitbreaker_config.rb
+++ /dev/null
@@ -1,26 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class RemoveOldCircuitbreakerConfig < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def up
- remove_column :application_settings,
- :circuitbreaker_backoff_threshold
- remove_column :application_settings,
- :circuitbreaker_failure_wait_time
- end
-
- def down
- add_column :application_settings,
- :circuitbreaker_backoff_threshold,
- :integer,
- default: 80
- add_column :application_settings,
- :circuitbreaker_failure_wait_time,
- :integer,
- default: 30
- end
-end
diff --git a/db/post_migrate/20171124095655_add_index_on_merge_request_diffs_merge_request_id_and_id.rb b/db/post_migrate/20171124095655_add_index_on_merge_request_diffs_merge_request_id_and_id.rb
deleted file mode 100644
index 2c65a4ae4f5..00000000000
--- a/db/post_migrate/20171124095655_add_index_on_merge_request_diffs_merge_request_id_and_id.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-class AddIndexOnMergeRequestDiffsMergeRequestIdAndId < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- add_concurrent_index(:merge_request_diffs, [:merge_request_id, :id])
- end
-
- def down
- if index_exists?(:merge_request_diffs, [:merge_request_id, :id])
- remove_concurrent_index(:merge_request_diffs, [:merge_request_id, :id])
- end
- end
-end
diff --git a/db/post_migrate/20171124100152_remove_index_on_merge_request_diffs_merge_request_diff_id.rb b/db/post_migrate/20171124100152_remove_index_on_merge_request_diffs_merge_request_diff_id.rb
deleted file mode 100644
index efd3714d668..00000000000
--- a/db/post_migrate/20171124100152_remove_index_on_merge_request_diffs_merge_request_diff_id.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-class RemoveIndexOnMergeRequestDiffsMergeRequestDiffId < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- if index_exists?(:merge_request_diffs, :merge_request_id)
- remove_concurrent_index(:merge_request_diffs, :merge_request_id)
- end
- end
-
- def down
- add_concurrent_index(:merge_request_diffs, :merge_request_id)
- end
-end
diff --git a/db/post_migrate/20171124104327_migrate_kubernetes_service_to_new_clusters_architectures.rb b/db/post_migrate/20171124104327_migrate_kubernetes_service_to_new_clusters_architectures.rb
deleted file mode 100644
index 58ceefe3c97..00000000000
--- a/db/post_migrate/20171124104327_migrate_kubernetes_service_to_new_clusters_architectures.rb
+++ /dev/null
@@ -1,151 +0,0 @@
-class MigrateKubernetesServiceToNewClustersArchitectures < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
- DEFAULT_KUBERNETES_SERVICE_CLUSTER_NAME = 'KubernetesService'.freeze
-
- disable_ddl_transaction!
-
- class Project < ActiveRecord::Base
- self.table_name = 'projects'
-
- has_many :cluster_projects, class_name: 'MigrateKubernetesServiceToNewClustersArchitectures::ClustersProject'
- has_many :clusters, through: :cluster_projects, class_name: 'MigrateKubernetesServiceToNewClustersArchitectures::Cluster'
- has_many :services, class_name: 'MigrateKubernetesServiceToNewClustersArchitectures::Service'
- has_one :kubernetes_service, -> { where(category: 'deployment', type: 'KubernetesService') }, class_name: 'MigrateKubernetesServiceToNewClustersArchitectures::Service', inverse_of: :project, foreign_key: :project_id
- end
-
- class Cluster < ActiveRecord::Base
- self.table_name = 'clusters'
-
- has_many :cluster_projects, class_name: 'MigrateKubernetesServiceToNewClustersArchitectures::ClustersProject'
- has_many :projects, through: :cluster_projects, class_name: 'MigrateKubernetesServiceToNewClustersArchitectures::Project'
- has_one :platform_kubernetes, class_name: 'MigrateKubernetesServiceToNewClustersArchitectures::PlatformsKubernetes'
-
- accepts_nested_attributes_for :platform_kubernetes
-
- enum platform_type: {
- kubernetes: 1
- }
-
- enum provider_type: {
- user: 0,
- gcp: 1
- }
- end
-
- class ClustersProject < ActiveRecord::Base
- self.table_name = 'cluster_projects'
-
- belongs_to :cluster, class_name: 'MigrateKubernetesServiceToNewClustersArchitectures::Cluster'
- belongs_to :project, class_name: 'MigrateKubernetesServiceToNewClustersArchitectures::Project'
- end
-
- class PlatformsKubernetes < ActiveRecord::Base
- self.table_name = 'cluster_platforms_kubernetes'
-
- belongs_to :cluster, class_name: 'MigrateKubernetesServiceToNewClustersArchitectures::Cluster'
-
- attr_encrypted :token,
- mode: :per_attribute_iv,
- key: Settings.attr_encrypted_db_key_base_truncated,
- algorithm: 'aes-256-cbc'
- end
-
- class Service < ActiveRecord::Base
- include EachBatch
-
- self.table_name = 'services'
- self.inheritance_column = :_type_disabled # Disable STI, otherwise KubernetesModel will be looked up
-
- belongs_to :project, class_name: 'MigrateKubernetesServiceToNewClustersArchitectures::Project', foreign_key: :project_id
-
- scope :unmanaged_kubernetes_service, -> do
- joins('LEFT JOIN projects ON projects.id = services.project_id')
- .joins('LEFT JOIN cluster_projects ON cluster_projects.project_id = projects.id')
- .joins('LEFT JOIN cluster_platforms_kubernetes ON cluster_platforms_kubernetes.cluster_id = cluster_projects.cluster_id')
- .where(category: 'deployment', type: 'KubernetesService', template: false)
- .where("services.properties LIKE '%api_url%'")
- .where("(services.properties NOT LIKE CONCAT('%', cluster_platforms_kubernetes.api_url, '%')) OR cluster_platforms_kubernetes.api_url IS NULL")
- .group(:id)
- .order(id: :asc)
- end
-
- scope :kubernetes_service_without_template, -> do
- where(category: 'deployment', type: 'KubernetesService', template: false)
- end
-
- def api_url
- parsed_properties['api_url']
- end
-
- def ca_pem
- parsed_properties['ca_pem']
- end
-
- def namespace
- parsed_properties['namespace']
- end
-
- def token
- parsed_properties['token']
- end
-
- private
-
- def parsed_properties
- @parsed_properties ||= JSON.parse(self.properties)
- end
- end
-
- def find_dedicated_environement_scope(project)
- environment_scopes = project.clusters.map(&:environment_scope)
-
- return '*' if environment_scopes.exclude?('*') # KubernetesService should be added as a default cluster (environment_scope: '*') at first place
- return 'migrated/*' if environment_scopes.exclude?('migrated/*') # If it's conflicted, the KubernetesService added as a migrated cluster
-
- unique_iid = 0
-
- # If it's still conflicted, finding an unique environment scope incrementaly
- loop do
- candidate = "migrated#{unique_iid}/*"
- return candidate if environment_scopes.exclude?(candidate)
-
- unique_iid += 1
- end
- end
-
- def up
- ActiveRecord::Base.transaction do
- MigrateKubernetesServiceToNewClustersArchitectures::Service
- .unmanaged_kubernetes_service.find_each(batch_size: 1) do |kubernetes_service|
- MigrateKubernetesServiceToNewClustersArchitectures::Cluster.create(
- enabled: kubernetes_service.active,
- user_id: nil, # KubernetesService doesn't have
- name: DEFAULT_KUBERNETES_SERVICE_CLUSTER_NAME,
- provider_type: MigrateKubernetesServiceToNewClustersArchitectures::Cluster.provider_types[:user],
- platform_type: MigrateKubernetesServiceToNewClustersArchitectures::Cluster.platform_types[:kubernetes],
- projects: [kubernetes_service.project],
- environment_scope: find_dedicated_environement_scope(kubernetes_service.project),
- platform_kubernetes_attributes: {
- api_url: kubernetes_service.api_url,
- ca_cert: kubernetes_service.ca_pem,
- namespace: kubernetes_service.namespace,
- username: nil, # KubernetesService doesn't have
- encrypted_password: nil, # KubernetesService doesn't have
- encrypted_password_iv: nil, # KubernetesService doesn't have
- token: kubernetes_service.token # encrypted_token and encrypted_token_iv
- } )
- end
- end
-
- MigrateKubernetesServiceToNewClustersArchitectures::Service
- .kubernetes_service_without_template.each_batch(of: 100) do |kubernetes_service|
- kubernetes_service.update_all(active: false)
- end
- end
-
- def down
- # noop
- end
-end
diff --git a/db/post_migrate/20171124150326_reschedule_fork_network_creation.rb b/db/post_migrate/20171124150326_reschedule_fork_network_creation.rb
deleted file mode 100644
index 8e320ea9e8d..00000000000
--- a/db/post_migrate/20171124150326_reschedule_fork_network_creation.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-class RescheduleForkNetworkCreation < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def up
- say 'Fork networks will be populated in 20171205190711 - RescheduleForkNetworkCreationCaller'
- end
-
- def down
- # nothing
- end
-end
diff --git a/db/post_migrate/20171205190711_reschedule_fork_network_creation_caller.rb b/db/post_migrate/20171205190711_reschedule_fork_network_creation_caller.rb
deleted file mode 100644
index 058f3a40817..00000000000
--- a/db/post_migrate/20171205190711_reschedule_fork_network_creation_caller.rb
+++ /dev/null
@@ -1,27 +0,0 @@
-class RescheduleForkNetworkCreationCaller < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- MIGRATION = 'PopulateForkNetworksRange'.freeze
- BATCH_SIZE = 100
- DELAY_INTERVAL = 15.seconds
-
- disable_ddl_transaction!
-
- class ForkedProjectLink < ActiveRecord::Base
- include EachBatch
-
- self.table_name = 'forked_project_links'
- end
-
- def up
- say 'Populating the `fork_networks` based on existing `forked_project_links`'
-
- queue_background_migration_jobs_by_range_at_intervals(ForkedProjectLink, MIGRATION, DELAY_INTERVAL, batch_size: BATCH_SIZE)
- end
-
- def down
- # nothing
- end
-end
diff --git a/db/post_migrate/20171207150300_remove_project_labels_group_id_copy.rb b/db/post_migrate/20171207150300_remove_project_labels_group_id_copy.rb
deleted file mode 100644
index 44273cebc9d..00000000000
--- a/db/post_migrate/20171207150300_remove_project_labels_group_id_copy.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-# Copy of 20180202111106 - this one should run before 20171207150343 to fix issues related to
-# the removal of groups with labels.
-
-class RemoveProjectLabelsGroupIdCopy < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- # rubocop:disable Migration/UpdateColumnInBatches
- update_column_in_batches(:labels, :group_id, nil) do |table, query|
- query.where(table[:type].eq('ProjectLabel').and(table[:group_id].not_eq(nil)))
- end
- # rubocop:enable Migration/UpdateColumnInBatches
- end
-
- def down
- end
-end
diff --git a/db/post_migrate/20171207150344_remove_deleted_at_columns.rb b/db/post_migrate/20171207150344_remove_deleted_at_columns.rb
deleted file mode 100644
index 5f1c70a2797..00000000000
--- a/db/post_migrate/20171207150344_remove_deleted_at_columns.rb
+++ /dev/null
@@ -1,31 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class RemoveDeletedAtColumns < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- TABLES = %i[issues merge_requests namespaces ci_pipeline_schedules ci_triggers].freeze
- COLUMN = :deleted_at
-
- def up
- TABLES.each do |table|
- remove_column(table, COLUMN) if column_exists?(table, COLUMN)
- end
- end
-
- def down
- TABLES.each do |table|
- unless column_exists?(table, COLUMN)
- add_column(table, COLUMN, :datetime_with_timezone)
- end
-
- unless index_exists?(table, COLUMN)
- add_concurrent_index(table, COLUMN)
- end
- end
- end
-end
diff --git a/db/post_migrate/20171213160445_migrate_github_importer_advance_stage_sidekiq_queue.rb b/db/post_migrate/20171213160445_migrate_github_importer_advance_stage_sidekiq_queue.rb
deleted file mode 100644
index 088c4b5d46b..00000000000
--- a/db/post_migrate/20171213160445_migrate_github_importer_advance_stage_sidekiq_queue.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class MigrateGithubImporterAdvanceStageSidekiqQueue < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- def up
- sidekiq_queue_migrate 'github_importer_advance_stage', to: 'github_import_advance_stage'
- end
-
- def down
- sidekiq_queue_migrate 'github_import_advance_stage', to: 'github_importer_advance_stage'
- end
-end
diff --git a/db/post_migrate/20171215121205_post_populate_can_push_from_deploy_keys_projects.rb b/db/post_migrate/20171215121205_post_populate_can_push_from_deploy_keys_projects.rb
deleted file mode 100644
index 1c81e56db55..00000000000
--- a/db/post_migrate/20171215121205_post_populate_can_push_from_deploy_keys_projects.rb
+++ /dev/null
@@ -1,63 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class PostPopulateCanPushFromDeployKeysProjects < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
- DATABASE_NAME = Gitlab::Database.database_name
-
- disable_ddl_transaction!
-
- class DeploysKeyProject < ActiveRecord::Base
- include EachBatch
-
- self.table_name = 'deploy_keys_projects'
- end
-
- def up
- DeploysKeyProject.each_batch(of: 10_000) do |batch|
- start_id, end_id = batch.pluck('MIN(id), MAX(id)').first
-
- if Gitlab::Database.mysql?
- execute <<-EOF.strip_heredoc
- UPDATE deploy_keys_projects, #{DATABASE_NAME}.keys
- SET deploy_keys_projects.can_push = #{DATABASE_NAME}.keys.can_push
- WHERE deploy_keys_projects.deploy_key_id = #{DATABASE_NAME}.keys.id
- AND deploy_keys_projects.id BETWEEN #{start_id} AND #{end_id}
- EOF
- else
- execute <<-EOF.strip_heredoc
- UPDATE deploy_keys_projects
- SET can_push = keys.can_push
- FROM keys
- WHERE deploy_key_id = keys.id
- AND deploy_keys_projects.id BETWEEN #{start_id} AND #{end_id}
- EOF
- end
- end
- end
-
- def down
- DeploysKeyProject.each_batch(of: 10_000) do |batch|
- start_id, end_id = batch.pluck('MIN(id), MAX(id)').first
-
- if Gitlab::Database.mysql?
- execute <<-EOF.strip_heredoc
- UPDATE deploy_keys_projects, #{DATABASE_NAME}.keys
- SET #{DATABASE_NAME}.keys.can_push = deploy_keys_projects.can_push
- WHERE deploy_keys_projects.deploy_key_id = #{DATABASE_NAME}.keys.id
- AND deploy_keys_projects.id BETWEEN #{start_id} AND #{end_id}
- EOF
- else
- execute <<-EOF.strip_heredoc
- UPDATE keys
- SET can_push = deploy_keys_projects.can_push
- FROM deploy_keys_projects
- WHERE deploy_keys_projects.deploy_key_id = keys.id
- AND deploy_keys_projects.id BETWEEN #{start_id} AND #{end_id}
- EOF
- end
- end
- end
-end
diff --git a/db/post_migrate/20171215121259_remove_can_push_from_keys.rb b/db/post_migrate/20171215121259_remove_can_push_from_keys.rb
deleted file mode 100644
index fc4045a383d..00000000000
--- a/db/post_migrate/20171215121259_remove_can_push_from_keys.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class RemoveCanPushFromKeys < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
- disable_ddl_transaction!
-
- def up
- remove_column :keys, :can_push
- end
-
- def down
- add_column_with_default :keys, :can_push, :boolean, default: false, allow_null: false
- end
-end
diff --git a/db/post_migrate/20171219121201_normalize_extern_uid_from_identities.rb b/db/post_migrate/20171219121201_normalize_extern_uid_from_identities.rb
deleted file mode 100644
index 45ef75fdb98..00000000000
--- a/db/post_migrate/20171219121201_normalize_extern_uid_from_identities.rb
+++ /dev/null
@@ -1,29 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class NormalizeExternUidFromIdentities < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
- MIGRATION = 'NormalizeLdapExternUidsRange'.freeze
- DELAY_INTERVAL = 10.seconds
-
- disable_ddl_transaction!
-
- class Identity < ActiveRecord::Base
- include EachBatch
-
- self.table_name = 'identities'
- end
-
- def up
- ldap_identities = Identity.where("provider like 'ldap%'")
-
- if ldap_identities.any?
- queue_background_migration_jobs_by_range_at_intervals(Identity, MIGRATION, DELAY_INTERVAL)
- end
- end
-
- def down
- end
-end
diff --git a/db/post_migrate/20171221140220_schedule_issues_closed_at_type_change.rb b/db/post_migrate/20171221140220_schedule_issues_closed_at_type_change.rb
deleted file mode 100644
index 6b5e6202688..00000000000
--- a/db/post_migrate/20171221140220_schedule_issues_closed_at_type_change.rb
+++ /dev/null
@@ -1,45 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-# rubocop:disable Migration/Datetime
-class ScheduleIssuesClosedAtTypeChange < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- class Issue < ActiveRecord::Base
- self.table_name = 'issues'
- include EachBatch
-
- def self.to_migrate
- where('closed_at IS NOT NULL')
- end
- end
-
- def up
- return unless migrate_column_type?
-
- change_column_type_using_background_migration(
- Issue.to_migrate,
- :closed_at,
- :datetime_with_timezone
- )
- end
-
- def down
- return if migrate_column_type?
-
- change_column_type_using_background_migration(
- Issue.to_migrate,
- :closed_at,
- :datetime
- )
- end
-
- def migrate_column_type?
- # Some environments may have already executed the previous version of this
- # migration, thus we don't need to migrate those environments again.
- column_for('issues', 'closed_at').type == :datetime
- end
-end
diff --git a/db/post_migrate/20180202111106_remove_project_labels_group_id.rb b/db/post_migrate/20180202111106_remove_project_labels_group_id.rb
deleted file mode 100644
index 31ec84f0d6a..00000000000
--- a/db/post_migrate/20180202111106_remove_project_labels_group_id.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-# See http://doc.gitlab.com/ce/development/migration_style_guide.html
-# for more information on how to write migrations for GitLab.
-
-class RemoveProjectLabelsGroupId < ActiveRecord::Migration[4.2]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- update_column_in_batches(:labels, :group_id, nil) do |table, query|
- query.where(table[:type].eq('ProjectLabel').and(table[:group_id].not_eq(nil)))
- end
- end
-
- def down
- end
-end
diff --git a/db/schema.rb b/db/schema.rb
index 50fee850f9f..9a8b64689bd 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema.define(version: 20190627051902) do
+ActiveRecord::Schema.define(version: 20190703130053) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -193,6 +193,7 @@ ActiveRecord::Schema.define(version: 20190627051902) do
t.string "required_instance_ci_template"
t.boolean "dns_rebinding_protection_enabled", default: true, null: false
t.boolean "default_project_deletion_protection", default: false, null: false
+ t.boolean "grafana_enabled", default: false, null: false
t.boolean "lock_memberships_to_ldap", default: false, null: false
t.text "help_text"
t.boolean "elasticsearch_indexing", default: false, null: false
@@ -226,6 +227,7 @@ ActiveRecord::Schema.define(version: 20190627051902) do
t.boolean "elasticsearch_limit_indexing", default: false, null: false
t.string "geo_node_allowed_ips", default: "0.0.0.0/0, ::/0"
t.boolean "time_tracking_limit_to_hours", default: false, null: false
+ t.string "grafana_url", default: "/-/grafana", null: false
t.index ["custom_project_templates_group_id"], name: "index_application_settings_on_custom_project_templates_group_id", using: :btree
t.index ["file_template_project_id"], name: "index_application_settings_on_file_template_project_id", using: :btree
t.index ["usage_stats_set_by_user_id"], name: "index_application_settings_on_usage_stats_set_by_user_id", using: :btree
@@ -1047,6 +1049,7 @@ ActiveRecord::Schema.define(version: 20190627051902) do
t.datetime_with_timezone "created_at", null: false
t.string "name", null: false
t.string "token", null: false
+ t.string "username"
t.index ["token", "expires_at", "id"], name: "index_deploy_tokens_on_token_and_expires_at_and_id", where: "(revoked IS FALSE)", using: :btree
t.index ["token"], name: "index_deploy_tokens_on_token", unique: true, using: :btree
end
@@ -1986,6 +1989,7 @@ ActiveRecord::Schema.define(version: 20190627051902) do
t.boolean "allow_maintainer_to_push"
t.integer "state_id", limit: 2
t.integer "approvals_before_merge"
+ t.string "rebase_jid"
t.index ["assignee_id"], name: "index_merge_requests_on_assignee_id", using: :btree
t.index ["author_id"], name: "index_merge_requests_on_author_id", using: :btree
t.index ["created_at"], name: "index_merge_requests_on_created_at", using: :btree
@@ -2112,6 +2116,7 @@ ActiveRecord::Schema.define(version: 20190627051902) do
t.integer "extra_shared_runners_minutes_limit"
t.string "ldap_sync_status", default: "ready", null: false
t.boolean "membership_lock", default: false
+ t.integer "last_ci_minutes_usage_notification_level"
t.index ["created_at"], name: "index_namespaces_on_created_at", using: :btree
t.index ["custom_project_templates_group_id", "type"], name: "index_namespaces_on_custom_project_templates_group_id_and_type", where: "(custom_project_templates_group_id IS NOT NULL)", using: :btree
t.index ["file_template_project_id"], name: "index_namespaces_on_file_template_project_id", using: :btree
@@ -2263,6 +2268,7 @@ ActiveRecord::Schema.define(version: 20190627051902) do
t.datetime_with_timezone "updated_at", null: false
t.boolean "active", null: false
t.string "environment_scope", default: "*", null: false
+ t.jsonb "strategies", default: [{"name"=>"default", "parameters"=>{}}], null: false
t.index ["feature_flag_id", "environment_scope"], name: "index_feature_flag_scopes_on_flag_id_and_environment_scope", unique: true, using: :btree
end
@@ -2900,6 +2906,7 @@ ActiveRecord::Schema.define(version: 20190627051902) do
t.integer "author_id"
t.string "name"
t.string "sha"
+ t.datetime_with_timezone "released_at", null: false
t.index ["author_id"], name: "index_releases_on_author_id", using: :btree
t.index ["project_id", "tag"], name: "index_releases_on_project_id_and_tag", using: :btree
t.index ["project_id"], name: "index_releases_on_project_id", using: :btree
@@ -3028,6 +3035,7 @@ ActiveRecord::Schema.define(version: 20190627051902) do
t.boolean "job_events", default: false, null: false
t.boolean "confidential_note_events", default: true
t.boolean "deployment_events", default: false, null: false
+ t.string "description", limit: 500
t.index ["project_id"], name: "index_services_on_project_id", using: :btree
t.index ["template"], name: "index_services_on_template", using: :btree
t.index ["type"], name: "index_services_on_type", using: :btree
diff --git a/doc/README.md b/doc/README.md
index 489c8117b9d..25db0efb960 100644
--- a/doc/README.md
+++ b/doc/README.md
@@ -86,7 +86,7 @@ The following documentation relates to the DevOps **Manage** stage:
| Manage Topics | Description |
|:--------------------------------------------------------------------------------------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| [Authentication and<br/>Authorization](administration/auth/README.md) **[CORE ONLY]** | Supported authentication and authorization providers. |
+| [Authentication and<br/>Authorization](administration/auth/README.md) **(CORE ONLY)** | Supported authentication and authorization providers. |
| [GitLab Cycle Analytics](user/project/cycle_analytics.md) | Measure the time it takes to go from an [idea to production](https://about.gitlab.com/2016/08/05/continuous-integration-delivery-and-deployment-with-gitlab/#from-idea-to-production-with-gitlab) for each project you have. |
| [Instance Statistics](user/instance_statistics/index.md) | Discover statistics on how many GitLab features you use and user activity. |
@@ -107,18 +107,18 @@ The following documentation relates to the DevOps **Plan** stage:
| Plan Topics | Description |
|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:-------------------------------------------------------------------------------------------------------------------------------------------------|
-| [Burndown Charts](user/project/milestones/burndown_charts.md) **[STARTER]** | Watch your project's progress throughout a specific milestone. |
+| [Burndown Charts](user/project/milestones/burndown_charts.md) **(STARTER)** | Watch your project's progress throughout a specific milestone. |
| [Discussions](user/discussions/index.md) | Threads, comments, and resolvable discussions in issues, commits, and merge requests. |
| [Due Dates](user/project/issues/due_dates.md) | Keep track of issue deadlines. |
-| [Epics](user/group/epics/index.md) **[ULTIMATE]** | Tracking groups of issues that share a theme. |
-| [Issues](user/project/issues/index.md), including [confidential issues](user/project/issues/confidential_issues.md),<br/>[issue and merge request templates](user/project/description_templates.md),<br/>and [moving issues](user/project/issues/moving_issues.md) | Project issues, restricting access to issues, create templates for submitting new issues and merge requests, and moving issues between projects. |
+| [Epics](user/group/epics/index.md) **(ULTIMATE)** | Tracking groups of issues that share a theme. |
+| [Issues](user/project/issues/index.md), including [confidential issues](user/project/issues/confidential_issues.md),<br/>[issue and merge request templates](user/project/description_templates.md),<br/>and [moving issues](user/project/issues/managing_issues.md#moving-issues) | Project issues, restricting access to issues, create templates for submitting new issues and merge requests, and moving issues between projects. |
| [Labels](user/project/labels.md) | Categorize issues or merge requests with descriptive labels. |
| [Milestones](user/project/milestones/index.md) | Set milestones for delivery of issues and merge requests, with optional due date. |
| [Project Issue Board](user/project/issue_board.md) | Display issues on a Scrum or Kanban board. |
| [Quick Actions](user/project/quick_actions.md) | Shortcuts for common actions on issues or merge requests, replacing the need to click buttons or use dropdowns in GitLab's UI. |
-| [Related Issues](user/project/issues/related_issues.md) **[STARTER]** | Create a relationship between issues. |
-| [Roadmap](user/group/roadmap/index.md) **[ULTIMATE]** | Visualize epic timelines. |
-| [Service Desk](user/project/service_desk.md) **[PREMIUM]** | A simple way to allow people to create issues in your GitLab instance without needing their own user account. |
+| [Related Issues](user/project/issues/related_issues.md) **(STARTER)** | Create a relationship between issues. |
+| [Roadmap](user/group/roadmap/index.md) **(ULTIMATE)** | Visualize epic timelines. |
+| [Service Desk](user/project/service_desk.md) **(PREMIUM)** | A simple way to allow people to create issues in your GitLab instance without needing their own user account. |
| [Time Tracking](workflow/time_tracking.md) | Track time spent on issues and merge requests. |
| [Todos](workflow/todos.md) | Keep track of work requiring attention with a chronological list displayed on a simple dashboard. |
@@ -143,14 +143,14 @@ The following documentation relates to the DevOps **Create** stage:
| Create Topics - Projects and Groups | Description |
|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:-------------------------------------------------------------------------------------------------|
-| [Advanced global search](user/search/advanced_global_search.md) **[STARTER]** | Leverage Elasticsearch for faster, more advanced code search across your entire GitLab instance. |
-| [Advanced syntax search](user/search/advanced_search_syntax.md) **[STARTER]** | Use advanced queries for more targeted search results. |
-| [Contribution analytics](user/group/contribution_analytics/index.md) **[STARTER]** | See detailed statistics of group contributors. |
+| [Advanced global search](user/search/advanced_global_search.md) **(STARTER)** | Leverage Elasticsearch for faster, more advanced code search across your entire GitLab instance. |
+| [Advanced syntax search](user/search/advanced_search_syntax.md) **(STARTER)** | Use advanced queries for more targeted search results. |
+| [Contribution analytics](user/group/contribution_analytics/index.md) **(STARTER)** | See detailed statistics of group contributors. |
| [Create](gitlab-basics/create-project.md) and [fork](gitlab-basics/fork-project.md) projects, and<br/>[import and export projects<br/>between instances](user/project/settings/import_export.md) | Create, duplicate, and move projects. |
-| [File locking](user/project/file_lock.md) **[PREMIUM]** | Lock files to avoid merge conflicts. |
+| [File locking](user/project/file_lock.md) **(PREMIUM)** | Lock files to avoid merge conflicts. |
| [GitLab Pages](user/project/pages/index.md) | Build, test, and deploy your static website with GitLab Pages. |
| [Groups](user/group/index.md) and [Subgroups](user/group/subgroups/index.md) | Organize your projects in groups. |
-| [Issues Analytics](user/group/issues_analytics/index.md) **[PREMIUM]** | Check how many issues were created per month. |
+| [Issues Analytics](user/group/issues_analytics/index.md) **(PREMIUM)** | Check how many issues were created per month. |
| [Projects](user/project/index.md), including [project access](public_access/public_access.md)<br/>and [settings](user/project/settings/index.md) | Host source code, and control your project's visibility and set configuration. |
| [Search through GitLab](user/search/index.md) | Search for issues, merge requests, projects, groups, and todos. |
| [Snippets](user/snippets.md) | Snippets allow you to create little bits of code. |
@@ -175,9 +175,9 @@ The following documentation relates to the DevOps **Create** stage:
| [Files](user/project/repository/index.md#files) | Files management. |
| [Jupyter Notebook files](user/project/repository/index.md#jupyter-notebook-files) | GitLab's support for `.ipynb` files. |
| [Protected branches](user/project/protected_branches.md) | Use protected branches. |
-| [Push rules](push_rules/push_rules.md) **[STARTER]** | Additional control over pushes to your projects. |
+| [Push rules](push_rules/push_rules.md) **(STARTER)** | Additional control over pushes to your projects. |
| [Repositories](user/project/repository/index.md) | Manage source code repositories in GitLab's user interface. |
-| [Repository mirroring](workflow/repository_mirroring.md) **[STARTER]** | Push to or pull from repositories outside of GitLab |
+| [Repository mirroring](workflow/repository_mirroring.md) **(STARTER)** | Push to or pull from repositories outside of GitLab |
| [Start a merge request](user/project/repository/web_editor.md#tips) | Start merge request when committing via GitLab's user interface. |
<div align="right">
@@ -209,7 +209,7 @@ The following documentation relates to the DevOps **Create** stage:
| [GitLab API](api/README.md) | Integrate GitLab via a simple and powerful API. |
| [GitLab Integration](integration/README.md) | Integrate with multiple third-party services with GitLab to allow external issue trackers and external authentication. |
| [GitLab Webhooks](user/project/integrations/webhooks.md) | Let GitLab notify you when new code has been pushed to your project. |
-| [Jira Development Panel](integration/jira_development_panel.md) **[PREMIUM]** | See GitLab information in the Jira Development Panel. |
+| [Jira Development Panel](integration/jira_development_panel.md) **(PREMIUM)** | See GitLab information in the Jira Development Panel. |
| [Project Services](user/project/integrations/project_services.md) | Integrate a project with external services, such as CI and chat. |
| [Trello Power-Up](integration/trello_power_up.md) | Integrate with GitLab's Trello Power-Up. |
@@ -233,10 +233,10 @@ The following documentation relates to the DevOps **Verify** stage:
| Verify Topics | Description |
|:----------------------------------------------------------------------------------|:--------------------------------------------------------------------------------------------------------|
-| [Code Quality reports](user/project/merge_requests/code_quality.md) **[STARTER]** | Analyze source code quality. |
+| [Code Quality reports](user/project/merge_requests/code_quality.md) **(STARTER)** | Analyze source code quality. |
| [GitLab CI/CD](ci/README.md) | Explore the features and capabilities of Continuous Integration with GitLab. |
| [JUnit test reports](ci/junit_test_reports.md) | Display JUnit test reports on merge requests. |
-| [Multi-project pipelines](ci/multi_project_pipelines.md) **[PREMIUM]** | Visualize entire pipelines that span multiple projects, including all cross-project inter-dependencies. |
+| [Multi-project pipelines](ci/multi_project_pipelines.md) **(PREMIUM)** | Visualize entire pipelines that span multiple projects, including all cross-project inter-dependencies. |
| [Pipeline Graphs](ci/pipelines.md#visualizing-pipelines) | Visualize builds. |
| [Review Apps](ci/review_apps/index.md) | Preview changes to your application right from a merge request. |
@@ -257,7 +257,7 @@ The following documentation relates to the DevOps **Package** stage:
| Package Topics | Description |
|:----------------------------------------------------------------|:-------------------------------------------------------|
| [GitLab Container Registry](user/project/container_registry.md) | Learn how to use GitLab's built-in Container Registry. |
-| [GitLab Packages](administration/packages.md) **[PREMIUM]** | Use GitLab as an NPM registry or Maven repository. |
+| [GitLab Packages](administration/packages.md) **(PREMIUM)** | Use GitLab as an NPM registry or Maven repository. |
<div align="right">
<a type="button" class="btn btn-default" href="#overview">
@@ -276,10 +276,10 @@ The following documentation relates to the DevOps **Release** stage:
| Release Topics | Description |
|:------------------------------------------------------------------------------------------------------------------------------------|:--------------------------------------------------------------------------------------------------------------------------------------|
| [Auto Deploy](topics/autodevops/index.md#auto-deploy) | Configure GitLab for the deployment of your application. |
-| [Canary Deployments](user/project/canary_deployments.md) **[PREMIUM]** | Employ a popular CI strategy where a small portion of the fleet is updated to the new version first. |
-| [Deploy Boards](user/project/deploy_boards.md) **[PREMIUM]** | View the current health and status of each CI environment running on Kubernetes, displaying the status of the pods in the deployment. |
+| [Canary Deployments](user/project/canary_deployments.md) **(PREMIUM)** | Employ a popular CI strategy where a small portion of the fleet is updated to the new version first. |
+| [Deploy Boards](user/project/deploy_boards.md) **(PREMIUM)** | View the current health and status of each CI environment running on Kubernetes, displaying the status of the pods in the deployment. |
| [Environments and deployments](ci/environments.md) | With environments, you can control the continuous deployment of your software within GitLab. |
-| [Environment-specific variables](ci/variables/README.md#limiting-environment-scopes-of-environment-variables-premium) **[PREMIUM]** | Limit scope of variables to specific environments. |
+| [Environment-specific variables](ci/variables/README.md#limiting-environment-scopes-of-environment-variables-premium) **(PREMIUM)** | Limit scope of variables to specific environments. |
| [GitLab CI/CD](ci/README.md) | Explore the features and capabilities of Continuous Deployment and Delivery with GitLab. |
| [GitLab Pages](user/project/pages/index.md) | Build, test, and deploy a static site directly from GitLab. |
| [Protected Runners](ci/runners/README.md#protected-runners) | Select Runners to only pick jobs for protected branches and tags. |
@@ -307,7 +307,7 @@ The following documentation relates to the DevOps **Configure** stage:
| [GitLab ChatOps](ci/chatops/README.md) | Interact with CI/CD jobs through chat services. |
| [Installing Applications](user/project/clusters/index.md#installing-applications) | Deploy Helm, Ingress, and Prometheus on Kubernetes. |
| [Mattermost slash commands](user/project/integrations/mattermost_slash_commands.md) | Enable and use slash commands from within Mattermost. |
-| [Multiple Kubernetes Clusters](user/project/clusters/index.md#multiple-kubernetes-clusters-premium) **[PREMIUM]** | Associate more than one Kubernetes clusters to your project. |
+| [Multiple Kubernetes Clusters](user/project/clusters/index.md#multiple-kubernetes-clusters-premium) **(PREMIUM)** | Associate more than one Kubernetes clusters to your project. |
| [Protected variables](ci/variables/README.md#protected-environment-variables) | Restrict variables to protected branches and tags. |
| [Serverless](user/project/clusters/serverless/index.md) | Run serverless workloads on Kubernetes. |
| [Slack slash commands](user/project/integrations/slack_slash_commands.md) | Enable and use slash commands from within Slack. |
@@ -329,8 +329,8 @@ The following documentation relates to the DevOps **Monitor** stage:
| Monitor Topics | Description |
|:------------------------------------------------------------------------------------------------|:-----------------------------------------------------------------------------------------------------------------------------------------|
-| [GitLab Performance Monitoring](administration/monitoring/performance/index.md) **[CORE ONLY]** | Use InfluxDB and Grafana to monitor the performance of your GitLab instance (will be eventually replaced by Prometheus). |
-| [GitLab Prometheus](administration/monitoring/prometheus/index.md) **[CORE ONLY]** | Configure the bundled Prometheus to collect various metrics from your GitLab instance. |
+| [GitLab Performance Monitoring](administration/monitoring/performance/index.md) **(CORE ONLY)** | Use InfluxDB and Grafana to monitor the performance of your GitLab instance (will be eventually replaced by Prometheus). |
+| [GitLab Prometheus](administration/monitoring/prometheus/index.md) **(CORE ONLY)** | Configure the bundled Prometheus to collect various metrics from your GitLab instance. |
| [Health check](user/admin_area/monitoring/health_check.md) | GitLab provides liveness and readiness probes to indicate service health and reachability to required services. |
| [Prometheus project integration](user/project/integrations/prometheus.md) | Configure the Prometheus integration per project and monitor your CI/CD environments. |
| [Prometheus metrics](user/project/integrations/prometheus_library/index.md) | Let Prometheus collect metrics from various services, like Kubernetes, NGINX, NGINX ingress controller, HAProxy, and Amazon Cloud Watch. |
@@ -353,13 +353,13 @@ The following documentation relates to the DevOps **Secure** stage:
| Secure Topics | Description |
|:------------------------------------------------------------------------------------------------------|:-----------------------------------------------------------------------|
-| [Container Scanning](user/application_security/container_scanning/index.md) **[ULTIMATE]** | Use Clair to scan docker images for known vulnerabilities. |
-| [Dependency Scanning](user/application_security/dependency_scanning/index.md) **[ULTIMATE]** | Analyze your dependencies for known vulnerabilities. |
-| [Dynamic Application Security Testing (DAST)](user/application_security/dast/index.md) **[ULTIMATE]** | Analyze running web applications for known vulnerabilities. |
-| [Group Security Dashboard](user/application_security/security_dashboard/index.md) **[ULTIMATE]** | View vulnerabilities in all the projects in a group and its subgroups. |
-| [License Management](user/application_security/license_management/index.md) **[ULTIMATE]** | Search your project's dependencies for their licenses. |
-| [Project Security Dashboard](user/application_security/security_dashboard/index.md) **[ULTIMATE]** | View the latest security reports for your project. |
-| [Static Application Security Testing (SAST)](user/application_security/sast/index.md) **[ULTIMATE]** | Analyze source code for known vulnerabilities. |
+| [Container Scanning](user/application_security/container_scanning/index.md) **(ULTIMATE)** | Use Clair to scan docker images for known vulnerabilities. |
+| [Dependency Scanning](user/application_security/dependency_scanning/index.md) **(ULTIMATE)** | Analyze your dependencies for known vulnerabilities. |
+| [Dynamic Application Security Testing (DAST)](user/application_security/dast/index.md) **(ULTIMATE)** | Analyze running web applications for known vulnerabilities. |
+| [Group Security Dashboard](user/application_security/security_dashboard/index.md) **(ULTIMATE)** | View vulnerabilities in all the projects in a group and its subgroups. |
+| [License Management](user/application_security/license_management/index.md) **(ULTIMATE)** | Search your project's dependencies for their licenses. |
+| [Project Security Dashboard](user/application_security/security_dashboard/index.md) **(ULTIMATE)** | View the latest security reports for your project. |
+| [Static Application Security Testing (SAST)](user/application_security/sast/index.md) **(ULTIMATE)** | Analyze source code for known vulnerabilities. |
## Subscribe to GitLab
diff --git a/doc/administration/audit_events.md b/doc/administration/audit_events.md
index d7a2e13b53e..a80ff330e03 100644
--- a/doc/administration/audit_events.md
+++ b/doc/administration/audit_events.md
@@ -2,7 +2,7 @@
last_updated: 2019-02-04
---
-# Audit Events **[STARTER]**
+# Audit Events **(STARTER)**
GitLab offers a way to view the changes made within the GitLab server for owners and administrators on a [paid plan][ee].
@@ -32,7 +32,7 @@ There are two kinds of events logged:
- Instance events scoped to the whole GitLab instance, used by your Compliance team to
perform formal audits.
-### Group events **[STARTER]**
+### Group events **(STARTER)**
NOTE: **Note:**
You need Owner [permissions] to view the group Audit Events page.
@@ -59,7 +59,7 @@ From there, you can see the following actions:
- 2FA enforcement/grace period changed
- Roles allowed to create project changed
-### Project events **[STARTER]**
+### Project events **(STARTER)**
NOTE: **Note:**
You need Maintainer [permissions] or higher to view the project Audit Events page.
@@ -74,7 +74,7 @@ From there, you can see the following actions:
- Permission changes of a user assigned to a project
- User was removed from project
-### Instance events **[PREMIUM ONLY]**
+### Instance events **(PREMIUM ONLY)**
> [Introduced][ee-2336] in [GitLab Premium][ee] 9.3.
@@ -99,7 +99,7 @@ It is possible to filter particular actions by choosing an audit data type from
the filter drop-down. You can further filter by specific group, project or user
(for authentication events).
-![audit log](audit_log.png)
+![audit log](img/audit_log.png)
### Missing events
diff --git a/doc/administration/auditor_users.md b/doc/administration/auditor_users.md
index ef8c8197d6d..65d36612d85 100644
--- a/doc/administration/auditor_users.md
+++ b/doc/administration/auditor_users.md
@@ -1,4 +1,4 @@
-# Auditor users **[PREMIUM ONLY]**
+# Auditor users **(PREMIUM ONLY)**
>[Introduced][ee-998] in [GitLab Premium][eep] 8.17.
@@ -52,7 +52,7 @@ section.
**Admin Area > Users**. You will find the option of the access level under
the 'Access' section.
- ![Admin Area Form](auditor_access_form.png)
+ ![Admin Area Form](img/auditor_access_form.png)
1. Click **Save changes** or **Create user** for the changes to take effect.
diff --git a/doc/administration/auth/README.md b/doc/administration/auth/README.md
index e215a0df6ec..d8094587d14 100644
--- a/doc/administration/auth/README.md
+++ b/doc/administration/auth/README.md
@@ -9,11 +9,11 @@ providers.
- [LDAP](ldap.md) Includes Active Directory, Apple Open Directory, Open LDAP,
and 389 Server
- - [LDAP for GitLab EE](ldap-ee.md): LDAP additions to GitLab Enterprise Editions **[STARTER ONLY]**
+ - [LDAP for GitLab EE](ldap-ee.md): LDAP additions to GitLab Enterprise Editions **(STARTER ONLY)**
- [OmniAuth](../../integration/omniauth.md) Sign in via Twitter, GitHub, GitLab.com, Google,
Bitbucket, Facebook, Shibboleth, Crowd, Azure, Authentiq ID, and JWT
- [CAS](../../integration/cas.md) Configure GitLab to sign in using CAS
- [SAML](../../integration/saml.md) Configure GitLab as a SAML 2.0 Service Provider
- [Okta](okta.md) Configure GitLab to sign in using Okta
- [Authentiq](authentiq.md): Enable the Authentiq OmniAuth provider for passwordless authentication
-- [Smartcard](smartcard.md) Smartcard authentication **[PREMIUM ONLY]**
+- [Smartcard](smartcard.md) Smartcard authentication **(PREMIUM ONLY)**
diff --git a/doc/administration/auth/google_secure_ldap.md b/doc/administration/auth/google_secure_ldap.md
index 760af0cfd1a..1db5bb4bc3f 100644
--- a/doc/administration/auth/google_secure_ldap.md
+++ b/doc/administration/auth/google_secure_ldap.md
@@ -1,4 +1,4 @@
-# Google Secure LDAP **[CORE ONLY]**
+# Google Secure LDAP **(CORE ONLY)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/46391) in GitLab 11.9.
@@ -13,7 +13,7 @@ The steps below cover:
## Configuring Google LDAP client
-1. Navigate to https://admin.google.com and sign in as a GSuite domain administrator.
+1. Navigate to <https://admin.google.com/Dashboard> and sign in as a GSuite domain administrator.
1. Go to **Apps > LDAP > Add Client**.
@@ -202,6 +202,5 @@ values obtained during the LDAP client configuration earlier:
1. Save the file and [restart] GitLab for the changes to take effect.
-
[reconfigure]: ../restart_gitlab.md#omnibus-gitlab-reconfigure
[restart]: ../restart_gitlab.md#installations-from-source
diff --git a/doc/administration/auth/how_to_configure_ldap_gitlab_ce/index.md b/doc/administration/auth/how_to_configure_ldap_gitlab_ce/index.md
index 1f67e8f5744..320a65b665d 100644
--- a/doc/administration/auth/how_to_configure_ldap_gitlab_ce/index.md
+++ b/doc/administration/auth/how_to_configure_ldap_gitlab_ce/index.md
@@ -111,7 +111,7 @@ The initial configuration of LDAP in GitLab requires changes to the `gitlab.rb`
The two Active Directory specific values are `active_directory: true` and `uid: 'sAMAccountName'`. `sAMAccountName` is an attribute returned by Active Directory used for GitLab usernames. See the example output from `ldapsearch` for a full list of attributes a "person" object (user) has in **AD** - [`ldapsearch` example](#using-ldapsearch-unix)
-> Both group_base and admin_group configuration options are only available in GitLab Enterprise Edition. See [GitLab EE - LDAP Features](../how_to_configure_ldap_gitlab_ee/index.html#gitlab-enterprise-edition---ldap-features) **[STARTER ONLY]**
+> Both group_base and admin_group configuration options are only available in GitLab Enterprise Edition. See [GitLab EE - LDAP Features](../how_to_configure_ldap_gitlab_ee/index.html#gitlab-enterprise-edition---ldap-features) **(STARTER ONLY)**
### Example `gitlab.rb` LDAP
@@ -267,4 +267,4 @@ have extended functionalities with LDAP, such as:
- Updating user permissions
- Multiple LDAP servers
-Read through the article on [LDAP for GitLab EE](../how_to_configure_ldap_gitlab_ee/index.md) **[STARTER ONLY]** for an overview.
+Read through the article on [LDAP for GitLab EE](../how_to_configure_ldap_gitlab_ee/index.md) **(STARTER ONLY)** for an overview.
diff --git a/doc/administration/auth/how_to_configure_ldap_gitlab_ee/index.md b/doc/administration/auth/how_to_configure_ldap_gitlab_ee/index.md
index 4d82a7370bb..2683950f143 100644
--- a/doc/administration/auth/how_to_configure_ldap_gitlab_ee/index.md
+++ b/doc/administration/auth/how_to_configure_ldap_gitlab_ee/index.md
@@ -6,7 +6,7 @@ article_type: admin guide
date: 2017-05-03
---
-# How to configure LDAP with GitLab EE **[STARTER ONLY]**
+# How to configure LDAP with GitLab EE **(STARTER ONLY)**
## Introduction
diff --git a/doc/administration/auth/ldap-ee.md b/doc/administration/auth/ldap-ee.md
index 15f093bb62d..1a8af0827ee 100644
--- a/doc/administration/auth/ldap-ee.md
+++ b/doc/administration/auth/ldap-ee.md
@@ -1,4 +1,4 @@
-# LDAP Additions in GitLab EE **[STARTER ONLY]**
+# LDAP Additions in GitLab EE **(STARTER ONLY)**
This is a continuation of the main [LDAP documentation](ldap.md), detailing LDAP
features specific to GitLab Enterprise Edition Starter, Premium and Ultimate.
@@ -185,7 +185,7 @@ group, as opposed to the full DN.
## Global group memberships lock
-"Lock memberships to LDAP synchronization" setting allows instance administrators
+"Lock memberships to LDAP synchronization" setting allows instance administrators
to lock down user abilities to invite new members to a group. When enabled following happens:
1. Only administrator can manage memberships of any group including access levels.
@@ -198,14 +198,14 @@ to lock down user abilities to invite new members to a group. When enabled follo
NOTE: **Note:**
These are cron formatted values. You can use a crontab generator to create
-these values, for example http://www.crontabgenerator.com/.
+these values, for example <http://www.crontabgenerator.com/>.
By default, GitLab will run a worker once per day at 01:30 a.m. server time to
check and update GitLab users against LDAP.
You can manually configure LDAP user sync times by setting the
following configuration values. The example below shows how to set LDAP user
-sync to run once every 12 hours at the top of the hour.
+sync to run once every 12 hours at the top of the hour.
**Omnibus installations**
@@ -233,7 +233,7 @@ sync to run once every 12 hours at the top of the hour.
NOTE: **Note:**
These are cron formatted values. You can use a crontab generator to create
-these values, for example http://www.crontabgenerator.com/.
+these values, for example <http://www.crontabgenerator.com/>.
By default, GitLab will run a group sync process every hour, on the hour.
@@ -245,8 +245,8 @@ for installations with a large number of LDAP users. Please review the
your installation compares before proceeding.
You can manually configure LDAP group sync times by setting the
-following configuration values. The example below shows how to set group
-sync to run once every 2 hours at the top of the hour.
+following configuration values. The example below shows how to set group
+sync to run once every 2 hours at the top of the hour.
**Omnibus installations**
diff --git a/doc/administration/auth/ldap.md b/doc/administration/auth/ldap.md
index 1f2961ea39a..2144f5753a8 100644
--- a/doc/administration/auth/ldap.md
+++ b/doc/administration/auth/ldap.md
@@ -1,6 +1,4 @@
-[//]: # (Do *NOT* modify this file in EE documentation. All changes in this)
-[//]: # (file should happen in CE, too. If the change is EE-specific, put)
-[//]: # (it in `ldap-ee.md`.)
+<!-- If the change is EE-specific, put it in `ldap-ee.md`, NOT here. -->
# LDAP
@@ -14,7 +12,7 @@ including group membership syncing as well as multiple LDAP servers support.
The information on this page is relevant for both GitLab CE and EE. For more
details about EE-specific LDAP features, see the
-[LDAP Enterprise Edition documentation](ldap-ee.md). **[STARTER ONLY]**
+[LDAP Enterprise Edition documentation](ldap-ee.md). **(STARTER ONLY)**
## Security
@@ -48,7 +46,7 @@ LDAP-enabled users can always authenticate with Git using their GitLab username
or email and LDAP password, even if password authentication for Git is disabled
in the application settings.
-## Google Secure LDAP **[CORE ONLY]**
+## Google Secure LDAP **(CORE ONLY)**
> Introduced in GitLab 11.9.
@@ -64,7 +62,7 @@ to connect to one GitLab server.
For a complete guide on configuring LDAP with GitLab Community Edition, please check
the admin guide [How to configure LDAP with GitLab CE](how_to_configure_ldap_gitlab_ce/index.md).
-For GitLab Enterprise Editions, see also [How to configure LDAP with GitLab EE](how_to_configure_ldap_gitlab_ee/index.md). **[STARTER ONLY]**
+For GitLab Enterprise Editions, see also [How to configure LDAP with GitLab EE](how_to_configure_ldap_gitlab_ee/index.md). **(STARTER ONLY)**
To enable LDAP integration you need to add your LDAP server settings in
`/etc/gitlab/gitlab.rb` or `/home/git/gitlab/config/gitlab.yml` for Omnibus
@@ -389,7 +387,7 @@ group, you can use the following syntax:
Find more information about this "LDAP_MATCHING_RULE_IN_CHAIN" filter at
<https://docs.microsoft.com/en-us/windows/desktop/ADSI/search-filter-syntax>. Support for
nested members in the user filter should not be confused with
-[group sync nested groups support](ldap-ee.md#supported-ldap-group-typesattributes). **[STARTER ONLY]**
+[group sync nested groups support](ldap-ee.md#supported-ldap-group-typesattributes). **(STARTER ONLY)**
Please note that GitLab does not support the custom filter syntax used by
omniauth-ldap.
diff --git a/doc/administration/auth/smartcard.md b/doc/administration/auth/smartcard.md
index b33c5359b44..a0d4e9ef3b5 100644
--- a/doc/administration/auth/smartcard.md
+++ b/doc/administration/auth/smartcard.md
@@ -1,4 +1,4 @@
-# Smartcard authentication **[PREMIUM ONLY]**
+# Smartcard authentication **(PREMIUM ONLY)**
GitLab supports authentication using smartcards.
@@ -184,3 +184,31 @@ attribute. As a prerequisite, you must use an LDAP server that:
1. Save the file and [restart](../restart_gitlab.md#installations-from-source)
GitLab for the changes to take effect.
+
+### Require browser session with smartcard sign-in for Git access
+
+**For Omnibus installations**
+
+1. Edit `/etc/gitlab/gitlab.rb`:
+
+ ```ruby
+ gitlab_rails['smartcard_required_for_git_access'] = true
+ ```
+
+1. Save the file and [reconfigure](../restart_gitlab.md#omnibus-gitlab-reconfigure)
+ GitLab for the changes to take effect.
+
+**For installations from source**
+
+1. Edit `config/gitlab.yml`:
+
+ ```yaml
+ ## Smartcard authentication settings
+ smartcard:
+ # snip...
+ # Browser session with smartcard sign-in is required for Git access
+ required_for_git_access: true
+ ```
+
+1. Save the file and [restart](../restart_gitlab.md#installations-from-source)
+ GitLab for the changes to take effect.
diff --git a/doc/administration/container_registry.md b/doc/administration/container_registry.md
index 4d55f2357c1..04f52783d22 100644
--- a/doc/administration/container_registry.md
+++ b/doc/administration/container_registry.md
@@ -1,7 +1,5 @@
# GitLab Container Registry administration
-> **Notes:**
->
> - [Introduced][ce-4040] in GitLab 8.8.
> - Container Registry manifest `v1` support was added in GitLab 8.9 to support
> Docker versions earlier than 1.10.
@@ -125,21 +123,21 @@ otherwise you will run into conflicts.
1. Your `/etc/gitlab/gitlab.rb` should contain the Registry URL as well as the
path to the existing TLS certificate and key used by GitLab:
- ```ruby
- registry_external_url 'https://gitlab.example.com:4567'
- ```
+ ```ruby
+ registry_external_url 'https://gitlab.example.com:4567'
+ ```
- Note how the `registry_external_url` is listening on HTTPS under the
- existing GitLab URL, but on a different port.
+ Note how the `registry_external_url` is listening on HTTPS under the
+ existing GitLab URL, but on a different port.
- If your TLS certificate is not in `/etc/gitlab/ssl/gitlab.example.com.crt`
- and key not in `/etc/gitlab/ssl/gitlab.example.com.key` uncomment the lines
- below:
+ If your TLS certificate is not in `/etc/gitlab/ssl/gitlab.example.com.crt`
+ and key not in `/etc/gitlab/ssl/gitlab.example.com.key` uncomment the lines
+ below:
- ```ruby
- registry_nginx['ssl_certificate'] = "/path/to/certificate.pem"
- registry_nginx['ssl_certificate_key'] = "/path/to/certificate.key"
- ```
+ ```ruby
+ registry_nginx['ssl_certificate'] = "/path/to/certificate.pem"
+ registry_nginx['ssl_certificate_key'] = "/path/to/certificate.key"
+ ```
1. Save the file and [reconfigure GitLab][] for the changes to take effect.
@@ -150,12 +148,12 @@ otherwise you will run into conflicts.
1. Open `/home/git/gitlab/config/gitlab.yml`, find the `registry` entry and
configure it with the following settings:
- ```
- registry:
- enabled: true
- host: gitlab.example.com
- port: 4567
- ```
+ ```
+ registry:
+ enabled: true
+ host: gitlab.example.com
+ port: 4567
+ ```
1. Save the file and [restart GitLab][] for the changes to take effect.
1. Make the relevant changes in NGINX as well (domain, port, TLS certificates path).
@@ -188,17 +186,17 @@ Let's assume that you want the container Registry to be accessible at
`/etc/gitlab/ssl/registry.gitlab.example.com.key` and make sure they have
correct permissions:
- ```bash
- chmod 600 /etc/gitlab/ssl/registry.gitlab.example.com.*
- ```
+ ```bash
+ chmod 600 /etc/gitlab/ssl/registry.gitlab.example.com.*
+ ```
1. Once the TLS certificate is in place, edit `/etc/gitlab/gitlab.rb` with:
- ```ruby
- registry_external_url 'https://registry.gitlab.example.com'
- ```
+ ```ruby
+ registry_external_url 'https://registry.gitlab.example.com'
+ ```
- Note how the `registry_external_url` is listening on HTTPS.
+ Note how the `registry_external_url` is listening on HTTPS.
1. Save the file and [reconfigure GitLab][] for the changes to take effect.
@@ -219,11 +217,11 @@ look like:
1. Open `/home/git/gitlab/config/gitlab.yml`, find the `registry` entry and
configure it with the following settings:
- ```
- registry:
- enabled: true
- host: registry.gitlab.example.com
- ```
+ ```yaml
+ registry:
+ enabled: true
+ host: registry.gitlab.example.com
+ ```
1. Save the file and [restart GitLab][] for the changes to take effect.
1. Make the relevant changes in NGINX as well (domain, port, TLS certificates path).
@@ -248,9 +246,9 @@ Registry application itself.
1. Open `/etc/gitlab/gitlab.rb` and set `registry['enable']` to `false`:
- ```ruby
- registry['enable'] = false
- ```
+ ```ruby
+ registry['enable'] = false
+ ```
1. Save the file and [reconfigure GitLab][] for the changes to take effect.
@@ -261,10 +259,10 @@ Registry application itself.
1. Open `/home/git/gitlab/config/gitlab.yml`, find the `registry` entry and
set `enabled` to `false`:
- ```
- registry:
- enabled: false
- ```
+ ```yaml
+ registry:
+ enabled: false
+ ```
1. Save the file and [restart GitLab][] for the changes to take effect.
@@ -280,9 +278,9 @@ the Container Registry by themselves, follow the steps below.
1. Edit `/etc/gitlab/gitlab.rb` and add the following line:
- ```ruby
- gitlab_rails['gitlab_default_projects_features_container_registry'] = false
- ```
+ ```ruby
+ gitlab_rails['gitlab_default_projects_features_container_registry'] = false
+ ```
1. Save the file and [reconfigure GitLab][] for the changes to take effect.
@@ -293,16 +291,16 @@ the Container Registry by themselves, follow the steps below.
1. Open `/home/git/gitlab/config/gitlab.yml`, find the `default_projects_features`
entry and configure it so that `container_registry` is set to `false`:
- ```
- ## Default project features settings
- default_projects_features:
- issues: true
- merge_requests: true
- wiki: true
- snippets: false
- builds: true
- container_registry: false
- ```
+ ```yaml
+ ## Default project features settings
+ default_projects_features:
+ issues: true
+ merge_requests: true
+ wiki: true
+ snippets: false
+ builds: true
+ container_registry: false
+ ```
1. Save the file and [restart GitLab][] for the changes to take effect.
@@ -332,9 +330,9 @@ The default location where images are stored in Omnibus, is
1. Edit `/etc/gitlab/gitlab.rb`:
- ```ruby
- gitlab_rails['registry_path'] = "/path/to/registry/storage"
- ```
+ ```ruby
+ gitlab_rails['registry_path'] = "/path/to/registry/storage"
+ ```
1. Save the file and [reconfigure GitLab][] for the changes to take effect.
@@ -348,10 +346,10 @@ The default location where images are stored in source installations, is
1. Open `/home/git/gitlab/config/gitlab.yml`, find the `registry` entry and
change the `path` setting:
- ```
- registry:
- path: shared/registry
- ```
+ ```yaml
+ registry:
+ path: shared/registry
+ ```
1. Save the file and [restart GitLab][] for the changes to take effect.
@@ -393,17 +391,17 @@ To configure the `s3` storage driver in Omnibus:
1. Edit `/etc/gitlab/gitlab.rb`:
- ```ruby
- registry['storage'] = {
- 's3' => {
- 'accesskey' => 's3-access-key',
- 'secretkey' => 's3-secret-key-for-access-key',
- 'bucket' => 'your-s3-bucket',
- 'region' => 'your-s3-region',
- 'regionendpoint' => 'your-s3-regionendpoint'
- }
- }
- ```
+ ```ruby
+ registry['storage'] = {
+ 's3' => {
+ 'accesskey' => 's3-access-key',
+ 'secretkey' => 's3-secret-key-for-access-key',
+ 'bucket' => 'your-s3-bucket',
+ 'region' => 'your-s3-region',
+ 'regionendpoint' => 'your-s3-regionendpoint'
+ }
+ }
+ ```
1. Save the file and [reconfigure GitLab][] for the changes to take effect.
@@ -442,9 +440,9 @@ In the examples below we set the Registry's port to `5001`.
1. Open `/etc/gitlab/gitlab.rb` and set `registry['registry_http_addr']`:
- ```ruby
- registry['registry_http_addr'] = "localhost:5001"
- ```
+ ```ruby
+ registry['registry_http_addr'] = "localhost:5001"
+ ```
1. Save the file and [reconfigure GitLab][] for the changes to take effect.
@@ -455,10 +453,10 @@ In the examples below we set the Registry's port to `5001`.
1. Open the configuration file of your Registry server and edit the
[`http:addr`][registry-http-config] value:
- ```
- http
- addr: localhost:5001
- ```
+ ```yaml
+ http
+ addr: localhost:5001
+ ```
1. Save the file and restart the Registry server.
@@ -476,14 +474,14 @@ You can use GitLab as an auth endpoint and use a non-bundled Container Registry.
1. Open `/etc/gitlab/gitlab.rb` and set necessary configurations:
- ```ruby
- gitlab_rails['registry_enabled'] = true
- gitlab_rails['registry_host'] = "registry.gitlab.example.com"
- gitlab_rails['registry_port'] = "5005"
- gitlab_rails['registry_api_url'] = "http://localhost:5000"
- gitlab_rails['registry_path'] = "/var/opt/gitlab/gitlab-rails/shared/registry"
- gitlab_rails['registry_issuer'] = "omnibus-gitlab-issuer"
- ```
+ ```ruby
+ gitlab_rails['registry_enabled'] = true
+ gitlab_rails['registry_host'] = "registry.gitlab.example.com"
+ gitlab_rails['registry_port'] = "5005"
+ gitlab_rails['registry_api_url'] = "http://localhost:5000"
+ gitlab_rails['registry_path'] = "/var/opt/gitlab/gitlab-rails/shared/registry"
+ gitlab_rails['registry_issuer'] = "omnibus-gitlab-issuer"
+ ```
1. A certificate keypair is required for GitLab and the Container Registry to
communicate securely. By default omnibus-gitlab will generate one keypair,
@@ -492,19 +490,19 @@ You can use GitLab as an auth endpoint and use a non-bundled Container Registry.
custom certificate key. To do that, add the following to
`/etc/gitlab/gitlab.rb`
- ```ruby
- gitlab_rails['registry_key_path'] = "/custom/path/to/registry-key.key"
- # registry['internal_key'] should contain the contents of the custom key
- # file. Line breaks in the key file should be marked using `\n` character
- # Example:
- registry['internal_key'] = "---BEGIN RSA PRIVATE KEY---\nMIIEpQIBAA\n"
- ```
+ ```ruby
+ gitlab_rails['registry_key_path'] = "/custom/path/to/registry-key.key"
+ # registry['internal_key'] should contain the contents of the custom key
+ # file. Line breaks in the key file should be marked using `\n` character
+ # Example:
+ registry['internal_key'] = "---BEGIN RSA PRIVATE KEY---\nMIIEpQIBAA\n"
+ ```
- **Note:** The file specified at `registry_key_path` gets populated with the
- content specified by `internal_key`, each time reconfigure is executed. If
- no file is specified, omnibus-gitlab will default it to
- `/var/opt/gitlab/gitlab-rails/etc/gitlab-registry.key` and will populate
- it.
+ **Note:** The file specified at `registry_key_path` gets populated with the
+ content specified by `internal_key`, each time reconfigure is executed. If
+ no file is specified, omnibus-gitlab will default it to
+ `/var/opt/gitlab/gitlab-rails/etc/gitlab-registry.key` and will populate
+ it.
1. Save the file and [reconfigure GitLab][] for the changes to take effect.
@@ -512,18 +510,18 @@ You can use GitLab as an auth endpoint and use a non-bundled Container Registry.
1. Open `/home/git/gitlab/config/gitlab.yml`, and edit the configuration settings under `registry`:
- ```
- ## Container Registry
+ ```yaml
+ ## Container Registry
- registry:
- enabled: true
- host: "registry.gitlab.example.com"
- port: "5005"
- api_url: "http://localhost:5000"
- path: /var/opt/gitlab/gitlab-rails/shared/registry
- key: /var/opt/gitlab/gitlab-rails/certificate.key
- issuer: omnibus-gitlab-issuer
- ```
+ registry:
+ enabled: true
+ host: "registry.gitlab.example.com"
+ port: "5005"
+ api_url: "http://localhost:5000"
+ path: /var/opt/gitlab/gitlab-rails/shared/registry
+ key: /var/opt/gitlab/gitlab-rails/certificate.key
+ issuer: omnibus-gitlab-issuer
+ ```
1. Save the file and [restart GitLab][] for the changes to take effect.
@@ -550,20 +548,20 @@ To configure a notification endpoint in Omnibus:
1. Edit `/etc/gitlab/gitlab.rb`:
- ```ruby
- registry['notifications'] = [
- {
- 'name' => 'test_endpoint',
- 'url' => 'https://gitlab.example.com/notify',
- 'timeout' => '500ms',
- 'threshold' => 5,
- 'backoff' => '1s',
- 'headers' => {
- "Authorization" => ["AUTHORIZATION_EXAMPLE_TOKEN"]
- }
- }
- ]
- ```
+ ```ruby
+ registry['notifications'] = [
+ {
+ 'name' => 'test_endpoint',
+ 'url' => 'https://gitlab.example.com/notify',
+ 'timeout' => '500ms',
+ 'threshold' => 5,
+ 'backoff' => '1s',
+ 'headers' => {
+ "Authorization" => ["AUTHORIZATION_EXAMPLE_TOKEN"]
+ }
+ }
+ ]
+ ```
1. Save the file and [reconfigure GitLab][] for the changes to take effect.
@@ -629,16 +627,16 @@ Start with a value between `25000000` (25MB) and `50000000` (50MB).
1. Edit `/etc/gitlab/gitlab.rb`:
- ```ruby
- registry['storage'] = {
- 's3' => {
- 'accesskey' => 'AKIAKIAKI',
- 'secretkey' => 'secret123',
- 'bucket' => 'gitlab-registry-bucket-AKIAKIAKI',
- 'chunksize' => 25000000
- }
- }
- ```
+ ```ruby
+ registry['storage'] = {
+ 's3' => {
+ 'accesskey' => 'AKIAKIAKI',
+ 'secretkey' => 'secret123',
+ 'bucket' => 'gitlab-registry-bucket-AKIAKIAKI',
+ 'chunksize' => 25000000
+ }
+ }
+ ```
1. Save the file and [reconfigure GitLab][] for the changes to take effect.
@@ -648,14 +646,14 @@ Start with a value between `25000000` (25MB) and `50000000` (50MB).
1. Edit `config/gitlab.yml`:
- ```yaml
- storage:
- s3:
- accesskey: 'AKIAKIAKI'
- secretkey: 'secret123'
- bucket: 'gitlab-registry-bucket-AKIAKIAKI'
- chunksize: 25000000
- ```
+ ```yaml
+ storage:
+ s3:
+ accesskey: 'AKIAKIAKI'
+ secretkey: 'secret123'
+ bucket: 'gitlab-registry-bucket-AKIAKIAKI'
+ chunksize: 25000000
+ ```
1. Save the file and [restart GitLab][] for the changes to take effect.
@@ -669,9 +667,9 @@ You can add a configuration option for backwards compatibility.
1. Edit `/etc/gitlab/gitlab.rb`:
- ```ruby
- registry['compatibility_schema1_enabled'] = true
- ```
+ ```ruby
+ registry['compatibility_schema1_enabled'] = true
+ ```
1. Save the file and [reconfigure GitLab][] for the changes to take effect.
@@ -681,14 +679,28 @@ You can add a configuration option for backwards compatibility.
1. Edit the YML configuration file you created when you [deployed the registry][registry-deploy]. Add the following snippet:
- ```yaml
- compatibility:
- schema1:
- enabled: true
- ```
+ ```yaml
+ compatibility:
+ schema1:
+ enabled: true
+ ```
1. Restart the registry for the changes to take affect.
+### Docker connection error
+
+A Docker connection error can occur when there are special characters in either the group,
+project or branch name. Special characters can include:
+
+- Leading underscore
+- Trailing hyphen/dash
+- Double hyphen/dash
+
+To get around this, you can [change the group path](../user/group/index.md#changing-a-groups-path),
+[change the project path](../user/project/settings/index.md#renaming-a-repository) or change the
+branch name. Another option is to create a [push rule](../push_rules/push_rules.html) to prevent
+this at the instance level.
+
[ce-18239]: https://gitlab.com/gitlab-org/gitlab-ce/issues/18239
[docker-insecure-self-signed]: https://docs.docker.com/registry/insecure/#use-self-signed-certificates
diff --git a/doc/administration/database_load_balancing.md b/doc/administration/database_load_balancing.md
index 98404ff2a10..dc4cc401fca 100644
--- a/doc/administration/database_load_balancing.md
+++ b/doc/administration/database_load_balancing.md
@@ -1,4 +1,4 @@
-# Database Load Balancing **[PREMIUM ONLY]**
+# Database Load Balancing **(PREMIUM ONLY)**
> [Introduced][ee-1283] in [GitLab Premium][eep] 9.0.
@@ -74,9 +74,9 @@ the following. This will balance the load between `host1.example.com` and
1. Edit `/etc/gitlab/gitlab.rb` and add the following line:
- ```ruby
- gitlab_rails['db_load_balancing'] = { 'hosts' => ['host1.example.com', 'host2.example.com'] }
- ```
+ ```ruby
+ gitlab_rails['db_load_balancing'] = { 'hosts' => ['host1.example.com', 'host2.example.com'] }
+ ```
1. Save the file and [reconfigure GitLab][] for the changes to take effect.
@@ -86,16 +86,16 @@ the following. This will balance the load between `host1.example.com` and
1. Edit `/home/git/gitlab/config/database.yml` and add or amend the following lines:
- ```yaml
- production:
- username: gitlab
- database: gitlab
- encoding: unicode
- load_balancing:
- hosts:
- - host1.example.com
- - host2.example.com
- ```
+ ```yaml
+ production:
+ username: gitlab
+ database: gitlab
+ encoding: unicode
+ load_balancing:
+ hosts:
+ - host1.example.com
+ - host2.example.com
+ ```
1. Save the file and [restart GitLab][] for the changes to take effect.
@@ -265,7 +265,7 @@ production:
replica_check_interval: 30
```
-[hot-standby]: https://www.postgresql.org/docs/9.6/static/hot-standby.html
+[hot-standby]: https://www.postgresql.org/docs/9.6/hot-standby.html
[ee-1283]: https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/1283
[eep]: https://about.gitlab.com/pricing/
[reconfigure gitlab]: restart_gitlab.md#omnibus-gitlab-reconfigure "How to reconfigure Omnibus GitLab"
diff --git a/doc/administration/dependency_proxy.md b/doc/administration/dependency_proxy.md
index 4dc1f4dcba4..776c60703fc 100644
--- a/doc/administration/dependency_proxy.md
+++ b/doc/administration/dependency_proxy.md
@@ -1,6 +1,6 @@
-# GitLab Dependency Proxy administration **[PREMIUM ONLY]**
+# GitLab Dependency Proxy administration **(PREMIUM ONLY)**
-> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/7934) in [GitLab Premium](https://about.gitlab.com/pricing) 11.11.
+> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/7934) in [GitLab Premium](https://about.gitlab.com/pricing/) 11.11.
GitLab can be utilized as a dependency proxy for a variety of common package managers.
diff --git a/doc/administration/geo/disaster_recovery/background_verification.md b/doc/administration/geo/disaster_recovery/background_verification.md
index d4c8c2d3624..8eee9427b56 100644
--- a/doc/administration/geo/disaster_recovery/background_verification.md
+++ b/doc/administration/geo/disaster_recovery/background_verification.md
@@ -1,4 +1,4 @@
-# Automatic background verification **[PREMIUM ONLY]**
+# Automatic background verification **(PREMIUM ONLY)**
NOTE: **Note:**
Automatic background verification of repositories and wikis was added in
@@ -143,11 +143,13 @@ If the **primary** and **secondary** nodes have a checksum verification mismatch
1. On the project admin page get the **Gitaly storage name**, and **Gitaly relative path**:
![Project admin page](img/checksum-differences-admin-project-page.png)
-1. Navigate to the project's repository directory on both **primary** and **secondary** nodes (the path is usually `/var/opt/gitlab/git-data/repositories`). Note that if `git_data_dirs` is customized, check the directory layout on your server to be sure.
+1. Navigate to the project's repository directory on both **primary** and **secondary** nodes
+ (the path is usually `/var/opt/gitlab/git-data/repositories`). Note that if `git_data_dirs`
+ is customized, check the directory layout on your server to be sure.
- ```sh
- cd /var/opt/gitlab/git-data/repositories
- ```
+ ```sh
+ cd /var/opt/gitlab/git-data/repositories
+ ```
1. Run the following command on the **primary** node, redirecting the output to a file:
diff --git a/doc/administration/geo/disaster_recovery/bring_primary_back.md b/doc/administration/geo/disaster_recovery/bring_primary_back.md
index f4d31a98080..30d35df25c7 100644
--- a/doc/administration/geo/disaster_recovery/bring_primary_back.md
+++ b/doc/administration/geo/disaster_recovery/bring_primary_back.md
@@ -1,4 +1,4 @@
-# Bring a demoted primary node back online **[PREMIUM ONLY]**
+# Bring a demoted primary node back online **(PREMIUM ONLY)**
After a failover, it is possible to fail back to the demoted **primary** node to
restore your original configuration. This process consists of two steps:
@@ -21,20 +21,20 @@ To bring the former **primary** node up to date:
1. SSH into the former **primary** node that has fallen behind.
1. Make sure all the services are up:
- ```sh
- sudo gitlab-ctl start
- ```
-
- > **Note 1:** If you [disabled the **primary** node permanently][disaster-recovery-disable-primary],
- > you need to undo those steps now. For Debian/Ubuntu you just need to run
- > `sudo systemctl enable gitlab-runsvdir`. For CentOS 6, you need to install
- > the GitLab instance from scratch and set it up as a **secondary** node by
- > following [Setup instructions][setup-geo]. In this case, you don't need to follow the next step.
- >
- > **Note 2:** If you [changed the DNS records](index.md#step-4-optional-updating-the-primary-domain-dns-record)
- > for this node during disaster recovery procedure you may need to [block
- > all the writes to this node](https://gitlab.com/gitlab-org/gitlab-ee/blob/master/doc/gitlab-geo/planned-failover.md#block-primary-traffic)
- > during this procedure.
+ ```sh
+ sudo gitlab-ctl start
+ ```
+
+ NOTE: **Note:** If you [disabled the **primary** node permanently][disaster-recovery-disable-primary],
+ you need to undo those steps now. For Debian/Ubuntu you just need to run
+ `sudo systemctl enable gitlab-runsvdir`. For CentOS 6, you need to install
+ the GitLab instance from scratch and set it up as a **secondary** node by
+ following [Setup instructions][setup-geo]. In this case, you don't need to follow the next step.
+
+ NOTE: **Note:** If you [changed the DNS records](index.md#step-4-optional-updating-the-primary-domain-dns-record)
+ for this node during disaster recovery procedure you may need to [block
+ all the writes to this node](planned_failover.md#prevent-updates-to-the-primary-node)
+ during this procedure.
1. [Setup database replication][database-replication]. Note that in this
case, **primary** node refers to the current **primary** node, and **secondary** node refers to the
diff --git a/doc/administration/geo/disaster_recovery/index.md b/doc/administration/geo/disaster_recovery/index.md
index 71dc797f281..d44e141b66b 100644
--- a/doc/administration/geo/disaster_recovery/index.md
+++ b/doc/administration/geo/disaster_recovery/index.md
@@ -1,4 +1,4 @@
-# Disaster Recovery **[PREMIUM ONLY]**
+# Disaster Recovery **(PREMIUM ONLY)**
Geo replicates your database, your Git repositories, and few other assets.
We will support and replicate more data in the future, that will enable you to
@@ -39,48 +39,50 @@ must disable the **primary** node.
1. SSH into the **primary** node to stop and disable GitLab, if possible:
- ```sh
- sudo gitlab-ctl stop
- ```
+ ```sh
+ sudo gitlab-ctl stop
+ ```
- Prevent GitLab from starting up again if the server unexpectedly reboots:
+ Prevent GitLab from starting up again if the server unexpectedly reboots:
- ```sh
- sudo systemctl disable gitlab-runsvdir
- ```
+ ```sh
+ sudo systemctl disable gitlab-runsvdir
+ ```
- > **CentOS only**: In CentOS 6 or older, there is no easy way to prevent GitLab from being
- > started if the machine reboots isn't available (see [gitlab-org/omnibus-gitlab#3058]).
- > It may be safest to uninstall the GitLab package completely:
+ NOTE: **Note:**
+ (**CentOS only**) In CentOS 6 or older, there is no easy way to prevent GitLab from being
+ started if the machine reboots isn't available (see [gitlab-org/omnibus-gitlab#3058]).
+ It may be safest to uninstall the GitLab package completely:
- ```sh
- yum remove gitlab-ee
- ```
+ ```sh
+ yum remove gitlab-ee
+ ```
- > **Ubuntu 14.04 LTS**: If you are using an older version of Ubuntu
- > or any other distro based on the Upstart init system, you can prevent GitLab
- > from starting if the machine reboots by doing the following:
+ NOTE: **Note:**
+ (**Ubuntu 14.04 LTS**) If you are using an older version of Ubuntu
+ or any other distro based on the Upstart init system, you can prevent GitLab
+ from starting if the machine reboots by doing the following:
- ```sh
- initctl stop gitlab-runsvvdir
- echo 'manual' > /etc/init/gitlab-runsvdir.override
- initctl reload-configuration
- ```
+ ```sh
+ initctl stop gitlab-runsvvdir
+ echo 'manual' > /etc/init/gitlab-runsvdir.override
+ initctl reload-configuration
+ ```
1. If you do not have SSH access to the **primary** node, take the machine offline and
- prevent it from rebooting by any means at your disposal.
- Since there are many ways you may prefer to accomplish this, we will avoid a
- single recommendation. You may need to:
- - Reconfigure the load balancers.
- - Change DNS records (e.g., point the primary DNS record to the **secondary**
- node in order to stop usage of the **primary** node).
- - Stop the virtual servers.
- - Block traffic through a firewall.
- - Revoke object storage permissions from the **primary** node.
- - Physically disconnect a machine.
-
-1. If you plan to
- [update the primary domain DNS record](#step-4-optional-updating-the-primary-domain-dns-record),
+ prevent it from rebooting by any means at your disposal.
+ Since there are many ways you may prefer to accomplish this, we will avoid a
+ single recommendation. You may need to:
+
+ - Reconfigure the load balancers.
+ - Change DNS records (e.g., point the primary DNS record to the **secondary**
+ node in order to stop usage of the **primary** node).
+ - Stop the virtual servers.
+ - Block traffic through a firewall.
+ - Revoke object storage permissions from the **primary** node.
+ - Physically disconnect a machine.
+
+1. If you plan to [update the primary domain DNS record](#step-4-optional-updating-the-primary-domain-dns-record),
you may wish to lower the TTL now to speed up propagation.
### Step 3. Promoting a **secondary** node
@@ -94,26 +96,26 @@ the **secondary** to the **primary**.
1. SSH in to your **secondary** node and login as root:
- ```sh
- sudo -i
- ```
+ ```sh
+ sudo -i
+ ```
1. Edit `/etc/gitlab/gitlab.rb` to reflect its new status as **primary** by
removing any lines that enabled the `geo_secondary_role`:
- ```ruby
- ## In pre-11.5 documentation, the role was enabled as follows. Remove this line.
- geo_secondary_role['enable'] = true
+ ```ruby
+ ## In pre-11.5 documentation, the role was enabled as follows. Remove this line.
+ geo_secondary_role['enable'] = true
- ## In 11.5+ documentation, the role was enabled as follows. Remove this line.
- roles ['geo_secondary_role']
- ```
+ ## In 11.5+ documentation, the role was enabled as follows. Remove this line.
+ roles ['geo_secondary_role']
+ ```
1. Promote the **secondary** node to the **primary** node. Execute:
- ```sh
- gitlab-ctl promote-to-primary-node
- ```
+ ```sh
+ gitlab-ctl promote-to-primary-node
+ ```
1. Verify you can connect to the newly promoted **primary** node using the URL used
previously for the **secondary** node.
@@ -129,31 +131,31 @@ do this manually.
1. SSH in to the database node in the **secondary** and trigger PostgreSQL to
promote to read-write:
- ```bash
- sudo gitlab-pg-ctl promote
- ```
+ ```bash
+ sudo gitlab-pg-ctl promote
+ ```
1. Edit `/etc/gitlab/gitlab.rb` on every machine in the **secondary** to
reflect its new status as **primary** by removing any lines that enabled the
`geo_secondary_role`:
- ```ruby
- ## In pre-11.5 documentation, the role was enabled as follows. Remove this line.
- geo_secondary_role['enable'] = true
+ ```ruby
+ ## In pre-11.5 documentation, the role was enabled as follows. Remove this line.
+ geo_secondary_role['enable'] = true
- ## In 11.5+ documentation, the role was enabled as follows. Remove this line.
- roles ['geo_secondary_role']
- ```
+ ## In 11.5+ documentation, the role was enabled as follows. Remove this line.
+ roles ['geo_secondary_role']
+ ```
- After making these changes [Reconfigure GitLab](../../restart_gitlab.md#omnibus-gitlab-reconfigure) each
- machine so the changes take effect.
+ After making these changes [Reconfigure GitLab](../../restart_gitlab.md#omnibus-gitlab-reconfigure) each
+ machine so the changes take effect.
1. Promote the **secondary** to **primary**. SSH into a single application
server and execute:
- ```bash
- sudo gitlab-rake geo:set_secondary_as_primary
- ```
+ ```bash
+ sudo gitlab-rake geo:set_secondary_as_primary
+ ```
1. Verify you can connect to the newly promoted **primary** using the URL used
previously for the **secondary**.
@@ -167,37 +169,37 @@ secondary domain, like changing Git remotes and API URLs.
1. SSH into the **secondary** node and login as root:
- ```sh
- sudo -i
- ```
+ ```sh
+ sudo -i
+ ```
1. Update the primary domain's DNS record. After updating the primary domain's
DNS records to point to the **secondary** node, edit `/etc/gitlab/gitlab.rb` on the
**secondary** node to reflect the new URL:
- ```ruby
- # Change the existing external_url configuration
- external_url 'https://<new_external_url>'
- ```
+ ```ruby
+ # Change the existing external_url configuration
+ external_url 'https://<new_external_url>'
+ ```
- NOTE: **Note**
- Changing `external_url` won't prevent access via the old secondary URL, as
- long as the secondary DNS records are still intact.
+ NOTE: **Note**
+ Changing `external_url` won't prevent access via the old secondary URL, as
+ long as the secondary DNS records are still intact.
1. Reconfigure the **secondary** node for the change to take effect:
- ```sh
- gitlab-ctl reconfigure
- ```
+ ```sh
+ gitlab-ctl reconfigure
+ ```
1. Execute the command below to update the newly promoted **primary** node URL:
- ```sh
- gitlab-rake geo:update_primary_node_url
- ```
+ ```sh
+ gitlab-rake geo:update_primary_node_url
+ ```
- This command will use the changed `external_url` configuration defined
- in `/etc/gitlab/gitlab.rb`.
+ This command will use the changed `external_url` configuration defined
+ in `/etc/gitlab/gitlab.rb`.
1. Verify you can connect to the newly promoted **primary** using its URL.
If you updated the DNS records for the primary domain, these changes may
@@ -231,62 +233,61 @@ and after that you also need two extra steps.
1. SSH into the new **primary** node and login as root:
- ```sh
- sudo -i
- ```
+ ```sh
+ sudo -i
+ ```
1. Edit `/etc/gitlab/gitlab.rb`
- ```ruby
- ## Enable a Geo Primary role (if you haven't yet)
- roles ['geo_primary_role']
+ ```ruby
+ ## Enable a Geo Primary role (if you haven't yet)
+ roles ['geo_primary_role']
- ##
- # Allow PostgreSQL client authentication from the primary and secondary IPs. These IPs may be
- # public or VPC addresses in CIDR format, for example ['198.51.100.1/32', '198.51.100.2/32']
- ##
- postgresql['md5_auth_cidr_addresses'] = ['<primary_node_ip>/32', '<secondary_node_ip>/32']
+ ##
+ # Allow PostgreSQL client authentication from the primary and secondary IPs. These IPs may be
+ # public or VPC addresses in CIDR format, for example ['198.51.100.1/32', '198.51.100.2/32']
+ ##
+ postgresql['md5_auth_cidr_addresses'] = ['<primary_node_ip>/32', '<secondary_node_ip>/32']
- # Every secondary server needs to have its own slot so specify the number of secondary nodes you're going to have
- postgresql['max_replication_slots'] = 1
+ # Every secondary server needs to have its own slot so specify the number of secondary nodes you're going to have
+ postgresql['max_replication_slots'] = 1
- ##
- ## Disable automatic database migrations temporarily
- ## (until PostgreSQL is restarted and listening on the private address).
- ##
- gitlab_rails['auto_migrate'] = false
+ ##
+ ## Disable automatic database migrations temporarily
+ ## (until PostgreSQL is restarted and listening on the private address).
+ ##
+ gitlab_rails['auto_migrate'] = false
+ ```
- ```
-
- (For more details about these settings you can read [Configure the primary server][configure-the-primary-server])
+ (For more details about these settings you can read [Configure the primary server][configure-the-primary-server])
1. Save the file and reconfigure GitLab for the database listen changes and
the replication slot changes to be applied.
- ```sh
- gitlab-ctl reconfigure
- ```
+ ```sh
+ gitlab-ctl reconfigure
+ ```
- Restart PostgreSQL for its changes to take effect:
+ Restart PostgreSQL for its changes to take effect:
- ```sh
- gitlab-ctl restart postgresql
- ```
+ ```sh
+ gitlab-ctl restart postgresql
+ ```
1. Re-enable migrations now that PostgreSQL is restarted and listening on the
private address.
- Edit `/etc/gitlab/gitlab.rb` and **change** the configuration to `true`:
+ Edit `/etc/gitlab/gitlab.rb` and **change** the configuration to `true`:
- ```ruby
- gitlab_rails['auto_migrate'] = true
- ```
+ ```ruby
+ gitlab_rails['auto_migrate'] = true
+ ```
- Save the file and reconfigure GitLab:
+ Save the file and reconfigure GitLab:
- ```sh
- gitlab-ctl reconfigure
- ```
+ ```sh
+ gitlab-ctl reconfigure
+ ```
### Step 2. Initiate the replication process
diff --git a/doc/administration/geo/disaster_recovery/planned_failover.md b/doc/administration/geo/disaster_recovery/planned_failover.md
index b8071b5993f..393326c3347 100644
--- a/doc/administration/geo/disaster_recovery/planned_failover.md
+++ b/doc/administration/geo/disaster_recovery/planned_failover.md
@@ -1,4 +1,4 @@
-# Disaster recovery for planned failover **[PREMIUM ONLY]**
+# Disaster recovery for planned failover **(PREMIUM ONLY)**
The primary use-case of Disaster Recovery is to ensure business continuity in
the event of unplanned outage, but it can be used in conjunction with a planned
@@ -143,26 +143,26 @@ access to the **primary** node during the maintenance window.
all HTTP, HTTPS and SSH traffic to/from the **primary** node, **except** for your IP and
the **secondary** node's IP.
- For instance, you might run the following commands on the server(s) making up your **primary** node:
+ For instance, you might run the following commands on the server(s) making up your **primary** node:
- ```sh
- sudo iptables -A INPUT -p tcp -s <secondary_node_ip> --destination-port 22 -j ACCEPT
- sudo iptables -A INPUT -p tcp -s <your_ip> --destination-port 22 -j ACCEPT
- sudo iptables -A INPUT --destination-port 22 -j REJECT
+ ```sh
+ sudo iptables -A INPUT -p tcp -s <secondary_node_ip> --destination-port 22 -j ACCEPT
+ sudo iptables -A INPUT -p tcp -s <your_ip> --destination-port 22 -j ACCEPT
+ sudo iptables -A INPUT --destination-port 22 -j REJECT
- sudo iptables -A INPUT -p tcp -s <secondary_node_ip> --destination-port 80 -j ACCEPT
- sudo iptables -A INPUT -p tcp -s <your_ip> --destination-port 80 -j ACCEPT
- sudo iptables -A INPUT --tcp-dport 80 -j REJECT
+ sudo iptables -A INPUT -p tcp -s <secondary_node_ip> --destination-port 80 -j ACCEPT
+ sudo iptables -A INPUT -p tcp -s <your_ip> --destination-port 80 -j ACCEPT
+ sudo iptables -A INPUT --tcp-dport 80 -j REJECT
- sudo iptables -A INPUT -p tcp -s <secondary_node_ip> --destination-port 443 -j ACCEPT
- sudo iptables -A INPUT -p tcp -s <your_ip> --destination-port 443 -j ACCEPT
- sudo iptables -A INPUT --tcp-dport 443 -j REJECT
- ```
+ sudo iptables -A INPUT -p tcp -s <secondary_node_ip> --destination-port 443 -j ACCEPT
+ sudo iptables -A INPUT -p tcp -s <your_ip> --destination-port 443 -j ACCEPT
+ sudo iptables -A INPUT --tcp-dport 443 -j REJECT
+ ```
- From this point, users will be unable to view their data or make changes on the
- **primary** node. They will also be unable to log in to the **secondary** node.
- However, existing sessions will work for the remainder of the maintenance period, and
- public data will be accessible throughout.
+ From this point, users will be unable to view their data or make changes on the
+ **primary** node. They will also be unable to log in to the **secondary** node.
+ However, existing sessions will work for the remainder of the maintenance period, and
+ public data will be accessible throughout.
1. Verify the **primary** node is blocked to HTTP traffic by visiting it in browser via
another IP. The server should refuse connection.
@@ -187,10 +187,11 @@ access to the **primary** node during the maintenance window.
before it is completed will cause the work to be lost.
1. On the **primary** node, navigate to **Admin Area > Geo** and wait for the
following conditions to be true of the **secondary** node you are failing over to:
- - All replication meters to each 100% replicated, 0% failures.
- - All verification meters reach 100% verified, 0% failures.
- - Database replication lag is 0ms.
- - The Geo log cursor is up to date (0 events behind).
+
+ - All replication meters to each 100% replicated, 0% failures.
+ - All verification meters reach 100% verified, 0% failures.
+ - Database replication lag is 0ms.
+ - The Geo log cursor is up to date (0 events behind).
1. On the **secondary** node, navigate to **Admin Area > Monitoring > Background Jobs > Queues**
and wait for all the `geo` queues to drop to 0 queued and 0 running jobs.
diff --git a/doc/administration/geo/replication/configuration.md b/doc/administration/geo/replication/configuration.md
index 3d4f69d3abe..0e11dffa0d6 100644
--- a/doc/administration/geo/replication/configuration.md
+++ b/doc/administration/geo/replication/configuration.md
@@ -1,4 +1,4 @@
-# Geo configuration **[PREMIUM ONLY]**
+# Geo configuration **(PREMIUM ONLY)**
## Configuring a new **secondary** node
@@ -16,11 +16,10 @@ The basic steps of configuring a **secondary** node are to:
You are encouraged to first read through all the steps before executing them
in your testing/production environment.
-> **Notes:**
-> - **Do not** setup any custom authentication for the **secondary** nodes. This will be
- handled by the **primary** node.
-> - Any change that requires access to the **Admin Area** needs to be done in the
- **primary** node because the **secondary** node is a read-only replica.
+NOTE: **Note:**
+**Do not** set up any custom authentication for the **secondary** nodes. This will be handled by the **primary** node.
+Any change that requires access to the **Admin Area** needs to be done in the
+**primary** node because the **secondary** node is a read-only replica.
### Step 1. Manually replicate secret GitLab values
@@ -31,47 +30,47 @@ they must be manually replicated to the **secondary** node.
1. SSH into the **primary** node, and execute the command below:
- ```sh
- sudo cat /etc/gitlab/gitlab-secrets.json
- ```
+ ```sh
+ sudo cat /etc/gitlab/gitlab-secrets.json
+ ```
- This will display the secrets that need to be replicated, in JSON format.
+ This will display the secrets that need to be replicated, in JSON format.
1. SSH into the **secondary** node and login as the `root` user:
- ```sh
- sudo -i
- ```
+ ```sh
+ sudo -i
+ ```
1. Make a backup of any existing secrets:
- ```sh
- mv /etc/gitlab/gitlab-secrets.json /etc/gitlab/gitlab-secrets.json.`date +%F`
- ```
+ ```sh
+ mv /etc/gitlab/gitlab-secrets.json /etc/gitlab/gitlab-secrets.json.`date +%F`
+ ```
1. Copy `/etc/gitlab/gitlab-secrets.json` from the **primary** node to the **secondary** node, or
copy-and-paste the file contents between nodes:
- ```sh
- sudo editor /etc/gitlab/gitlab-secrets.json
+ ```sh
+ sudo editor /etc/gitlab/gitlab-secrets.json
- # paste the output of the `cat` command you ran on the primary
- # save and exit
- ```
+ # paste the output of the `cat` command you ran on the primary
+ # save and exit
+ ```
1. Ensure the file permissions are correct:
- ```sh
- chown root:root /etc/gitlab/gitlab-secrets.json
- chmod 0600 /etc/gitlab/gitlab-secrets.json
- ```
+ ```sh
+ chown root:root /etc/gitlab/gitlab-secrets.json
+ chmod 0600 /etc/gitlab/gitlab-secrets.json
+ ```
1. Reconfigure the **secondary** node for the change to take effect:
- ```sh
- gitlab-ctl reconfigure
- gitlab-ctl restart
- ```
+ ```sh
+ gitlab-ctl reconfigure
+ gitlab-ctl restart
+ ```
### Step 2. Manually replicate the **primary** node's SSH host keys
@@ -89,80 +88,80 @@ keys must be manually replicated to the **secondary** node.
1. SSH into the **secondary** node and login as the `root` user:
- ```sh
- sudo -i
- ```
+ ```sh
+ sudo -i
+ ```
1. Make a backup of any existing SSH host keys:
- ```sh
- find /etc/ssh -iname ssh_host_* -exec cp {} {}.backup.`date +%F` \;
- ```
+ ```sh
+ find /etc/ssh -iname ssh_host_* -exec cp {} {}.backup.`date +%F` \;
+ ```
1. Copy OpenSSH host keys from the **primary** node:
- If you can access your **primary** node using the **root** user:
+ If you can access your **primary** node using the **root** user:
- ```sh
- # Run this from the secondary node, change `<primary_node_fqdn>` for the IP or FQDN of the server
- scp root@<primary_node_fqdn>:/etc/ssh/ssh_host_*_key* /etc/ssh
- ```
+ ```sh
+ # Run this from the secondary node, change `<primary_node_fqdn>` for the IP or FQDN of the server
+ scp root@<primary_node_fqdn>:/etc/ssh/ssh_host_*_key* /etc/ssh
+ ```
- If you only have access through a user with **sudo** privileges:
+ If you only have access through a user with **sudo** privileges:
- ```sh
- # Run this from your primary node:
- sudo tar --transform 's/.*\///g' -zcvf ~/geo-host-key.tar.gz /etc/ssh/ssh_host_*_key*
+ ```sh
+ # Run this from your primary node:
+ sudo tar --transform 's/.*\///g' -zcvf ~/geo-host-key.tar.gz /etc/ssh/ssh_host_*_key*
- # Run this from your secondary node:
- scp <user_with_sudo>@<primary_node_fqdn>:geo-host-key.tar.gz .
- tar zxvf ~/geo-host-key.tar.gz -C /etc/ssh
- ```
+ # Run this from your secondary node:
+ scp <user_with_sudo>@<primary_node_fqdn>:geo-host-key.tar.gz .
+ tar zxvf ~/geo-host-key.tar.gz -C /etc/ssh
+ ```
1. On your **secondary** node, ensure the file permissions are correct:
- ```sh
- chown root:root /etc/ssh/ssh_host_*_key*
- chmod 0600 /etc/ssh/ssh_host_*_key*
- ```
+ ```sh
+ chown root:root /etc/ssh/ssh_host_*_key*
+ chmod 0600 /etc/ssh/ssh_host_*_key*
+ ```
1. To verify key fingerprint matches, execute the following command on both nodes:
- ```sh
- for file in /etc/ssh/ssh_host_*_key; do ssh-keygen -lf $file; done
- ```
+ ```sh
+ for file in /etc/ssh/ssh_host_*_key; do ssh-keygen -lf $file; done
+ ```
- You should get an output similar to this one and they should be identical on both nodes:
+ You should get an output similar to this one and they should be identical on both nodes:
- ```sh
- 1024 SHA256:FEZX2jQa2bcsd/fn/uxBzxhKdx4Imc4raXrHwsbtP0M root@serverhostname (DSA)
- 256 SHA256:uw98R35Uf+fYEQ/UnJD9Br4NXUFPv7JAUln5uHlgSeY root@serverhostname (ECDSA)
- 256 SHA256:sqOUWcraZQKd89y/QQv/iynPTOGQxcOTIXU/LsoPmnM root@serverhostname (ED25519)
- 2048 SHA256:qwa+rgir2Oy86QI+PZi/QVR+MSmrdrpsuH7YyKknC+s root@serverhostname (RSA)
- ```
+ ```sh
+ 1024 SHA256:FEZX2jQa2bcsd/fn/uxBzxhKdx4Imc4raXrHwsbtP0M root@serverhostname (DSA)
+ 256 SHA256:uw98R35Uf+fYEQ/UnJD9Br4NXUFPv7JAUln5uHlgSeY root@serverhostname (ECDSA)
+ 256 SHA256:sqOUWcraZQKd89y/QQv/iynPTOGQxcOTIXU/LsoPmnM root@serverhostname (ED25519)
+ 2048 SHA256:qwa+rgir2Oy86QI+PZi/QVR+MSmrdrpsuH7YyKknC+s root@serverhostname (RSA)
+ ```
1. Verify that you have the correct public keys for the existing private keys:
- ```sh
- # This will print the fingerprint for private keys:
- for file in /etc/ssh/ssh_host_*_key; do ssh-keygen -lf $file; done
+ ```sh
+ # This will print the fingerprint for private keys:
+ for file in /etc/ssh/ssh_host_*_key; do ssh-keygen -lf $file; done
- # This will print the fingerprint for public keys:
- for file in /etc/ssh/ssh_host_*_key.pub; do ssh-keygen -lf $file; done
- ```
+ # This will print the fingerprint for public keys:
+ for file in /etc/ssh/ssh_host_*_key.pub; do ssh-keygen -lf $file; done
+ ```
- NOTE: **Note**:
- The output for private keys and public keys command should generate the same fingerprint.
+ NOTE: **Note:**
+ The output for private keys and public keys command should generate the same fingerprint.
1. Restart sshd on your **secondary** node:
- ```sh
- # Debian or Ubuntu installations
- sudo service ssh reload
+ ```sh
+ # Debian or Ubuntu installations
+ sudo service ssh reload
- # CentOS installations
- sudo service sshd reload
- ```
+ # CentOS installations
+ sudo service sshd reload
+ ```
### Step 3. Add the **secondary** node
@@ -176,22 +175,22 @@ keys must be manually replicated to the **secondary** node.
1. Click the **Add node** button.
1. SSH into your GitLab **secondary** server and restart the services:
- ```sh
- gitlab-ctl restart
- ```
+ ```sh
+ gitlab-ctl restart
+ ```
- Check if there are any common issue with your Geo setup by running:
+ Check if there are any common issue with your Geo setup by running:
- ```sh
- gitlab-rake gitlab:geo:check
- ```
+ ```sh
+ gitlab-rake gitlab:geo:check
+ ```
1. SSH into your **primary** server and login as root to verify the
**secondary** node is reachable or there are any common issue with your Geo setup:
- ```sh
- gitlab-rake gitlab:geo:check
- ```
+ ```sh
+ gitlab-rake gitlab:geo:check
+ ```
Once added to the admin panel and restarted, the **secondary** node will automatically start
replicating missing data from the **primary** node in a process known as **backfill**.
@@ -250,9 +249,8 @@ The two most obvious issues that can become apparent in the dashboard are:
1. Database replication not working well.
1. Instance to instance notification not working. In that case, it can be
something of the following:
- - You are using a custom certificate or custom CA (see the
- [troubleshooting document]).
- - The instance is firewalled (check your firewall rules).
+ - You are using a custom certificate or custom CA (see the [troubleshooting document](troubleshooting.md)).
+ - The instance is firewalled (check your firewall rules).
Please note that disabling a **secondary** node will stop the synchronization process.
@@ -304,5 +302,4 @@ See the [troubleshooting document](troubleshooting.md).
[gitlab-org/gitlab-ee#3789]: https://gitlab.com/gitlab-org/gitlab-ee/issues/3789
[gitlab-com/infrastructure#2821]: https://gitlab.com/gitlab-com/infrastructure/issues/2821
[omnibus-ssl]: https://docs.gitlab.com/omnibus/settings/ssl.html
-[troubleshooting document]: troubleshooting.md
[using-geo]: using_a_geo_server.md
diff --git a/doc/administration/geo/replication/database.md b/doc/administration/geo/replication/database.md
index 6658c37752a..71a1ce87833 100644
--- a/doc/administration/geo/replication/database.md
+++ b/doc/administration/geo/replication/database.md
@@ -1,4 +1,4 @@
-# Geo database replication **[PREMIUM ONLY]**
+# Geo database replication **(PREMIUM ONLY)**
NOTE: **Note:**
The following steps are for Omnibus installs only. Using Geo with source-based installs was **deprecated** in GitLab 11.5.
@@ -52,186 +52,188 @@ There is an [issue where support is being discussed](https://gitlab.com/gitlab-o
1. SSH into your GitLab **primary** server and login as root:
- ```sh
- sudo -i
- ```
+ ```sh
+ sudo -i
+ ```
1. Execute the command below to define the node as **primary** node:
- ```sh
- gitlab-ctl set-geo-primary-node
- ```
+ ```sh
+ gitlab-ctl set-geo-primary-node
+ ```
- This command will use your defined `external_url` in `/etc/gitlab/gitlab.rb`.
+ This command will use your defined `external_url` in `/etc/gitlab/gitlab.rb`.
1. GitLab 10.4 and up only: Do the following to make sure the `gitlab` database user has a password defined:
- Generate a MD5 hash of the desired password:
+ Generate a MD5 hash of the desired password:
- ```sh
- gitlab-ctl pg-password-md5 gitlab
- # Enter password: <your_password_here>
- # Confirm password: <your_password_here>
- # fca0b89a972d69f00eb3ec98a5838484
- ```
+ ```sh
+ gitlab-ctl pg-password-md5 gitlab
+ # Enter password: <your_password_here>
+ # Confirm password: <your_password_here>
+ # fca0b89a972d69f00eb3ec98a5838484
+ ```
- Edit `/etc/gitlab/gitlab.rb`:
+ Edit `/etc/gitlab/gitlab.rb`:
- ```ruby
- # Fill with the hash generated by `gitlab-ctl pg-password-md5 gitlab`
- postgresql['sql_user_password'] = '<md5_hash_of_your_password>'
+ ```ruby
+ # Fill with the hash generated by `gitlab-ctl pg-password-md5 gitlab`
+ postgresql['sql_user_password'] = '<md5_hash_of_your_password>'
- # Every node that runs Unicorn or Sidekiq needs to have the database
- # password specified as below. If you have a high-availability setup, this
- # must be present in all application nodes.
- gitlab_rails['db_password'] = '<your_password_here>'
- ```
+ # Every node that runs Unicorn or Sidekiq needs to have the database
+ # password specified as below. If you have a high-availability setup, this
+ # must be present in all application nodes.
+ gitlab_rails['db_password'] = '<your_password_here>'
+ ```
1. Omnibus GitLab already has a [replication user]
called `gitlab_replicator`. You must set the password for this user manually.
You will be prompted to enter a password:
- ```sh
- gitlab-ctl set-replication-password
- ```
+ ```sh
+ gitlab-ctl set-replication-password
+ ```
- This command will also read the `postgresql['sql_replication_user']` Omnibus
- setting in case you have changed `gitlab_replicator` username to something
- else.
+ This command will also read the `postgresql['sql_replication_user']` Omnibus
+ setting in case you have changed `gitlab_replicator` username to something
+ else.
- If you are using an external database not managed by Omnibus GitLab, you need
- to create the replicator user and define a password to it manually:
+ If you are using an external database not managed by Omnibus GitLab, you need
+ to create the replicator user and define a password to it manually:
- ```sql
- --- Create a new user 'replicator'
- CREATE USER gitlab_replicator;
+ ```sql
+ --- Create a new user 'replicator'
+ CREATE USER gitlab_replicator;
- --- Set/change a password and grants replication privilege
- ALTER USER gitlab_replicator WITH REPLICATION ENCRYPTED PASSWORD '<replication_password>';
- ```
+ --- Set/change a password and grants replication privilege
+ ALTER USER gitlab_replicator WITH REPLICATION ENCRYPTED PASSWORD '<replication_password>';
+ ```
1. Configure PostgreSQL to listen on network interfaces:
- For security reasons, PostgreSQL does not listen on any network interfaces
- by default. However, Geo requires the **secondary** node to be able to
- connect to the **primary** node's database. For this reason, we need the address of
- each node. Note: For external PostgreSQL instances, see [additional instructions](external_database.md).
-
- If you are using a cloud provider, you can lookup the addresses for each
- Geo node through your cloud provider's management console.
-
- To lookup the address of a Geo node, SSH in to the Geo node and execute:
-
- ```sh
- ##
- ## Private address
- ##
- ip route get 255.255.255.255 | awk '{print "Private address:", $NF; exit}'
-
- ##
- ## Public address
- ##
- echo "External address: $(curl --silent ipinfo.io/ip)"
- ```
-
- In most cases, the following addresses will be used to configure GitLab
- Geo:
-
- | Configuration | Address |
- |:----------------------------------------|:------------------------------------------------------|
- | `postgresql['listen_address']` | **Primary** node's public or VPC private address. |
- | `postgresql['md5_auth_cidr_addresses']` | **Secondary** node's public or VPC private addresses. |
-
- If you are using Google Cloud Platform, SoftLayer, or any other vendor that
- provides a virtual private cloud (VPC) you can use the **secondary** node's private
- address (corresponds to "internal address" for Google Cloud Platform) for
- `postgresql['md5_auth_cidr_addresses']` and `postgresql['listen_address']`.
-
- The `listen_address` option opens PostgreSQL up to network connections
- with the interface corresponding to the given address. See [the PostgreSQL
- documentation][pg-docs-runtime-conn] for more details.
-
- Depending on your network configuration, the suggested addresses may not
- be correct. If your **primary** node and **secondary** nodes connect over a local
- area network, or a virtual network connecting availability zones like
- [Amazon's VPC](https://aws.amazon.com/vpc/) or [Google's VPC](https://cloud.google.com/vpc/)
- you should use the **secondary** node's private address for `postgresql['md5_auth_cidr_addresses']`.
-
- Edit `/etc/gitlab/gitlab.rb` and add the following, replacing the IP
- addresses with addresses appropriate to your network configuration:
-
- ```ruby
- ##
- ## Geo Primary role
- ## - configure dependent flags automatically to enable Geo
- ##
- roles ['geo_primary_role']
-
- ##
- ## Primary address
- ## - replace '<primary_node_ip>' with the public or VPC address of your Geo primary node
- ##
- postgresql['listen_address'] = '<primary_node_ip>'
-
- ##
- # Allow PostgreSQL client authentication from the primary and secondary IPs. These IPs may be
- # public or VPC addresses in CIDR format, for example ['198.51.100.1/32', '198.51.100.2/32']
- ##
- postgresql['md5_auth_cidr_addresses'] = ['<primary_node_ip>/32', '<secondary_node_ip>/32']
-
- ##
- ## Replication settings
- ## - set this to be the number of Geo secondary nodes you have
- ##
- postgresql['max_replication_slots'] = 1
- # postgresql['max_wal_senders'] = 10
- # postgresql['wal_keep_segments'] = 10
-
- ##
- ## Disable automatic database migrations temporarily
- ## (until PostgreSQL is restarted and listening on the private address).
- ##
- gitlab_rails['auto_migrate'] = false
- ```
+ For security reasons, PostgreSQL does not listen on any network interfaces
+ by default. However, Geo requires the **secondary** node to be able to
+ connect to the **primary** node's database. For this reason, we need the address of
+ each node.
+
+ NOTE: **Note:** For external PostgreSQL instances, see [additional instructions](external_database.md).
+
+ If you are using a cloud provider, you can lookup the addresses for each
+ Geo node through your cloud provider's management console.
+
+ To lookup the address of a Geo node, SSH in to the Geo node and execute:
+
+ ```sh
+ ##
+ ## Private address
+ ##
+ ip route get 255.255.255.255 | awk '{print "Private address:", $NF; exit}'
+
+ ##
+ ## Public address
+ ##
+ echo "External address: $(curl --silent ipinfo.io/ip)"
+ ```
+
+ In most cases, the following addresses will be used to configure GitLab
+ Geo:
+
+ | Configuration | Address |
+ |:----------------------------------------|:------------------------------------------------------|
+ | `postgresql['listen_address']` | **Primary** node's public or VPC private address. |
+ | `postgresql['md5_auth_cidr_addresses']` | **Secondary** node's public or VPC private addresses. |
+
+ If you are using Google Cloud Platform, SoftLayer, or any other vendor that
+ provides a virtual private cloud (VPC) you can use the **secondary** node's private
+ address (corresponds to "internal address" for Google Cloud Platform) for
+ `postgresql['md5_auth_cidr_addresses']` and `postgresql['listen_address']`.
+
+ The `listen_address` option opens PostgreSQL up to network connections
+ with the interface corresponding to the given address. See [the PostgreSQL
+ documentation][pg-docs-runtime-conn] for more details.
+
+ Depending on your network configuration, the suggested addresses may not
+ be correct. If your **primary** node and **secondary** nodes connect over a local
+ area network, or a virtual network connecting availability zones like
+ [Amazon's VPC](https://aws.amazon.com/vpc/) or [Google's VPC](https://cloud.google.com/vpc/)
+ you should use the **secondary** node's private address for `postgresql['md5_auth_cidr_addresses']`.
+
+ Edit `/etc/gitlab/gitlab.rb` and add the following, replacing the IP
+ addresses with addresses appropriate to your network configuration:
+
+ ```ruby
+ ##
+ ## Geo Primary role
+ ## - configure dependent flags automatically to enable Geo
+ ##
+ roles ['geo_primary_role']
+
+ ##
+ ## Primary address
+ ## - replace '<primary_node_ip>' with the public or VPC address of your Geo primary node
+ ##
+ postgresql['listen_address'] = '<primary_node_ip>'
+
+ ##
+ # Allow PostgreSQL client authentication from the primary and secondary IPs. These IPs may be
+ # public or VPC addresses in CIDR format, for example ['198.51.100.1/32', '198.51.100.2/32']
+ ##
+ postgresql['md5_auth_cidr_addresses'] = ['<primary_node_ip>/32', '<secondary_node_ip>/32']
+
+ ##
+ ## Replication settings
+ ## - set this to be the number of Geo secondary nodes you have
+ ##
+ postgresql['max_replication_slots'] = 1
+ # postgresql['max_wal_senders'] = 10
+ # postgresql['wal_keep_segments'] = 10
+
+ ##
+ ## Disable automatic database migrations temporarily
+ ## (until PostgreSQL is restarted and listening on the private address).
+ ##
+ gitlab_rails['auto_migrate'] = false
+ ```
1. Optional: If you want to add another **secondary** node, the relevant setting would look like:
- ```ruby
- postgresql['md5_auth_cidr_addresses'] = ['<primary_node_ip>/32', '<secondary_node_ip>/32', '<another_secondary_node_ip>/32']
- ```
+ ```ruby
+ postgresql['md5_auth_cidr_addresses'] = ['<primary_node_ip>/32', '<secondary_node_ip>/32', '<another_secondary_node_ip>/32']
+ ```
- You may also want to edit the `wal_keep_segments` and `max_wal_senders` to
- match your database replication requirements. Consult the [PostgreSQL -
- Replication documentation][pg-docs-runtime-replication]
- for more information.
+ You may also want to edit the `wal_keep_segments` and `max_wal_senders` to
+ match your database replication requirements. Consult the [PostgreSQL -
+ Replication documentation][pg-docs-runtime-replication]
+ for more information.
1. Save the file and reconfigure GitLab for the database listen changes and
the replication slot changes to be applied:
- ```sh
- gitlab-ctl reconfigure
- ```
+ ```sh
+ gitlab-ctl reconfigure
+ ```
- Restart PostgreSQL for its changes to take effect:
+ Restart PostgreSQL for its changes to take effect:
- ```sh
- gitlab-ctl restart postgresql
- ```
+ ```sh
+ gitlab-ctl restart postgresql
+ ```
1. Re-enable migrations now that PostgreSQL is restarted and listening on the
private address.
- Edit `/etc/gitlab/gitlab.rb` and **change** the configuration to `true`:
+ Edit `/etc/gitlab/gitlab.rb` and **change** the configuration to `true`:
- ```ruby
- gitlab_rails['auto_migrate'] = true
- ```
+ ```ruby
+ gitlab_rails['auto_migrate'] = true
+ ```
- Save the file and reconfigure GitLab:
+ Save the file and reconfigure GitLab:
- ```sh
- gitlab-ctl reconfigure
- ```
+ ```sh
+ gitlab-ctl reconfigure
+ ```
1. Now that the PostgreSQL server is set up to accept remote connections, run
`netstat -plnt | grep 5432` to make sure that PostgreSQL is listening on port
@@ -241,143 +243,143 @@ There is an [issue where support is being discussed](https://gitlab.com/gitlab-o
will be used automatically to protect your PostgreSQL traffic from
eavesdroppers, but to protect against active ("man-in-the-middle") attackers,
the **secondary** node needs a copy of the certificate. Make a copy of the PostgreSQL
- `server.crt` file on the **primary** node by running this command:
+ `server.crt` file on the **primary** node by running this command:
- ```sh
- cat ~gitlab-psql/data/server.crt
- ```
+ ```sh
+ cat ~gitlab-psql/data/server.crt
+ ```
- Copy the output into a clipboard or into a local file. You
- will need it when setting up the **secondary** node! The certificate is not sensitive
- data.
+ Copy the output into a clipboard or into a local file. You
+ will need it when setting up the **secondary** node! The certificate is not sensitive
+ data.
### Step 2. Configure the **secondary** server
1. SSH into your GitLab **secondary** server and login as root:
- ```
- sudo -i
- ```
+ ```
+ sudo -i
+ ```
1. Stop application server and Sidekiq
- ```
- gitlab-ctl stop unicorn
- gitlab-ctl stop sidekiq
- ```
+ ```
+ gitlab-ctl stop unicorn
+ gitlab-ctl stop sidekiq
+ ```
- NOTE: **Note**:
- This step is important so we don't try to execute anything before the node is fully configured.
+ NOTE: **Note:**
+ This step is important so we don't try to execute anything before the node is fully configured.
1. [Check TCP connectivity][rake-maintenance] to the **primary** node's PostgreSQL server:
- ```sh
- gitlab-rake gitlab:tcp_check[<primary_node_ip>,5432]
- ```
+ ```sh
+ gitlab-rake gitlab:tcp_check[<primary_node_ip>,5432]
+ ```
- NOTE: **Note**:
- If this step fails, you may be using the wrong IP address, or a firewall may
- be preventing access to the server. Check the IP address, paying close
- attention to the difference between public and private addresses and ensure
- that, if a firewall is present, the **secondary** node is permitted to connect to the
- **primary** node on port 5432.
+ NOTE: **Note:**
+ If this step fails, you may be using the wrong IP address, or a firewall may
+ be preventing access to the server. Check the IP address, paying close
+ attention to the difference between public and private addresses and ensure
+ that, if a firewall is present, the **secondary** node is permitted to connect to the
+ **primary** node on port 5432.
1. Create a file `server.crt` in the **secondary** server, with the content you got on the last step of the **primary** node's setup:
- ```
- editor server.crt
- ```
+ ```
+ editor server.crt
+ ```
1. Set up PostgreSQL TLS verification on the **secondary** node:
- Install the `server.crt` file:
+ Install the `server.crt` file:
- ```sh
- install \
- -D \
- -o gitlab-psql \
- -g gitlab-psql \
- -m 0400 \
- -T server.crt ~gitlab-psql/.postgresql/root.crt
- ```
+ ```sh
+ install \
+ -D \
+ -o gitlab-psql \
+ -g gitlab-psql \
+ -m 0400 \
+ -T server.crt ~gitlab-psql/.postgresql/root.crt
+ ```
- PostgreSQL will now only recognize that exact certificate when verifying TLS
- connections. The certificate can only be replicated by someone with access
- to the private key, which is **only** present on the **primary** node.
+ PostgreSQL will now only recognize that exact certificate when verifying TLS
+ connections. The certificate can only be replicated by someone with access
+ to the private key, which is **only** present on the **primary** node.
1. Test that the `gitlab-psql` user can connect to the **primary** node's database
(the default Omnibus database name is gitlabhq_production):
- ```sh
- sudo \
- -u gitlab-psql /opt/gitlab/embedded/bin/psql \
- --list \
- -U gitlab_replicator \
- -d "dbname=gitlabhq_production sslmode=verify-ca" \
- -W \
- -h <primary_node_ip>
- ```
+ ```sh
+ sudo \
+ -u gitlab-psql /opt/gitlab/embedded/bin/psql \
+ --list \
+ -U gitlab_replicator \
+ -d "dbname=gitlabhq_production sslmode=verify-ca" \
+ -W \
+ -h <primary_node_ip>
+ ```
- When prompted enter the password you set in the first step for the
- `gitlab_replicator` user. If all worked correctly, you should see
- the list of **primary** node's databases.
+ When prompted enter the password you set in the first step for the
+ `gitlab_replicator` user. If all worked correctly, you should see
+ the list of **primary** node's databases.
- A failure to connect here indicates that the TLS configuration is incorrect.
- Ensure that the contents of `~gitlab-psql/data/server.crt` on the **primary** node
- match the contents of `~gitlab-psql/.postgresql/root.crt` on the **secondary** node.
+ A failure to connect here indicates that the TLS configuration is incorrect.
+ Ensure that the contents of `~gitlab-psql/data/server.crt` on the **primary** node
+ match the contents of `~gitlab-psql/.postgresql/root.crt` on the **secondary** node.
1. Configure PostgreSQL to enable FDW support:
- This step is similar to how we configured the **primary** instance.
- We need to enable this, to enable FDW support, even if using a single node.
-
- Edit `/etc/gitlab/gitlab.rb` and add the following, replacing the IP
- addresses with addresses appropriate to your network configuration:
-
- ```ruby
- ##
- ## Geo Secondary role
- ## - configure dependent flags automatically to enable Geo
- ##
- roles ['geo_secondary_role']
-
- ##
- ## Secondary address
- ## - replace '<secondary_node_ip>' with the public or VPC address of your Geo secondary node
- ##
- postgresql['listen_address'] = '<secondary_node_ip>'
- postgresql['md5_auth_cidr_addresses'] = ['<secondary_node_ip>/32']
-
- ##
- ## Database credentials password (defined previously in primary node)
- ## - replicate same values here as defined in primary node
- ##
- postgresql['sql_user_password'] = '<md5_hash_of_your_password>'
- gitlab_rails['db_password'] = '<your_password_here>'
-
- ##
- ## Enable FDW support for the Geo Tracking Database (improves performance)
- ##
- geo_secondary['db_fdw'] = true
- ```
-
- For external PostgreSQL instances, see [additional instructions](external_database.md).
- If you bring a former **primary** node back online to serve as a **secondary** node, then you also need to remove `roles ['geo_primary_role']` or `geo_primary_role['enable'] = true`.
+ This step is similar to how we configured the **primary** instance.
+ We need to enable this, to enable FDW support, even if using a single node.
+
+ Edit `/etc/gitlab/gitlab.rb` and add the following, replacing the IP
+ addresses with addresses appropriate to your network configuration:
+
+ ```ruby
+ ##
+ ## Geo Secondary role
+ ## - configure dependent flags automatically to enable Geo
+ ##
+ roles ['geo_secondary_role']
+
+ ##
+ ## Secondary address
+ ## - replace '<secondary_node_ip>' with the public or VPC address of your Geo secondary node
+ ##
+ postgresql['listen_address'] = '<secondary_node_ip>'
+ postgresql['md5_auth_cidr_addresses'] = ['<secondary_node_ip>/32']
+
+ ##
+ ## Database credentials password (defined previously in primary node)
+ ## - replicate same values here as defined in primary node
+ ##
+ postgresql['sql_user_password'] = '<md5_hash_of_your_password>'
+ gitlab_rails['db_password'] = '<your_password_here>'
+
+ ##
+ ## Enable FDW support for the Geo Tracking Database (improves performance)
+ ##
+ geo_secondary['db_fdw'] = true
+ ```
+
+ For external PostgreSQL instances, see [additional instructions](external_database.md).
+ If you bring a former **primary** node back online to serve as a **secondary** node, then you also need to remove `roles ['geo_primary_role']` or `geo_primary_role['enable'] = true`.
1. Reconfigure GitLab for the changes to take effect:
- ```sh
- gitlab-ctl reconfigure
- ```
+ ```sh
+ gitlab-ctl reconfigure
+ ```
1. Restart PostgreSQL for the IP change to take effect and reconfigure again:
- ```sh
- gitlab-ctl restart postgresql
- gitlab-ctl reconfigure
- ```
+ ```sh
+ gitlab-ctl restart postgresql
+ gitlab-ctl reconfigure
+ ```
- This last reconfigure will provision the FDW configuration and enable it.
+ This last reconfigure will provision the FDW configuration and enable it.
### Step 3. Initiate the replication process
@@ -394,9 +396,9 @@ data before running `pg_basebackup`.
1. SSH into your GitLab **secondary** server and login as root:
- ```sh
- sudo -i
- ```
+ ```sh
+ sudo -i
+ ```
1. Choose a database-friendly name to use for your **secondary** node to
use as the replication slot name. For example, if your domain is
@@ -404,38 +406,40 @@ data before running `pg_basebackup`.
name as shown in the commands below.
1. Execute the command below to start a backup/restore and begin the replication
- CAUTION: **Warning:** Each Geo **secondary** node must have its own unique replication slot name.
- Using the same slot name between two secondaries will break PostgreSQL replication.
-
- ```sh
- gitlab-ctl replicate-geo-database \
- --slot-name=<secondary_node_name> \
- --host=<primary_node_ip>
- ```
-
- When prompted, enter the _plaintext_ password you set up for the `gitlab_replicator`
- user in the first step.
-
- This command also takes a number of additional options. You can use `--help`
- to list them all, but here are a couple of tips:
- - If PostgreSQL is listening on a non-standard port, add `--port=` as well.
- - If your database is too large to be transferred in 30 minutes, you will need
- to increase the timeout, e.g., `--backup-timeout=3600` if you expect the
- initial replication to take under an hour.
- - Pass `--sslmode=disable` to skip PostgreSQL TLS authentication altogether
- (e.g., you know the network path is secure, or you are using a site-to-site
- VPN). This is **not** safe over the public Internet!
- - You can read more details about each `sslmode` in the
- [PostgreSQL documentation][pg-docs-ssl];
- the instructions above are carefully written to ensure protection against
- both passive eavesdroppers and active "man-in-the-middle" attackers.
- - Change the `--slot-name` to the name of the replication slot
- to be used on the **primary** database. The script will attempt to create the
- replication slot automatically if it does not exist.
- - If you're repurposing an old server into a Geo **secondary** node, you'll need to
- add `--force` to the command line.
- - When not in a production machine you can disable backup step if you
- really sure this is what you want by adding `--skip-backup`
+
+ CAUTION: **Warning:** Each Geo **secondary** node must have its own unique replication slot name.
+ Using the same slot name between two secondaries will break PostgreSQL replication.
+
+ ```sh
+ gitlab-ctl replicate-geo-database \
+ --slot-name=<secondary_node_name> \
+ --host=<primary_node_ip>
+ ```
+
+ When prompted, enter the _plaintext_ password you set up for the `gitlab_replicator`
+ user in the first step.
+
+ This command also takes a number of additional options. You can use `--help`
+ to list them all, but here are a couple of tips:
+
+ - If PostgreSQL is listening on a non-standard port, add `--port=` as well.
+ - If your database is too large to be transferred in 30 minutes, you will need
+ to increase the timeout, e.g., `--backup-timeout=3600` if you expect the
+ initial replication to take under an hour.
+ - Pass `--sslmode=disable` to skip PostgreSQL TLS authentication altogether
+ (e.g., you know the network path is secure, or you are using a site-to-site
+ VPN). This is **not** safe over the public Internet!
+ - You can read more details about each `sslmode` in the
+ [PostgreSQL documentation][pg-docs-ssl];
+ the instructions above are carefully written to ensure protection against
+ both passive eavesdroppers and active "man-in-the-middle" attackers.
+ - Change the `--slot-name` to the name of the replication slot
+ to be used on the **primary** database. The script will attempt to create the
+ replication slot automatically if it does not exist.
+ - If you're repurposing an old server into a Geo **secondary** node, you'll need to
+ add `--force` to the command line.
+ - When not in a production machine you can disable backup step if you
+ really sure this is what you want by adding `--skip-backup`
The replication process is now complete.
@@ -452,42 +456,42 @@ it will need a separate read-only user to make [PostgreSQL FDW queries][FDW]
work:
1. On the **primary** Geo database, enter the PostgreSQL on the console as an
- admin user. If you are using an Omnibus-managed database, log onto the **primary**
- node that is running the PostgreSQL database (the default Omnibus database name is gitlabhq_production):
+ admin user. If you are using an Omnibus-managed database, log onto the **primary**
+ node that is running the PostgreSQL database (the default Omnibus database name is gitlabhq_production):
- ```sh
- sudo \
- -u gitlab-psql /opt/gitlab/embedded/bin/psql \
- -h /var/opt/gitlab/postgresql gitlabhq_production
- ```
+ ```sh
+ sudo \
+ -u gitlab-psql /opt/gitlab/embedded/bin/psql \
+ -h /var/opt/gitlab/postgresql gitlabhq_production
+ ```
1. Then create the read-only user:
- ```sql
- -- NOTE: Use the password defined earlier
- CREATE USER gitlab_geo_fdw WITH password 'mypassword';
- GRANT CONNECT ON DATABASE gitlabhq_production to gitlab_geo_fdw;
- GRANT USAGE ON SCHEMA public TO gitlab_geo_fdw;
- GRANT SELECT ON ALL TABLES IN SCHEMA public TO gitlab_geo_fdw;
- GRANT SELECT ON ALL SEQUENCES IN SCHEMA public TO gitlab_geo_fdw;
+ ```sql
+ -- NOTE: Use the password defined earlier
+ CREATE USER gitlab_geo_fdw WITH password 'mypassword';
+ GRANT CONNECT ON DATABASE gitlabhq_production to gitlab_geo_fdw;
+ GRANT USAGE ON SCHEMA public TO gitlab_geo_fdw;
+ GRANT SELECT ON ALL TABLES IN SCHEMA public TO gitlab_geo_fdw;
+ GRANT SELECT ON ALL SEQUENCES IN SCHEMA public TO gitlab_geo_fdw;
- -- Tables created by "gitlab" should be made read-only for "gitlab_geo_fdw"
- -- automatically.
- ALTER DEFAULT PRIVILEGES FOR USER gitlab IN SCHEMA public GRANT SELECT ON TABLES TO gitlab_geo_fdw;
- ALTER DEFAULT PRIVILEGES FOR USER gitlab IN SCHEMA public GRANT SELECT ON SEQUENCES TO gitlab_geo_fdw;
- ```
+ -- Tables created by "gitlab" should be made read-only for "gitlab_geo_fdw"
+ -- automatically.
+ ALTER DEFAULT PRIVILEGES FOR USER gitlab IN SCHEMA public GRANT SELECT ON TABLES TO gitlab_geo_fdw;
+ ALTER DEFAULT PRIVILEGES FOR USER gitlab IN SCHEMA public GRANT SELECT ON SEQUENCES TO gitlab_geo_fdw;
+ ```
1. On the **secondary** nodes, change `/etc/gitlab/gitlab.rb`:
- ```
- geo_postgresql['fdw_external_user'] = 'gitlab_geo_fdw'
- ```
+ ```
+ geo_postgresql['fdw_external_user'] = 'gitlab_geo_fdw'
+ ```
1. Save the file and reconfigure GitLab for the changes to be applied:
- ```sh
- gitlab-ctl reconfigure
- ```
+ ```sh
+ gitlab-ctl reconfigure
+ ```
## Troubleshooting
diff --git a/doc/administration/geo/replication/docker_registry.md b/doc/administration/geo/replication/docker_registry.md
index 5b02b861c61..d5c2d2362b1 100644
--- a/doc/administration/geo/replication/docker_registry.md
+++ b/doc/administration/geo/replication/docker_registry.md
@@ -1,4 +1,4 @@
-# Docker Registry for a secondary node **[PREMIUM ONLY]**
+# Docker Registry for a secondary node **(PREMIUM ONLY)**
You can set up a [Docker Registry] on your
**secondary** Geo node that mirrors the one on the **primary** Geo node.
diff --git a/doc/administration/geo/replication/external_database.md b/doc/administration/geo/replication/external_database.md
index 177ca68613e..85687d4a648 100644
--- a/doc/administration/geo/replication/external_database.md
+++ b/doc/administration/geo/replication/external_database.md
@@ -1,10 +1,10 @@
-# Geo with external PostgreSQL instances **[PREMIUM ONLY]**
+# Geo with external PostgreSQL instances **(PREMIUM ONLY)**
This document is relevant if you are using a PostgreSQL instance that is *not
managed by Omnibus*. This includes cloud-managed instances like AWS RDS, or
manually installed and configured PostgreSQL instances.
-NOTE: **Note**:
+NOTE: **Note:**
We strongly recommend running Omnibus-managed instances as they are actively
developed and tested. We aim to be compatible with most external
(not managed by Omnibus) databases but we do not guarantee compatibility.
@@ -13,17 +13,17 @@ developed and tested. We aim to be compatible with most external
1. SSH into a GitLab **primary** application server and login as root:
- ```sh
- sudo -i
- ```
+ ```sh
+ sudo -i
+ ```
1. Execute the command below to define the node as **primary** node:
- ```sh
- gitlab-ctl set-geo-primary-node
- ```
+ ```sh
+ gitlab-ctl set-geo-primary-node
+ ```
- This command will use your defined `external_url` in `/etc/gitlab/gitlab.rb`.
+ This command will use your defined `external_url` in `/etc/gitlab/gitlab.rb`.
### Configure the external database to be replicated
@@ -101,26 +101,27 @@ To configure the connection to the external read-replica database and enable Log
1. SSH into a GitLab **secondary** application server and login as root:
- ```bash
- sudo -i
- ```
+ ```bash
+ sudo -i
+ ```
1. Edit `/etc/gitlab/gitlab.rb` and add the following
- ```ruby
- ##
- ## Geo Secondary role
- ## - configure dependent flags automatically to enable Geo
- ##
- roles ['geo_secondary_role']
+ ```ruby
+ ##
+ ## Geo Secondary role
+ ## - configure dependent flags automatically to enable Geo
+ ##
+ roles ['geo_secondary_role']
+
+ # note this is shared between both databases,
+ # make sure you define the same password in both
+ gitlab_rails['db_password'] = '<your_password_here>'
- # note this is shared between both databases,
- # make sure you define the same password in both
- gitlab_rails['db_password'] = '<your_password_here>'
+ gitlab_rails['db_username'] = 'gitlab'
+ gitlab_rails['db_host'] = '<database_read_replica_host>'
+ ```
- gitlab_rails['db_username'] = 'gitlab'
- gitlab_rails['db_host'] = '<database_read_replica_host>'
- ```
1. Save the file and [reconfigure GitLab](../../restart_gitlab.md#omnibus-gitlab-reconfigure)
### Configure the tracking database
@@ -147,73 +148,72 @@ the tracking database on port 5432.
1. SSH into a GitLab **secondary** server and login as root:
- ```bash
- sudo -i
- ```
+ ```bash
+ sudo -i
+ ```
1. Edit `/etc/gitlab/gitlab.rb` with the connection params and credentials for
- the machine with the PostgreSQL instance:
+ the machine with the PostgreSQL instance:
- ```ruby
- geo_secondary['db_username'] = 'gitlab_geo'
- geo_secondary['db_password'] = '<your_password_here>'
+ ```ruby
+ geo_secondary['db_username'] = 'gitlab_geo'
+ geo_secondary['db_password'] = '<your_password_here>'
- geo_secondary['db_host'] = '<tracking_database_host>'
- geo_secondary['db_port'] = <tracking_database_port> # change to the correct port
- geo_secondary['db_fdw'] = true # enable FDW
- geo_postgresql['enable'] = false # don't use internal managed instance
- ```
+ geo_secondary['db_host'] = '<tracking_database_host>'
+ geo_secondary['db_port'] = <tracking_database_port> # change to the correct port
+ geo_secondary['db_fdw'] = true # enable FDW
+ geo_postgresql['enable'] = false # don't use internal managed instance
+ ```
1. Save the file and [reconfigure GitLab](../../restart_gitlab.md#omnibus-gitlab-reconfigure)
1. Run the tracking database migrations:
- ```bash
- gitlab-rake geo:db:create
- gitlab-rake geo:db:migrate
- ```
-
-1. Configure the
- [PostgreSQL FDW](https://www.postgresql.org/docs/9.6/static/postgres-fdw.html)
- connection and credentials:
-
- Save the script below in a file, ex. `/tmp/geo_fdw.sh` and modify the connection
- params to match your environment. Execute it to set up the FDW connection.
-
- ```bash
- #!/bin/bash
-
- # Secondary Database connection params:
- DB_HOST="<public_ip_or_vpc_private_ip>"
- DB_NAME="gitlabhq_production"
- DB_USER="gitlab"
- DB_PASS="<your_password_here>"
- DB_PORT="5432"
-
- # Tracking Database connection params:
- GEO_DB_HOST="<public_ip_or_vpc_private_ip>"
- GEO_DB_NAME="gitlabhq_geo_production"
- GEO_DB_USER="gitlab_geo"
- GEO_DB_PORT="5432"
-
- query_exec () {
- gitlab-psql -h $GEO_DB_HOST -d $GEO_DB_NAME -p $GEO_DB_PORT -c "${1}"
- }
-
- query_exec "CREATE EXTENSION postgres_fdw;"
- query_exec "CREATE SERVER gitlab_secondary FOREIGN DATA WRAPPER postgres_fdw OPTIONS (host '${DB_HOST}', dbname '${DB_NAME}', port '${DB_PORT}');"
- query_exec "CREATE USER MAPPING FOR ${GEO_DB_USER} SERVER gitlab_secondary OPTIONS (user '${DB_USER}', password '${DB_PASS}');"
- query_exec "CREATE SCHEMA gitlab_secondary;"
- query_exec "GRANT USAGE ON FOREIGN SERVER gitlab_secondary TO ${GEO_DB_USER};"
- ```
-
- NOTE: **Note:** The script template above uses `gitlab-psql` as it's intended to be executed from the Geo machine,
- but you can change it to `psql` and run it from any machine that has access to the database. We also recommend using
- `psql` for AWS RDS.
+ ```bash
+ gitlab-rake geo:db:create
+ gitlab-rake geo:db:migrate
+ ```
+
+1. Configure the [PostgreSQL FDW](https://www.postgresql.org/docs/9.6/static/postgres-fdw.html)
+ connection and credentials:
+
+ Save the script below in a file, ex. `/tmp/geo_fdw.sh` and modify the connection
+ params to match your environment. Execute it to set up the FDW connection.
+
+ ```bash
+ #!/bin/bash
+
+ # Secondary Database connection params:
+ DB_HOST="<public_ip_or_vpc_private_ip>"
+ DB_NAME="gitlabhq_production"
+ DB_USER="gitlab"
+ DB_PASS="<your_password_here>"
+ DB_PORT="5432"
+
+ # Tracking Database connection params:
+ GEO_DB_HOST="<public_ip_or_vpc_private_ip>"
+ GEO_DB_NAME="gitlabhq_geo_production"
+ GEO_DB_USER="gitlab_geo"
+ GEO_DB_PORT="5432"
+
+ query_exec () {
+ gitlab-psql -h $GEO_DB_HOST -d $GEO_DB_NAME -p $GEO_DB_PORT -c "${1}"
+ }
+
+ query_exec "CREATE EXTENSION postgres_fdw;"
+ query_exec "CREATE SERVER gitlab_secondary FOREIGN DATA WRAPPER postgres_fdw OPTIONS (host '${DB_HOST}', dbname '${DB_NAME}', port '${DB_PORT}');"
+ query_exec "CREATE USER MAPPING FOR ${GEO_DB_USER} SERVER gitlab_secondary OPTIONS (user '${DB_USER}', password '${DB_PASS}');"
+ query_exec "CREATE SCHEMA gitlab_secondary;"
+ query_exec "GRANT USAGE ON FOREIGN SERVER gitlab_secondary TO ${GEO_DB_USER};"
+ ```
+
+ NOTE: **Note:** The script template above uses `gitlab-psql` as it's intended to be executed from the Geo machine,
+ but you can change it to `psql` and run it from any machine that has access to the database. We also recommend using
+ `psql` for AWS RDS.
1. Save the file and [restart GitLab](../../restart_gitlab.md#omnibus-gitlab-restart)
1. Populate the FDW tables:
- ```bash
- gitlab-rake geo:db:refresh_foreign_tables
- ```
+ ```bash
+ gitlab-rake geo:db:refresh_foreign_tables
+ ```
diff --git a/doc/administration/geo/replication/faq.md b/doc/administration/geo/replication/faq.md
index c527248bc72..b3580a706c3 100644
--- a/doc/administration/geo/replication/faq.md
+++ b/doc/administration/geo/replication/faq.md
@@ -1,4 +1,4 @@
-# Geo Frequently Asked Questions **[PREMIUM ONLY]**
+# Geo Frequently Asked Questions **(PREMIUM ONLY)**
## What are the minimum requirements to run Geo?
diff --git a/doc/administration/geo/replication/high_availability.md b/doc/administration/geo/replication/high_availability.md
index 28ad89c4446..c737fa37077 100644
--- a/doc/administration/geo/replication/high_availability.md
+++ b/doc/administration/geo/replication/high_availability.md
@@ -1,4 +1,4 @@
-# Geo High Availability **[PREMIUM ONLY]**
+# Geo High Availability **(PREMIUM ONLY)**
This document describes a minimal reference architecture for running Geo
in a high availability configuration. If your HA setup differs from the one
@@ -50,17 +50,17 @@ The following steps enable a GitLab cluster to serve as the **primary** node.
1. Edit `/etc/gitlab/gitlab.rb` and add the following:
- ```ruby
- ##
- ## Enable the Geo primary role
- ##
- roles ['geo_primary_role']
+ ```ruby
+ ##
+ ## Enable the Geo primary role
+ ##
+ roles ['geo_primary_role']
- ##
- ## Disable automatic migrations
- ##
- gitlab_rails['auto_migrate'] = false
- ```
+ ##
+ ## Disable automatic migrations
+ ##
+ gitlab_rails['auto_migrate'] = false
+ ```
After making these changes, [reconfigure GitLab][gitlab-reconfigure] so the changes take effect.
@@ -107,36 +107,36 @@ Configure the [**secondary** database](database.md) as a read-only replica of
the **primary** database. Use the following as a guide.
1. Edit `/etc/gitlab/gitlab.rb` in the replica database machine, and add the
- following:
-
- ```ruby
- ##
- ## Configure the PostgreSQL role
- ##
- roles ['postgres_role']
-
- ##
- ## Secondary address
- ## - replace '<secondary_node_ip>' with the public or VPC address of your Geo secondary node
- ## - replace '<tracking_database_ip>' with the public or VPC address of your Geo tracking database node
- ##
- postgresql['listen_address'] = '<secondary_node_ip>'
- postgresql['md5_auth_cidr_addresses'] = ['<secondary_node_ip>/32', '<tracking_database_ip>/32']
-
- ##
- ## Database credentials password (defined previously in primary node)
- ## - replicate same values here as defined in primary node
- ##
- postgresql['sql_user_password'] = '<md5_hash_of_your_password>'
- gitlab_rails['db_password'] = '<your_password_here>'
-
- ##
- ## When running the Geo tracking database on a separate machine, disable it
- ## here and allow connections from the tracking database host. And ensure
- ## the tracking database IP is in postgresql['md5_auth_cidr_addresses'] above.
- ##
- geo_postgresql['enable'] = false
- ```
+ following:
+
+ ```ruby
+ ##
+ ## Configure the PostgreSQL role
+ ##
+ roles ['postgres_role']
+
+ ##
+ ## Secondary address
+ ## - replace '<secondary_node_ip>' with the public or VPC address of your Geo secondary node
+ ## - replace '<tracking_database_ip>' with the public or VPC address of your Geo tracking database node
+ ##
+ postgresql['listen_address'] = '<secondary_node_ip>'
+ postgresql['md5_auth_cidr_addresses'] = ['<secondary_node_ip>/32', '<tracking_database_ip>/32']
+
+ ##
+ ## Database credentials password (defined previously in primary node)
+ ## - replicate same values here as defined in primary node
+ ##
+ postgresql['sql_user_password'] = '<md5_hash_of_your_password>'
+ gitlab_rails['db_password'] = '<your_password_here>'
+
+ ##
+ ## When running the Geo tracking database on a separate machine, disable it
+ ## here and allow connections from the tracking database host. And ensure
+ ## the tracking database IP is in postgresql['md5_auth_cidr_addresses'] above.
+ ##
+ geo_postgresql['enable'] = false
+ ```
After making these changes, [reconfigure GitLab][gitlab-reconfigure] so the changes take effect.
@@ -151,47 +151,47 @@ only a single machine, rather than as a PostgreSQL cluster.
Configure the tracking database.
1. Edit `/etc/gitlab/gitlab.rb` in the tracking database machine, and add the
- following:
-
- ```ruby
- ##
- ## Enable the Geo secondary tracking database
- ##
- geo_postgresql['enable'] = true
- geo_postgresql['listen_address'] = '<ip_address_of_this_host>'
- geo_postgresql['sql_user_password'] = '<tracking_database_password_md5_hash>'
-
- ##
- ## Configure FDW connection to the replica database
- ##
- geo_secondary['db_fdw'] = true
- geo_postgresql['fdw_external_password'] = '<replica_database_password_plaintext>'
- geo_postgresql['md5_auth_cidr_addresses'] = ['<replica_database_ip>/32']
- gitlab_rails['db_host'] = '<replica_database_ip>'
-
- # Prevent reconfigure from attempting to run migrations on the replica DB
- gitlab_rails['auto_migrate'] = false
-
- ##
- ## Disable all other services that aren't needed, since we don't have a role
- ## that does this.
- ##
- alertmanager['enable'] = false
- consul['enable'] = false
- gitaly['enable'] = false
- gitlab_monitor['enable'] = false
- gitlab_workhorse['enable'] = false
- nginx['enable'] = false
- node_exporter['enable'] = false
- pgbouncer_exporter['enable'] = false
- postgresql['enable'] = false
- prometheus['enable'] = false
- redis['enable'] = false
- redis_exporter['enable'] = false
- repmgr['enable'] = false
- sidekiq['enable'] = false
- unicorn['enable'] = false
- ```
+ following:
+
+ ```ruby
+ ##
+ ## Enable the Geo secondary tracking database
+ ##
+ geo_postgresql['enable'] = true
+ geo_postgresql['listen_address'] = '<ip_address_of_this_host>'
+ geo_postgresql['sql_user_password'] = '<tracking_database_password_md5_hash>'
+
+ ##
+ ## Configure FDW connection to the replica database
+ ##
+ geo_secondary['db_fdw'] = true
+ geo_postgresql['fdw_external_password'] = '<replica_database_password_plaintext>'
+ geo_postgresql['md5_auth_cidr_addresses'] = ['<replica_database_ip>/32']
+ gitlab_rails['db_host'] = '<replica_database_ip>'
+
+ # Prevent reconfigure from attempting to run migrations on the replica DB
+ gitlab_rails['auto_migrate'] = false
+
+ ##
+ ## Disable all other services that aren't needed, since we don't have a role
+ ## that does this.
+ ##
+ alertmanager['enable'] = false
+ consul['enable'] = false
+ gitaly['enable'] = false
+ gitlab_monitor['enable'] = false
+ gitlab_workhorse['enable'] = false
+ nginx['enable'] = false
+ node_exporter['enable'] = false
+ pgbouncer_exporter['enable'] = false
+ postgresql['enable'] = false
+ prometheus['enable'] = false
+ redis['enable'] = false
+ redis_exporter['enable'] = false
+ repmgr['enable'] = false
+ sidekiq['enable'] = false
+ unicorn['enable'] = false
+ ```
After making these changes, [reconfigure GitLab][gitlab-reconfigure] so the changes take effect.
@@ -211,50 +211,50 @@ following modifications:
1. Edit `/etc/gitlab/gitlab.rb` on each application server in the **secondary**
cluster, and add the following:
- ```ruby
- ##
- ## Enable the Geo secondary role
- ##
- roles ['geo_secondary_role', 'application_role']
-
- ##
- ## Disable automatic migrations
- ##
- gitlab_rails['auto_migrate'] = false
-
- ##
- ## Configure the connection to the tracking DB. And disable application
- ## servers from running tracking databases.
- ##
- geo_secondary['db_host'] = '<geo_tracking_db_host>'
- geo_secondary['db_password'] = '<geo_tracking_db_password>'
- geo_postgresql['enable'] = false
-
- ##
- ## Configure connection to the streaming replica database, if you haven't
- ## already
- ##
- gitlab_rails['db_host'] = '<replica_database_host>'
- gitlab_rails['db_password'] = '<replica_database_password>'
-
- ##
- ## Configure connection to Redis, if you haven't already
- ##
- gitlab_rails['redis_host'] = '<redis_host>'
- gitlab_rails['redis_password'] = '<redis_password>'
-
- ##
- ## If you are using custom users not managed by Omnibus, you need to specify
- ## UIDs and GIDs like below, and ensure they match between servers in a
- ## cluster to avoid permissions issues
- ##
- user['uid'] = 9000
- user['gid'] = 9000
- web_server['uid'] = 9001
- web_server['gid'] = 9001
- registry['uid'] = 9002
- registry['gid'] = 9002
- ```
+ ```ruby
+ ##
+ ## Enable the Geo secondary role
+ ##
+ roles ['geo_secondary_role', 'application_role']
+
+ ##
+ ## Disable automatic migrations
+ ##
+ gitlab_rails['auto_migrate'] = false
+
+ ##
+ ## Configure the connection to the tracking DB. And disable application
+ ## servers from running tracking databases.
+ ##
+ geo_secondary['db_host'] = '<geo_tracking_db_host>'
+ geo_secondary['db_password'] = '<geo_tracking_db_password>'
+ geo_postgresql['enable'] = false
+
+ ##
+ ## Configure connection to the streaming replica database, if you haven't
+ ## already
+ ##
+ gitlab_rails['db_host'] = '<replica_database_host>'
+ gitlab_rails['db_password'] = '<replica_database_password>'
+
+ ##
+ ## Configure connection to Redis, if you haven't already
+ ##
+ gitlab_rails['redis_host'] = '<redis_host>'
+ gitlab_rails['redis_password'] = '<redis_password>'
+
+ ##
+ ## If you are using custom users not managed by Omnibus, you need to specify
+ ## UIDs and GIDs like below, and ensure they match between servers in a
+ ## cluster to avoid permissions issues
+ ##
+ user['uid'] = 9000
+ user['gid'] = 9000
+ web_server['uid'] = 9001
+ web_server['gid'] = 9001
+ registry['uid'] = 9002
+ registry['gid'] = 9002
+ ```
NOTE: **Note:**
If you had set up PostgreSQL cluster using the omnibus package and you had set
diff --git a/doc/administration/geo/replication/index.md b/doc/administration/geo/replication/index.md
index 54377f7ae4e..f0d329d5296 100644
--- a/doc/administration/geo/replication/index.md
+++ b/doc/administration/geo/replication/index.md
@@ -1,4 +1,4 @@
-# Geo Replication **[PREMIUM ONLY]**
+# Geo Replication **(PREMIUM ONLY)**
Geo is the solution for widely distributed development teams.
@@ -80,8 +80,8 @@ In this diagram:
- If present, the [LDAP server](#ldap) should be configured to replicate for [Disaster Recovery](../disaster_recovery/index.md) scenarios.
- A **secondary** node performs different type of synchronizations against the **primary** node, using a special
authorization protected by JWT:
- - Repositories are cloned/updated via Git over HTTPS.
- - Attachments, LFS objects, and other files are downloaded via HTTPS using a private API endpoint.
+ - Repositories are cloned/updated via Git over HTTPS.
+ - Attachments, LFS objects, and other files are downloaded via HTTPS using a private API endpoint.
From the perspective of a user performing Git operations:
@@ -107,8 +107,8 @@ The following are required to run Geo:
- An operating system that supports OpenSSH 6.9+ (needed for
[fast lookup of authorized SSH keys in the database](../../operations/fast_ssh_key_lookup.md))
The following operating systems are known to ship with a current version of OpenSSH:
- - [CentOS](https://www.centos.org) 7.4+
- - [Ubuntu](https://www.ubuntu.com) 16.04+
+ - [CentOS](https://www.centos.org) 7.4+
+ - [Ubuntu](https://www.ubuntu.com) 16.04+
- PostgreSQL 9.6+ with [FDW](https://www.postgresql.org/docs/9.6/postgres-fdw.html) support and [Streaming Replication](https://wiki.postgresql.org/wiki/Streaming_Replication)
- Git 2.9+
@@ -178,7 +178,7 @@ The steps below should be followed in the order they appear. **Make sure the Git
If you installed GitLab using the Omnibus packages (highly recommended):
-1. [Install GitLab Enterprise Edition](https://about.gitlab.com/installation/) on the server that will serve as the **secondary** node. Do not create an account or log in to the new **secondary** node.
+1. [Install GitLab Enterprise Edition](https://about.gitlab.com/install/) on the server that will serve as the **secondary** node. Do not create an account or log in to the new **secondary** node.
1. [Upload the GitLab License](../../../user/admin_area/license.md) on the **primary** node to unlock Geo. The license must be for [GitLab Premium](https://about.gitlab.com/pricing/) or higher.
1. [Set up the database replication](database.md) (`primary (read-write) <-> secondary (read-only)` topology).
1. [Configure fast lookup of authorized SSH keys in the database](../../operations/fast_ssh_key_lookup.md). This step is required and needs to be done on **both** the **primary** and **secondary** nodes.
diff --git a/doc/administration/geo/replication/object_storage.md b/doc/administration/geo/replication/object_storage.md
index c3c11dbaf1e..878b67a8f8e 100644
--- a/doc/administration/geo/replication/object_storage.md
+++ b/doc/administration/geo/replication/object_storage.md
@@ -1,4 +1,4 @@
-# Geo with Object storage **[PREMIUM ONLY]**
+# Geo with Object storage **(PREMIUM ONLY)**
Geo can be used in combination with Object Storage (AWS S3, or
other compatible object storage).
@@ -34,10 +34,10 @@ the bucket used by **secondary** nodes.
If you are using Google Cloud Storage, consider using
[Multi-Regional Storage](https://cloud.google.com/storage/docs/storage-classes#multi-regional).
-Or you can use the [Storage Transfer Service](https://cloud.google.com/storage/transfer/),
+Or you can use the [Storage Transfer Service](https://cloud.google.com/storage-transfer/docs/),
although this only supports daily synchronization.
For manual synchronization, or scheduled by `cron`, please have a look at:
-- [`s3cmd sync`](http://s3tools.org/s3cmd-sync)
+- [`s3cmd sync`](https://s3tools.org/s3cmd-sync)
- [`gsutil rsync`](https://cloud.google.com/storage/docs/gsutil/commands/rsync)
diff --git a/doc/administration/geo/replication/remove_geo_node.md b/doc/administration/geo/replication/remove_geo_node.md
index b190fe7d42d..4f64e21f8ef 100644
--- a/doc/administration/geo/replication/remove_geo_node.md
+++ b/doc/administration/geo/replication/remove_geo_node.md
@@ -1,4 +1,4 @@
-# Removing secondary Geo nodes **[PREMIUM ONLY]**
+# Removing secondary Geo nodes **(PREMIUM ONLY)**
**Secondary** nodes can be removed from the Geo cluster using the Geo admin page of the **primary** node. To remove a **secondary** node:
@@ -10,41 +10,42 @@ Once removed from the Geo admin page, you must stop and uninstall the **secondar
1. On the **secondary** node, stop GitLab:
- ```bash
- sudo gitlab-ctl stop
- ```
+ ```bash
+ sudo gitlab-ctl stop
+ ```
+
1. On the **secondary** node, uninstall GitLab:
- ```bash
- # Stop gitlab and remove its supervision process
- sudo gitlab-ctl uninstall
+ ```bash
+ # Stop gitlab and remove its supervision process
+ sudo gitlab-ctl uninstall
- # Debian/Ubuntu
- sudo dpkg --remove gitlab-ee
+ # Debian/Ubuntu
+ sudo dpkg --remove gitlab-ee
- # Redhat/Centos
- sudo rpm --erase gitlab-ee
- ```
+ # Redhat/Centos
+ sudo rpm --erase gitlab-ee
+ ```
Once GitLab has been uninstalled from the **secondary** node, the replication slot must be dropped from the **primary** node's database as follows:
1. On the **primary** node, start a PostgreSQL console session:
- ```bash
- sudo gitlab-psql
- ```
+ ```bash
+ sudo gitlab-psql
+ ```
- NOTE: **Note:**
- Using `gitlab-rails dbconsole` will not work, because managing replication slots requires superuser permissions.
+ NOTE: **Note:**
+ Using `gitlab-rails dbconsole` will not work, because managing replication slots requires superuser permissions.
1. Find the name of the relevant replication slot. This is the slot that is specified with `--slot-name` when running the replicate command: `gitlab-ctl replicate-geo-database`.
- ```sql
- SELECT * FROM pg_replication_slots;
- ```
+ ```sql
+ SELECT * FROM pg_replication_slots;
+ ```
1. Remove the replication slot for the **secondary** node:
- ```sql
- SELECT pg_drop_replication_slot('<name_of_slot>');
- ```
+ ```sql
+ SELECT pg_drop_replication_slot('<name_of_slot>');
+ ```
diff --git a/doc/administration/geo/replication/security_review.md b/doc/administration/geo/replication/security_review.md
index cd54e2dc8c4..ed3f1faa93e 100644
--- a/doc/administration/geo/replication/security_review.md
+++ b/doc/administration/geo/replication/security_review.md
@@ -1,4 +1,4 @@
-# Geo security review (Q&A) **[PREMIUM ONLY]**
+# Geo security review (Q&A) **(PREMIUM ONLY)**
The following security review of the Geo feature set focuses on security
aspects of the feature as they apply to customers running their own GitLab
@@ -115,7 +115,7 @@ questions from [owasp.org](https://www.owasp.org).
### What operating systems support the application?
- Geo imposes no additional restrictions on operating system (see the
- [GitLab installation](https://about.gitlab.com/installation/) page for more
+ [GitLab installation](https://about.gitlab.com/install/) page for more
details), however we recommend using the operating systems listed in the [Geo documentation](index.md#requirements-for-running-geo).
### What details regarding required OS components and lock‐down needs have been defined?
diff --git a/doc/administration/geo/replication/troubleshooting.md b/doc/administration/geo/replication/troubleshooting.md
index 5bd6cc81362..28abfff973d 100644
--- a/doc/administration/geo/replication/troubleshooting.md
+++ b/doc/administration/geo/replication/troubleshooting.md
@@ -1,4 +1,4 @@
-# Geo Troubleshooting **[PREMIUM ONLY]**
+# Geo Troubleshooting **(PREMIUM ONLY)**
Setting up Geo requires careful attention to details and sometimes it's easy to
miss a step.
@@ -184,17 +184,17 @@ log data to build up in `pg_xlog`. Removing the unused slots can reduce the amou
1. Start a PostgreSQL console session:
- ```sh
- sudo gitlab-psql gitlabhq_production
- ```
+ ```sh
+ sudo gitlab-psql gitlabhq_production
+ ```
- > Note that using `gitlab-rails dbconsole` will not work, because managing replication slots requires superuser permissions.
+ Note: **Note:** Using `gitlab-rails dbconsole` will not work, because managing replication slots requires superuser permissions.
1. View your replication slots with:
- ```sql
- SELECT * FROM pg_replication_slots;
- ```
+ ```sql
+ SELECT * FROM pg_replication_slots;
+ ```
Slots where `active` is `f` are not active.
@@ -204,9 +204,9 @@ Slots where `active` is `f` are not active.
- If you are no longer using the slot (e.g. you no longer have Geo enabled), you can remove it with in the
PostgreSQL console session:
- ```sql
- SELECT pg_drop_replication_slot('<name_of_extra_slot>');
- ```
+ ```sql
+ SELECT pg_drop_replication_slot('<name_of_extra_slot>');
+ ```
### Very large repositories never successfully synchronize on the **secondary** node
@@ -237,82 +237,82 @@ to start again from scratch, there are a few steps that can help you:
1. Stop Sidekiq and the Geo LogCursor
- It's possible to make Sidekiq stop gracefully, but making it stop getting new jobs and
- wait until the current jobs to finish processing.
+ It's possible to make Sidekiq stop gracefully, but making it stop getting new jobs and
+ wait until the current jobs to finish processing.
- You need to send a **SIGTSTP** kill signal for the first phase and them a **SIGTERM**
- when all jobs have finished. Otherwise just use the `gitlab-ctl stop` commands.
+ You need to send a **SIGTSTP** kill signal for the first phase and them a **SIGTERM**
+ when all jobs have finished. Otherwise just use the `gitlab-ctl stop` commands.
- ```sh
- gitlab-ctl status sidekiq
- # run: sidekiq: (pid 10180) <- this is the PID you will use
- kill -TSTP 10180 # change to the correct PID
+ ```sh
+ gitlab-ctl status sidekiq
+ # run: sidekiq: (pid 10180) <- this is the PID you will use
+ kill -TSTP 10180 # change to the correct PID
- gitlab-ctl stop sidekiq
- gitlab-ctl stop geo-logcursor
- ```
+ gitlab-ctl stop sidekiq
+ gitlab-ctl stop geo-logcursor
+ ```
- You can watch sidekiq logs to know when sidekiq jobs processing have finished:
+ You can watch sidekiq logs to know when sidekiq jobs processing have finished:
- ```sh
- gitlab-ctl tail sidekiq
- ```
+ ```sh
+ gitlab-ctl tail sidekiq
+ ```
1. Rename repository storage folders and create new ones
- ```sh
- mv /var/opt/gitlab/git-data/repositories /var/opt/gitlab/git-data/repositories.old
- mkdir -p /var/opt/gitlab/git-data/repositories
- chown git:git /var/opt/gitlab/git-data/repositories
- ```
+ ```sh
+ mv /var/opt/gitlab/git-data/repositories /var/opt/gitlab/git-data/repositories.old
+ mkdir -p /var/opt/gitlab/git-data/repositories
+ chown git:git /var/opt/gitlab/git-data/repositories
+ ```
- TIP: **Tip**
- You may want to remove the `/var/opt/gitlab/git-data/repositories.old` in the future
- as soon as you confirmed that you don't need it anymore, to save disk space.
+ TIP: **Tip**
+ You may want to remove the `/var/opt/gitlab/git-data/repositories.old` in the future
+ as soon as you confirmed that you don't need it anymore, to save disk space.
1. _(Optional)_ Rename other data folders and create new ones
- CAUTION: **Caution**:
- You may still have files on the **secondary** node that have been removed from **primary** node but
- removal have not been reflected. If you skip this step, they will never be removed
- from this Geo node.
+ CAUTION: **Caution**:
+ You may still have files on the **secondary** node that have been removed from **primary** node but
+ removal have not been reflected. If you skip this step, they will never be removed
+ from this Geo node.
- Any uploaded content like file attachments, avatars or LFS objects are stored in a
- subfolder in one of the two paths below:
+ Any uploaded content like file attachments, avatars or LFS objects are stored in a
+ subfolder in one of the two paths below:
- 1. /var/opt/gitlab/gitlab-rails/shared
- 1. /var/opt/gitlab/gitlab-rails/uploads
+ - /var/opt/gitlab/gitlab-rails/shared
+ - /var/opt/gitlab/gitlab-rails/uploads
- To rename all of them:
+ To rename all of them:
- ```sh
- gitlab-ctl stop
+ ```sh
+ gitlab-ctl stop
- mv /var/opt/gitlab/gitlab-rails/shared /var/opt/gitlab/gitlab-rails/shared.old
- mkdir -p /var/opt/gitlab/gitlab-rails/shared
+ mv /var/opt/gitlab/gitlab-rails/shared /var/opt/gitlab/gitlab-rails/shared.old
+ mkdir -p /var/opt/gitlab/gitlab-rails/shared
- mv /var/opt/gitlab/gitlab-rails/uploads /var/opt/gitlab/gitlab-rails/uploads.old
- mkdir -p /var/opt/gitlab/gitlab-rails/uploads
- ```
+ mv /var/opt/gitlab/gitlab-rails/uploads /var/opt/gitlab/gitlab-rails/uploads.old
+ mkdir -p /var/opt/gitlab/gitlab-rails/uploads
+ ```
- Reconfigure in order to recreate the folders and make sure permissions and ownership
- are correctly
+ Reconfigure in order to recreate the folders and make sure permissions and ownership
+ are correctly
- ```sh
- gitlab-ctl reconfigure
- ```
+ ```sh
+ gitlab-ctl reconfigure
+ ```
1. Reset the Tracking Database
- ```sh
- gitlab-rake geo:db:reset
- ```
+ ```sh
+ gitlab-rake geo:db:reset
+ ```
1. Restart previously stopped services
- ```sh
- gitlab-ctl start
- ```
+ ```sh
+ gitlab-ctl start
+ ```
## Fixing Foreign Data Wrapper errors
@@ -345,108 +345,106 @@ To check the configuration:
1. Enter the database console:
- ```sh
- gitlab-geo-psql
- ```
+ ```sh
+ gitlab-geo-psql
+ ```
1. Check whether any tables are present. If everything is working, you
should see something like this:
- ```sql
- gitlabhq_geo_production=# SELECT * from information_schema.foreign_tables;
- foreign_table_catalog | foreign_table_schema | foreign_table_name | foreign_server_catalog | foreign_server_n
- ame
- -------------------------+----------------------+-------------------------------------------------+-------------------------+-----------------
- ----
- gitlabhq_geo_production | gitlab_secondary | abuse_reports | gitlabhq_geo_production | gitlab_secondary
- gitlabhq_geo_production | gitlab_secondary | appearances | gitlabhq_geo_production | gitlab_secondary
- gitlabhq_geo_production | gitlab_secondary | application_setting_terms | gitlabhq_geo_production | gitlab_secondary
- gitlabhq_geo_production | gitlab_secondary | application_settings | gitlabhq_geo_production | gitlab_secondary
- <snip>
- ```
-
- However, if the query returns with `0 rows`, then continue onto the next steps.
+ ```sql
+ gitlabhq_geo_production=# SELECT * from information_schema.foreign_tables;
+ foreign_table_catalog | foreign_table_schema | foreign_table_name | foreign_server_catalog | foreign_server_name
+ -------------------------+----------------------+-------------------------------------------------+-------------------------+---------------------
+ gitlabhq_geo_production | gitlab_secondary | abuse_reports | gitlabhq_geo_production | gitlab_secondary
+ gitlabhq_geo_production | gitlab_secondary | appearances | gitlabhq_geo_production | gitlab_secondary
+ gitlabhq_geo_production | gitlab_secondary | application_setting_terms | gitlabhq_geo_production | gitlab_secondary
+ gitlabhq_geo_production | gitlab_secondary | application_settings | gitlabhq_geo_production | gitlab_secondary
+ <snip>
+ ```
+
+ However, if the query returns with `0 rows`, then continue onto the next steps.
1. Check that the foreign server mapping is correct via `\des+`. The
results should look something like this:
- ```sql
- gitlabhq_geo_production=# \des+
- List of foreign servers
- -[ RECORD 1 ]--------+------------------------------------------------------------
- Name | gitlab_secondary
- Owner | gitlab-psql
- Foreign-data wrapper | postgres_fdw
- Access privileges | "gitlab-psql"=U/"gitlab-psql" +
- | gitlab_geo=U/"gitlab-psql"
- Type |
- Version |
- FDW Options | (host '0.0.0.0', port '5432', dbname 'gitlabhq_production')
- Description |
- ```
-
- NOTE: **Note:** Pay particular attention to the host and port under
- FDW options. That configuration should point to the Geo secondary
- database.
-
- If you need to experiment with changing the host or password, the
- following queries demonstrate how:
-
- ```sql
- ALTER SERVER gitlab_secondary OPTIONS (SET host '<my_new_host>');
- ALTER SERVER gitlab_secondary OPTIONS (SET port 5432);
- ```
-
- If you change the host and/or port, you will also have to adjust the
- following settings in `/etc/gitlab/gitlab.rb` and run `gitlab-ctl
- reconfigure`:
-
- - `gitlab_rails['db_host']`
- - `gitlab_rails['db_port']`
+ ```sql
+ gitlabhq_geo_production=# \des+
+ List of foreign servers
+ -[ RECORD 1 ]--------+------------------------------------------------------------
+ Name | gitlab_secondary
+ Owner | gitlab-psql
+ Foreign-data wrapper | postgres_fdw
+ Access privileges | "gitlab-psql"=U/"gitlab-psql" +
+ | gitlab_geo=U/"gitlab-psql"
+ Type |
+ Version |
+ FDW Options | (host '0.0.0.0', port '5432', dbname 'gitlabhq_production')
+ Description |
+ ```
+
+ NOTE: **Note:** Pay particular attention to the host and port under
+ FDW options. That configuration should point to the Geo secondary
+ database.
+
+ If you need to experiment with changing the host or password, the
+ following queries demonstrate how:
+
+ ```sql
+ ALTER SERVER gitlab_secondary OPTIONS (SET host '<my_new_host>');
+ ALTER SERVER gitlab_secondary OPTIONS (SET port 5432);
+ ```
+
+ If you change the host and/or port, you will also have to adjust the
+ following settings in `/etc/gitlab/gitlab.rb` and run `gitlab-ctl
+ reconfigure`:
+
+ - `gitlab_rails['db_host']`
+ - `gitlab_rails['db_port']`
1. Check that the user mapping is configured properly via `\deu+`:
- ```sql
- gitlabhq_geo_production=# \deu+
- List of user mappings
- Server | User name | FDW Options
- ------------------+------------+--------------------------------------------------------------------------------
- gitlab_secondary | gitlab_geo | ("user" 'gitlab', password 'YOUR-PASSWORD-HERE')
- (1 row)
- ```
+ ```sql
+ gitlabhq_geo_production=# \deu+
+ List of user mappings
+ Server | User name | FDW Options
+ ------------------+------------+--------------------------------------------------------------------------------
+ gitlab_secondary | gitlab_geo | ("user" 'gitlab', password 'YOUR-PASSWORD-HERE')
+ (1 row)
+ ```
- Make sure the password is correct. You can test that logins work by running `psql`:
+ Make sure the password is correct. You can test that logins work by running `psql`:
- ```sh
- # Connect to the tracking database as the `gitlab_geo` user
- sudo \
- -u git /opt/gitlab/embedded/bin/psql \
- -h /var/opt/gitlab/geo-postgresql \
- -p 5431 \
- -U gitlab_geo \
- -W \
- -d gitlabhq_geo_production
- ```
+ ```sh
+ # Connect to the tracking database as the `gitlab_geo` user
+ sudo \
+ -u git /opt/gitlab/embedded/bin/psql \
+ -h /var/opt/gitlab/geo-postgresql \
+ -p 5431 \
+ -U gitlab_geo \
+ -W \
+ -d gitlabhq_geo_production
+ ```
- If you need to correct the password, the following query shows how:
+ If you need to correct the password, the following query shows how:
- ```sql
- ALTER USER MAPPING FOR gitlab_geo SERVER gitlab_secondary OPTIONS (SET password '<my_new_password>');
- ```
+ ```sql
+ ALTER USER MAPPING FOR gitlab_geo SERVER gitlab_secondary OPTIONS (SET password '<my_new_password>');
+ ```
- If you change the user or password, you will also have to adjust the
- following settings in `/etc/gitlab/gitlab.rb` and run `gitlab-ctl
- reconfigure`:
+ If you change the user or password, you will also have to adjust the
+ following settings in `/etc/gitlab/gitlab.rb` and run `gitlab-ctl
+ reconfigure`:
- - `gitlab_rails['db_username']`
- - `gitlab_rails['db_password']`
+ - `gitlab_rails['db_username']`
+ - `gitlab_rails['db_password']`
- If you are using [PgBouncer in front of the secondary
- database](database.md#pgbouncer-support-optional), be sure to update
- the following settings:
+ If you are using [PgBouncer in front of the secondary
+ database](database.md#pgbouncer-support-optional), be sure to update
+ the following settings:
- - `geo_postgresql['fdw_external_user']`
- - `geo_postgresql['fdw_external_password']`
+ - `geo_postgresql['fdw_external_user']`
+ - `geo_postgresql['fdw_external_password']`
#### Manual reload of FDW schema
@@ -456,34 +454,34 @@ reload of the FDW schema. To manually reload the FDW schema:
1. On the node running the Geo tracking database, enter the PostgreSQL console via
the `gitlab_geo` user:
- ```sh
- sudo \
- -u git /opt/gitlab/embedded/bin/psql \
- -h /var/opt/gitlab/geo-postgresql \
- -p 5431 \
- -U gitlab_geo \
- -W \
- -d gitlabhq_geo_production
- ```
+ ```sh
+ sudo \
+ -u git /opt/gitlab/embedded/bin/psql \
+ -h /var/opt/gitlab/geo-postgresql \
+ -p 5431 \
+ -U gitlab_geo \
+ -W \
+ -d gitlabhq_geo_production
+ ```
- Be sure to adjust the port and hostname for your configuration. You
- may be asked to enter a password.
+ Be sure to adjust the port and hostname for your configuration. You
+ may be asked to enter a password.
1. Reload the schema via:
- ```sql
- DROP SCHEMA IF EXISTS gitlab_secondary CASCADE;
- CREATE SCHEMA gitlab_secondary;
- GRANT USAGE ON FOREIGN SERVER gitlab_secondary TO gitlab_geo;
- IMPORT FOREIGN SCHEMA public FROM SERVER gitlab_secondary INTO gitlab_secondary;
- ```
+ ```sql
+ DROP SCHEMA IF EXISTS gitlab_secondary CASCADE;
+ CREATE SCHEMA gitlab_secondary;
+ GRANT USAGE ON FOREIGN SERVER gitlab_secondary TO gitlab_geo;
+ IMPORT FOREIGN SCHEMA public FROM SERVER gitlab_secondary INTO gitlab_secondary;
+ ```
1. Test that queries work:
- ```sql
- SELECT * from information_schema.foreign_tables;
- SELECT * FROM gitlab_secondary.projects limit 1;
- ```
+ ```sql
+ SELECT * from information_schema.foreign_tables;
+ SELECT * FROM gitlab_secondary.projects limit 1;
+ ```
[database-start-replication]: database.md#step-3-initiate-the-replication-process
[database-pg-replication]: database.md#postgresql-replication
diff --git a/doc/administration/geo/replication/tuning.md b/doc/administration/geo/replication/tuning.md
index 1943f2230df..3ee9937774a 100644
--- a/doc/administration/geo/replication/tuning.md
+++ b/doc/administration/geo/replication/tuning.md
@@ -1,4 +1,4 @@
-# Tuning Geo **[PREMIUM ONLY]**
+# Tuning Geo **(PREMIUM ONLY)**
## Changing the sync capacity values
diff --git a/doc/administration/geo/replication/updating_the_geo_nodes.md b/doc/administration/geo/replication/updating_the_geo_nodes.md
index 933a75c47d8..c27f6c78455 100644
--- a/doc/administration/geo/replication/updating_the_geo_nodes.md
+++ b/doc/administration/geo/replication/updating_the_geo_nodes.md
@@ -1,4 +1,4 @@
-# Updating the Geo nodes **[PREMIUM ONLY]**
+# Updating the Geo nodes **(PREMIUM ONLY)**
Depending on which version of Geo you are updating to/from, there may be
different steps.
@@ -30,70 +30,70 @@ We now require this change as we use this password to enable the Foreign Data Wr
the Geo Tracking Database. We are also improving security by disabling the use of **trust**
authentication method.
-1. **[primary]** Login to your **primary** node and run:
+1. **(primary)** Login to your **primary** node and run:
- ```sh
- gitlab-ctl pg-password-md5 gitlab
- # Enter password: <your_password_here>
- # Confirm password: <your_password_here>
- # fca0b89a972d69f00eb3ec98a5838484
- ```
+ ```sh
+ gitlab-ctl pg-password-md5 gitlab
+ # Enter password: <your_password_here>
+ # Confirm password: <your_password_here>
+ # fca0b89a972d69f00eb3ec98a5838484
+ ```
- Copy the generated hash and edit `/etc/gitlab/gitlab.rb`:
+ Copy the generated hash and edit `/etc/gitlab/gitlab.rb`:
- ```ruby
- # Fill with the hash generated by `gitlab-ctl pg-password-md5 gitlab`
- postgresql['sql_user_password'] = '<md5_hash_of_your_password>'
+ ```ruby
+ # Fill with the hash generated by `gitlab-ctl pg-password-md5 gitlab`
+ postgresql['sql_user_password'] = '<md5_hash_of_your_password>'
- # Every node that runs Unicorn or Sidekiq needs to have the database
- # password specified as below. If you have a high-availability setup, this
- # must be present in all application nodes.
- gitlab_rails['db_password'] = '<your_password_here>'
- ```
+ # Every node that runs Unicorn or Sidekiq needs to have the database
+ # password specified as below. If you have a high-availability setup, this
+ # must be present in all application nodes.
+ gitlab_rails['db_password'] = '<your_password_here>'
+ ```
- Still in the configuration file, locate and remove the `trust_auth_cidr_address`:
+ Still in the configuration file, locate and remove the `trust_auth_cidr_address`:
- ```ruby
- postgresql['trust_auth_cidr_addresses'] = ['127.0.0.1/32','1.2.3.4/32'] # <- Remove this
- ```
+ ```ruby
+ postgresql['trust_auth_cidr_addresses'] = ['127.0.0.1/32','1.2.3.4/32'] # <- Remove this
+ ```
-1. **[primary]** Reconfigure and restart:
+1. **(primary)** Reconfigure and restart:
- ```sh
- sudo gitlab-ctl reconfigure
- sudo gitlab-ctl restart
- ```
+ ```sh
+ sudo gitlab-ctl reconfigure
+ sudo gitlab-ctl restart
+ ```
-1. **[secondary]** Login to all **secondary** nodes and edit `/etc/gitlab/gitlab.rb`:
+1. **(secondary)** Login to all **secondary** nodes and edit `/etc/gitlab/gitlab.rb`:
- ```ruby
- # Fill with the hash generated by `gitlab-ctl pg-password-md5 gitlab`
- postgresql['sql_user_password'] = '<md5_hash_of_your_password>'
+ ```ruby
+ # Fill with the hash generated by `gitlab-ctl pg-password-md5 gitlab`
+ postgresql['sql_user_password'] = '<md5_hash_of_your_password>'
- # Every node that runs Unicorn or Sidekiq needs to have the database
- # password specified as below. If you have a high-availability setup, this
- # must be present in all application nodes.
- gitlab_rails['db_password'] = '<your_password_here>'
+ # Every node that runs Unicorn or Sidekiq needs to have the database
+ # password specified as below. If you have a high-availability setup, this
+ # must be present in all application nodes.
+ gitlab_rails['db_password'] = '<your_password_here>'
- # Enable Foreign Data Wrapper
- geo_secondary['db_fdw'] = true
+ # Enable Foreign Data Wrapper
+ geo_secondary['db_fdw'] = true
- # Secondary address in CIDR format, for example '5.6.7.8/32'
- postgresql['md5_auth_cidr_addresses'] = ['<secondary_node_ip>/32']
- ```
+ # Secondary address in CIDR format, for example '5.6.7.8/32'
+ postgresql['md5_auth_cidr_addresses'] = ['<secondary_node_ip>/32']
+ ```
- Still in the configuration file, locate and remove the `trust_auth_cidr_address`:
+ Still in the configuration file, locate and remove the `trust_auth_cidr_address`:
- ```ruby
- postgresql['trust_auth_cidr_addresses'] = ['127.0.0.1/32','5.6.7.8/32'] # <- Remove this
- ```
+ ```ruby
+ postgresql['trust_auth_cidr_addresses'] = ['127.0.0.1/32','5.6.7.8/32'] # <- Remove this
+ ```
-1. **[secondary]** Reconfigure and restart:
+1. **(secondary)** Reconfigure and restart:
- ```sh
- sudo gitlab-ctl reconfigure
- sudo gitlab-ctl restart
- ```
+ ```sh
+ sudo gitlab-ctl reconfigure
+ sudo gitlab-ctl restart
+ ```
## Upgrading to GitLab 10.5
@@ -169,11 +169,11 @@ After you've verified that HTTP/HTTPS replication is working, you should remove
the now-unused SSH keys from your secondaries, as they may cause problems if the
**secondary** node if ever promoted to a **primary** node:
-1. **[secondary]** Login to **all** your **secondary** nodes and run:
+1. **(secondary)** Login to **all** your **secondary** nodes and run:
- ```ruby
- sudo -u git -H rm ~git/.ssh/id_rsa ~git/.ssh/id_rsa.pub
- ```
+ ```ruby
+ sudo -u git -H rm ~git/.ssh/id_rsa ~git/.ssh/id_rsa.pub
+ ```
### Hashed Storage
@@ -236,12 +236,12 @@ instructions below.
When in doubt, it does not hurt to do a resync. The easiest way to do this in
Omnibus is the following:
- 1. Make sure you have Omnibus GitLab on the **primary** server.
- 1. Run `gitlab-ctl reconfigure` and `gitlab-ctl restart postgresql`. This will enable replication slots on the **primary** database.
- 1. Check the steps about defining `postgresql['sql_user_password']`, `gitlab_rails['db_password']`.
- 1. Make sure `postgresql['max_replication_slots']` matches the number of **secondary** Geo nodes locations.
- 1. Install GitLab on the **secondary** server.
- 1. Re-run the [database replication process][database-replication].
+1. Make sure you have Omnibus GitLab on the **primary** server.
+1. Run `gitlab-ctl reconfigure` and `gitlab-ctl restart postgresql`. This will enable replication slots on the **primary** database.
+1. Check the steps about defining `postgresql['sql_user_password']`, `gitlab_rails['db_password']`.
+1. Make sure `postgresql['max_replication_slots']` matches the number of **secondary** Geo nodes locations.
+1. Install GitLab on the **secondary** server.
+1. Re-run the [database replication process][database-replication].
## Special update notes for 9.0.x
@@ -260,157 +260,154 @@ Make sure to follow the steps in the exact order as they appear below and pay
extra attention in what node (either **primary** or **secondary**) you execute them! Each step
is prepended with the relevant node for better clarity:
-1. **[secondary]** Login to **all** your **secondary** nodes and stop all services:
+1. **(secondary)** Login to **all** your **secondary** nodes and stop all services:
- ```ruby
- sudo gitlab-ctl stop
- ```
+ ```ruby
+ sudo gitlab-ctl stop
+ ```
-1. **[secondary]** Make a backup of the `recovery.conf` file on **all**
+1. **(secondary)** Make a backup of the `recovery.conf` file on **all**
**secondary** nodes to preserve PostgreSQL's credentials:
- ```sh
- sudo cp /var/opt/gitlab/postgresql/data/recovery.conf /var/opt/gitlab/
- ```
+ ```sh
+ sudo cp /var/opt/gitlab/postgresql/data/recovery.conf /var/opt/gitlab/
+ ```
-1. **[primary]** Update the **primary** node to GitLab 9.0 following the
+1. **(primary)** Update the **primary** node to GitLab 9.0 following the
[regular update docs][update]. At the end of the update, the **primary** node
will be running with PostgreSQL 9.6.
-1. **[primary]** To prevent a de-synchronization of the repository replication,
+1. **(primary)** To prevent a de-synchronization of the repository replication,
stop all services except `postgresql` as we will use it to re-initialize the
**secondary** node's database:
- ```sh
- sudo gitlab-ctl stop
- sudo gitlab-ctl start postgresql
- ```
+ ```sh
+ sudo gitlab-ctl stop
+ sudo gitlab-ctl start postgresql
+ ```
-1. **[secondary]** Run the following steps on each of the **secondary** nodes:
+1. **(secondary)** Run the following steps on each of the **secondary** nodes:
- 1. **[secondary]** Stop all services:
+ 1. **(secondary)** Stop all services:
- ```sh
- sudo gitlab-ctl stop
- ```
+ ```sh
+ sudo gitlab-ctl stop
+ ```
- 1. **[secondary]** Prevent running database migrations:
+ 1. **(secondary)** Prevent running database migrations:
- ```sh
- sudo touch /etc/gitlab/skip-auto-migrations
- ```
+ ```sh
+ sudo touch /etc/gitlab/skip-auto-migrations
+ ```
- 1. **[secondary]** Move the old database to another directory:
+ 1. **(secondary)** Move the old database to another directory:
- ```sh
- sudo mv /var/opt/gitlab/postgresql{,.bak}
- ```
+ ```sh
+ sudo mv /var/opt/gitlab/postgresql{,.bak}
+ ```
- 1. **[secondary]** Update to GitLab 9.0 following the [regular update docs][update].
- At the end of the update, the node will be running with PostgreSQL 9.6.
+ 1. **(secondary)** Update to GitLab 9.0 following the [regular update docs][update].
+ At the end of the update, the node will be running with PostgreSQL 9.6.
- 1. **[secondary]** Make sure all services are up:
+ 1. **(secondary)** Make sure all services are up:
- ```sh
- sudo gitlab-ctl start
- ```
+ ```sh
+ sudo gitlab-ctl start
+ ```
- 1. **[secondary]** Reconfigure GitLab:
+ 1. **(secondary)** Reconfigure GitLab:
- ```sh
- sudo gitlab-ctl reconfigure
- ```
+ ```sh
+ sudo gitlab-ctl reconfigure
+ ```
- 1. **[secondary]** Run the PostgreSQL upgrade command:
+ 1. **(secondary)** Run the PostgreSQL upgrade command:
- ```sh
- sudo gitlab-ctl pg-upgrade
- ```
+ ```sh
+ sudo gitlab-ctl pg-upgrade
+ ```
- 1. **[secondary]** See the stored credentials for the database that you will
- need to re-initialize the replication:
+ 1. **(secondary)** See the stored credentials for the database that you will
+ need to re-initialize the replication:
- ```sh
- sudo grep -s primary_conninfo /var/opt/gitlab/recovery.conf
- ```
+ ```sh
+ sudo grep -s primary_conninfo /var/opt/gitlab/recovery.conf
+ ```
- 1. **[secondary]** Create the `replica.sh` script as described in the
- [database configuration document][database-source-replication].
+ 1. **(secondary)** Save the snippet below in a file, let's say `/tmp/replica.sh`. Modify the
+ embedded paths if necessary:
- 1. 1. **[secondary]** Save the snippet below in a file, let's say `/tmp/replica.sh`. Modify the
- embedded paths if necessary:
+ ```
+ #!/bin/bash
- ```
- #!/bin/bash
+ PORT="5432"
+ USER="gitlab_replicator"
+ echo ---------------------------------------------------------------
+ echo WARNING: Make sure this script is run from the secondary server
+ echo ---------------------------------------------------------------
+ echo
+ echo Enter the IP or FQDN of the primary PostgreSQL server
+ read HOST
+ echo Enter the password for $USER@$HOST
+ read -s PASSWORD
+ echo Enter the required sslmode
+ read SSLMODE
- PORT="5432"
- USER="gitlab_replicator"
- echo ---------------------------------------------------------------
- echo WARNING: Make sure this script is run from the secondary server
- echo ---------------------------------------------------------------
- echo
- echo Enter the IP or FQDN of the primary PostgreSQL server
- read HOST
- echo Enter the password for $USER@$HOST
- read -s PASSWORD
- echo Enter the required sslmode
- read SSLMODE
+ echo Stopping PostgreSQL and all GitLab services
+ sudo service gitlab stop
+ sudo service postgresql stop
- echo Stopping PostgreSQL and all GitLab services
- sudo service gitlab stop
- sudo service postgresql stop
+ echo Backing up postgresql.conf
+ sudo -u postgres mv /var/opt/gitlab/postgresql/data/postgresql.conf /var/opt/gitlab/postgresql/
- echo Backing up postgresql.conf
- sudo -u postgres mv /var/opt/gitlab/postgresql/data/postgresql.conf /var/opt/gitlab/postgresql/
+ echo Cleaning up old cluster directory
+ sudo -u postgres rm -rf /var/opt/gitlab/postgresql/data
- echo Cleaning up old cluster directory
- sudo -u postgres rm -rf /var/opt/gitlab/postgresql/data
+ echo Starting base backup as the replicator user
+ echo Enter the password for $USER@$HOST
+ sudo -u postgres /opt/gitlab/embedded/bin/pg_basebackup -h $HOST -D /var/opt/gitlab/postgresql/data -U gitlab_replicator -v -x -P
- echo Starting base backup as the replicator user
- echo Enter the password for $USER@$HOST
- sudo -u postgres /opt/gitlab/embedded/bin/pg_basebackup -h $HOST -D /var/opt/gitlab/postgresql/data -U gitlab_replicator -v -x -P
+ echo Writing recovery.conf file
+ sudo -u postgres bash -c "cat > /var/opt/gitlab/postgresql/data/recovery.conf <<- _EOF1_
+ standby_mode = 'on'
+ primary_conninfo = 'host=$HOST port=$PORT user=$USER password=$PASSWORD sslmode=$SSLMODE'
+ _EOF1_
+ "
- echo Writing recovery.conf file
- sudo -u postgres bash -c "cat > /var/opt/gitlab/postgresql/data/recovery.conf <<- _EOF1_
- standby_mode = 'on'
- primary_conninfo = 'host=$HOST port=$PORT user=$USER password=$PASSWORD sslmode=$SSLMODE'
- _EOF1_
- "
+ echo Restoring postgresql.conf
+ sudo -u postgres mv /var/opt/gitlab/postgresql/postgresql.conf /var/opt/gitlab/postgresql/data/
- echo Restoring postgresql.conf
- sudo -u postgres mv /var/opt/gitlab/postgresql/postgresql.conf /var/opt/gitlab/postgresql/data/
+ echo Starting PostgreSQL
+ sudo service postgresql start
+ ```
- echo Starting PostgreSQL
- sudo service postgresql start
- ```
+ 1. **(secondary)** Run the recovery script using the credentials from the
+ previous step:
- 1. **[secondary]** Run the recovery script using the credentials from the
- previous step:
+ ```sh
+ sudo bash /tmp/replica.sh
+ ```
- ```sh
- sudo bash /tmp/replica.sh
- ```
+ 1. **(secondary)** Reconfigure GitLab:
- 1. **[secondary]** Reconfigure GitLab:
+ ```sh
+ sudo gitlab-ctl reconfigure
+ ```
- ```sh
- sudo gitlab-ctl reconfigure
- ```
+ 1. **(secondary)** Start all services:
- 1. **[secondary]** Start all services:
+ ```sh
+ sudo gitlab-ctl start
+ ```
- ```sh
- sudo gitlab-ctl start
- ```
+ 1. **(secondary)** Repeat the steps for the remaining **secondary** nodes.
- 1. **[secondary]** Repeat the steps for the remaining **secondary** nodes.
-
-1. **[primary]** After all **secondary** nodes are updated, start all services in
+1. **(primary)** After all **secondary** nodes are updated, start all services in
**primary** node:
- ```sh
- sudo gitlab-ctl start
- ```
+ ```sh
+ sudo gitlab-ctl start
+ ```
## Check status after updating
@@ -419,9 +416,9 @@ everything is working correctly:
1. Run the Geo raketask on all nodes, everything should be green:
- ```sh
- sudo gitlab-rake gitlab:geo:check
- ```
+ ```sh
+ sudo gitlab-rake gitlab:geo:check
+ ```
1. Check the **primary** node's Geo dashboard for any errors.
1. Test the data replication by pushing code to the **primary** node and see if it
@@ -435,9 +432,9 @@ and it is required since 10.0.
1. Run database migrations on tracking database:
- ```sh
- sudo gitlab-rake geo:db:migrate
- ```
+ ```sh
+ sudo gitlab-rake geo:db:migrate
+ ```
1. Repeat this step for each **secondary** node.
diff --git a/doc/administration/geo/replication/using_a_geo_server.md b/doc/administration/geo/replication/using_a_geo_server.md
index f1f1fe48748..55b5d486676 100644
--- a/doc/administration/geo/replication/using_a_geo_server.md
+++ b/doc/administration/geo/replication/using_a_geo_server.md
@@ -1,6 +1,6 @@
[//]: # (Please update EE::GitLab::GeoGitAccess::GEO_SERVER_DOCS_URL if this file is moved)
-# Using a Geo Server **[PREMIUM ONLY]**
+# Using a Geo Server **(PREMIUM ONLY)**
After you set up the [database replication and configure the Geo nodes][req], use your closest GitLab node as you would a normal standalone GitLab instance.
diff --git a/doc/administration/gitaly/index.md b/doc/administration/gitaly/index.md
index 0bffe2f7472..4407facfca9 100644
--- a/doc/administration/gitaly/index.md
+++ b/doc/administration/gitaly/index.md
@@ -91,7 +91,7 @@ your GitLab installation has two repository storages, `default` and
First install Gitaly using either Omnibus or from source.
-Omnibus: [Download/install](https://about.gitlab.com/installation) the Omnibus GitLab
+Omnibus: [Download/install](https://about.gitlab.com/install/) the Omnibus GitLab
package you want using **steps 1 and 2** from the GitLab downloads page but
**_do not_** provide the `EXTERNAL_URL=` value.
@@ -220,7 +220,7 @@ network, firewall, or name resolution problem preventing your GitLab
server from reaching the Gitaly server then all Gitaly requests will
fail.
-Additionally, you need to
+Additionally, you need to
[disable Rugged if previously manually enabled](../high_availability/nfs.md#improving-nfs-performance-with-gitlab).
We assume that your Gitaly server can be reached at
@@ -247,8 +247,10 @@ gitlab:
repositories:
storages:
default:
+ path: /mnt/gitlab/default/repositories
gitaly_address: tcp://gitaly.internal:8075
storage1:
+ path: /mnt/gitlab/storage1/repositories
gitaly_address: tcp://gitaly.internal:8075
gitaly:
@@ -267,7 +269,7 @@ repository from your GitLab server over HTTP.
Gitaly supports TLS encryption. To be able to communicate
with a Gitaly instance that listens for secure connections you will need to use `tls://` url
-scheme in the `gitaly_address` of the corresponding storage entry in the gitlab configuration.
+scheme in the `gitaly_address` of the corresponding storage entry in the GitLab configuration.
The admin needs to bring their own certificate as we do not provide that automatically.
The certificate to be used needs to be installed on all Gitaly nodes and on all client nodes that communicate with it following procedures described in [GitLab custom certificate configuration](https://docs.gitlab.com/omnibus/settings/ssl.html#install-custom-public-certificates).
@@ -293,8 +295,8 @@ sum(rate(gitaly_connections_total[5m])) by (type)
```ruby
# /etc/gitlab/gitlab.rb
git_data_dirs({
- 'default' => { 'path' => '/mnt/gitlab/default', 'gitaly_address' => 'tls://gitaly.internal:9999' },
- 'storage1' => { 'path' => '/mnt/gitlab/storage1', 'gitaly_address' => 'tls://gitaly.internal:9999' },
+ 'default' => { 'gitaly_address' => 'tls://gitaly.internal:9999' },
+ 'storage1' => { 'gitaly_address' => 'tls://gitaly.internal:9999' },
})
gitlab_rails['gitaly_token'] = 'abc123secret'
@@ -434,17 +436,17 @@ particular machine.
## Eliminating NFS altogether
-If you are planning to use Gitaly without NFS for your storage needs
-and want to eliminate NFS from your environment altogether, there are
+If you are planning to use Gitaly without NFS for your storage needs
+and want to eliminate NFS from your environment altogether, there are
a few things that you need to do:
1. Make sure the [`git` user home directory](https://docs.gitlab.com/omnibus/settings/configuration.html#moving-the-home-directory-for-a-user) is on local disk.
- 1. Configure [database lookup of SSH keys](https://docs.gitlab.com/ce/administration/operations/fast_ssh_key_lookup.html)
+ 1. Configure [database lookup of SSH keys](../operations/fast_ssh_key_lookup.md)
to eliminate the need for a shared authorized_keys file.
- 1. Configure [object storage for job artifacts](https://docs.gitlab.com/ce/administration/job_artifacts.html#using-object-storage)
- including [live tracing](https://docs.gitlab.com/ce/administration/job_traces.html#new-live-trace-architecture).
- 1. Configure [object storage for LFS objects](https://docs.gitlab.com/ce/workflow/lfs/lfs_administration.html#storing-lfs-objects-in-remote-object-storage).
- 1. Configure [object storage for uploads](https://docs.gitlab.com/ce/administration/uploads.html#using-object-storage-core-only).
+ 1. Configure [object storage for job artifacts](../job_artifacts.md#using-object-storage)
+ including [live tracing](../job_traces.md#new-live-trace-architecture).
+ 1. Configure [object storage for LFS objects](../../workflow/lfs/lfs_administration.md#storing-lfs-objects-in-remote-object-storage).
+ 1. Configure [object storage for uploads](../uploads.md#using-object-storage-core-only).
NOTE: **Note:** One current feature of GitLab still requires a shared directory (NFS): [GitLab Pages](../../user/project/pages/index.md).
There is [work in progress](https://gitlab.com/gitlab-org/gitlab-pages/issues/196)
diff --git a/doc/administration/high_availability/README.md b/doc/administration/high_availability/README.md
index 0c4f926c579..e81d2741082 100644
--- a/doc/administration/high_availability/README.md
+++ b/doc/administration/high_availability/README.md
@@ -171,12 +171,12 @@ are a work-in-progress representation of the work so far. Quality will be
certifying this environment in FY20-Q2. The specifications may be adjusted
prior to certification based on performance testing.
-- 3 PostgreSQL - 4 CPU, 8GB RAM
+- 3 PostgreSQL - 4 CPU, 8GB RAM per node
- 1 PgBouncer - 2 CPU, 4GB RAM
-- 2 Redis - 2 CPU, 8GB RAM
-- 3 Consul/Sentinel - 2 CPU, 2GB RAM
-- 4 Sidekiq - 4 CPU, 8GB RAM
-- 5 GitLab application nodes - 20 CPU, 64GB RAM
+- 2 Redis - 2 CPU, 8GB RAM per node
+- 3 Consul/Sentinel - 2 CPU, 2GB RAM per node
+- 4 Sidekiq - 4 CPU, 8GB RAM per node
+- 5 GitLab application nodes - 20 CPU, 64GB RAM per node
- 1 Gitaly - 20 CPU, 64GB RAM
- 1 Monitoring node - 4 CPU, 8GB RAM
diff --git a/doc/administration/high_availability/consul.md b/doc/administration/high_availability/consul.md
index 056b7fc15d9..49199b659bc 100644
--- a/doc/administration/high_availability/consul.md
+++ b/doc/administration/high_availability/consul.md
@@ -1,11 +1,77 @@
-# Working with the bundled Consul service **[PREMIUM ONLY]**
+# Working with the bundled Consul service **(PREMIUM ONLY)**
## Overview
-As part of its High Availability stack, GitLab Premium includes a bundled version of [Consul](http://consul.io) that can be managed through `/etc/gitlab/gitlab.rb`.
+As part of its High Availability stack, GitLab Premium includes a bundled version of [Consul](https://www.consul.io/) that can be managed through `/etc/gitlab/gitlab.rb`.
A Consul cluster consists of multiple server agents, as well as client agents that run on other nodes which need to talk to the consul cluster.
+## Prerequisites
+
+First, make sure to [download/install](https://about.gitlab.com/install/)
+GitLab Omnibus **on each node**.
+
+Choose an installation method, then make sure you complete steps:
+
+1. Install and configure the necessary dependencies.
+1. Add the GitLab package repository and install the package.
+
+When installing the GitLab package, do not supply `EXTERNAL_URL` value.
+
+## Configuring the Consul nodes
+
+On each Consul node perform the following:
+
+1. Make sure you collect [`CONSUL_SERVER_NODES`](database.md#consul-information), which are the IP addresses or DNS records of the Consul server nodes, for the next step, before executing the next step.
+
+1. Edit `/etc/gitlab/gitlab.rb` replacing values noted in the `# START user configuration` section:
+
+ ```ruby
+ # Disable all components except Consul
+ roles ['consul_role']
+
+ # START user configuration
+ # Replace placeholders:
+ #
+ # Y.Y.Y.Y consul1.gitlab.example.com Z.Z.Z.Z
+ # with the addresses gathered for CONSUL_SERVER_NODES
+ consul['configuration'] = {
+ server: true,
+ retry_join: %w(Y.Y.Y.Y consul1.gitlab.example.com Z.Z.Z.Z)
+ }
+
+ # Disable auto migrations
+ gitlab_rails['auto_migrate'] = false
+ #
+ # END user configuration
+ ```
+
+ > `consul_role` was introduced with GitLab 10.3
+
+1. [Reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure) for the changes
+ to take effect.
+
+### Consul checkpoint
+
+Before moving on, make sure Consul is configured correctly. Run the following
+command to verify all server nodes are communicating:
+
+```sh
+/opt/gitlab/embedded/bin/consul members
+```
+
+The output should be similar to:
+
+```
+Node Address Status Type Build Protocol DC
+CONSUL_NODE_ONE XXX.XXX.XXX.YYY:8301 alive server 0.9.2 2 gitlab_consul
+CONSUL_NODE_TWO XXX.XXX.XXX.YYY:8301 alive server 0.9.2 2 gitlab_consul
+CONSUL_NODE_THREE XXX.XXX.XXX.YYY:8301 alive server 0.9.2 2 gitlab_consul
+```
+
+If any of the nodes isn't `alive` or if any of the three nodes are missing,
+check the [Troubleshooting section](#troubleshooting) before proceeding.
+
## Operations
### Checking cluster membership
diff --git a/doc/administration/high_availability/database.md b/doc/administration/high_availability/database.md
index 20bbfdb2603..c32a73080ff 100644
--- a/doc/administration/high_availability/database.md
+++ b/doc/administration/high_availability/database.md
@@ -1,6 +1,6 @@
# Configuring PostgreSQL for Scaling and High Availability
-## Provide your own PostgreSQL instance **[CORE ONLY]**
+## Provide your own PostgreSQL instance **(CORE ONLY)**
If you're hosting GitLab on a cloud provider, you can optionally use a
managed service for PostgreSQL. For example, AWS offers a managed Relational
@@ -21,17 +21,17 @@ This section is relevant for [Scaled Architecture](README.md#scalable-architectu
environments including [Basic Scaling](README.md#basic-scaling) and
[Full Scaling](README.md#full-scaling).
-### Provide your own PostgreSQL instance **[CORE ONLY]**
+### Provide your own PostgreSQL instance **(CORE ONLY)**
If you want to use your own deployed PostgreSQL instance(s),
see [Provide your own PostgreSQL instance](#provide-your-own-postgresql-instance-core-only)
for more details. However, you can use the GitLab Omnibus package to easily
deploy the bundled PostgreSQL.
-### Standalone PostgreSQL using GitLab Omnibus **[CORE ONLY]**
+### Standalone PostgreSQL using GitLab Omnibus **(CORE ONLY)**
1. SSH into the PostgreSQL server.
-1. [Download/install](https://about.gitlab.com/installation) the Omnibus GitLab
+1. [Download/install](https://about.gitlab.com/install/) the Omnibus GitLab
package you want using **steps 1 and 2** from the GitLab downloads page.
- Do not complete any other steps on the download page.
1. Generate a password hash for PostgreSQL. This assumes you will use the default
@@ -97,14 +97,14 @@ environments including [Horizontal](README.md#horizontal),
[Hybrid](README.md#hybrid), and
[Fully Distributed](README.md#fully-distributed).
-### Provide your own PostgreSQL instance **[CORE ONLY]**
+### Provide your own PostgreSQL instance **(CORE ONLY)**
If you want to use your own deployed PostgreSQL instance(s),
see [Provide your own PostgreSQL instance](#provide-your-own-postgresql-instance-core-only)
for more details. However, you can use the GitLab Omnibus package to easily
deploy the bundled PostgreSQL.
-### High Availability with GitLab Omnibus **[PREMIUM ONLY]**
+### High Availability with GitLab Omnibus **(PREMIUM ONLY)**
> Important notes:
>
@@ -281,68 +281,17 @@ Few notes on the service itself:
#### Installing Omnibus GitLab
-First, make sure to [download/install](https://about.gitlab.com/installation)
+First, make sure to [download/install](https://about.gitlab.com/install/)
GitLab Omnibus **on each node**.
Make sure you install the necessary dependencies from step 1,
add GitLab package repository from step 2.
When installing the GitLab package, do not supply `EXTERNAL_URL` value.
-#### Configuring the Consul nodes
-
-On each Consul node perform the following:
-
-1. Make sure you collect [`CONSUL_SERVER_NODES`](#consul-information) before executing the next step.
-
-1. Edit `/etc/gitlab/gitlab.rb` replacing values noted in the `# START user configuration` section:
-
- ```ruby
- # Disable all components except Consul
- roles ['consul_role']
-
- # START user configuration
- # Replace placeholders:
- #
- # Y.Y.Y.Y consul1.gitlab.example.com Z.Z.Z.Z
- # with the addresses gathered for CONSUL_SERVER_NODES
- consul['configuration'] = {
- server: true,
- retry_join: %w(Y.Y.Y.Y consul1.gitlab.example.com Z.Z.Z.Z)
- }
-
- # Disable auto migrations
- gitlab_rails['auto_migrate'] = false
- #
- # END user configuration
- ```
-
- > `consul_role` was introduced with GitLab 10.3
-
-1. [Reconfigure GitLab] for the changes to take effect.
-
-##### Consul Checkpoint
-
-Before moving on, make sure Consul is configured correctly. Run the following
-command to verify all server nodes are communicating:
-
-```sh
-/opt/gitlab/embedded/bin/consul members
-```
-
-The output should be similar to:
-
-```
-Node Address Status Type Build Protocol DC
-CONSUL_NODE_ONE XXX.XXX.XXX.YYY:8301 alive server 0.9.2 2 gitlab_consul
-CONSUL_NODE_TWO XXX.XXX.XXX.YYY:8301 alive server 0.9.2 2 gitlab_consul
-CONSUL_NODE_THREE XXX.XXX.XXX.YYY:8301 alive server 0.9.2 2 gitlab_consul
-```
-
-If any of the nodes isn't `alive` or if any of the three nodes are missing,
-check the [Troubleshooting section](#troubleshooting) before proceeding.
#### Configuring the Database nodes
+1. Make sure to [configure the Consul nodes](consul.md).
1. Make sure you collect [`CONSUL_SERVER_NODES`](#consul-information), [`PGBOUNCER_PASSWORD_HASH`](#pgbouncer-information), [`POSTGRESQL_PASSWORD_HASH`](#postgresql-information), the [number of db nodes](#postgresql-information), and the [network address](#network-information) before executing the next step.
1. On the master database node, edit `/etc/gitlab/gitlab.rb` replacing values noted in the `# START user configuration` section:
@@ -570,7 +519,7 @@ Check the [Troubleshooting section](#troubleshooting) before proceeding.
1. [Reconfigure GitLab] for the changes to take effect.
-1. Create a `.pgpass` file so Consule is able to
+1. Create a `.pgpass` file so Consul is able to
reload pgbouncer. Enter the `PGBOUNCER_PASSWORD` twice when asked:
```sh
@@ -1109,7 +1058,7 @@ If you enable Monitoring, it must be enabled on **all** database servers.
## Troubleshooting
-#### Consul and PostgreSQL changes not taking effect.
+### Consul and PostgreSQL changes not taking effect.
Due to the potential impacts, `gitlab-ctl reconfigure` only reloads Consul and PostgreSQL, it will not restart the services. However, not all changes can be activated by reloading.
@@ -1119,7 +1068,7 @@ For PostgreSQL, it is usually safe to restart the master node by default. Automa
On the consul server nodes, it is important to restart the consul service in a controlled fashion. Read our [consul documentation](consul.md#restarting-the-server-cluster) for instructions on how to restart the service.
-#### `gitlab-ctl repmgr-check-master` command produces errors
+### `gitlab-ctl repmgr-check-master` command produces errors
If this command displays errors about database permissions it is likely that something failed during
install, resulting in the `gitlab-consul` database user getting incorrect permissions. Follow these
@@ -1134,7 +1083,7 @@ steps to fix the problem:
Now there should not be errors. If errors still occur then there is another problem.
-#### PGBouncer error `ERROR: pgbouncer cannot connect to server`
+### PGBouncer error `ERROR: pgbouncer cannot connect to server`
You may get this error when running `gitlab-rake gitlab:db:configure` or you
may see the error in the PGBouncer log file.
@@ -1162,7 +1111,7 @@ postgresql['trust_auth_cidr_addresses'] = %w(123.123.123.123/32 <other_cidrs>)
[Reconfigure GitLab] for the changes to take effect.
-#### Issues with other components
+### Issues with other components
If you're running into an issue with a component not outlined here, be sure to check the troubleshooting section of their specific documentation page.
diff --git a/doc/administration/high_availability/gitlab.md b/doc/administration/high_availability/gitlab.md
index 3045be616a6..9b1b7142e83 100644
--- a/doc/administration/high_availability/gitlab.md
+++ b/doc/administration/high_availability/gitlab.md
@@ -125,7 +125,7 @@ need some extra configuration.
from running on upgrade. Only the primary GitLab application server should
handle migrations.
-1. **Optional** Configure host keys. Copy all contents(primary and public keys) inside `/etc/ssh/` on
+1. **Recommended** Configure host keys. Copy the contents (primary and public keys) of `/etc/ssh/` on
the primary application server to `/etc/ssh` on all secondary servers. This
prevents false man-in-the-middle-attack alerts when accessing servers in your
High Availability cluster behind a load balancer.
diff --git a/doc/administration/high_availability/monitoring_node.md b/doc/administration/high_availability/monitoring_node.md
index ef415dde10a..385e7441ac9 100644
--- a/doc/administration/high_availability/monitoring_node.md
+++ b/doc/administration/high_availability/monitoring_node.md
@@ -12,7 +12,7 @@ The steps below are the minimum necessary to configure a Monitoring node running
Omnibus:
1. SSH into the Monitoring node.
-1. [Download/install](https://about.gitlab.com/installation) the Omnibus GitLab
+1. [Download/install](https://about.gitlab.com/install) the Omnibus GitLab
package you want using **steps 1 and 2** from the GitLab downloads page.
- Do not complete any other steps on the download page.
diff --git a/doc/administration/high_availability/redis.md b/doc/administration/high_availability/redis.md
index 8621224272c..27310c59755 100644
--- a/doc/administration/high_availability/redis.md
+++ b/doc/administration/high_availability/redis.md
@@ -1,6 +1,6 @@
# Configuring Redis for Scaling and High Availability
-## Provide your own Redis instance **[CORE ONLY]**
+## Provide your own Redis instance **(CORE ONLY)**
The following are the requirements for providing your own Redis instance:
@@ -20,14 +20,14 @@ This section is relevant for [Scaled Architecture](README.md#scalable-architectu
environments including [Basic Scaling](README.md#basic-scaling) and
[Full Scaling](README.md#full-scaling).
-### Provide your own Redis instance **[CORE ONLY]**
+### Provide your own Redis instance **(CORE ONLY)**
If you want to use your own deployed Redis instance(s),
see [Provide your own Redis instance](#provide-your-own-redis-instance-core-only)
for more details. However, you can use the GitLab Omnibus package to easily
deploy the bundled Redis.
-### Standalone Redis using GitLab Omnibus **[CORE ONLY]**
+### Standalone Redis using GitLab Omnibus **(CORE ONLY)**
The GitLab Omnibus package can be used to configure a standalone Redis server.
In this configuration Redis is not highly available, and represents a single
@@ -41,7 +41,7 @@ The steps below are the minimum necessary to configure a Redis server with
Omnibus:
1. SSH into the Redis server.
-1. [Download/install](https://about.gitlab.com/installation) the Omnibus GitLab
+1. [Download/install](https://about.gitlab.com/install/) the Omnibus GitLab
package you want using **steps 1 and 2** from the GitLab downloads page.
- Do not complete any other steps on the download page.
@@ -89,14 +89,14 @@ environments including [Horizontal](README.md#horizontal),
[Hybrid](README.md#hybrid), and
[Fully Distributed](README.md#fully-distributed).
-### Provide your own Redis instance **[CORE ONLY]**
+### Provide your own Redis instance **(CORE ONLY)**
If you want to use your own deployed Redis instance(s),
see [Provide your own Redis instance](#provide-your-own-redis-instance-core-only)
for more details. However, you can use the GitLab Omnibus package to easily
deploy the bundled Redis.
-### High Availability with GitLab Omnibus **[PREMIUM ONLY]**
+### High Availability with GitLab Omnibus **(PREMIUM ONLY)**
> Experimental Redis Sentinel support was [introduced in GitLab 8.11][ce-1877].
Starting with 8.14, Redis Sentinel is no longer experimental.
@@ -357,7 +357,7 @@ The prerequisites for a HA Redis setup are the following:
### Step 1. Configuring the master Redis instance
1. SSH into the **master** Redis server.
-1. [Download/install](https://about.gitlab.com/installation) the Omnibus GitLab
+1. [Download/install](https://about.gitlab.com/install/) the Omnibus GitLab
package you want using **steps 1 and 2** from the GitLab downloads page.
- Make sure you select the correct Omnibus package, with the same version
and type (Community, Enterprise editions) of your current install.
@@ -383,7 +383,6 @@ The prerequisites for a HA Redis setup are the following:
redis['password'] = 'redis-password-goes-here'
```
-
1. Only the primary GitLab application server should handle migrations. To
prevent database migrations from running on upgrade, add the following
configuration to your `/etc/gitlab/gitlab.rb` file:
@@ -395,13 +394,13 @@ The prerequisites for a HA Redis setup are the following:
1. [Reconfigure Omnibus GitLab][reconfigure] for the changes to take effect.
> Note: You can specify multiple roles like sentinel and redis as:
-> roles ['redis_sentinel_role', 'redis_master_role']. Read more about high
-> availability roles at https://docs.gitlab.com/omnibus/roles/
+> `roles ['redis_sentinel_role', 'redis_master_role']`. Read more about high
+> availability roles at <https://docs.gitlab.com/omnibus/roles/>.
### Step 2. Configuring the slave Redis instances
1. SSH into the **slave** Redis server.
-1. [Download/install](https://about.gitlab.com/installation) the Omnibus GitLab
+1. [Download/install](https://about.gitlab.com/install/) the Omnibus GitLab
package you want using **steps 1 and 2** from the GitLab downloads page.
- Make sure you select the correct Omnibus package, with the same version
and type (Community, Enterprise editions) of your current install.
@@ -444,8 +443,8 @@ The prerequisites for a HA Redis setup are the following:
1. Go through the steps again for all the other slave nodes.
> Note: You can specify multiple roles like sentinel and redis as:
-> roles ['redis_sentinel_role', 'redis_slave_role']. Read more about high
-> availability roles at https://docs.gitlab.com/omnibus/roles/
+> `roles ['redis_sentinel_role', 'redis_slave_role']`. Read more about high
+> availability roles at <https://docs.gitlab.com/omnibus/roles/>.
---
diff --git a/doc/administration/audit_log.png b/doc/administration/img/audit_log.png
index d4f4c2abf38..d4f4c2abf38 100644
--- a/doc/administration/audit_log.png
+++ b/doc/administration/img/audit_log.png
Binary files differ
diff --git a/doc/administration/auditor_access_form.png b/doc/administration/img/auditor_access_form.png
index c179a7d3b0a..c179a7d3b0a 100644
--- a/doc/administration/auditor_access_form.png
+++ b/doc/administration/img/auditor_access_form.png
Binary files differ
diff --git a/doc/administration/incoming_email.md b/doc/administration/incoming_email.md
index 8271c579f5b..73a39a6dd35 100644
--- a/doc/administration/incoming_email.md
+++ b/doc/administration/incoming_email.md
@@ -4,14 +4,14 @@ GitLab has several features based on receiving incoming emails:
- [Reply by Email](reply_by_email.md): allow GitLab users to comment on issues
and merge requests by replying to notification emails.
-- [New issue by email](../user/project/issues/create_new_issue.md#new-issue-via-email):
+- [New issue by email](../user/project/issues/managing_issues.md#new-issue-via-email):
allow GitLab users to create a new issue by sending an email to a
user-specific email address.
- [New merge request by email](../user/project/merge_requests/index.md#create-new-merge-requests-by-email):
allow GitLab users to create a new merge request by sending an email to a
user-specific email address.
- [Service Desk](../user/project/service_desk.md): provide e-mail support to
- your customers through GitLab. **[PREMIUM]**
+ your customers through GitLab. **(PREMIUM)**
## Requirements
@@ -102,16 +102,16 @@ for a real-world example of this exploit.
1. Reconfigure GitLab for the changes to take effect:
- ```sh
- sudo gitlab-ctl reconfigure
- sudo gitlab-ctl restart
- ```
+ ```sh
+ sudo gitlab-ctl reconfigure
+ sudo gitlab-ctl restart
+ ```
1. Verify that everything is configured correctly:
- ```sh
- sudo gitlab-rake gitlab:incoming_email:check
- ```
+ ```sh
+ sudo gitlab-rake gitlab:incoming_email:check
+ ```
Reply by email should now be working.
@@ -119,31 +119,31 @@ Reply by email should now be working.
1. Go to the GitLab installation directory:
- ```sh
- cd /home/git/gitlab
- ```
+ ```sh
+ cd /home/git/gitlab
+ ```
1. Find the `incoming_email` section in `config/gitlab.yml`, enable the feature
and fill in the details for your specific IMAP server and email account (see [examples](#config-examples) below).
1. Enable `mail_room` in the init script at `/etc/default/gitlab`:
- ```sh
- sudo mkdir -p /etc/default
- echo 'mail_room_enabled=true' | sudo tee -a /etc/default/gitlab
- ```
+ ```sh
+ sudo mkdir -p /etc/default
+ echo 'mail_room_enabled=true' | sudo tee -a /etc/default/gitlab
+ ```
1. Restart GitLab:
- ```sh
- sudo service gitlab restart
- ```
+ ```sh
+ sudo service gitlab restart
+ ```
1. Verify that everything is configured correctly:
- ```sh
- sudo -u git -H bundle exec rake gitlab:incoming_email:check RAILS_ENV=production
- ```
+ ```sh
+ sudo -u git -H bundle exec rake gitlab:incoming_email:check RAILS_ENV=production
+ ```
Reply by email should now be working.
diff --git a/doc/administration/index.md b/doc/administration/index.md
index 602eecb9746..00c8863f200 100644
--- a/doc/administration/index.md
+++ b/doc/administration/index.md
@@ -2,7 +2,7 @@
description: 'Learn how to install, configure, update, and maintain your GitLab instance.'
---
-# Administrator documentation **[CORE ONLY]**
+# Administrator documentation **(CORE ONLY)**
Learn how to administer your self-managed GitLab instance.
@@ -11,7 +11,7 @@ GitLab has two product distributions available through [different subscriptions]
- The open source [GitLab Community Edition (CE)](https://gitlab.com/gitlab-org/gitlab-ce).
- The open core [GitLab Enterprise Edition (EE)](https://gitlab.com/gitlab-org/gitlab-ee).
-You can [install either GitLab CE or GitLab EE](https://about.gitlab.com/installation/ce-or-ee/).
+You can [install either GitLab CE or GitLab EE](https://about.gitlab.com/install/ce-or-ee/).
However, the features you'll have access to depend on the subscription you choose
(Core, Starter, Premium, or Ultimate).
@@ -32,14 +32,14 @@ Learn how to install, configure, update, and maintain your GitLab instance.
### Installing GitLab
- [Install](../install/README.md): Requirements, directory structures, and installation methods.
- - [Database load balancing](database_load_balancing.md): Distribute database queries among multiple database servers. **[STARTER ONLY]**
- - [Omnibus support for log forwarding](https://docs.gitlab.com/omnibus/settings/logs.html#udp-log-shipping-gitlab-enterprise-edition-only) **[STARTER ONLY]**
+ - [Database load balancing](database_load_balancing.md): Distribute database queries among multiple database servers. **(STARTER ONLY)**
+ - [Omnibus support for log forwarding](https://docs.gitlab.com/omnibus/settings/logs.html#udp-log-shipping-gitlab-enterprise-edition-only) **(STARTER ONLY)**
- [High Availability](high_availability/README.md): Configure multiple servers for scaling or high availability.
- [Installing GitLab HA on Amazon Web Services (AWS)](../install/aws/index.md): Set up GitLab High Availability on Amazon AWS.
-- [Geo](geo/replication/index.md): Replicate your GitLab instance to other geographic locations as a read-only fully operational version. **[PREMIUM ONLY]**
-- [Disaster Recovery](geo/disaster_recovery/index.md): Quickly fail-over to a different site with minimal effort in a disaster situation. **[PREMIUM ONLY]**
-- [Pivotal Tile](../install/pivotal/index.md): Deploy GitLab as a pre-configured appliance using Ops Manager (BOSH) for Pivotal Cloud Foundry. **[PREMIUM ONLY]**
-- [Add License](../user/admin_area/license.md): Upload a license at install time to unlock features that are in paid tiers of GitLab. **[STARTER ONLY]**
+- [Geo](geo/replication/index.md): Replicate your GitLab instance to other geographic locations as a read-only fully operational version. **(PREMIUM ONLY)**
+- [Disaster Recovery](geo/disaster_recovery/index.md): Quickly fail-over to a different site with minimal effort in a disaster situation. **(PREMIUM ONLY)**
+- [Pivotal Tile](../install/pivotal/index.md): Deploy GitLab as a pre-configured appliance using Ops Manager (BOSH) for Pivotal Cloud Foundry. **(PREMIUM ONLY)**
+- [Add License](../user/admin_area/license.md): Upload a license at install time to unlock features that are in paid tiers of GitLab. **(STARTER ONLY)**
### Configuring GitLab
@@ -60,9 +60,9 @@ Learn how to install, configure, update, and maintain your GitLab instance.
- [Diff limits](../user/admin_area/diff_limits.md): Configure the diff rendering size limits of branch comparison pages.
- [Merge request diffs storage](merge_request_diffs.md): Configure merge requests diffs external storage.
- [Broadcast Messages](../user/admin_area/broadcast_messages.md): Send messages to GitLab users through the UI.
-- [Elasticsearch](../integration/elasticsearch.md): Enable Elasticsearch to empower GitLab's Advanced Global Search. Useful when you deal with a huge amount of data. **[STARTER ONLY]**
-- [External Classification Policy Authorization](../user/admin_area/settings/external_authorization.md) **[PREMIUM ONLY]**
-- [Upload a license](../user/admin_area/license.md): Upload a license to unlock features that are in paid tiers of GitLab. **[STARTER ONLY]**
+- [Elasticsearch](../integration/elasticsearch.md): Enable Elasticsearch to empower GitLab's Advanced Global Search. Useful when you deal with a huge amount of data. **(STARTER ONLY)**
+- [External Classification Policy Authorization](../user/admin_area/settings/external_authorization.md) **(PREMIUM ONLY)**
+- [Upload a license](../user/admin_area/license.md): Upload a license to unlock features that are in paid tiers of GitLab. **(STARTER ONLY)**
- [Admin Area](../user/admin_area/index.md): for self-managed instance-wide configuration and maintenance.
#### Customizing GitLab's appearance
@@ -72,7 +72,7 @@ Learn how to install, configure, update, and maintain your GitLab instance.
- [Branded login page](../customization/branded_login_page.md): Customize the login page with your own logo, title, and description.
- [Welcome message](../customization/welcome_message.md): Add a custom welcome message to the sign-in page.
- ["New Project" page](../customization/new_project_page.md): Customize the text to be displayed on the page that opens whenever your users create a new project.
-- [Additional custom email text](../user/admin_area/settings/email.md#custom-additional-text-premium-only): Add additional custom text to emails sent from GitLab. **[PREMIUM ONLY]**
+- [Additional custom email text](../user/admin_area/settings/email.md#custom-additional-text-premium-only): Add additional custom text to emails sent from GitLab. **(PREMIUM ONLY)**
### Maintaining GitLab
@@ -107,17 +107,17 @@ Learn how to install, configure, update, and maintain your GitLab instance.
- [Sign-up restrictions](../user/admin_area/settings/sign_up_restrictions.md): block email addresses of specific domains, or whitelist only specific domains.
- [Access restrictions](../user/admin_area/settings/visibility_and_access_controls.md#enabled-git-access-protocols): Define which Git access protocols can be used to talk to GitLab (SSH, HTTP, HTTPS).
- [Authentication and Authorization](auth/README.md): Configure external authentication with LDAP, SAML, CAS and additional providers.
- - [Sync LDAP](auth/ldap-ee.md) **[STARTER ONLY]**
- - [Kerberos authentication](../integration/kerberos.md) **[STARTER ONLY]**
+ - [Sync LDAP](auth/ldap-ee.md) **(STARTER ONLY)**
+ - [Kerberos authentication](../integration/kerberos.md) **(STARTER ONLY)**
- See also other [authentication](../topics/authentication/index.md#gitlab-administrators) topics (for example, enforcing 2FA).
-- [Email users](../tools/email.md): Email GitLab users from within GitLab. **[STARTER ONLY]**
+- [Email users](../tools/email.md): Email GitLab users from within GitLab. **(STARTER ONLY)**
- [User Cohorts](../user/admin_area/user_cohorts.md): Display the monthly cohorts of new users and their activities over time.
- [Audit logs and events](audit_events.md): View the changes made within the GitLab server for:
- - Groups and projects. **[STARTER]**
- - Instances. **[PREMIUM ONLY]**
-- [Auditor users](auditor_users.md): Users with read-only access to all projects, groups, and other resources on the GitLab instance. **[PREMIUM ONLY]**
+ - Groups and projects. **(STARTER)**
+ - Instances. **(PREMIUM ONLY)**
+- [Auditor users](auditor_users.md): Users with read-only access to all projects, groups, and other resources on the GitLab instance. **(PREMIUM ONLY)**
- [Incoming email](incoming_email.md): Configure incoming emails to allow
- users to [reply by email](reply_by_email.md), create [issues by email](../user/project/issues/create_new_issue.md#new-issue-via-email) and
+ users to [reply by email](reply_by_email.md), create [issues by email](../user/project/issues/managing_issues.md#new-issue-via-email) and
[merge requests by email](../user/project/merge_requests/index.md#create-new-merge-requests-by-email), and to enable [Service Desk](../user/project/service_desk.md).
- [Postfix for incoming email](reply_by_email_postfix_setup.md): Set up a
basic Postfix mail server with IMAP authentication on Ubuntu for incoming
@@ -131,15 +131,15 @@ Learn how to install, configure, update, and maintain your GitLab instance.
- [Gitaly](gitaly/index.md): Configuring Gitaly, GitLab's Git repository storage service.
- [Default labels](../user/admin_area/labels.md): Create labels that will be automatically added to every new project.
- [Restrict the use of public or internal projects](../public_access/public_access.md#restricting-the-use-of-public-or-internal-projects): Restrict the use of visibility levels for users when they create a project or a snippet.
-- [Custom project templates](../user/admin_area/custom_project_templates.md): Configure a set of projects to be used as custom templates when creating a new project. **[PREMIUM ONLY]**
-- [Packages](packages.md): Enable GitLab to act as a Maven repository or NPM registry. **[PREMIUM ONLY]**
+- [Custom project templates](../user/admin_area/custom_project_templates.md): Configure a set of projects to be used as custom templates when creating a new project. **(PREMIUM ONLY)**
+- [Packages](packages.md): Enable GitLab to act as a Maven repository or NPM registry. **(PREMIUM ONLY)**
### Repository settings
- [Repository checks](repository_checks.md): Periodic Git repository checks.
- [Repository storage paths](repository_storage_paths.md): Manage the paths used to store repositories.
- [Repository storage rake tasks](raketasks/storage.md): A collection of rake tasks to list and migrate existing projects and attachments associated with it from Legacy storage to Hashed storage.
-- [Limit repository size](../user/admin_area/settings/account_and_limit_settings.md): Set a hard limit for your repositories' size. **[STARTER ONLY]**
+- [Limit repository size](../user/admin_area/settings/account_and_limit_settings.md): Set a hard limit for your repositories' size. **(STARTER ONLY)**
## Continuous Integration settings
@@ -148,7 +148,7 @@ Learn how to install, configure, update, and maintain your GitLab instance.
- [Job artifacts](job_artifacts.md): Enable, disable, and configure job artifacts (a set of files and directories which are outputted by a job when it completes successfully).
- [Job traces](job_traces.md): Information about the job traces (logs).
- [Register Shared and specific Runners](../ci/runners/README.md#registering-a-shared-runner): Learn how to register and configure Shared and specific Runners to your own instance.
-- [Shared Runners pipelines quota](../user/admin_area/settings/continuous_integration.md#shared-runners-pipeline-minutes-quota-starter-only): Limit the usage of pipeline minutes for Shared Runners. **[STARTER ONLY]**
+- [Shared Runners pipelines quota](../user/admin_area/settings/continuous_integration.md#shared-runners-pipeline-minutes-quota-starter-only): Limit the usage of pipeline minutes for Shared Runners. **(STARTER ONLY)**
- [Enable/disable Auto DevOps](../topics/autodevops/index.md#enablingdisabling-auto-devops): Enable or disable Auto DevOps for your instance.
## Git configuration options
@@ -178,7 +178,7 @@ Learn how to install, configure, update, and maintain your GitLab instance.
## Analytics
-- [Pseudonymizer](pseudonymizer.md): Export data from GitLab's database to CSV files in a secure way. **[ULTIMATE]**
+- [Pseudonymizer](pseudonymizer.md): Export data from GitLab's database to CSV files in a secure way. **(ULTIMATE)**
## Troubleshooting
diff --git a/doc/administration/instance_review.md b/doc/administration/instance_review.md
index b1244f44e95..ab6a4646a71 100644
--- a/doc/administration/instance_review.md
+++ b/doc/administration/instance_review.md
@@ -1,4 +1,4 @@
-# Instance Review **[CORE ONLY]**
+# Instance Review **(CORE ONLY)**
> [Introduced][6995] in [GitLab Core][ee] 11.3.
diff --git a/doc/administration/integration/plantuml.md b/doc/administration/integration/plantuml.md
index 82e0c14ffc2..8de7b0bc57e 100644
--- a/doc/administration/integration/plantuml.md
+++ b/doc/administration/integration/plantuml.md
@@ -94,7 +94,7 @@ our AsciiDoc snippets, wikis and repos using delimited blocks:
Alice -> Bob: Go Away
```
- You can also use the `uml::` directive for compatibility with [sphinxcontrib-plantuml](https://pypi.python.org/pypi/sphinxcontrib-plantuml), but please note that we currently only support the `caption` option.
+ You can also use the `uml::` directive for compatibility with [sphinxcontrib-plantuml](https://pypi.org/project/sphinxcontrib-plantuml/), but please note that we currently only support the `caption` option.
The above blocks will be converted to an HTML img tag with source pointing to the
PlantUML instance. If the PlantUML server is correctly configured, this should
diff --git a/doc/administration/issue_closing_pattern.md b/doc/administration/issue_closing_pattern.md
index 160da47c780..e1bbabb2878 100644
--- a/doc/administration/issue_closing_pattern.md
+++ b/doc/administration/issue_closing_pattern.md
@@ -1,4 +1,4 @@
-# Issue closing pattern
+# Issue closing pattern **(CORE ONLY)**
>**Note:**
This is the administration documentation.
@@ -27,9 +27,10 @@ Because Rubular doesn't understand `%{issue_ref}`, you can replace this by
1. Change the value of `gitlab_rails['gitlab_issue_closing_pattern']` to a regular
expression of your liking:
- ```ruby
- gitlab_rails['gitlab_issue_closing_pattern'] = "\b((?:[Cc]los(?:e[sd]|ing)|\b[Ff]ix(?:e[sd]|ing)?) +(?:(?:issues? +)?%{issue_ref}(?:(?:, *| +and +)?))+)"
- ```
+ ```ruby
+ gitlab_rails['gitlab_issue_closing_pattern'] = "\b((?:[Cc]los(?:e[sd]|ing)|\b[Ff]ix(?:e[sd]|ing)?) +(?:(?:issues? +)?%{issue_ref}(?:(?:, *| +and +)?))+)"
+ ```
+
1. [Reconfigure] GitLab for the changes to take effect.
**For installations from source**
@@ -37,13 +38,13 @@ Because Rubular doesn't understand `%{issue_ref}`, you can replace this by
1. Open `gitlab.yml` with your editor.
1. Change the value of `issue_closing_pattern`:
- ```yaml
- issue_closing_pattern: "\b((?:[Cc]los(?:e[sd]|ing)|\b[Ff]ix(?:e[sd]|ing)?) +(?:(?:issues? +)?%{issue_ref}(?:(?:, *| +and +)?))+)"
- ```
+ ```yaml
+ issue_closing_pattern: "\b((?:[Cc]los(?:e[sd]|ing)|\b[Ff]ix(?:e[sd]|ing)?) +(?:(?:issues? +)?%{issue_ref}(?:(?:, *| +and +)?))+)"
+ ```
1. [Restart] GitLab for the changes to take effect.
[gitlab.yml.example]: https://gitlab.com/gitlab-org/gitlab-ce/blob/master/config/gitlab.yml.example
[reconfigure]: restart_gitlab.md#omnibus-gitlab-reconfigure
[restart]: restart_gitlab.md#installations-from-source
-[user documentation]: ../user/project/issues/automatic_issue_closing.md
+[user documentation]: ../user/project/issues/managing_issues.md#closing-issues-automatically
diff --git a/doc/administration/job_artifacts.md b/doc/administration/job_artifacts.md
index 05e15fc303b..9df7b2526e2 100644
--- a/doc/administration/job_artifacts.md
+++ b/doc/administration/job_artifacts.md
@@ -1,7 +1,5 @@
# Jobs artifacts administration
-> **Notes:**
->
> - Introduced in GitLab 8.2 and GitLab Runner 0.7.0.
> - Starting with GitLab 8.4 and GitLab Runner 1.0, the artifacts archive format changed to `ZIP`.
> - Starting with GitLab 8.17, builds are renamed to jobs.
@@ -21,9 +19,9 @@ To disable artifacts site-wide, follow the steps below.
1. Edit `/etc/gitlab/gitlab.rb` and add the following line:
- ```ruby
- gitlab_rails['artifacts_enabled'] = false
- ```
+ ```ruby
+ gitlab_rails['artifacts_enabled'] = false
+ ```
1. Save the file and [reconfigure GitLab][] for the changes to take effect.
@@ -33,10 +31,10 @@ To disable artifacts site-wide, follow the steps below.
1. Edit `/home/git/gitlab/config/gitlab.yml` and add or amend the following lines:
- ```yaml
- artifacts:
- enabled: false
- ```
+ ```yaml
+ artifacts:
+ enabled: false
+ ```
1. Save the file and [restart GitLab][] for the changes to take effect.
@@ -61,9 +59,9 @@ _The artifacts are stored by default in
1. To change the storage path for example to `/mnt/storage/artifacts`, edit
`/etc/gitlab/gitlab.rb` and add the following line:
- ```ruby
- gitlab_rails['artifacts_path'] = "/mnt/storage/artifacts"
- ```
+ ```ruby
+ gitlab_rails['artifacts_path'] = "/mnt/storage/artifacts"
+ ```
1. Save the file and [reconfigure GitLab][] for the changes to take effect.
@@ -77,18 +75,16 @@ _The artifacts are stored by default in
1. To change the storage path for example to `/mnt/storage/artifacts`, edit
`/home/git/gitlab/config/gitlab.yml` and add or amend the following lines:
- ```yaml
- artifacts:
- enabled: true
- path: /mnt/storage/artifacts
- ```
+ ```yaml
+ artifacts:
+ enabled: true
+ path: /mnt/storage/artifacts
+ ```
1. Save the file and [restart GitLab][] for the changes to take effect.
### Using object storage
-> **Notes:**
->
> - [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/1762) in
> [GitLab Premium](https://about.gitlab.com/pricing/) 9.4.
> - Since version 9.5, artifacts are [browsable](../user/project/pipelines/job_artifacts.md#browsing-artifacts),
@@ -141,35 +137,35 @@ _The artifacts are stored by default in
1. Edit `/etc/gitlab/gitlab.rb` and add the following lines by replacing with
the values you want:
- ```ruby
- gitlab_rails['artifacts_enabled'] = true
- gitlab_rails['artifacts_object_store_enabled'] = true
- gitlab_rails['artifacts_object_store_remote_directory'] = "artifacts"
- gitlab_rails['artifacts_object_store_connection'] = {
- 'provider' => 'AWS',
- 'region' => 'eu-central-1',
- 'aws_access_key_id' => 'AWS_ACCESS_KEY_ID',
- 'aws_secret_access_key' => 'AWS_SECRET_ACCESS_KEY'
- }
- ```
-
- NOTE: For GitLab 9.4+, if you are using AWS IAM profiles, be sure to omit the
- AWS access key and secret access key/value pairs. For example:
-
- ```ruby
- gitlab_rails['artifacts_object_store_connection'] = {
- 'provider' => 'AWS',
- 'region' => 'eu-central-1',
- 'use_iam_profile' => true
- }
- ```
+ ```ruby
+ gitlab_rails['artifacts_enabled'] = true
+ gitlab_rails['artifacts_object_store_enabled'] = true
+ gitlab_rails['artifacts_object_store_remote_directory'] = "artifacts"
+ gitlab_rails['artifacts_object_store_connection'] = {
+ 'provider' => 'AWS',
+ 'region' => 'eu-central-1',
+ 'aws_access_key_id' => 'AWS_ACCESS_KEY_ID',
+ 'aws_secret_access_key' => 'AWS_SECRET_ACCESS_KEY'
+ }
+ ```
+
+ NOTE: For GitLab 9.4+, if you are using AWS IAM profiles, be sure to omit the
+ AWS access key and secret access key/value pairs. For example:
+
+ ```ruby
+ gitlab_rails['artifacts_object_store_connection'] = {
+ 'provider' => 'AWS',
+ 'region' => 'eu-central-1',
+ 'use_iam_profile' => true
+ }
+ ```
1. Save the file and [reconfigure GitLab][] for the changes to take effect.
1. Migrate any existing local artifacts to the object storage:
- ```bash
- gitlab-rake gitlab:artifacts:migrate
- ```
+ ```bash
+ gitlab-rake gitlab:artifacts:migrate
+ ```
---
@@ -181,25 +177,25 @@ _The artifacts are stored by default in
1. Edit `/home/git/gitlab/config/gitlab.yml` and add or amend the following
lines:
- ```yaml
- artifacts:
- enabled: true
- object_store:
- enabled: true
- remote_directory: "artifacts" # The bucket name
- connection:
- provider: AWS # Only AWS supported at the moment
- aws_access_key_id: AWS_ACCESS_KEY_ID
- aws_secret_access_key: AWS_SECRET_ACCESS_KEY
- region: eu-central-1
- ```
+ ```yaml
+ artifacts:
+ enabled: true
+ object_store:
+ enabled: true
+ remote_directory: "artifacts" # The bucket name
+ connection:
+ provider: AWS # Only AWS supported at the moment
+ aws_access_key_id: AWS_ACCESS_KEY_ID
+ aws_secret_access_key: AWS_SECRET_ACCESS_KEY
+ region: eu-central-1
+ ```
1. Save the file and [restart GitLab][] for the changes to take effect.
1. Migrate any existing local artifacts to the object storage:
- ```bash
- sudo -u git -H bundle exec rake gitlab:artifacts:migrate RAILS_ENV=production
- ```
+ ```bash
+ sudo -u git -H bundle exec rake gitlab:artifacts:migrate RAILS_ENV=production
+ ```
## Expiring artifacts
@@ -217,9 +213,9 @@ steps below.
1. Edit `/etc/gitlab/gitlab.rb` and comment out or add the following line
- ```ruby
- gitlab_rails['expire_build_artifacts_worker_cron'] = "50 * * * *"
- ```
+ ```ruby
+ gitlab_rails['expire_build_artifacts_worker_cron'] = "50 * * * *"
+ ```
1. Save the file and [reconfigure GitLab][] for the changes to take effect.
@@ -230,10 +226,10 @@ steps below.
1. Edit `/home/git/gitlab/config/gitlab.yml` and add or amend the following
lines:
- ```yaml
- expire_build_artifacts_worker:
- cron: "50 * * * *"
- ```
+ ```yaml
+ expire_build_artifacts_worker:
+ cron: "50 * * * *"
+ ```
1. Save the file and [restart GitLab][] for the changes to take effect.
@@ -250,15 +246,15 @@ you can flip the feature flag from a Rails console.
1. Enter the Rails console:
- ```sh
- sudo gitlab-rails console
- ```
+ ```sh
+ sudo gitlab-rails console
+ ```
1. Flip the switch and disable it:
- ```ruby
- Feature.enable('ci_disable_validates_dependencies')
- ```
+ ```ruby
+ Feature.enable('ci_disable_validates_dependencies')
+ ```
---
@@ -266,16 +262,16 @@ you can flip the feature flag from a Rails console.
1. Enter the Rails console:
- ```sh
- cd /home/git/gitlab
- RAILS_ENV=production sudo -u git -H bundle exec rails console
- ```
+ ```sh
+ cd /home/git/gitlab
+ RAILS_ENV=production sudo -u git -H bundle exec rails console
+ ```
1. Flip the switch and disable it:
- ```ruby
- Feature.enable('ci_disable_validates_dependencies')
- ```
+ ```ruby
+ Feature.enable('ci_disable_validates_dependencies')
+ ```
## Set the maximum file size of the artifacts
diff --git a/doc/administration/job_traces.md b/doc/administration/job_traces.md
index aa9d87562a3..957916893d7 100644
--- a/doc/administration/job_traces.md
+++ b/doc/administration/job_traces.md
@@ -25,11 +25,11 @@ To change the location where the job logs will be stored, follow the steps below
**In Omnibus installations:**
-1. Edit `/etc/gitlab/gitlab.rb` and add or amend the following line:
+1. Edit `/etc/gitlab/gitlab.rb` and add or amend the following line:
- ```
- gitlab_ci['builds_directory'] = '/mnt/to/gitlab-ci/builds'
- ```
+ ```ruby
+ gitlab_ci['builds_directory'] = '/mnt/to/gitlab-ci/builds'
+ ```
1. Save the file and [reconfigure GitLab][] for the changes to take effect.
@@ -39,12 +39,12 @@ To change the location where the job logs will be stored, follow the steps below
1. Edit `/home/git/gitlab/config/gitlab.yml` and add or amend the following lines:
- ```yaml
- gitlab_ci:
- # The location where build traces are stored (default: builds/).
- # Relative paths are relative to Rails.root.
- builds_path: path/to/builds/
- ```
+ ```yaml
+ gitlab_ci:
+ # The location where build traces are stored (default: builds/).
+ # Relative paths are relative to Rails.root.
+ builds_path: path/to/builds/
+ ```
1. Save the file and [restart GitLab][] for the changes to take effect.
@@ -67,24 +67,24 @@ To archive those legacy job traces, please follow the instruction below.
1. Execute the following command
- ```bash
- gitlab-rake gitlab:traces:archive
- ```
+ ```bash
+ gitlab-rake gitlab:traces:archive
+ ```
- After you executed this task, GitLab instance queues up Sidekiq jobs (asynchronous processes)
- for migrating job trace files from local storage to object storage.
- It could take time to complete the all migration jobs. You can check the progress by the following command
+ After you executed this task, GitLab instance queues up Sidekiq jobs (asynchronous processes)
+ for migrating job trace files from local storage to object storage.
+ It could take time to complete the all migration jobs. You can check the progress by the following command
- ```bash
- sudo gitlab-rails console
- ```
+ ```bash
+ sudo gitlab-rails console
+ ```
- ```bash
- [1] pry(main)> Sidekiq::Stats.new.queues['pipeline_background:archive_trace']
- => 100
- ```
+ ```bash
+ [1] pry(main)> Sidekiq::Stats.new.queues['pipeline_background:archive_trace']
+ => 100
+ ```
- If the count becomes zero, the archiving processes are done
+ If the count becomes zero, the archiving processes are done
## How to migrate archived job traces to object storage
diff --git a/doc/administration/logs.md b/doc/administration/logs.md
index 9921ffd8ea0..5a2f389d298 100644
--- a/doc/administration/logs.md
+++ b/doc/administration/logs.md
@@ -4,7 +4,7 @@ GitLab has an advanced log system where everything is logged so that you
can analyze your instance using various system log files. In addition to
system log files, GitLab Enterprise Edition comes with Audit Events.
Find more about them [in Audit Events
-documentation](https://docs.gitlab.com/ee/administration/audit_events.html)
+documentation](audit_events.md)
System log files are typically plain text in a standard log file format.
This guide talks about how to read and use these system log files.
@@ -288,6 +288,9 @@ installations from source.
It logs information whenever [Rack Attack] registers an abusive request.
+NOTE: **Note:**
+From [%12.1](https://gitlab.com/gitlab-org/gitlab-ce/issues/62756), user id and username are available on this log.
+
## `graphql_json.log`
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/59587) in GitLab 12.0.
diff --git a/doc/administration/merge_request_diffs.md b/doc/administration/merge_request_diffs.md
index 5e9ba4f640f..99cd9051778 100644
--- a/doc/administration/merge_request_diffs.md
+++ b/doc/administration/merge_request_diffs.md
@@ -1,4 +1,4 @@
-# Merge request diffs storage **[CORE ONLY]**
+# Merge request diffs storage **(CORE ONLY)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/52568) in GitLab 11.8.
@@ -10,7 +10,7 @@ By default, merge request diffs are stored in the database, in a table named
`merge_request_diff_files`. Larger installations may find this table grows too
large, in which case, switching to external storage is recommended.
-### Using external storage
+## Using external storage
Merge request diffs can be stored on disk, or in object storage. In general, it
is better to store the diffs in the database than on disk.
@@ -21,18 +21,18 @@ To enable external storage of merge request diffs, follow the instructions below
1. Edit `/etc/gitlab/gitlab.rb` and add the following line:
- ```ruby
- gitlab_rails['external_diffs_enabled'] = true
- ```
+ ```ruby
+ gitlab_rails['external_diffs_enabled'] = true
+ ```
1. _The external diffs will be stored in in
`/var/opt/gitlab/gitlab-rails/shared/external-diffs`._ To change the path,
for example, to `/mnt/storage/external-diffs`, edit `/etc/gitlab/gitlab.rb`
and add the following line:
- ```ruby
- gitlab_rails['external_diffs_storage_path'] = "/mnt/storage/external-diffs"
- ```
+ ```ruby
+ gitlab_rails['external_diffs_storage_path'] = "/mnt/storage/external-diffs"
+ ```
1. Save the file and [reconfigure GitLab](restart_gitlab.md#omnibus-gitlab-reconfigure) for the changes to take effect.
@@ -41,31 +41,31 @@ To enable external storage of merge request diffs, follow the instructions below
1. Edit `/home/git/gitlab/config/gitlab.yml` and add or amend the following
lines:
- ```yaml
- external_diffs:
- enabled: true
- ```
+ ```yaml
+ external_diffs:
+ enabled: true
+ ```
-1. _The external diffs will be stored in
+1. _The external diffs will be stored in
`/home/git/gitlab/shared/external-diffs`._ To change the path, for example,
to `/mnt/storage/external-diffs`, edit `/home/git/gitlab/config/gitlab.yml`
and add or amend the following lines:
- ```yaml
- external_diffs:
- enabled: true
- storage_path: /mnt/storage/external-diffs
- ```
+ ```yaml
+ external_diffs:
+ enabled: true
+ storage_path: /mnt/storage/external-diffs
+ ```
1. Save the file and [restart GitLab](restart_gitlab.md#installations-from-source) for the changes to take effect.
-### Using object storage
+## Using object storage
Instead of storing the external diffs on disk, we recommended the use of an object
store like AWS S3 instead. This configuration relies on valid AWS credentials to
be configured already.
-### Object Storage Settings
+## Object Storage Settings
For source installations, these settings are nested under `external_diffs:` and
then `object_store:`. On Omnibus installations, they are prefixed by
@@ -80,7 +80,7 @@ then `object_store:`. On Omnibus installations, they are prefixed by
| `proxy_download` | Set to true to enable proxying all files served. Option allows to reduce egress traffic as this allows clients to download directly from remote storage instead of proxying all data | `false` |
| `connection` | Various connection options described below | |
-#### S3 compatible connection settings
+### S3 compatible connection settings
The connection settings match those provided by [Fog](https://github.com/fog), and are as follows:
@@ -101,28 +101,28 @@ The connection settings match those provided by [Fog](https://github.com/fog), a
1. Edit `/etc/gitlab/gitlab.rb` and add the following lines by replacing with
the values you want:
- ```ruby
- gitlab_rails['external_diffs_enabled'] = true
- gitlab_rails['external_diffs_object_store_enabled'] = true
- gitlab_rails['external_diffs_object_store_remote_directory'] = "external-diffs"
- gitlab_rails['external_diffs_object_store_connection'] = {
- 'provider' => 'AWS',
- 'region' => 'eu-central-1',
- 'aws_access_key_id' => 'AWS_ACCESS_KEY_ID',
- 'aws_secret_access_key' => 'AWS_SECRET_ACCESS_KEY'
- }
- ```
-
- Note that, if you are using AWS IAM profiles, be sure to omit the
- AWS access key and secret access key/value pairs. For example:
-
- ```ruby
- gitlab_rails['external_diffs_object_store_connection'] = {
- 'provider' => 'AWS',
- 'region' => 'eu-central-1',
- 'use_iam_profile' => true
- }
- ```
+ ```ruby
+ gitlab_rails['external_diffs_enabled'] = true
+ gitlab_rails['external_diffs_object_store_enabled'] = true
+ gitlab_rails['external_diffs_object_store_remote_directory'] = "external-diffs"
+ gitlab_rails['external_diffs_object_store_connection'] = {
+ 'provider' => 'AWS',
+ 'region' => 'eu-central-1',
+ 'aws_access_key_id' => 'AWS_ACCESS_KEY_ID',
+ 'aws_secret_access_key' => 'AWS_SECRET_ACCESS_KEY'
+ }
+ ```
+
+ Note that, if you are using AWS IAM profiles, be sure to omit the
+ AWS access key and secret access key/value pairs. For example:
+
+ ```ruby
+ gitlab_rails['external_diffs_object_store_connection'] = {
+ 'provider' => 'AWS',
+ 'region' => 'eu-central-1',
+ 'use_iam_profile' => true
+ }
+ ```
1. Save the file and [reconfigure GitLab](restart_gitlab.md#omnibus-gitlab-reconfigure) for the changes to take effect.
@@ -131,22 +131,22 @@ The connection settings match those provided by [Fog](https://github.com/fog), a
1. Edit `/home/git/gitlab/config/gitlab.yml` and add or amend the following
lines:
- ```yaml
- external_diffs:
- enabled: true
- object_store:
- enabled: true
- remote_directory: "external-diffs" # The bucket name
- connection:
- provider: AWS # Only AWS supported at the moment
- aws_access_key_id: AWS_ACCESS_KEY_ID
- aws_secret_access_key: AWS_SECRET_ACCESS_KEY
- region: eu-central-1
- ```
+ ```yaml
+ external_diffs:
+ enabled: true
+ object_store:
+ enabled: true
+ remote_directory: "external-diffs" # The bucket name
+ connection:
+ provider: AWS # Only AWS supported at the moment
+ aws_access_key_id: AWS_ACCESS_KEY_ID
+ aws_secret_access_key: AWS_SECRET_ACCESS_KEY
+ region: eu-central-1
+ ```
1. Save the file and [restart GitLab](restart_gitlab.md#installations-from-source) for the changes to take effect.
-### Alternative in-database storage
+## Alternative in-database storage
Enabling external diffs may reduce the performance of merge requests, as they
must be retrieved in a separate operation to other data. A compromise may be
@@ -157,11 +157,11 @@ To enable this feature, perform the following steps:
**In Omnibus installations:**
-1. Edit `/etc/gitlab/gitlab.rb` and add the following line:
+1. Edit `/etc/gitlab/gitlab.rb` and add the following line:
- ```ruby
- gitlab_rails['external_diffs_when'] = 'outdated'
- ```
+ ```ruby
+ gitlab_rails['external_diffs_when'] = 'outdated'
+ ```
1. Save the file and [reconfigure GitLab](restart_gitlab.md#omnibus-gitlab-reconfigure) for the changes to take effect.
@@ -170,11 +170,11 @@ To enable this feature, perform the following steps:
1. Edit `/home/git/gitlab/config/gitlab.yml` and add or amend the following
lines:
- ```yaml
- external_diffs:
- enabled: true
- when: outdated
- ```
+ ```yaml
+ external_diffs:
+ enabled: true
+ when: outdated
+ ```
1. Save the file and [restart GitLab](restart_gitlab.md#installations-from-source) for the changes to take effect.
diff --git a/doc/administration/monitoring/performance/grafana_configuration.md b/doc/administration/monitoring/performance/grafana_configuration.md
index 187fb2f73a1..4dd0bbbe937 100644
--- a/doc/administration/monitoring/performance/grafana_configuration.md
+++ b/doc/administration/monitoring/performance/grafana_configuration.md
@@ -1,6 +1,6 @@
# Grafana Configuration
-[Grafana](http://grafana.org/) is a tool that allows you to visualize time
+[Grafana](https://grafana.org/) is a tool that allows you to visualize time
series metrics through graphs and dashboards. It supports several backend
data stores, including InfluxDB. GitLab writes performance data to InfluxDB
and Grafana will allow you to query to display useful graphs.
@@ -13,7 +13,7 @@ services.
[GitLab Omnibus can help you install Grafana (recommended)](https://docs.gitlab.com/omnibus/settings/grafana.html)
or Grafana supplies package repositories (Yum/Apt) for easy installation.
-See [Grafana installation documentation](http://docs.grafana.org/installation/)
+See [Grafana installation documentation](https://grafana.com/docs/installation/)
for detailed steps.
NOTE: **Note:**
@@ -103,6 +103,21 @@ repository for more information on this process.
[grafana-dashboards]: https://gitlab.com/gitlab-org/grafana-dashboards
+## Integration with GitLab UI
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/61005) in GitLab 12.1.
+
+If you have set up Grafana, you can enable a link to access it easily from the sidebar:
+
+1. Go to the admin area under **Settings > Metrics and profiling**
+ and expand "Metrics - Grafana".
+1. Check the "Enable access to Grafana" checkbox.
+1. If Grafana is enabled through Omnibus GitLab and on the same server,
+ leave "Grafana URL" unchanged. In any other case, enter the full URL
+ path of the Grafana instance.
+1. Click **Save changes**.
+1. The new link will be available in the admin area under **Monitoring > Metrics Dashboard**.
+
---
Read more on:
diff --git a/doc/administration/monitoring/performance/influxdb_configuration.md b/doc/administration/monitoring/performance/influxdb_configuration.md
index fa281f47ed8..cf6728510fe 100644
--- a/doc/administration/monitoring/performance/influxdb_configuration.md
+++ b/doc/administration/monitoring/performance/influxdb_configuration.md
@@ -187,7 +187,7 @@ Read more on:
[influxdb documentation]: https://docs.influxdata.com/influxdb/v0.9/
[influxdb cli]: https://docs.influxdata.com/influxdb/v0.9/tools/shell/
[udp]: https://docs.influxdata.com/influxdb/v0.9/write_protocols/udp/
-[influxdb]: https://influxdata.com/time-series-platform/influxdb/
+[influxdb]: https://www.influxdata.com/products/influxdb-overview/
[tsm tree]: https://influxdata.com/blog/new-storage-engine-time-structured-merge-tree/
[tsm1-commit]: https://github.com/influxdata/influxdb/commit/15d723dc77651bac83e09e2b1c94be480966cb0d
[influx-admin]: https://docs.influxdata.com/influxdb/v0.9/administration/authentication_and_authorization/#create-a-new-admin-user
diff --git a/doc/administration/monitoring/prometheus/gitlab_metrics.md b/doc/administration/monitoring/prometheus/gitlab_metrics.md
index 84b71ae6f1c..89501f20d99 100644
--- a/doc/administration/monitoring/prometheus/gitlab_metrics.md
+++ b/doc/administration/monitoring/prometheus/gitlab_metrics.md
@@ -49,7 +49,7 @@ The following metrics are available:
| unicorn_queued_connections | Gauge | 11.0 | The number of queued Unicorn connections |
| unicorn_workers | Gauge | 12.0 | The number of Unicorn workers |
-## Sidekiq Metrics available for Geo **[PREMIUM]**
+## Sidekiq Metrics available for Geo **(PREMIUM)**
Sidekiq jobs may also gather metrics, and these metrics can be accessed if the Sidekiq exporter is enabled (e.g. via
the `monitoring.sidekiq_exporter` configuration option in `gitlab.yml`.
@@ -104,11 +104,11 @@ Some basic Ruby runtime metrics are available:
| ruby_process_cpu_seconds_total | Gauge | 12.0 | Total amount of CPU time per process |
| ruby_process_max_fds | Gauge | 12.0 | Maximum number of open file descriptors per process |
| ruby_process_resident_memory_bytes | Gauge | 12.0 | Memory usage by process, measured in bytes |
-| ruby_process_start_time_seconds | Gauge | 12.0 | The elapsed time between system boot and the process started, measured in seconds |
+| ruby_process_start_time_seconds | Gauge | 12.0 | UNIX timestamp of process start time |
[GC.stat]: https://ruby-doc.org/core-2.3.0/GC.html#method-c-stat
-## Puma Metrics **[EXPERIMENTAL]**
+## Puma Metrics **(EXPERIMENTAL)**
When Puma is used instead of Unicorn, following metrics are available:
diff --git a/doc/administration/operations/extra_sidekiq_processes.md b/doc/administration/operations/extra_sidekiq_processes.md
index 7297507f599..a16cd5166b7 100644
--- a/doc/administration/operations/extra_sidekiq_processes.md
+++ b/doc/administration/operations/extra_sidekiq_processes.md
@@ -1,4 +1,4 @@
-# Extra Sidekiq processes **[STARTER ONLY]**
+# Extra Sidekiq processes **(STARTER ONLY)**
NOTE: **Note:**
The information in this page applies only to Omnibus GitLab.
diff --git a/doc/administration/operations/fast_ssh_key_lookup.md b/doc/administration/operations/fast_ssh_key_lookup.md
index 3631ea0822f..b329abdca08 100644
--- a/doc/administration/operations/fast_ssh_key_lookup.md
+++ b/doc/administration/operations/fast_ssh_key_lookup.md
@@ -6,7 +6,7 @@ using [ssh certificates](ssh_certificates.md), they are even faster,
but are not a drop-in replacement.
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/1631) in
-> [GitLab Starter](https://about.gitlab.com/gitlab-ee) 9.3.
+> [GitLab Starter](https://about.gitlab.com/pricing/) 9.3.
>
> [Available in](https://gitlab.com/gitlab-org/gitlab-ee/issues/3953) GitLab
> Community Edition 10.4.
@@ -30,7 +30,7 @@ instructions will break installations using older versions of OpenSSH, such as
those included with CentOS 6 as of September 2017. If you want to use this
feature for CentOS 6, follow [the instructions on how to build and install a custom OpenSSH package](#compiling-a-custom-version-of-openssh-for-centos-6) before continuing.
-## Fast lookup is required for Geo **[PREMIUM]**
+## Fast lookup is required for Geo **(PREMIUM)**
By default, GitLab manages an `authorized_keys` file, which contains all the
public SSH keys for users allowed to access GitLab. However, to maintain a
diff --git a/doc/administration/operations/index.md b/doc/administration/operations/index.md
index df795a48169..df208b3f427 100644
--- a/doc/administration/operations/index.md
+++ b/doc/administration/operations/index.md
@@ -11,7 +11,7 @@ Keep your GitLab instance up and running smoothly.
by GitLab to another file system or another server.
- [Sidekiq MemoryKiller](sidekiq_memory_killer.md): Configure Sidekiq MemoryKiller
to restart Sidekiq.
-- [Extra Sidekiq operations](extra_sidekiq_processes.md): Configure an extra set of Sidekiq processes to ensure certain queues always have dedicated workers, no matter the amount of jobs that need to be processed. **[STARTER ONLY]**
+- [Extra Sidekiq operations](extra_sidekiq_processes.md): Configure an extra set of Sidekiq processes to ensure certain queues always have dedicated workers, no matter the amount of jobs that need to be processed. **(STARTER ONLY)**
- [Unicorn](unicorn.md): Understand Unicorn and unicorn-worker-killer.
- Speed up SSH operations by [Authorizing SSH users via a fast,
indexed lookup to the GitLab database](fast_ssh_key_lookup.md), and/or
diff --git a/doc/administration/operations/unicorn.md b/doc/administration/operations/unicorn.md
index 0e2079cb093..ae67d7f08d6 100644
--- a/doc/administration/operations/unicorn.md
+++ b/doc/administration/operations/unicorn.md
@@ -2,7 +2,7 @@
## Unicorn
-GitLab uses [Unicorn](http://unicorn.bogomips.org/), a pre-forking Ruby web
+GitLab uses [Unicorn](https://bogomips.org/unicorn/), a pre-forking Ruby web
server, to handle web requests (web browsers and Git HTTP clients). Unicorn is
a daemon written in Ruby and C that can load and run a Ruby on Rails
application; in our case the Rails application is GitLab Community Edition or
diff --git a/doc/administration/packages.md b/doc/administration/packages.md
index 0d5f784b71e..c0f8777a8c0 100644
--- a/doc/administration/packages.md
+++ b/doc/administration/packages.md
@@ -1,4 +1,4 @@
-# GitLab Packages administration **[PREMIUM ONLY]**
+# GitLab Packages administration **(PREMIUM ONLY)**
GitLab Packages allows organizations to utilize GitLab as a private repository
for a variety of common package managers. Users are able to build and publish
@@ -11,7 +11,7 @@ The Packages feature allows GitLab to act as a repository for the following:
| [Maven Repository](../user/project/packages/maven_repository.md) | The GitLab Maven Repository enables every project in GitLab to have its own space to store [Maven](https://maven.apache.org/) packages. | 11.3+ |
| [NPM Registry](../user/project/packages/npm_registry.md) | The GitLab NPM Registry enables every project in GitLab to have its own space to store [NPM](https://www.npmjs.com/) packages. | 11.7+ |
-Don't you see your package management system supported yet?
+Don't you see your package management system supported yet?
Please consider contributing
to GitLab. This [development documentation](../development/packages.md) will guide you through the process.
@@ -28,9 +28,9 @@ To enable the Packages feature:
1. Edit `/etc/gitlab/gitlab.rb` and add the following line:
- ```ruby
- gitlab_rails['packages_enabled'] = true
- ```
+ ```ruby
+ gitlab_rails['packages_enabled'] = true
+ ```
1. Save the file and [reconfigure GitLab][] for the changes to take effect.
@@ -39,10 +39,11 @@ To enable the Packages feature:
1. After the installation is complete, you will have to configure the `packages`
section in `config/gitlab.yml`. Set to `true` to enable it:
- ```yaml
- packages:
- enabled: true
- ```
+ ```yaml
+ packages:
+ enabled: true
+ ```
+
1. [Restart GitLab] for the changes to take effect.
## Changing the storage path
@@ -61,9 +62,9 @@ To change the local storage path:
1. Edit `/etc/gitlab/gitlab.rb` and add the following line:
- ```ruby
- gitlab_rails['packages_storage_path'] = "/mnt/packages"
- ```
+ ```ruby
+ gitlab_rails['packages_storage_path'] = "/mnt/packages"
+ ```
1. Save the file and [reconfigure GitLab][] for the changes to take effect.
@@ -71,11 +72,12 @@ To change the local storage path:
1. Edit the `packages` section in `config/gitlab.yml`:
- ```yaml
- packages:
- enabled: true
- storage_path: shared/packages
- ```
+ ```yaml
+ packages:
+ enabled: true
+ storage_path: shared/packages
+ ```
+
1. [Restart GitLab] for the changes to take effect.
### Using object storage
@@ -88,31 +90,31 @@ upload packages:
1. Edit `/etc/gitlab/gitlab.rb` and add the following lines (uncomment where
necessary):
- ```ruby
- gitlab_rails['packages_enabled'] = true
- gitlab_rails['packages_storage_path'] = "/var/opt/gitlab/gitlab-rails/shared/packages"
- gitlab_rails['packages_object_store_enabled'] = true
- gitlab_rails['packages_object_store_remote_directory'] = "packages" # The bucket name.
- gitlab_rails['packages_object_store_direct_upload'] = false # Use Object Storage directly for uploads instead of background uploads if enabled (Default: false).
- gitlab_rails['packages_object_store_background_upload'] = true # Temporary option to limit automatic upload (Default: true).
- gitlab_rails['packages_object_store_proxy_download'] = false # Passthrough all downloads via GitLab instead of using Redirects to Object Storage.
- gitlab_rails['packages_object_store_connection'] = {
- ##
- ## If the provider is AWS S3, uncomment the following
- ##
- #'provider' => 'AWS',
- #'region' => 'eu-west-1',
- #'aws_access_key_id' => 'AWS_ACCESS_KEY_ID',
- #'aws_secret_access_key' => 'AWS_SECRET_ACCESS_KEY',
- ##
- ## If the provider is other than AWS (an S3-compatible one), uncomment the following
- ##
- #'host' => 's3.amazonaws.com',
- #'aws_signature_version' => 4 # For creation of signed URLs. Set to 2 if provider does not support v4.
- #'endpoint' => 'https://s3.amazonaws.com' # Useful for S3-compliant services such as DigitalOcean Spaces.
- #'path_style' => false # If true, use 'host/bucket_name/object' instead of 'bucket_name.host/object'.
- }
- ```
+ ```ruby
+ gitlab_rails['packages_enabled'] = true
+ gitlab_rails['packages_storage_path'] = "/var/opt/gitlab/gitlab-rails/shared/packages"
+ gitlab_rails['packages_object_store_enabled'] = true
+ gitlab_rails['packages_object_store_remote_directory'] = "packages" # The bucket name.
+ gitlab_rails['packages_object_store_direct_upload'] = false # Use Object Storage directly for uploads instead of background uploads if enabled (Default: false).
+ gitlab_rails['packages_object_store_background_upload'] = true # Temporary option to limit automatic upload (Default: true).
+ gitlab_rails['packages_object_store_proxy_download'] = false # Passthrough all downloads via GitLab instead of using Redirects to Object Storage.
+ gitlab_rails['packages_object_store_connection'] = {
+ ##
+ ## If the provider is AWS S3, uncomment the following
+ ##
+ #'provider' => 'AWS',
+ #'region' => 'eu-west-1',
+ #'aws_access_key_id' => 'AWS_ACCESS_KEY_ID',
+ #'aws_secret_access_key' => 'AWS_SECRET_ACCESS_KEY',
+ ##
+ ## If the provider is other than AWS (an S3-compatible one), uncomment the following
+ ##
+ #'host' => 's3.amazonaws.com',
+ #'aws_signature_version' => 4 # For creation of signed URLs. Set to 2 if provider does not support v4.
+ #'endpoint' => 'https://s3.amazonaws.com' # Useful for S3-compliant services such as DigitalOcean Spaces.
+ #'path_style' => false # If true, use 'host/bucket_name/object' instead of 'bucket_name.host/object'.
+ }
+ ```
1. Save the file and [reconfigure GitLab][] for the changes to take effect.
@@ -120,35 +122,35 @@ upload packages:
1. Edit the `packages` section in `config/gitlab.yml` (uncomment where necessary):
- ```yaml
- packages:
- enabled: true
- ##
- ## The location where build packages are stored (default: shared/packages).
- ##
- #storage_path: shared/packages
- object_store:
- enabled: false
- remote_directory: packages # The bucket name.
- #direct_upload: false # Use Object Storage directly for uploads instead of background uploads if enabled (Default: false).
- #background_upload: true # Temporary option to limit automatic upload (Default: true).
- #proxy_download: false # Passthrough all downloads via GitLab instead of using Redirects to Object Storage.
- connection:
- ##
- ## If the provider is AWS S3, uncomment the following
- ##
- #provider: AWS
- #region: us-east-1
- #aws_access_key_id: AWS_ACCESS_KEY_ID
- #aws_secret_access_key: AWS_SECRET_ACCESS_KEY
- ##
- ## If the provider is other than AWS (an S3-compatible one), uncomment the following
- ##
- #host: 's3.amazonaws.com' # default: s3.amazonaws.com.
- #aws_signature_version: 4 # For creation of signed URLs. Set to 2 if provider does not support v4.
- #endpoint: 'https://s3.amazonaws.com' # Useful for S3-compliant services such as DigitalOcean Spaces.
- #path_style: false # If true, use 'host/bucket_name/object' instead of 'bucket_name.host/object'.
- ```
+ ```yaml
+ packages:
+ enabled: true
+ ##
+ ## The location where build packages are stored (default: shared/packages).
+ ##
+ #storage_path: shared/packages
+ object_store:
+ enabled: false
+ remote_directory: packages # The bucket name.
+ #direct_upload: false # Use Object Storage directly for uploads instead of background uploads if enabled (Default: false).
+ #background_upload: true # Temporary option to limit automatic upload (Default: true).
+ #proxy_download: false # Passthrough all downloads via GitLab instead of using Redirects to Object Storage.
+ connection:
+ ##
+ ## If the provider is AWS S3, uncomment the following
+ ##
+ #provider: AWS
+ #region: us-east-1
+ #aws_access_key_id: AWS_ACCESS_KEY_ID
+ #aws_secret_access_key: AWS_SECRET_ACCESS_KEY
+ ##
+ ## If the provider is other than AWS (an S3-compatible one), uncomment the following
+ ##
+ #host: 's3.amazonaws.com' # default: s3.amazonaws.com.
+ #aws_signature_version: 4 # For creation of signed URLs. Set to 2 if provider does not support v4.
+ #endpoint: 'https://s3.amazonaws.com' # Useful for S3-compliant services such as DigitalOcean Spaces.
+ #path_style: false # If true, use 'host/bucket_name/object' instead of 'bucket_name.host/object'.
+ ```
1. [Restart GitLab] for the changes to take effect.
diff --git a/doc/administration/pseudonymizer.md b/doc/administration/pseudonymizer.md
index 036e1d3fe61..78b2751da13 100644
--- a/doc/administration/pseudonymizer.md
+++ b/doc/administration/pseudonymizer.md
@@ -1,4 +1,4 @@
-# Pseudonymizer **[ULTIMATE]**
+# Pseudonymizer **(ULTIMATE)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/5532) in [GitLab Ultimate][ee] 11.1.
@@ -22,36 +22,36 @@ To configure the pseudonymizer, you need to:
- Provide a manifest file that describes which fields should be included or
pseudonymized ([example `manifest.yml` file](https://gitlab.com/gitlab-org/gitlab-ee/tree/master/config/pseudonymizer.yml)).
- A default manifest is provided with the GitLab installation. Using a relative file path will be resolved from the Rails root.
+ A default manifest is provided with the GitLab installation. Using a relative file path will be resolved from the Rails root.
Alternatively, you can use an absolute file path.
-- Use an object storage and specify the connection parameters in the `pseudonymizer.upload.connection` configuration option.
+- Use an object storage and specify the connection parameters in the `pseudonymizer.upload.connection` configuration option.
**For Omnibus installations:**
1. Edit `/etc/gitlab/gitlab.rb` and add the following lines by replacing with
the values you want:
- ```ruby
- gitlab_rails['pseudonymizer_manifest'] = 'config/pseudonymizer.yml'
- gitlab_rails['pseudonymizer_upload_remote_directory'] = 'gitlab-elt' # bucket name
- gitlab_rails['pseudonymizer_upload_connection'] = {
- 'provider' => 'AWS',
- 'region' => 'eu-central-1',
- 'aws_access_key_id' => 'AWS_ACCESS_KEY_ID',
- 'aws_secret_access_key' => 'AWS_SECRET_ACCESS_KEY'
- }
- ```
-
- NOTE: **Note:**
- If you are using AWS IAM profiles, be sure to omit the AWS access key and secret access key/value pairs.
-
- ```ruby
- gitlab_rails['pseudonymizer_upload_connection'] = {
- 'provider' => 'AWS',
- 'region' => 'eu-central-1',
- 'use_iam_profile' => true
- }
- ```
+ ```ruby
+ gitlab_rails['pseudonymizer_manifest'] = 'config/pseudonymizer.yml'
+ gitlab_rails['pseudonymizer_upload_remote_directory'] = 'gitlab-elt' # bucket name
+ gitlab_rails['pseudonymizer_upload_connection'] = {
+ 'provider' => 'AWS',
+ 'region' => 'eu-central-1',
+ 'aws_access_key_id' => 'AWS_ACCESS_KEY_ID',
+ 'aws_secret_access_key' => 'AWS_SECRET_ACCESS_KEY'
+ }
+ ```
+
+ NOTE: **Note:**
+ If you are using AWS IAM profiles, be sure to omit the AWS access key and secret access key/value pairs.
+
+ ```ruby
+ gitlab_rails['pseudonymizer_upload_connection'] = {
+ 'provider' => 'AWS',
+ 'region' => 'eu-central-1',
+ 'use_iam_profile' => true
+ }
+ ```
1. Save the file and [reconfigure GitLab](restart_gitlab.md#omnibus-gitlab-reconfigure)
for the changes to take effect.
@@ -63,17 +63,17 @@ To configure the pseudonymizer, you need to:
1. Edit `/home/git/gitlab/config/gitlab.yml` and add or amend the following
lines:
- ```yaml
- pseudonymizer:
- manifest: config/pseudonymizer.yml
- upload:
- remote_directory: 'gitlab-elt' # bucket name
- connection:
- provider: AWS
- aws_access_key_id: AWS_ACCESS_KEY_ID
- aws_secret_access_key: AWS_SECRET_ACCESS_KEY
- region: eu-central-1
- ```
+ ```yaml
+ pseudonymizer:
+ manifest: config/pseudonymizer.yml
+ upload:
+ remote_directory: 'gitlab-elt' # bucket name
+ connection:
+ provider: AWS
+ aws_access_key_id: AWS_ACCESS_KEY_ID
+ aws_secret_access_key: AWS_SECRET_ACCESS_KEY
+ region: eu-central-1
+ ```
1. Save the file and [restart GitLab](restart_gitlab.md#installations-from-source)
for the changes to take effect.
diff --git a/doc/administration/raketasks/geo.md b/doc/administration/raketasks/geo.md
index 9f3b31442f3..435aed8c413 100644
--- a/doc/administration/raketasks/geo.md
+++ b/doc/administration/raketasks/geo.md
@@ -1,4 +1,4 @@
-# Geo Rake Tasks **[PREMIUM ONLY]**
+# Geo Rake Tasks **(PREMIUM ONLY)**
## Git housekeeping
diff --git a/doc/administration/raketasks/maintenance.md b/doc/administration/raketasks/maintenance.md
index becd480a08f..2b31233d429 100644
--- a/doc/administration/raketasks/maintenance.md
+++ b/doc/administration/raketasks/maintenance.md
@@ -61,7 +61,7 @@ It will check that each component was set up according to the installation guide
You may also have a look at our Troubleshooting Guides:
-- [Troubleshooting Guide (GitLab)](http://docs.gitlab.com/ee/README.html#troubleshooting)
+- [Troubleshooting Guide (GitLab)](../index.md#troubleshooting)
- [Troubleshooting Guide (Omnibus Gitlab)](https://docs.gitlab.com/omnibus/README.html#troubleshooting)
**Omnibus Installation**
diff --git a/doc/administration/raketasks/project_import_export.md b/doc/administration/raketasks/project_import_export.md
index 6ca23aabdec..0599e12b913 100644
--- a/doc/administration/raketasks/project_import_export.md
+++ b/doc/administration/raketasks/project_import_export.md
@@ -1,4 +1,4 @@
-# Project import/export administration **[CORE ONLY]**
+# Project import/export administration **(CORE ONLY)**
>**Note:**
>
diff --git a/doc/administration/reply_by_email_postfix_setup.md b/doc/administration/reply_by_email_postfix_setup.md
index d57fc67c83e..406f7e8a034 100644
--- a/doc/administration/reply_by_email_postfix_setup.md
+++ b/doc/administration/reply_by_email_postfix_setup.md
@@ -14,109 +14,109 @@ The instructions make the assumption that you will be using the email address `i
1. Install the `postfix` package if it is not installed already:
- ```sh
- sudo apt-get install postfix
- ```
+ ```sh
+ sudo apt-get install postfix
+ ```
- When asked about the environment, select 'Internet Site'. When asked to confirm the hostname, make sure it matches `gitlab.example.com`.
+ When asked about the environment, select 'Internet Site'. When asked to confirm the hostname, make sure it matches gitlab.example.com`.
1. Install the `mailutils` package.
- ```sh
- sudo apt-get install mailutils
- ```
+ ```sh
+ sudo apt-get install mailutils
+ ```
## Create user
1. Create a user for incoming email.
- ```sh
- sudo useradd -m -s /bin/bash incoming
- ```
+ ```sh
+ sudo useradd -m -s /bin/bash incoming
+ ```
1. Set a password for this user.
- ```sh
- sudo passwd incoming
- ```
+ ```sh
+ sudo passwd incoming
+ ```
- Be sure not to forget this, you'll need it later.
+ Be sure not to forget this, you'll need it later.
## Test the out-of-the-box setup
1. Connect to the local SMTP server:
- ```sh
- telnet localhost 25
- ```
+ ```sh
+ telnet localhost 25
+ ```
- You should see a prompt like this:
+ You should see a prompt like this:
- ```sh
- Trying 127.0.0.1...
- Connected to localhost.
- Escape character is '^]'.
- 220 gitlab.example.com ESMTP Postfix (Ubuntu)
- ```
+ ```sh
+ Trying 127.0.0.1...
+ Connected to localhost.
+ Escape character is '^]'.
+ 220 gitlab.example.com ESMTP Postfix (Ubuntu)
+ ```
- If you get a `Connection refused` error instead, verify that `postfix` is running:
+ If you get a `Connection refused` error instead, verify that `postfix` is running:
- ```sh
- sudo postfix status
- ```
+ ```sh
+ sudo postfix status
+ ```
- If it is not, start it:
+ If it is not, start it:
- ```sh
- sudo postfix start
- ```
+ ```sh
+ sudo postfix start
+ ```
1. Send the new `incoming` user a dummy email to test SMTP, by entering the following into the SMTP prompt:
- ```
- ehlo localhost
- mail from: root@localhost
- rcpt to: incoming@localhost
- data
- Subject: Re: Some issue
+ ```
+ ehlo localhost
+ mail from: root@localhost
+ rcpt to: incoming@localhost
+ data
+ Subject: Re: Some issue
- Sounds good!
- .
- quit
- ```
+ Sounds good!
+ .
+ quit
+ ```
- _**Note:** The `.` is a literal period on its own line._
+ _**Note:** The `.` is a literal period on its own line._
- _**Note:** If you receive an error after entering `rcpt to: incoming@localhost`
- then your Postfix `my_network` configuration is not correct. The error will
- say 'Temporary lookup failure'. See
- [Configure Postfix to receive email from the Internet](#configure-postfix-to-receive-email-from-the-internet)._
+ _**Note:** If you receive an error after entering `rcpt to: incoming@localhost`
+ then your Postfix `my_network` configuration is not correct. The error will
+ say 'Temporary lookup failure'. See
+ [Configure Postfix to receive email from the Internet](#configure-postfix-to-receive-email-from-the-internet)._
1. Check if the `incoming` user received the email:
- ```sh
- su - incoming
- mail
- ```
+ ```sh
+ su - incoming
+ mail
+ ```
- You should see output like this:
+ You should see output like this:
- ```
- "/var/mail/incoming": 1 message 1 unread
- >U 1 root@localhost 59/2842 Re: Some issue
- ```
+ ```
+ "/var/mail/incoming": 1 message 1 unread
+ >U 1 root@localhost 59/2842 Re: Some issue
+ ```
- Quit the mail app:
+ Quit the mail app:
- ```sh
- q
- ```
+ ```sh
+ q
+ ```
1. Log out of the `incoming` account and go back to being `root`:
- ```sh
- logout
- ```
+ ```sh
+ logout
+ ```
## Configure Postfix to use Maildir-style mailboxes
@@ -124,208 +124,212 @@ Courier, which we will install later to add IMAP authentication, requires mailbo
1. Configure Postfix to use Maildir-style mailboxes:
- ```sh
- sudo postconf -e "home_mailbox = Maildir/"
- ```
+ ```sh
+ sudo postconf -e "home_mailbox = Maildir/"
+ ```
1. Restart Postfix:
- ```sh
- sudo /etc/init.d/postfix restart
- ```
+ ```sh
+ sudo /etc/init.d/postfix restart
+ ```
1. Test the new setup:
- 1. Follow steps 1 and 2 of _[Test the out-of-the-box setup](#test-the-out-of-the-box-setup)_.
- 1. Check if the `incoming` user received the email:
+ 1. Follow steps 1 and 2 of _[Test the out-of-the-box setup](#test-the-out-of-the-box-setup)_.
+ 1. Check if the `incoming` user received the email:
- ```sh
- su - incoming
- MAIL=/home/incoming/Maildir
- mail
- ```
+ ```sh
+ su - incoming
+ MAIL=/home/incoming/Maildir
+ mail
+ ```
- You should see output like this:
+ You should see output like this:
- ```
- "/home/incoming/Maildir": 1 message 1 unread
- >U 1 root@localhost 59/2842 Re: Some issue
- ```
+ ```
+ "/home/incoming/Maildir": 1 message 1 unread
+ >U 1 root@localhost 59/2842 Re: Some issue
+ ```
- Quit the mail app:
+ Quit the mail app:
- ```sh
- q
- ```
+ ```sh
+ q
+ ```
- _**Note:** If `mail` returns an error `Maildir: Is a directory` then your
- version of `mail` doesn't support Maildir style mailboxes. Install
- `heirloom-mailx` by running `sudo apt-get install heirloom-mailx`. Then,
- try the above steps again, substituting `heirloom-mailx` for the `mail`
- command._
+ _**Note:** If `mail` returns an error `Maildir: Is a directory` then your
+ version of `mail` doesn't support Maildir style mailboxes. Install
+ `heirloom-mailx` by running `sudo apt-get install heirloom-mailx`. Then,
+ try the above steps again, substituting `heirloom-mailx` for the `mail`
+ command._
1. Log out of the `incoming` account and go back to being `root`:
- ```sh
- logout
- ```
+ ```sh
+ logout
+ ```
## Install the Courier IMAP server
1. Install the `courier-imap` package:
- ```sh
- sudo apt-get install courier-imap
- ```
+ ```sh
+ sudo apt-get install courier-imap
+ ```
- And start `imapd`:
- ```sh
- imapd start
- ```
+ And start `imapd`:
+
+ ```sh
+ imapd start
+ ```
1. The courier-authdaemon isn't started after installation. Without it, imap authentication will fail:
- ```sh
- sudo service courier-authdaemon start
- ```
- You can also configure courier-authdaemon to start on boot:
- ```sh
- sudo systemctl enable courier-authdaemon
- ```
+
+ ```sh
+ sudo service courier-authdaemon start
+ ```
+
+ You can also configure courier-authdaemon to start on boot:
+
+ ```sh
+ sudo systemctl enable courier-authdaemon
+ ```
## Configure Postfix to receive email from the internet
1. Let Postfix know about the domains that it should consider local:
- ```sh
- sudo postconf -e "mydestination = gitlab.example.com, localhost.localdomain, localhost"
- ```
+ ```sh
+ sudo postconf -e "mydestination = gitlab.example.com, localhost.localdomain, localhost"
+ ```
1. Let Postfix know about the IPs that it should consider part of the LAN:
- We'll assume `192.168.1.0/24` is your local LAN. You can safely skip this step if you don't have other machines in the same local network.
+ We'll assume `192.168.1.0/24` is your local LAN. You can safely skip this step if you don't have other machines in the same local network.
- ```sh
- sudo postconf -e "mynetworks = 127.0.0.0/8, 192.168.1.0/24"
- ```
+ ```sh
+ sudo postconf -e "mynetworks = 127.0.0.0/8, 192.168.1.0/24"
+ ```
1. Configure Postfix to receive mail on all interfaces, which includes the internet:
- ```sh
- sudo postconf -e "inet_interfaces = all"
- ```
+ ```sh
+ sudo postconf -e "inet_interfaces = all"
+ ```
1. Configure Postfix to use the `+` delimiter for sub-addressing:
- ```sh
- sudo postconf -e "recipient_delimiter = +"
- ```
+ ```sh
+ sudo postconf -e "recipient_delimiter = +"
+ ```
1. Restart Postfix:
- ```sh
- sudo service postfix restart
- ```
+ ```sh
+ sudo service postfix restart
+ ```
## Test the final setup
1. Test SMTP under the new setup:
- 1. Connect to the SMTP server:
+ 1. Connect to the SMTP server:
- ```sh
- telnet gitlab.example.com 25
- ```
+ ```sh
+ telnet gitlab.example.com 25
+ ```
- You should see a prompt like this:
+ You should see a prompt like this:
- ```sh
- Trying 123.123.123.123...
- Connected to gitlab.example.com.
- Escape character is '^]'.
- 220 gitlab.example.com ESMTP Postfix (Ubuntu)
- ```
+ ```sh
+ Trying 123.123.123.123...
+ Connected to gitlab.example.com.
+ Escape character is '^]'.
+ 220 gitlab.example.com ESMTP Postfix (Ubuntu)
+ ```
- If you get a `Connection refused` error instead, make sure your firewall is set up 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:
+ 1. Send the `incoming` user a dummy email to test SMTP, by entering the following into the SMTP prompt:
- ```
- ehlo gitlab.example.com
- mail from: root@gitlab.example.com
- rcpt to: incoming@gitlab.example.com
- data
- Subject: Re: Some issue
+ ```
+ ehlo gitlab.example.com
+ mail from: root@gitlab.example.com
+ rcpt to: incoming@gitlab.example.com
+ data
+ Subject: Re: Some issue
- Sounds good!
- .
- quit
- ```
+ Sounds good!
+ .
+ quit
+ ```
- (Note: The `.` is a literal period on its own line)
+ (Note: The `.` is a literal period on its own line)
- 1. Check if the `incoming` user received the email:
+ 1. Check if the `incoming` user received the email:
- ```sh
- su - incoming
- MAIL=/home/incoming/Maildir
- mail
- ```
+ ```sh
+ su - incoming
+ MAIL=/home/incoming/Maildir
+ mail
+ ```
- You should see output like this:
+ You should see output like this:
- ```
- "/home/incoming/Maildir": 1 message 1 unread
- >U 1 root@gitlab.example.com 59/2842 Re: Some issue
- ```
+ ```
+ "/home/incoming/Maildir": 1 message 1 unread
+ >U 1 root@gitlab.example.com 59/2842 Re: Some issue
+ ```
- Quit the mail app:
+ Quit the mail app:
- ```sh
- q
- ```
+ ```sh
+ q
+ ```
- 1. Log out of the `incoming` account and go back to being `root`:
+ 1. Log out of the `incoming` account and go back to being `root`:
- ```sh
- logout
- ```
+ ```sh
+ logout
+ ```
1. Test IMAP under the new setup:
- 1. Connect to the IMAP server:
+ 1. Connect to the IMAP server:
- ```sh
- telnet gitlab.example.com 143
- ```
+ ```sh
+ telnet gitlab.example.com 143
+ ```
- You should see a prompt like this:
+ You should see a prompt like this:
- ```sh
- Trying 123.123.123.123...
- Connected to mail.example.gitlab.com.
- Escape character is '^]'.
- - OK [CAPABILITY IMAP4rev1 UIDPLUS CHILDREN NAMESPACE THREAD=ORDEREDSUBJECT THREAD=REFERENCES SORT QUOTA IDLE ACL ACL2=UNION] Courier-IMAP ready. Copyright 1998-2011 Double Precision, Inc. See COPYING for distribution information.
- ```
+ ```sh
+ Trying 123.123.123.123...
+ Connected to mail.example.gitlab.com.
+ Escape character is '^]'.
+ - OK [CAPABILITY IMAP4rev1 UIDPLUS CHILDREN NAMESPACE THREAD=ORDEREDSUBJECT THREAD=REFERENCES SORT QUOTA IDLE ACL ACL2=UNION] Courier-IMAP ready. Copyright 1998-2011 Double Precision, Inc. See COPYING for distribution information.
+ ```
- 1. Sign in as the `incoming` user to test IMAP, by entering the following into the IMAP prompt:
+ 1. Sign in as the `incoming` user to test IMAP, by entering the following into the IMAP prompt:
- ```
- a login incoming PASSWORD
- ```
+ ```
+ a login incoming PASSWORD
+ ```
- Replace PASSWORD with the password you set on the `incoming` user earlier.
+ Replace PASSWORD with the password you set on the `incoming` user earlier.
- You should see output like this:
+ You should see output like this:
- ```
- a OK LOGIN Ok.
- ```
+ ```
+ a OK LOGIN Ok.
+ ```
- 1. Disconnect from the IMAP server:
+ 1. Disconnect from the IMAP server:
- ```sh
- a logout
- ```
+ ```sh
+ a logout
+ ```
## Done!
diff --git a/doc/administration/repository_storage_paths.md b/doc/administration/repository_storage_paths.md
index 4aafc06cfdc..3de860f9240 100644
--- a/doc/administration/repository_storage_paths.md
+++ b/doc/administration/repository_storage_paths.md
@@ -68,18 +68,18 @@ NOTE: **Note:** This example uses NFS and CephFS. We do not recommend using EFS
1. Edit `gitlab.yml` and add the storage paths:
- ```yaml
- repositories:
- # Paths where repositories can be stored. Give the canonicalized absolute pathname.
- # NOTE: REPOS PATHS MUST NOT CONTAIN ANY SYMLINK!!!
- storages: # You must have at least a 'default' storage path.
- default:
- path: /home/git/repositories
- nfs:
- path: /mnt/nfs/repositories
- cephfs:
- path: /mnt/cephfs/repositories
- ```
+ ```yaml
+ repositories:
+ # Paths where repositories can be stored. Give the canonicalized absolute pathname.
+ # NOTE: REPOS PATHS MUST NOT CONTAIN ANY SYMLINK!!!
+ storages: # You must have at least a 'default' storage path.
+ default:
+ path: /home/git/repositories
+ nfs:
+ path: /mnt/nfs/repositories
+ cephfs:
+ path: /mnt/cephfs/repositories
+ ```
1. [Restart GitLab][restart-gitlab] for the changes to take effect.
@@ -97,16 +97,16 @@ working, you can remove the `repos_path` line.
1. Edit `/etc/gitlab/gitlab.rb` by appending the rest of the paths to the
default one:
- ```ruby
- git_data_dirs({
- "default" => { "path" => "/var/opt/gitlab/git-data" },
- "nfs" => { "path" => "/mnt/nfs/git-data" },
- "cephfs" => { "path" => "/mnt/cephfs/git-data" }
- })
- ```
+ ```ruby
+ git_data_dirs({
+ "default" => { "path" => "/var/opt/gitlab/git-data" },
+ "nfs" => { "path" => "/mnt/nfs/git-data" },
+ "cephfs" => { "path" => "/mnt/cephfs/git-data" }
+ })
+ ```
- Note that Omnibus stores the repositories in a `repositories` subdirectory
- of the `git-data` directory.
+ Note that Omnibus stores the repositories in a `repositories` subdirectory
+ of the `git-data` directory.
## Choose where new project repositories will be stored
diff --git a/doc/administration/repository_storage_types.md b/doc/administration/repository_storage_types.md
index 834b41b3a2c..9dea6074a3f 100644
--- a/doc/administration/repository_storage_types.md
+++ b/doc/administration/repository_storage_types.md
@@ -6,19 +6,19 @@ Two different storage layouts can be used
to store the repositories on disk and their characteristics.
GitLab can be configured to use one or multiple repository shard locations
-that can be:
+that can be:
- Mounted to the local disk
- Exposed as an NFS shared volume
- Acessed via [gitaly] on its own machine.
In GitLab, this is configured in `/etc/gitlab/gitlab.rb` by the `git_data_dirs({})`
-configuration hash. The storage layouts discussed here will apply to any shard
+configuration hash. The storage layouts discussed here will apply to any shard
defined in it.
The `default` repository shard that is available in any installations
that haven't customized it, points to the local folder: `/var/opt/gitlab/git-data`.
-Anything discussed below is expected to be part of that folder.
+Anything discussed below is expected to be part of that folder.
## Legacy Storage
@@ -80,25 +80,20 @@ by another folder with the next 2 characters. They are both stored in a special
### Hashed object pools
-CAUTION: **Beta:**
-Hashed objects pools are considered beta, and are not ready for production use.
-Follow [gitaly#1548](https://gitlab.com/gitlab-org/gitaly/issues/1548) for
-updates.
+> [Introduced](https://gitlab.com/gitlab-org/gitaly/issues/1606) in GitLab 12.1.
-For deduplication of public forks and their parent repository, objects are pooled
-in an object pool. These object pools are a third repository where shared objects
-are stored.
+Forks of public projects are deduplicated by creating a third repository, the object pool, containing the objects from the source project. Using `objects/info/alternates`, the source project and forks use the object pool for shared objects. Objects are moved from the source project to the object pool when housekeeping is run on the source project.
```ruby
# object pool paths
"@pools/#{hash[0..1]}/#{hash[2..3]}/#{hash}.git"
```
-The object pool feature is behind the `object_pools` feature flag, and can be
-enabled for individual projects by executing
-`Feature.enable(:object_pools, Project.find(<id>))`. Note that the project has to
-be on hashed storage, should not be a fork itself, and hashed storage should be
-enabled for all new projects.
+Object pools can be disabled using the `object_pools` feature flag, and can be
+disabled for individual projects by executing
+`Feature.disable(:object_pools, Project.find(<id>))`. Disabling object pools
+will not change existing deduplicated forks, but will prevent new forks from
+being deduplicated.
DANGER: **Danger:**
Do not run `git prune` or `git gc` in pool repositories! This can
@@ -108,7 +103,7 @@ question.
### How to migrate to Hashed Storage
To start a migration, enable Hashed Storage for new projects:
-
+
1. Go to **Admin > Settings > Repository** and expand the **Repository Storage** section.
2. Select the **Use hashed storage paths for newly created and renamed projects** checkbox.
@@ -129,7 +124,7 @@ an Omnibus Gitlab installation:
sudo gitlab-rake gitlab:storage:migrate_to_hashed ID_FROM=50 ID_TO=100
```
-Check the [documentation][rake/migrate-to-hashed] for additional information and instructions for
+Check the [documentation][rake/migrate-to-hashed] for additional information and instructions for
source-based installation.
#### Rollback
@@ -140,12 +135,12 @@ projects:
1. Go to **Admin > Settings > Repository** and expand the **Repository Storage** section.
2. Uncheck the **Use hashed storage paths for newly created and renamed projects** checkbox.
-To schedule a complete rollback, see the
+To schedule a complete rollback, see the
[rake task documentation for storage rollback](raketasks/storage.md#rollback-from-hashed-storage-to-legacy-storage) for instructions.
The rollback task also supports specifying a range of Project IDs. Here is an example
of limiting the rollout to Project IDs 50 to 100, in an Omnibus Gitlab installation:
-
+
```bash
sudo gitlab-rake gitlab:storage:rollback_to_legacy ID_FROM=50 ID_TO=100
```
diff --git a/doc/administration/restart_gitlab.md b/doc/administration/restart_gitlab.md
index cbc3fbd9473..e23f2052d04 100644
--- a/doc/administration/restart_gitlab.md
+++ b/doc/administration/restart_gitlab.md
@@ -137,9 +137,9 @@ If you are using other init systems, like systemd, you can check the
[GitLab Recipes][gl-recipes] repository for some unofficial services. These are
**not** officially supported so use them at your own risk.
-[omnibus-dl]: https://about.gitlab.com/downloads/ "Download the Omnibus packages"
+[omnibus-dl]: https://about.gitlab.com/install/ "Download the Omnibus packages"
[install]: ../install/installation.md "Documentation to install GitLab from source"
[mailroom]: reply_by_email.md "Used for replying by email in GitLab issues and merge requests"
-[chef]: https://www.chef.io/chef/ "Chef official website"
+[chef]: https://www.chef.io/products/chef-infra/ "Chef official website"
[src-service]: https://gitlab.com/gitlab-org/gitlab-ce/blob/master/lib/support/init.d/gitlab "GitLab init service file"
[gl-recipes]: https://gitlab.com/gitlab-org/gitlab-recipes/tree/master/init "GitLab Recipes repository"
diff --git a/doc/administration/uploads.md b/doc/administration/uploads.md
index 708b59a273b..c6529812ec3 100644
--- a/doc/administration/uploads.md
+++ b/doc/administration/uploads.md
@@ -3,7 +3,7 @@
>**Notes:**
Uploads represent all user data that may be sent to GitLab as a single file. As an example, avatars and notes' attachments are uploads. Uploads are integral to GitLab functionality, and therefore cannot be disabled.
-### Using local storage
+## Using local storage
>**Notes:**
This is the default configuration
@@ -23,10 +23,10 @@ _The uploads are stored by default in `/var/opt/gitlab/gitlab-rails/uploads`._
1. To change the storage path for example to `/mnt/storage/uploads`, edit
`/etc/gitlab/gitlab.rb` and add the following line:
- ```ruby
- gitlab_rails['uploads_storage_path'] = "/mnt/storage/"
- gitlab_rails['uploads_base_dir'] = "uploads"
- ```
+ ```ruby
+ gitlab_rails['uploads_storage_path'] = "/mnt/storage/"
+ gitlab_rails['uploads_base_dir'] = "uploads"
+ ```
1. Save the file and [reconfigure GitLab][] for the changes to take effect.
@@ -40,15 +40,15 @@ _The uploads are stored by default in
1. To change the storage path for example to `/mnt/storage/uploads`, edit
`/home/git/gitlab/config/gitlab.yml` and add or amend the following lines:
- ```yaml
- uploads:
- storage_path: /mnt/storage
- base_dir: uploads
- ```
+ ```yaml
+ uploads:
+ storage_path: /mnt/storage
+ base_dir: uploads
+ ```
1. Save the file and [restart GitLab][] for the changes to take effect.
-### Using object storage **[CORE ONLY]**
+## Using object storage **(CORE ONLY)**
> **Notes:**
>
@@ -60,7 +60,7 @@ If you don't want to use the local disk where GitLab is installed to store the
uploads, you can use an object storage provider like AWS S3 instead.
This configuration relies on valid AWS credentials to be configured already.
-### Object Storage Settings
+## Object Storage Settings
For source installations the following settings are nested under `uploads:` and then `object_store:`. On omnibus installs they are prefixed by `uploads_object_store_`.
@@ -73,7 +73,7 @@ For source installations the following settings are nested under `uploads:` and
| `proxy_download` | Set to true to enable proxying all files served. Option allows to reduce egress traffic as this allows clients to download directly from remote storage instead of proxying all data | `false` |
| `connection` | Various connection options described below | |
-#### S3 compatible connection settings
+### S3 compatible connection settings
The connection settings match those provided by [Fog](https://github.com/fog), and are as follows:
@@ -97,27 +97,27 @@ _The uploads are stored by default in
1. Edit `/etc/gitlab/gitlab.rb` and add the following lines by replacing with
the values you want:
- ```ruby
- gitlab_rails['uploads_object_store_enabled'] = true
- gitlab_rails['uploads_object_store_remote_directory'] = "uploads"
- gitlab_rails['uploads_object_store_connection'] = {
- 'provider' => 'AWS',
- 'region' => 'eu-central-1',
- 'aws_access_key_id' => 'AWS_ACCESS_KEY_ID',
- 'aws_secret_access_key' => 'AWS_SECRET_ACCESS_KEY'
- }
- ```
-
- >**Note:**
- If you are using AWS IAM profiles, be sure to omit the AWS access key and secret access key/value pairs.
-
- ```ruby
- gitlab_rails['uploads_object_store_connection'] = {
- 'provider' => 'AWS',
- 'region' => 'eu-central-1',
- 'use_iam_profile' => true
- }
- ```
+ ```ruby
+ gitlab_rails['uploads_object_store_enabled'] = true
+ gitlab_rails['uploads_object_store_remote_directory'] = "uploads"
+ gitlab_rails['uploads_object_store_connection'] = {
+ 'provider' => 'AWS',
+ 'region' => 'eu-central-1',
+ 'aws_access_key_id' => 'AWS_ACCESS_KEY_ID',
+ 'aws_secret_access_key' => 'AWS_SECRET_ACCESS_KEY'
+ }
+ ```
+
+ >**Note:**
+ >If you are using AWS IAM profiles, be sure to omit the AWS access key and secret access key/value pairs.
+
+ ```ruby
+ gitlab_rails['uploads_object_store_connection'] = {
+ 'provider' => 'AWS',
+ 'region' => 'eu-central-1',
+ 'use_iam_profile' => true
+ }
+ ```
1. Save the file and [reconfigure GitLab][] for the changes to take effect.
1. Migrate any existing local uploads to the object storage using [`gitlab:uploads:migrate` rake task](raketasks/uploads/migrate.md).
@@ -132,17 +132,17 @@ _The uploads are stored by default in
1. Edit `/home/git/gitlab/config/gitlab.yml` and add or amend the following
lines:
- ```yaml
- uploads:
- object_store:
- enabled: true
- remote_directory: "uploads" # The bucket name
- connection:
- provider: AWS # Only AWS supported at the moment
- aws_access_key_id: AWS_ACESS_KEY_ID
- aws_secret_access_key: AWS_SECRET_ACCESS_KEY
- region: eu-central-1
- ```
+ ```yaml
+ uploads:
+ object_store:
+ enabled: true
+ remote_directory: "uploads" # The bucket name
+ connection:
+ provider: AWS # Only AWS supported at the moment
+ aws_access_key_id: AWS_ACESS_KEY_ID
+ aws_secret_access_key: AWS_SECRET_ACCESS_KEY
+ region: eu-central-1
+ ```
1. Save the file and [restart GitLab][] for the changes to take effect.
1. Migrate any existing local uploads to the object storage using [`gitlab:uploads:migrate` rake task](raketasks/uploads/migrate.md).
diff --git a/doc/api/README.md b/doc/api/README.md
index 23c69deef23..3ded230370c 100644
--- a/doc/api/README.md
+++ b/doc/api/README.md
@@ -37,16 +37,16 @@ The following API resources are available in the project context:
| [Issues](issues.md) | `/projects/:id/issues` (also available for groups and standalone) |
| [Issues Statistics](issues_statistics.md) | `/projects/:id/issues_statistics` (also available for groups and standalone) |
| [Issue boards](boards.md) | `/projects/:id/boards` |
-| [Issue links](issue_links.md) **[STARTER]** | `/projects/:id/issues/.../links` |
+| [Issue links](issue_links.md) **(STARTER)** | `/projects/:id/issues/.../links` |
| [Jobs](jobs.md) | `/projects/:id/jobs`, `/projects/:id/pipelines/.../jobs` |
| [Labels](labels.md) | `/projects/:id/labels` |
-| [Managed licenses](managed_licenses.md) **[ULTIMATE]** | `/projects/:id/managed_licenses` |
+| [Managed licenses](managed_licenses.md) **(ULTIMATE)** | `/projects/:id/managed_licenses` |
| [Members](members.md) | `/projects/:id/members` (also available for groups) |
-| [Merge request approvals](merge_request_approvals.md) **[STARTER]** | `/projects/:id/approvals`, `/projects/:id/merge_requests/.../approvals` |
+| [Merge request approvals](merge_request_approvals.md) **(STARTER)** | `/projects/:id/approvals`, `/projects/:id/merge_requests/.../approvals` |
| [Merge requests](merge_requests.md) | `/projects/:id/merge_requests` (also available for groups and standalone) |
| [Notes](notes.md) (comments) | `/projects/:id/issues/.../notes`, `/projects/:id/snippets/.../notes`, `/projects/:id/merge_requests/.../notes` (also available for groups) |
| [Notification settings](notification_settings.md) | `/projects/:id/notification_settings` (also available for groups and standalone) |
-| [Packages](packages.md) **[PREMIUM]** | `/projects/:id/packages` |
+| [Packages](packages.md) **(PREMIUM)** | `/projects/:id/packages` |
| [Pages domains](pages_domains.md) | `/projects/:id/pages` (also available standalone) |
| [Pipelines](pipelines.md) | `/projects/:id/pipelines` |
| [Pipeline schedules](pipeline_schedules.md) | `/projects/:id/pipeline_schedules` |
@@ -71,7 +71,7 @@ The following API resources are available in the project context:
| [Search](search.md) | `/projects/:id/search` (also available for groups and standalone) |
| [Services](services.md) | `/projects/:id/services` |
| [Tags](tags.md) | `/projects/:id/repository/tags` |
-| [Vulnerabilities](vulnerabilities.md) **[ULTIMATE]** | `/projects/:id/vulnerabilities` (also available for groups) |
+| [Vulnerabilities](vulnerabilities.md) **(ULTIMATE)** | `/projects/:id/vulnerabilities` (also available for groups) |
| [Wikis](wikis.md) | `/projects/:id/wikis` |
### Group resources
@@ -82,10 +82,10 @@ The following API resources are available in the group context:
|:-----------------------------------------------------------------|:---------------------------------------------------------------------------------|
| [Access requests](access_requests.md) | `/groups/:id/access_requests/` (also available for projects) |
| [Custom attributes](custom_attributes.md) | `/groups/:id/custom_attributes` (also available for projects and users) |
-| [Discussions](discussions.md) (threaded comments) **[ULTIMATE]** | `/groups/:id/epics/.../discussions` (also available for projects) |
-| [Epic issues](epic_issues.md) **[ULTIMATE]** | `/groups/:id/epics/.../issues` |
-| [Epic links](epic_links.md) **[ULTIMATE]** | `/groups/:id/epics/.../epics` |
-| [Epics](epics.md) **[ULTIMATE]** | `/groups/:id/epics` |
+| [Discussions](discussions.md) (threaded comments) **(ULTIMATE)** | `/groups/:id/epics/.../discussions` (also available for projects) |
+| [Epic issues](epic_issues.md) **(ULTIMATE)** | `/groups/:id/epics/.../issues` |
+| [Epic links](epic_links.md) **(ULTIMATE)** | `/groups/:id/epics/.../epics` |
+| [Epics](epics.md) **(ULTIMATE)** | `/groups/:id/epics` |
| [Groups](groups.md) | `/groups`, `/groups/.../subgroups` |
| [Group badges](group_badges.md) | `/groups/:id/badges` |
| [Group issue boards](group_boards.md) | `/groups/:id/boards` |
@@ -115,12 +115,12 @@ The following API resources are available outside of project and group contexts
| [Deploy keys](deploy_keys.md) | `/deploy_keys` (also available for projects) |
| [Events](events.md) | `/events`, `/users/:id/events` (also available for projects) |
| [Feature flags](features.md) | `/features` |
-| [Geo Nodes](geo_nodes.md) **[PREMIUM ONLY]** | `/geo_nodes` |
+| [Geo Nodes](geo_nodes.md) **(PREMIUM ONLY)** | `/geo_nodes` |
| [Import repository from GitHub](import.md) | `/import/github` |
| [Issues](issues.md) | `/issues` (also available for groups and projects) |
| [Issues Statistics](issues_statistics.md) | `/issues_statistics` (also available for groups and projects) |
| [Keys](keys.md) | `/keys` |
-| [License](license.md) **[CORE ONLY]** | `/license` |
+| [License](license.md) **(CORE ONLY)** | `/license` |
| [Markdown](markdown.md) | `/markdown` |
| [Merge requests](merge_requests.md) | `/merge_requests` (also available for groups and projects) |
| [Namespaces](namespaces.md) | `/namespaces` |
@@ -147,7 +147,7 @@ Endpoints are available for:
- [GitLab CI YAML templates](templates/gitlab_ci_ymls.md).
- [Open source license templates](templates/licenses.md).
-## SCIM **[SILVER ONLY]**
+## SCIM **(SILVER ONLY)**
[GitLab.com Silver and above](https://about.gitlab.com/pricing/) provides an [SCIM API](scim.md) that implements [the RFC7644 protocol](https://tools.ietf.org/html/rfc7644) and provides
the `/Users` endpoint. The base URL is: `/api/scim/v2/groups/:group_path/Users/`.
@@ -311,9 +311,9 @@ By default, impersonation is enabled. To disable impersonation:
1. Edit `/etc/gitlab/gitlab.rb`:
- ```ruby
- gitlab_rails['impersonation_enabled'] = false
- ```
+ ```ruby
+ gitlab_rails['impersonation_enabled'] = false
+ ```
1. Save the file and [reconfigure](../administration/restart_gitlab.md#omnibus-gitlab-reconfigure)
GitLab for the changes to take effect.
@@ -326,10 +326,10 @@ To re-enable impersonation, remove this configuration and reconfigure GitLab.
1. Edit `config/gitlab.yml`:
- ```yaml
- gitlab:
- impersonation_enabled: false
- ```
+ ```yaml
+ gitlab:
+ impersonation_enabled: false
+ ```
1. Save the file and [restart](../administration/restart_gitlab.md#installations-from-source)
GitLab for the changes to take effect.
diff --git a/doc/api/boards.md b/doc/api/boards.md
index a96206f5df3..08ec1d832df 100644
--- a/doc/api/boards.md
+++ b/doc/api/boards.md
@@ -141,7 +141,7 @@ Example response:
}
```
-## Create a board **[STARTER]**
+## Create a board **(STARTER)**
Creates a board.
@@ -209,7 +209,7 @@ Example response:
}
```
-## Update a board **[STARTER]**
+## Update a board **(STARTER)**
> [Introduced][ee-5954] in [GitLab Starter](https://about.gitlab.com/pricing/) 11.1.
@@ -229,7 +229,6 @@ PUT /projects/:id/boards/:board_id
| `labels` | string | no | Comma-separated list of label names which the board should be scoped to |
| `weight` | integer | no | The weight range from 0 to 9, to which the board should be scoped to |
-
```bash
curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/boards/1?name=new_name&milestone_id=43&assignee_id=1&labels=Doing&weight=4
```
@@ -291,7 +290,7 @@ Example response:
}
```
-## Delete a board **[STARTER]**
+## Delete a board **(STARTER)**
Deletes a board.
@@ -405,8 +404,8 @@ POST /projects/:id/boards/:board_id/lists
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
| `board_id` | integer | yes | The ID of a board |
| `label_id` | integer | no | The ID of a label |
-| `assignee_id` **[PREMIUM]** | integer | no | The ID of a user |
-| `milestone_id` **[PREMIUM]** | integer | no | The ID of a milestone |
+| `assignee_id` **(PREMIUM)** | integer | no | The ID of a user |
+| `milestone_id` **(PREMIUM)** | integer | no | The ID of a milestone |
NOTE: **Note**:
Label, assignee and milestone arguments are mutually exclusive,
diff --git a/doc/api/deploy_keys.md b/doc/api/deploy_keys.md
index 1d7523fcc3d..41f6ab436e8 100644
--- a/doc/api/deploy_keys.md
+++ b/doc/api/deploy_keys.md
@@ -19,13 +19,13 @@ Example response:
{
"id": 1,
"title": "Public key",
- "key": "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt4596k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0=",
+ "key": "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt4596k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0=",
"created_at": "2013-10-02T10:12:29Z"
},
{
"id": 3,
"title": "Another Public key",
- "key": "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt4596k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0=",
+ "key": "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt4596k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0=",
"created_at": "2013-10-02T11:12:29Z"
}
]
diff --git a/doc/api/discussions.md b/doc/api/discussions.md
index 9defef4fd53..208b8dca2e2 100644
--- a/doc/api/discussions.md
+++ b/doc/api/discussions.md
@@ -4,7 +4,7 @@ Discussions are a set of related notes on:
- Snippets
- Issues
-- Epics **[ULTIMATE]**
+- Epics **(ULTIMATE)**
- Merge requests
- Commits
@@ -430,7 +430,7 @@ Parameters:
curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/snippets/11/discussions/636
```
-## Epics **[ULTIMATE]**
+## Epics **(ULTIMATE)**
### List group epic discussions
diff --git a/doc/api/epic_issues.md b/doc/api/epic_issues.md
index ec59ea7068e..02317cc6c09 100644
--- a/doc/api/epic_issues.md
+++ b/doc/api/epic_issues.md
@@ -1,4 +1,4 @@
-# Epic Issues API **[ULTIMATE]**
+# Epic Issues API **(ULTIMATE)**
Every API call to epic_issues must be authenticated.
diff --git a/doc/api/epic_links.md b/doc/api/epic_links.md
index 9ad90a6d0f1..6089198e46a 100644
--- a/doc/api/epic_links.md
+++ b/doc/api/epic_links.md
@@ -1,4 +1,4 @@
-# Epic Links API **[ULTIMATE]**
+# Epic Links API **(ULTIMATE)**
>**Note:**
> This endpoint was [introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/9188) in GitLab 11.8.
diff --git a/doc/api/epics.md b/doc/api/epics.md
index 0541cfaa715..d05eb0a8804 100644
--- a/doc/api/epics.md
+++ b/doc/api/epics.md
@@ -1,4 +1,4 @@
-# Epics API **[ULTIMATE]**
+# Epics API **(ULTIMATE)**
Every API call to epic must be authenticated.
@@ -302,7 +302,7 @@ POST /groups/:id/epics/:epic_iid/todo
| Attribute | Type | Required | Description |
|-------------|---------|----------|--------------------------------------|
| `id` | integer/string | yes | The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) owned by the authenticated user |
-| `epic_iid ` | integer | yes | The internal ID of a group's epic |
+| `epic_iid` | integer | yes | The internal ID of a group's epic |
```bash
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/groups/1/epics/5/todo
diff --git a/doc/api/geo_nodes.md b/doc/api/geo_nodes.md
index ea31abdd87e..ac64cbedf7d 100644
--- a/doc/api/geo_nodes.md
+++ b/doc/api/geo_nodes.md
@@ -1,4 +1,4 @@
-# Geo Nodes API **[PREMIUM ONLY]**
+# Geo Nodes API **(PREMIUM ONLY)**
In order to interact with Geo node endpoints, you need to authenticate yourself
as an admin.
diff --git a/doc/api/graphql/index.md b/doc/api/graphql/index.md
index 6c1cce620ca..db073321808 100644
--- a/doc/api/graphql/index.md
+++ b/doc/api/graphql/index.md
@@ -1,4 +1,4 @@
-# GraphQL API (Alpha)
+# GraphQL API
> [Introduced][ce-19008] in GitLab 11.0.
@@ -23,30 +23,20 @@ programmatically with GitLab. To achieve this, it needs full coverage - anything
possible in the REST API should also be possible in the GraphQL API.
To help us meet this vision, the frontend should use GraphQL in preference to
-the REST API for new features, although the alpha status of GraphQL may prevent
-this from being a possibility at times.
+the REST API for new features.
There are no plans to deprecate the REST API. To reduce the technical burden of
supporting two APIs in parallel, they should share implementations as much as
possible.
-## Enabling the GraphQL feature
-
-The GraphQL API itself is currently in Alpha, and therefore hidden behind a
-feature flag. You can enable the feature using the [features api][features-api] on a self-hosted instance.
-
-For example:
-
-```shell
-curl --data "value=100" --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/features/graphql
-```
+As of the 12.1 release, GraphQL is always enabled.
## Available queries
A first iteration of a GraphQL API includes the following queries
1. `project` : Within a project it is also possible to fetch a `mergeRequest` by IID.
-1. `group` : Basic group information and epics **[ULTIMATE]** are currently supported.
+1. `group` : Basic group information and epics **(ULTIMATE)** are currently supported.
1. `namespace` : Within a namespace it is also possible to fetch `projects`.
### Multiplex queries
diff --git a/doc/api/group_boards.md b/doc/api/group_boards.md
index 9b0ac23b41c..4d10f83720b 100644
--- a/doc/api/group_boards.md
+++ b/doc/api/group_boards.md
@@ -5,7 +5,7 @@ Every API call to group boards must be authenticated.
If a user is not a member of a group and the group is private, a `GET`
request will result in `404` status code.
-## Group Board
+## List all group issue boards in a group
Lists Issue Boards in the given group.
@@ -27,7 +27,68 @@ Example response:
[
{
"id": 1,
- "group_id": 5,
+ "name:": "group issue board",
+ "group": {
+ "id": 5,
+ "name": "Documentcloud",
+ "web_url": "http://example.com/groups/documentcloud"
+ },
+ "milestone": {
+ "id": 12
+ "title": "10.0"
+ },
+ "lists" : [
+ {
+ "id" : 1,
+ "label" : {
+ "name" : "Testing",
+ "color" : "#F0AD4E",
+ "description" : null
+ },
+ "position" : 1
+ },
+ {
+ "id" : 2,
+ "label" : {
+ "name" : "Ready",
+ "color" : "#FF0000",
+ "description" : null
+ },
+ "position" : 2
+ },
+ {
+ "id" : 3,
+ "label" : {
+ "name" : "Production",
+ "color" : "#FF5F00",
+ "description" : null
+ },
+ "position" : 3
+ }
+ ]
+ }
+]
+```
+
+Users on GitLab [Premium, Silver, or higher](https://about.gitlab.com/pricing/) will see
+different parameters, due to the ability to have multiple group boards.
+
+Example response:
+
+```json
+[
+ {
+ "id": 1,
+ "name:": "group issue board",
+ "group": {
+ "id": 5,
+ "name": "Documentcloud",
+ "web_url": "http://example.com/groups/documentcloud"
+ },
+ "milestone": {
+ "id": 12
+ "title": "10.0"
+ },
"lists" : [
{
"id" : 1,
@@ -61,9 +122,9 @@ Example response:
]
```
-## Single board
+## Single group issue board
-Gets a single board.
+Gets a single group issue board.
```
GET /groups/:id/boards/:board_id
@@ -83,7 +144,66 @@ Example response:
```json
{
"id": 1,
- "group_id": 5,
+ "name:": "group issue board",
+ "group": {
+ "id": 5,
+ "name": "Documentcloud",
+ "web_url": "http://example.com/groups/documentcloud"
+ },
+ "milestone": {
+ "id": 12
+ "title": "10.0"
+ },
+ "lists" : [
+ {
+ "id" : 1,
+ "label" : {
+ "name" : "Testing",
+ "color" : "#F0AD4E",
+ "description" : null
+ },
+ "position" : 1
+ },
+ {
+ "id" : 2,
+ "label" : {
+ "name" : "Ready",
+ "color" : "#FF0000",
+ "description" : null
+ },
+ "position" : 2
+ },
+ {
+ "id" : 3,
+ "label" : {
+ "name" : "Production",
+ "color" : "#FF5F00",
+ "description" : null
+ },
+ "position" : 3
+ }
+ ]
+ }
+```
+
+Users on GitLab [Premium, Silver, or higher](https://about.gitlab.com/pricing/) will see
+different parameters, due to the ability to have multiple group issue boards.s
+
+Example response:
+
+```json
+ {
+ "id": 1,
+ "name:": "group issue board",
+ "group": {
+ "id": 5,
+ "name": "Documentcloud",
+ "web_url": "http://example.com/groups/documentcloud"
+ },
+ "milestone": {
+ "id": 12
+ "title": "10.0"
+ },
"lists" : [
{
"id" : 1,
@@ -116,7 +236,156 @@ Example response:
}
```
-## List board lists
+## Create a group issue board **(PREMIUM)**
+
+Creates a Group Issue Board.
+
+```
+POST /groups/:id/boards
+```
+
+| Attribute | Type | Required | Description |
+| --------- | ---- | -------- | ----------- |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) owned by the authenticated user |
+| `name` | string | yes | The name of the new board |
+
+```bash
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/groups/5/boards?name=newboard
+```
+
+Example response:
+
+```json
+ {
+ "id": 1,
+ "name": "newboard",
+ "group": {
+ "id": 5,
+ "name": "Documentcloud",
+ "web_url": "http://example.com/groups/documentcloud"
+ },
+ "milestone": {
+ "id": 12
+ "title": "10.0"
+ },
+ "lists" : [
+ {
+ "id" : 1,
+ "label" : {
+ "name" : "Testing",
+ "color" : "#F0AD4E",
+ "description" : null
+ },
+ "position" : 1
+ },
+ {
+ "id" : 2,
+ "label" : {
+ "name" : "Ready",
+ "color" : "#FF0000",
+ "description" : null
+ },
+ "position" : 2
+ },
+ {
+ "id" : 3,
+ "label" : {
+ "name" : "Production",
+ "color" : "#FF5F00",
+ "description" : null
+ },
+ "position" : 3
+ }
+ ]
+ }
+```
+
+## Update a group issue board **(PREMIUM)**
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/5954) in GitLab 11.1.
+
+Updates a Group Issue Board.
+
+```
+PUT /groups/:id/boards/:board_id
+```
+
+| Attribute | Type | Required | Description |
+| ------------------- | -------------- | -------- | ----------- |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) owned by the authenticated user |
+| `board_id` | integer | yes | The ID of a board |
+| `name` | string | no | The new name of the board |
+| `assignee_id` | integer | no | The assignee the board should be scoped to |
+| `milestone_id` | integer | no | The milestone the board should be scoped to |
+| `labels` | string | no | Comma-separated list of label names which the board should be scoped to |
+| `weight` | integer | no | The weight range from 0 to 9, to which the board should be scoped to |
+
+```bash
+curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/groups/5/boards/1?name=new_name&milestone_id=44&assignee_id=1&labels=GroupLabel&weight=4
+```
+
+Example response:
+
+```json
+ {
+ "id": 1,
+ "project": null,
+ "lists": [],
+ "name": "new_name",
+ "group": {
+ "id": 5,
+ "name": "Documentcloud",
+ "web_url": "http://example.com/groups/documentcloud"
+ },
+ "milestone": {
+ "id": 44,
+ "iid": 1,
+ "group_id": 5,
+ "title": "Group Milestone",
+ "description": "Group Milestone Desc",
+ "state": "active",
+ "created_at": "2018-07-03T07:15:19.271Z",
+ "updated_at": "2018-07-03T07:15:19.271Z",
+ "due_date": null,
+ "start_date": null,
+ "web_url": "http://example.com/groups/documentcloud/-/milestones/1"
+ },
+ "assignee": {
+ "id": 1,
+ "name": "Administrator",
+ "username": "root",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon",
+ "web_url": "http://example.com/root"
+ },
+ "labels": [{
+ "id": 11,
+ "name": "GroupLabel",
+ "color": "#428BCA",
+ "description": ""
+ }],
+ "weight": 4
+ }
+```
+
+## Delete a group issue board **(PREMIUM)**
+
+Deletes a Group Issue Board.
+
+```
+DELETE /groups/:id/boards/:board_id
+```
+
+| Attribute | Type | Required | Description |
+| --------- | ---- | -------- | ----------- |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) owned by the authenticated user |
+| `board_id` | integer | yes | The ID of a board |
+
+```bash
+curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/groups/5/boards/1
+```
+
+## List group issue board lists
Get a list of the board's lists.
Does not include `open` and `closed` lists
@@ -168,7 +437,7 @@ Example response:
]
```
-## Single board list
+## Single group issue board list
Get a single board list.
@@ -200,7 +469,7 @@ Example response:
}
```
-## New board list
+## New group issue board list
Creates a new Issue Board list.
@@ -232,7 +501,7 @@ Example response:
}
```
-## Edit board list
+## Edit group issue board list
Updates an existing Issue Board list. This call is used to change list position.
@@ -265,7 +534,7 @@ Example response:
}
```
-## Delete a board list
+## Delete a group issue board list
Only for admins and group owners. Soft deletes the board list in question.
diff --git a/doc/api/group_milestones.md b/doc/api/group_milestones.md
index 260eb09cc38..a819e06bcd9 100644
--- a/doc/api/group_milestones.md
+++ b/doc/api/group_milestones.md
@@ -18,13 +18,13 @@ GET /groups/:id/milestones?search=version
Parameters:
-| Attribute | Type | Required | Description |
-| --------- | ---- | -------- | ----------- |
-| `id` | integer/string | yes | The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) owned by the authenticated user |
-| `iids[]` | Array[integer] | optional | Return only the milestones having the given `iid` |
-| `state` | string | optional | Return only `active` or `closed` milestones |
-| `title` | string | optional | Return only the milestones having the given `title` |
-| `search` | string | optional | Return only milestones with a title or description matching the provided string |
+| Attribute | Type | Required | Description |
+| --------- | ------ | -------- | ----------- |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) owned by the authenticated user |
+| `iids[]` | integer array | optional | Return only the milestones having the given `iid` |
+| `state` | string | optional | Return only `active` or `closed` milestones |
+| `title` | string | optional | Return only the milestones having the given `title` |
+| `search` | string | optional | Return only milestones with a title or description matching the provided string |
```bash
curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/groups/5/milestones
@@ -136,3 +136,18 @@ Parameters:
- `milestone_id` (required) - The ID of a group milestone
[ce-12819]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/12819
+
+## Get all burndown chart events for a single milestone **(STARTER)**
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/4737) in GitLab 12.1
+
+Get all burndown chart events for a single milestone.
+
+```
+GET /groups/:id/milestones/:milestone_id/burndown_events
+```
+
+Parameters:
+
+- `id` (required) - The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) owned by the authenticated user
+- `milestone_id` (required) - The ID of a group milestone
diff --git a/doc/api/groups.md b/doc/api/groups.md
index 20789a1d4a4..d05e4b29fef 100644
--- a/doc/api/groups.md
+++ b/doc/api/groups.md
@@ -7,17 +7,17 @@ authentication, only public groups are returned.
Parameters:
-| Attribute | Type | Required | Description |
-| --------- | ---- | -------- | ----------- |
-| `skip_groups` | array of integers | no | Skip the group IDs passed |
-| `all_available` | boolean | no | Show all the groups you have access to (defaults to `false` for authenticated users, `true` for admin); Attributes `owned` and `min_access_level` have precedence |
-| `search` | string | no | Return the list of authorized groups matching the search criteria |
-| `order_by` | string | no | Order groups by `name`, `path` or `id`. Default is `name` |
-| `sort` | string | no | Order groups in `asc` or `desc` order. Default is `asc` |
-| `statistics` | boolean | no | Include group statistics (admins only) |
-| `with_custom_attributes` | boolean | no | Include [custom attributes](custom_attributes.md) in response (admins only) |
-| `owned` | boolean | no | Limit to groups explicitly owned by the current user |
-| `min_access_level` | integer | no | Limit to groups where current user has at least this [access level](members.md) |
+| Attribute | Type | Required | Description |
+| ------------------------ | ----------------- | -------- | ---------- |
+| `skip_groups` | array of integers | no | Skip the group IDs passed |
+| `all_available` | boolean | no | Show all the groups you have access to (defaults to `false` for authenticated users, `true` for admin); Attributes `owned` and `min_access_level` have precedence |
+| `search` | string | no | Return the list of authorized groups matching the search criteria |
+| `order_by` | string | no | Order groups by `name`, `path` or `id`. Default is `name` |
+| `sort` | string | no | Order groups in `asc` or `desc` order. Default is `asc` |
+| `statistics` | boolean | no | Include group statistics (admins only) |
+| `with_custom_attributes` | boolean | no | Include [custom attributes](custom_attributes.md) in response (admins only) |
+| `owned` | boolean | no | Limit to groups explicitly owned by the current user |
+| `min_access_level` | integer | no | Limit to groups where current user has at least this [access level](members.md) |
```
GET /groups
@@ -70,8 +70,8 @@ GET /groups?statistics=true
"repository_size" : 33,
"wiki_size" : 100,
"lfs_objects_size" : 123,
- "job_artifacts_size" : 57
-
+ "job_artifacts_size" : 57,
+ "packages_size": 0
}
}
]
@@ -94,18 +94,18 @@ When accessed without authentication, only public groups are returned.
Parameters:
-| Attribute | Type | Required | Description |
-| --------- | ---- | -------- | ----------- |
-| `id` | integer/string | yes | The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) of the parent group |
-| `skip_groups` | array of integers | no | Skip the group IDs passed |
-| `all_available` | boolean | no | Show all the groups you have access to (defaults to `false` for authenticated users, `true` for admin); Attributes `owned` and `min_access_level` have precedence |
-| `search` | string | no | Return the list of authorized groups matching the search criteria |
-| `order_by` | string | no | Order groups by `name`, `path` or `id`. Default is `name` |
-| `sort` | string | no | Order groups in `asc` or `desc` order. Default is `asc` |
-| `statistics` | boolean | no | Include group statistics (admins only) |
-| `with_custom_attributes` | boolean | no | Include [custom attributes](custom_attributes.md) in response (admins only) |
-| `owned` | boolean | no | Limit to groups explicitly owned by the current user |
-| `min_access_level` | integer | no | Limit to groups where current user has at least this [access level](members.md) |
+| Attribute | Type | Required | Description |
+| ------------------------ | ----------------- | -------- | ----------- |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) of the parent group |
+| `skip_groups` | array of integers | no | Skip the group IDs passed |
+| `all_available` | boolean | no | Show all the groups you have access to (defaults to `false` for authenticated users, `true` for admin); Attributes `owned` and `min_access_level` have preceden |
+| `search` | string | no | Return the list of authorized groups matching the search criteria |
+| `order_by` | string | no | Order groups by `name`, `path` or `id`. Default is `name` |
+| `sort` | string | no | Order groups in `asc` or `desc` order. Default is `asc` |
+| `statistics` | boolean | no | Include group statistics (admins only) |
+| `with_custom_attributes` | boolean | no | Include [custom attributes](custom_attributes.md) in response (admins only) |
+| `owned` | boolean | no | Limit to groups explicitly owned by the current user |
+| `min_access_level` | integer | no | Limit to groups where current user has at least this [access level](members.md) |
```
GET /groups/:id/subgroups
@@ -142,22 +142,22 @@ GET /groups/:id/projects
Parameters:
-| Attribute | Type | Required | Description |
-| --------- | ---- | -------- | ----------- |
-| `id` | integer/string | yes | The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) owned by the authenticated user |
-| `archived` | boolean | no | Limit by archived status |
-| `visibility` | string | no | Limit by visibility `public`, `internal`, or `private` |
-| `order_by` | string | no | Return projects ordered by `id`, `name`, `path`, `created_at`, `updated_at`, or `last_activity_at` fields. Default is `created_at` |
-| `sort` | string | no | Return projects sorted in `asc` or `desc` order. Default is `desc` |
-| `search` | string | no | Return list of authorized projects matching the search criteria |
-| `simple` | boolean | no | Return only the ID, URL, name, and path of each project |
-| `owned` | boolean | no | Limit by projects owned by the current user |
-| `starred` | boolean | no | Limit by projects starred by the current user |
-| `with_issues_enabled` | boolean | no | Limit by projects with issues feature enabled. Default is `false` |
-| `with_merge_requests_enabled` | boolean | no | Limit by projects with merge requests feature enabled. Default is `false` |
-| `with_shared` | boolean | no | Include projects shared to this group. Default is `true` |
-| `include_subgroups` | boolean | no | Include projects in subgroups of this group. Default is `false` |
-| `with_custom_attributes` | boolean | no | Include [custom attributes](custom_attributes.md) in response (admins only) |
+| Attribute | Type | Required | Description |
+| ----------------------------- | -------------- | -------- | ----------- |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) owned by the authenticated user |
+| `archived` | boolean | no | Limit by archived status |
+| `visibility` | string | no | Limit by visibility `public`, `internal`, or `private` |
+| `order_by` | string | no | Return projects ordered by `id`, `name`, `path`, `created_at`, `updated_at`, or `last_activity_at` fields. Default is `created_at` |
+| `sort` | string | no | Return projects sorted in `asc` or `desc` order. Default is `desc` |
+| `search` | string | no | Return list of authorized projects matching the search criteria |
+| `simple` | boolean | no | Return only the ID, URL, name, and path of each project |
+| `owned` | boolean | no | Limit by projects owned by the current user |
+| `starred` | boolean | no | Limit by projects starred by the current user |
+| `with_issues_enabled` | boolean | no | Limit by projects with issues feature enabled. Default is `false` |
+| `with_merge_requests_enabled` | boolean | no | Limit by projects with merge requests feature enabled. Default is `false` |
+| `with_shared` | boolean | no | Include projects shared to this group. Default is `true` |
+| `include_subgroups` | boolean | no | Include projects in subgroups of this group. Default is `false` |
+| `with_custom_attributes` | boolean | no | Include [custom attributes](custom_attributes.md) in response (admins only) |
Example response:
@@ -214,11 +214,11 @@ GET /groups/:id
Parameters:
-| Attribute | Type | Required | Description |
-| --------- | ---- | -------- | ----------- |
-| `id` | integer/string | yes | The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) owned by the authenticated user |
-| `with_custom_attributes` | boolean | no | Include [custom attributes](custom_attributes.md) in response (admins only) |
-| `with_projects` | boolean | no | Include details from projects that belong to the specified group (defaults to `true`). |
+| Attribute | Type | Required | Description |
+| ------------------------ | -------------- | -------- | ----------- |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) owned by the authenticated user. |
+| `with_custom_attributes` | boolean | no | Include [custom attributes](custom_attributes.md) in response (admins only). |
+| `with_projects` | boolean | no | Include details from projects that belong to the specified group (defaults to `true`). |
```bash
curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/groups/4
@@ -375,6 +375,21 @@ Example response:
}
```
+Users on GitLab [Starter, Bronze, or higher](https://about.gitlab.com/pricing/) will also see
+the `shared_runners_minutes_limit` and `extra_shared_runners_minutes_limit` parameters:
+
+Additional response parameters:
+
+```json
+{
+ "id": 4,
+ "description": "Aliquid qui quis dignissimos distinctio ut commodi voluptas est.",
+ "shared_runners_minutes_limit": 133,
+ "extra_shared_runners_minutes_limit": 133,
+ ...
+}
+```
+
When adding the parameter `with_projects=false`, projects will not be returned.
```bash
@@ -410,15 +425,17 @@ POST /groups
Parameters:
-| Attribute | Type | Required | Description |
-| --------- | ---- | -------- | ----------- |
-| `name` | string | yes | The name of the group |
-| `path` | string | yes | The path of the group |
-| `description` | string | no | The group's description |
-| `visibility` | string | no | The group's visibility. Can be `private`, `internal`, or `public`. |
-| `lfs_enabled` | boolean | no | Enable/disable Large File Storage (LFS) for the projects in this group |
-| `request_access_enabled` | boolean | no | Allow users to request member access. |
-| `parent_id` | integer | no | The parent group id for creating nested group. |
+| Attribute | Type | Required | Description |
+| ------------------------------------ | ------- | -------- | ----------- |
+| `name` | string | yes | The name of the group. |
+| `path` | string | yes | The path of the group. |
+| `description` | string | no | The group's description. |
+| `visibility` | string | no | The group's visibility. Can be `private`, `internal`, or `public`. |
+| `lfs_enabled` | boolean | no | Enable/disable Large File Storage (LFS) for the projects in this group. |
+| `request_access_enabled` | boolean | no | Allow users to request member access. |
+| `parent_id` | integer | no | The parent group ID for creating nested group. |
+| `shared_runners_minutes_limit` | integer | no | **(STARTER ONLY)** Pipeline minutes quota for this group. |
+| `extra_shared_runners_minutes_limit` | integer | no | **(STARTER ONLY)** Extra pipeline minutes quota for this group. |
## Transfer project to group
@@ -430,10 +447,10 @@ POST /groups/:id/projects/:project_id
Parameters:
-| Attribute | Type | Required | Description |
-| --------- | ---- | -------- | ----------- |
-| `id` | integer/string | yes | The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) owned by the authenticated user |
-| `project_id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
+| Attribute | Type | Required | Description |
+| ------------ | -------------- | -------- | ----------- |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) owned by the authenticated user |
+| `project_id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
## Update group
@@ -443,16 +460,20 @@ Updates the project group. Only available to group owners and administrators.
PUT /groups/:id
```
-| Attribute | Type | Required | Description |
-| --------- | ---- | -------- | ----------- |
-| `id` | integer | yes | The ID of the group |
-| `name` | string | no | The name of the group |
-| `path` | string | no | The path of the group |
-| `description` | string | no | The description of the group |
-| `visibility` | string | no | The visibility level of the group. Can be `private`, `internal`, or `public`. |
-| `lfs_enabled` (optional) | boolean | no | Enable/disable Large File Storage (LFS) for the projects in this group |
-| `request_access_enabled` | boolean | no | Allow users to request member access. |
-| `file_template_project_id` | integer | no | **(Premium)** The ID of a project to load custom file templates from |
+| Attribute | Type | Required | Description |
+| ------------------------------------ | ------- | -------- | ----------- |
+| `id` | integer | yes | The ID of the group. |
+| `name` | string | no | The name of the group. |
+| `path` | string | no | The path of the group. |
+| `description` | string | no | The description of the group. |
+| `membership_lock` | boolean | no | **(STARTER)** Prevent adding new members to project membership within this group. |
+| `share_with_group_lock` | boolean | no | Prevent sharing a project with another group within this group. |
+| `visibility` | string | no | The visibility level of the group. Can be `private`, `internal`, or `public`. |
+| `lfs_enabled` (optional) | boolean | no | Enable/disable Large File Storage (LFS) for the projects in this group. |
+| `request_access_enabled` | boolean | no | Allow users to request member access. |
+| `file_template_project_id` | integer | no | **(PREMIUM)** The ID of a project to load custom file templates from. |
+| `shared_runners_minutes_limit` | integer | no | **(STARTER ONLY)** Pipeline minutes quota for this group. |
+| `extra_shared_runners_minutes_limit` | integer | no | **(STARTER ONLY)** Extra pipeline minutes quota for this group. |
```bash
curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/groups/5?name=Experimental"
@@ -520,7 +541,7 @@ Example response:
## Remove group
-Removes group with all projects inside.
+Removes group with all projects inside. Only available to group owners and administrators.
```
DELETE /groups/:id
@@ -552,10 +573,62 @@ GET /groups?search=foobar
]
```
+## Sync group with LDAP **(CORE ONLY)**
+
+Syncs the group with its linked LDAP group. Only available to group owners and administrators.
+
+```
+POST /groups/:id/ldap_sync
+```
+
+Parameters:
+
+- `id` (required) - The ID or path of a user group
+
## Group members
Please consult the [Group Members](members.md) documentation.
+### Add LDAP group link **(CORE ONLY)**
+
+Adds an LDAP group link.
+
+```
+POST /groups/:id/ldap_group_links
+```
+
+Parameters:
+
+- `id` (required) - The ID of a group
+- `cn` (required) - The CN of a LDAP group
+- `group_access` (required) - Minimum access level for members of the LDAP group
+- `provider` (required) - LDAP provider for the LDAP group
+
+### Delete LDAP group link **(CORE ONLY)**
+
+Deletes an LDAP group link.
+
+```
+DELETE /groups/:id/ldap_group_links/:cn
+```
+
+Parameters:
+
+- `id` (required) - The ID of a group
+- `cn` (required) - The CN of a LDAP group
+
+Deletes a LDAP group link for a specific LDAP provider
+
+```
+DELETE /groups/:id/ldap_group_links/:provider/:cn
+```
+
+Parameters:
+
+- `id` (required) - The ID of a group
+- `cn` (required) - The CN of a LDAP group
+- `provider` (required) - Name of a LDAP provider
+
## Namespaces in groups
By default, groups only get 20 namespaces at a time because the API results are paginated.
diff --git a/doc/api/issue_links.md b/doc/api/issue_links.md
index 1c7db6a8e4c..280431fa87c 100644
--- a/doc/api/issue_links.md
+++ b/doc/api/issue_links.md
@@ -1,4 +1,4 @@
-# Issue links API **[STARTER]**
+# Issue links API **(STARTER)**
## List issue relations
@@ -67,7 +67,6 @@ POST /projects/:id/issues/:issue_iid/links
| `target_project_id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) of a target project |
| `target_issue_iid` | integer/string | yes | The internal ID of a target project's issue |
-
```json
{
"source_issue" : {
@@ -141,14 +140,12 @@ Deletes an issue link, thus removes the two-way relationship.
DELETE /projects/:id/issues/:issue_iid/links/:issue_link_id
```
-
| 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 |
| `issue_iid` | integer | yes | The internal ID of a project's issue |
| `issue_link_id` | integer/string | yes | The ID of an issue relationship |
-
```json
{
"source_issue" : {
diff --git a/doc/api/issues.md b/doc/api/issues.md
index 0d96cfa1b21..23126a05b66 100644
--- a/doc/api/issues.md
+++ b/doc/api/issues.md
@@ -3,7 +3,7 @@
Every API call to issues must be authenticated.
If a user is not a member of a project and the project is private, a `GET`
-request on that project will result to a `404` status code.
+request on that project will result in a `404` status code.
## Issues pagination
@@ -39,15 +39,16 @@ GET /issues?confidential=true
| ------------------- | ---------------- | ---------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| `state` | string | no | Return `all` issues or just those that are `opened` or `closed` |
| `labels` | string | no | Comma-separated list of label names, issues must have all labels to be returned. `None` lists all issues with no labels. `Any` lists all issues with at least one label. `No+Label` (Deprecated) lists all issues with no labels. Predefined names are case-insensitive. |
-| `with_labels_details`| Boolean | no | If `true`, response will return more details for each label in labels field: `:name`, `:color`, `:description`, `:text_color`. Default is `false`. |
+| `with_labels_details` | Boolean | no | If `true`, response will return more details for each label in labels field: `:name`, `:color`, `:description`, `:text_color`. Default is `false`. |
| `milestone` | string | no | The milestone title. `None` lists all issues with no milestone. `Any` lists all issues that have an assigned milestone. |
| `scope` | string | no | Return issues for the given scope: `created_by_me`, `assigned_to_me` or `all`. Defaults to `created_by_me`<br> For versions before 11.0, use the now deprecated `created-by-me` or `assigned-to-me` scopes instead.<br> _([Introduced][ce-13004] in GitLab 9.5. [Changed to snake_case][ce-18935] in GitLab 11.0)_ |
| `author_id` | integer | no | Return issues created by the given user `id`. Mutually exclusive with `author_username`. Combine with `scope=all` or `scope=assigned_to_me`. _([Introduced][ce-13004] in GitLab 9.5)_ |
-| `author_username` | string | no | Return issues created by the given `username`. Simillar to `author_id` and mutually exclusive with `author_id`. |
+| `author_username` | string | no | Return issues created by the given `username`. Similar to `author_id` and mutually exclusive with `author_id`. |
| `assignee_id` | integer | no | Return issues assigned to the given user `id`. Mutually exclusive with `assignee_username`. `None` returns unassigned issues. `Any` returns issues with an assignee. _([Introduced][ce-13004] in GitLab 9.5)_ |
-| `assignee_username` | Array[String] | no | Return issues assigned to the given `username`. Simillar to `assignee_id` and mutually exclusive with `assignee_id`. In CE version `assignee_username` array should only contain a single value or an invalid param error will be returned otherwise. |
+| `assignee_username` | string array | no | Return issues assigned to the given `username`. Similar to `assignee_id` and mutually exclusive with `assignee_id`. In CE version `assignee_username` array should only contain a single value or an invalid param error will be returned otherwise. |
| `my_reaction_emoji` | string | no | Return issues reacted by the authenticated user by the given `emoji`. `None` returns issues not given a reaction. `Any` returns issues given at least one reaction. _([Introduced][ce-14016] in GitLab 10.0)_ |
-| `iids[]` | Array[integer] | no | Return only the issues having the given `iid` |
+| `weight` **(STARTER)** | integer | no | Return issues with the specified `weight`. `None` returns issues with no weight assigned. `Any` returns issues with a weight assigned. |
+| `iids[]` | integer array | no | Return only the issues having the given `iid` |
| `order_by` | string | no | Return issues ordered by `created_at` or `updated_at` fields. Default is `created_at` |
| `sort` | string | no | Return issues sorted in `asc` or `desc` order. Default is `desc` |
| `search` | string | no | Search issues against their `title` and `description` |
@@ -56,7 +57,7 @@ GET /issues?confidential=true
| `created_before` | datetime | no | Return issues created on or before the given time |
| `updated_after` | datetime | no | Return issues updated on or after the given time |
| `updated_before` | datetime | no | Return issues updated on or before the given time |
-| `confidential ` | Boolean | no | Filter confidential or public issues. |
+| `confidential` | Boolean | no | Filter confidential or public issues. |
```bash
curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/issues
@@ -144,6 +145,20 @@ Example response:
]
```
+Users on GitLab [Starter, Bronze, or higher](https://about.gitlab.com/pricing/) will also see
+the `weight` parameter:
+
+```json
+[
+ {
+ "state" : "opened",
+ "description" : "Ratione dolores corrupti mollitia soluta quia.",
+ "weight": null,
+ ...
+ }
+]
+```
+
**Note**: `assignee` column is deprecated, now we show it as a single-sized array `assignees` to conform to the GitLab EE API.
**Note**: The `closed_by` attribute was [introduced in GitLab 10.6][ce-17042]. This value will only be present for issues which were closed after GitLab 10.6 and when the user account that closed the issue still exists.
@@ -174,15 +189,16 @@ GET /groups/:id/issues?confidential=true
| `id` | integer/string | yes | The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) owned by the authenticated user |
| `state` | string | no | Return all issues or just those that are `opened` or `closed` |
| `labels` | string | no | Comma-separated list of label names, issues must have all labels to be returned. `None` lists all issues with no labels. `Any` lists all issues with at least one label. `No+Label` (Deprecated) lists all issues with no labels. Predefined names are case-insensitive. |
-| `with_labels_details`| Boolean | no | If `true`, response will return more details for each label in labels field: `:name`, `:color`, `:description`, `:text_color`. Default is `false`. |
-| `iids[]` | Array[integer] | no | Return only the issues having the given `iid` |
+| `with_labels_details` | Boolean | no | If `true`, response will return more details for each label in labels field: `:name`, `:color`, `:description`, `:text_color`. Default is `false`. |
+| `iids[]` | integer array | no | Return only the issues having the given `iid` |
| `milestone` | string | no | The milestone title. `None` lists all issues with no milestone. `Any` lists all issues that have an assigned milestone. |
| `scope` | string | no | Return issues for the given scope: `created_by_me`, `assigned_to_me` or `all`.<br> For versions before 11.0, use the now deprecated `created-by-me` or `assigned-to-me` scopes instead.<br> _([Introduced][ce-13004] in GitLab 9.5. [Changed to snake_case][ce-18935] in GitLab 11.0)_ |
| `author_id` | integer | no | Return issues created by the given user `id`. Mutually exclusive with `author_username`. Combine with `scope=all` or `scope=assigned_to_me`. _([Introduced][ce-13004] in GitLab 9.5)_ |
-| `author_username` | string | no | Return issues created by the given `username`. Simillar to `author_id` and mutually exclusive with `author_id`. |
+| `author_username` | string | no | Return issues created by the given `username`. Similar to `author_id` and mutually exclusive with `author_id`. |
| `assignee_id` | integer | no | Return issues assigned to the given user `id`. Mutually exclusive with `assignee_username`. `None` returns unassigned issues. `Any` returns issues with an assignee. _([Introduced][ce-13004] in GitLab 9.5)_ |
-| `assignee_username` | Array[String] | no | Return issues assigned to the given `username`. Simillar to `assignee_id` and mutually exclusive with `assignee_id`. In CE version `assignee_username` array should only contain a single value or an invalid param error will be returned otherwise. |
+| `assignee_username` | string array | no | Return issues assigned to the given `username`. Similar to `assignee_id` and mutually exclusive with `assignee_id`. In CE version `assignee_username` array should only contain a single value or an invalid param error will be returned otherwise. |
| `my_reaction_emoji` | string | no | Return issues reacted by the authenticated user by the given `emoji`. `None` returns issues not given a reaction. `Any` returns issues given at least one reaction. _([Introduced][ce-14016] in GitLab 10.0)_ |
+| `weight` **(STARTER)** | integer | no | Return issues with the specified `weight`. `None` returns issues with no weight assigned. `Any` returns issues with a weight assigned. |
| `order_by` | string | no | Return issues ordered by `created_at` or `updated_at` fields. Default is `created_at` |
| `sort` | string | no | Return issues sorted in `asc` or `desc` order. Default is `desc` |
| `search` | string | no | Search group issues against their `title` and `description` |
@@ -190,7 +206,7 @@ GET /groups/:id/issues?confidential=true
| `created_before` | datetime | no | Return issues created on or before the given time |
| `updated_after` | datetime | no | Return issues updated on or after the given time |
| `updated_before` | datetime | no | Return issues updated on or before the given time |
-| `confidential ` | Boolean | no | Filter confidential or public issues. |
+| `confidential` | Boolean | no | Filter confidential or public issues. |
```bash
curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/groups/4/issues
@@ -278,6 +294,20 @@ Example response:
]
```
+Users on GitLab [Starter, Bronze, or higher](https://about.gitlab.com/pricing/) will also see
+the `weight` parameter:
+
+```json
+[
+ {
+ "project_id" : 4,
+ "description" : "Omnis vero earum sunt corporis dolor et placeat.",
+ "weight": null,
+ ...
+ }
+]
+```
+
**Note**: `assignee` column is deprecated, now we show it as a single-sized array `assignees` to conform to the GitLab EE API.
**Note**: The `closed_by` attribute was [introduced in GitLab 10.6][ce-17042]. This value will only be present for issues which were closed after GitLab 10.6 and when the user account that closed the issue still exists.
@@ -306,17 +336,18 @@ GET /projects/:id/issues?confidential=true
| 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 |
-| `iids[]` | Array[integer] | no | Return only the milestone having the given `iid` |
+| `iids[]` | integer array | no | Return only the milestone having the given `iid` |
| `state` | string | no | Return all issues or just those that are `opened` or `closed` |
| `labels` | string | no | Comma-separated list of label names, issues must have all labels to be returned. `None` lists all issues with no labels. `Any` lists all issues with at least one label. `No+Label` (Deprecated) lists all issues with no labels. Predefined names are case-insensitive. |
-| `with_labels_details`| Boolean | no | If `true`, response will return more details for each label in labels field: `:name`, `:color`, `:description`, `:text_color`. Default is `false`. |
+| `with_labels_details` | Boolean | no | If `true`, response will return more details for each label in labels field: `:name`, `:color`, `:description`, `:text_color`. Default is `false`. |
| `milestone` | string | no | The milestone title. `None` lists all issues with no milestone. `Any` lists all issues that have an assigned milestone. |
| `scope` | string | no | Return issues for the given scope: `created_by_me`, `assigned_to_me` or `all`.<br> For versions before 11.0, use the now deprecated `created-by-me` or `assigned-to-me` scopes instead.<br> _([Introduced][ce-13004] in GitLab 9.5. [Changed to snake_case][ce-18935] in GitLab 11.0)_ |
| `author_id` | integer | no | Return issues created by the given user `id`. Mutually exclusive with `author_username`. Combine with `scope=all` or `scope=assigned_to_me`. _([Introduced][ce-13004] in GitLab 9.5)_ |
-| `author_username` | string | no | Return issues created by the given `username`. Simillar to `author_id` and mutually exclusive with `author_id`. |
+| `author_username` | string | no | Return issues created by the given `username`. Similar to `author_id` and mutually exclusive with `author_id`. |
| `assignee_id` | integer | no | Return issues assigned to the given user `id`. Mutually exclusive with `assignee_username`. `None` returns unassigned issues. `Any` returns issues with an assignee. _([Introduced][ce-13004] in GitLab 9.5)_ |
-| `assignee_username` | Array[String] | no | Return issues assigned to the given `username`. Simillar to `assignee_id` and mutually exclusive with `assignee_id`. In CE version `assignee_username` array should only contain a single value or an invalid param error will be returned otherwise. |
+| `assignee_username` | string array | no | Return issues assigned to the given `username`. Similar to `assignee_id` and mutually exclusive with `assignee_id`. In CE version `assignee_username` array should only contain a single value or an invalid param error will be returned otherwise. |
| `my_reaction_emoji` | string | no | Return issues reacted by the authenticated user by the given `emoji`. `None` returns issues not given a reaction. `Any` returns issues given at least one reaction. _([Introduced][ce-14016] in GitLab 10.0)_ |
+| `weight` **(STARTER)** | integer | no | Return issues with the specified `weight`. `None` returns issues with no weight assigned. `Any` returns issues with a weight assigned. |
| `order_by` | string | no | Return issues ordered by `created_at` or `updated_at` fields. Default is `created_at` |
| `sort` | string | no | Return issues sorted in `asc` or `desc` order. Default is `desc` |
| `search` | string | no | Search project issues against their `title` and `description` |
@@ -324,7 +355,7 @@ GET /projects/:id/issues?confidential=true
| `created_before` | datetime | no | Return issues created on or before the given time |
| `updated_after` | datetime | no | Return issues updated on or after the given time |
| `updated_before` | datetime | no | Return issues updated on or before the given time |
-| `confidential ` | Boolean | no | Filter confidential or public issues. |
+| `confidential` | Boolean | no | Filter confidential or public issues. |
```bash
@@ -420,6 +451,20 @@ Example response:
]
```
+Users on GitLab [Starter, Bronze, or higher](https://about.gitlab.com/pricing/) will also see
+the `weight` parameter:
+
+```json
+[
+ {
+ "project_id" : 4,
+ "description" : "Omnis vero earum sunt corporis dolor et placeat.",
+ "weight": null,
+ ...
+ }
+]
+```
+
**Note**: `assignee` column is deprecated, now we show it as a single-sized array `assignees` to conform to the GitLab EE API.
**Note**: The `closed_by` attribute was [introduced in GitLab 10.6][ce-17042]. This value will only be present for issues which were closed after GitLab 10.6 and when the user account that closed the issue still exists.
@@ -520,6 +565,18 @@ Example response:
}
```
+Users on GitLab [Starter, Bronze, or higher](https://about.gitlab.com/pricing/) will also see
+the `weight` parameter:
+
+```json
+{
+ "project_id" : 4,
+ "description" : "Omnis vero earum sunt corporis dolor et placeat.",
+ "weight": null,
+ ...
+}
+```
+
**Note**: `assignee` column is deprecated, now we show it as a single-sized array `assignees` to conform to the GitLab EE API.
**Note**: The `closed_by` attribute was [introduced in GitLab 10.6][ce-17042]. This value will only be present for issues which were closed after GitLab 10.6 and when the user account that closed the issue still exists.
@@ -536,16 +593,17 @@ POST /projects/:id/issues
|-------------------------------------------|----------------|----------|--------------|
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
| `iid` | integer/string | no | The internal ID of the project's issue (requires admin or project owner rights) |
-| `title` | string | yes | The title of an issue |
-| `description` | string | no | The description of an issue |
-| `confidential` | boolean | no | Set an issue to be confidential. Default is `false`. |
-| `assignee_ids` | Array[integer] | no | The ID of the users to assign issue |
-| `milestone_id` | integer | no | The global ID of a milestone to assign issue |
-| `labels` | string | no | Comma-separated label names for an issue |
-| `created_at` | string | no | Date time string, ISO 8601 formatted, e.g. `2016-03-11T03:45:40Z` (requires admin or project/group owner rights) |
-| `due_date` | string | no | Date time string in the format YEAR-MONTH-DAY, e.g. `2016-03-11` |
-| `merge_request_to_resolve_discussions_of` | integer | no | The IID of a merge request in which to resolve all issues. This will fill the issue with a default description and mark all discussions as resolved. When passing a description or title, these values will take precedence over the default values.|
-| `discussion_to_resolve` | string | no | The ID of a discussion to resolve. This will fill in the issue with a default description and mark the discussion as resolved. Use in combination with `merge_request_to_resolve_discussions_of`. |
+| `title` | string | yes | The title of an issue |
+| `description` | string | no | The description of an issue |
+| `confidential` | boolean | no | Set an issue to be confidential. Default is `false`. |
+| `assignee_ids` | integer array | no | The ID of a user to assign issue |
+| `milestone_id` | integer | no | The global ID of a milestone to assign issue |
+| `labels` | string | no | Comma-separated label names for an issue |
+| `created_at` | string | no | Date time string, ISO 8601 formatted, e.g. `2016-03-11T03:45:40Z` (requires admin or project/group owner rights) |
+| `due_date` | string | no | Date time string in the format YEAR-MONTH-DAY, e.g. `2016-03-11` |
+| `merge_request_to_resolve_discussions_of` | integer | no | The IID of a merge request in which to resolve all issues. This will fill the issue with a default description and mark all discussions as resolved. When passing a description or title, these values will take precedence over the default values.|
+| `discussion_to_resolve` | string | no | The ID of a discussion to resolve. This will fill in the issue with a default description and mark the discussion as resolved. Use in combination with `merge_request_to_resolve_discussions_of`. |
+| `weight` **(STARTER)** | integer | no | The weight of the issue. Valid values are greater than or equal to 0. |
```bash
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/4/issues?title=Issues%20with%20auth&labels=bug
@@ -607,6 +665,18 @@ Example response:
}
```
+Users on GitLab [Starter, Bronze, or higher](https://about.gitlab.com/pricing/) will also see
+the `weight` parameter:
+
+```json
+{
+ "project_id" : 4,
+ "description" : null,
+ "weight": null,
+ ...
+}
+```
+
**Note**: `assignee` column is deprecated, now we show it as a single-sized array `assignees` to conform to the GitLab EE API.
**Note**: The `closed_by` attribute was [introduced in GitLab 10.6][ce-17042]. This value will only be present for issues which were closed after GitLab 10.6 and when the user account that closed the issue still exists.
@@ -622,17 +692,18 @@ PUT /projects/:id/issues/:issue_iid
| 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 |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
| `issue_iid` | integer | yes | The internal ID of a project's issue |
| `title` | string | no | The title of an issue |
| `description` | string | no | The description of an issue |
| `confidential` | boolean | no | Updates an issue to be confidential |
-| `assignee_ids` | Array[integer] | no | The ID of the user(s) to assign the issue to. Set to `0` or provide an empty value to unassign all assignees. |
+| `assignee_ids` | integer array | no | The ID of the user(s) to assign the issue to. Set to `0` or provide an empty value to unassign all assignees. |
| `milestone_id` | integer | no | The global ID of a milestone to assign the issue to. Set to `0` or provide an empty value to unassign a milestone.|
| `labels` | string | no | Comma-separated label names for an issue. Set to an empty string to unassign all labels. |
| `state_event` | string | no | The state event of an issue. Set `close` to close the issue and `reopen` to reopen it |
| `updated_at` | string | no | Date time string, ISO 8601 formatted, e.g. `2016-03-11T03:45:40Z` (requires admin or project owner rights) |
| `due_date` | string | no | Date time string in the format YEAR-MONTH-DAY, e.g. `2016-03-11` |
+| `weight` **(STARTER)** | integer | no | The weight of the issue. Valid values are greater than or equal to 0. 0 |
| `discussion_locked` | boolean | no | Flag indicating if the issue's discussion is locked. If the discussion is locked only project members can add or edit comments. |
```bash
@@ -702,6 +773,18 @@ Example response:
}
```
+Users on GitLab [Starter, Bronze, or higher](https://about.gitlab.com/pricing/) will also see
+the `weight` parameter:
+
+```json
+{
+ "project_id" : 4,
+ "description" : null,
+ "weight": null,
+ ...
+}
+```
+
**Note**: `assignee` column is deprecated, now we show it as a single-sized array `assignees` to conform to the GitLab EE API.
**Note**: The `closed_by` attribute was [introduced in GitLab 10.6][ce-17042]. This value will only be present for issues which were closed after GitLab 10.6 and when the user account that closed the issue still exists.
@@ -812,6 +895,18 @@ Example response:
}
```
+Users on GitLab [Starter, Bronze, or higher](https://about.gitlab.com/pricing/) will also see
+the `weight` parameter:
+
+```json
+{
+ "project_id": 5,
+ "description": "Repellat voluptas quibusdam voluptatem exercitationem.",
+ "weight": null,
+ ...
+}
+```
+
**Note**: `assignee` column is deprecated, now we show it as a single-sized array `assignees` to conform to the GitLab EE API.
**Note**: The `closed_by` attribute was [introduced in GitLab 10.6][ce-17042]. This value will only be present for issues which were closed after GitLab 10.6 and when the user account that closed the issue still exists.
@@ -901,6 +996,18 @@ Example response:
}
```
+Users on GitLab [Starter, Bronze, or higher](https://about.gitlab.com/pricing/) will also see
+the `weight` parameter:
+
+```json
+{
+ "project_id": 5,
+ "description": "Repellat voluptas quibusdam voluptatem exercitationem.",
+ "weight": null,
+ ...
+}
+```
+
**Note**: `assignee` column is deprecated, now we show it as a single-sized array `assignees` to conform to the GitLab EE API.
**Note**: The `closed_by` attribute was [introduced in GitLab 10.6][ce-17042]. This value will only be present for issues which were closed after GitLab 10.6 and when the user account that closed the issue still exists.
diff --git a/doc/api/issues_statistics.md b/doc/api/issues_statistics.md
index 82bc9c142cc..d7edb296be2 100644
--- a/doc/api/issues_statistics.md
+++ b/doc/api/issues_statistics.md
@@ -34,16 +34,16 @@ GET /issues_statistics?confidential=true
| `author_id` | integer | no | Return issues created by the given user `id`. Mutually exclusive with `author_username`. Combine with `scope=all` or `scope=assigned_to_me`. |
| `author_username` | string | no | Return issues created by the given `username`. Similar to `author_id` and mutually exclusive with `author_id`. |
| `assignee_id` | integer | no | Return issues assigned to the given user `id`. Mutually exclusive with `assignee_username`. `None` returns unassigned issues. `Any` returns issues with an assignee. |
-| `assignee_username` | Array[String] | no | Return issues assigned to the given `username`. Similar to `assignee_id` and mutually exclusive with `assignee_id`. In CE version `assignee_username` array should only contain a single value or an invalid param error will be returned otherwise. |
+| `assignee_username` | string array | no | Return issues assigned to the given `username`. Similar to `assignee_id` and mutually exclusive with `assignee_id`. In CE version `assignee_username` array should only contain a single value or an invalid param error will be returned otherwise. |
| `my_reaction_emoji` | string | no | Return issues reacted by the authenticated user by the given `emoji`. `None` returns issues not given a reaction. `Any` returns issues given at least one reaction. |
-| `iids[]` | Array[integer] | no | Return only the issues having the given `iid` |
+| `iids[]` | integer array | no | Return only the issues having the given `iid` |
| `search` | string | no | Search issues against their `title` and `description` |
| `in` | string | no | Modify the scope of the `search` attribute. `title`, `description`, or a string joining them with comma. Default is `title,description` |
| `created_after` | datetime | no | Return issues created on or after the given time |
| `created_before` | datetime | no | Return issues created on or before the given time |
| `updated_after` | datetime | no | Return issues updated on or after the given time |
| `updated_before` | datetime | no | Return issues updated on or before the given time |
-| `confidential ` | Boolean | no | Filter confidential or public issues. |
+| `confidential` | Boolean | no | Filter confidential or public issues. |
```bash
curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/issues_statistics
@@ -86,20 +86,20 @@ GET /groups/:id/issues_statistics?confidential=true
| ------------------- | ---------------- | ---------- | ----------------------------------------------------------------------------------------------------------------------------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) owned by the authenticated user |
| `labels` | string | no | Comma-separated list of label names, issues must have all labels to be returned. `None` lists all issues with no labels. `Any` lists all issues with at least one label. |
-| `iids[]` | Array[integer] | no | Return only the issues having the given `iid` |
+| `iids[]` | integer array | no | Return only the issues having the given `iid` |
| `milestone` | string | no | The milestone title. `None` lists all issues with no milestone. `Any` lists all issues that have an assigned milestone. |
| `scope` | string | no | Return issues for the given scope: `created_by_me`, `assigned_to_me` or `all`. |
| `author_id` | integer | no | Return issues created by the given user `id`. Mutually exclusive with `author_username`. Combine with `scope=all` or `scope=assigned_to_me`. |
| `author_username` | string | no | Return issues created by the given `username`. Similar to `author_id` and mutually exclusive with `author_id`. |
| `assignee_id` | integer | no | Return issues assigned to the given user `id`. Mutually exclusive with `assignee_username`. `None` returns unassigned issues. `Any` returns issues with an assignee. |
-| `assignee_username` | Array[String] | no | Return issues assigned to the given `username`. Similar to `assignee_id` and mutually exclusive with `assignee_id`. In CE version `assignee_username` array should only contain a single value or an invalid param error will be returned otherwise. |
+| `assignee_username` | string array | no | Return issues assigned to the given `username`. Similar to `assignee_id` and mutually exclusive with `assignee_id`. In CE version `assignee_username` array should only contain a single value or an invalid param error will be returned otherwise. |
| `my_reaction_emoji` | string | no | Return issues reacted by the authenticated user by the given `emoji`. `None` returns issues not given a reaction. `Any` returns issues given at least one reaction. |
| `search` | string | no | Search group issues against their `title` and `description` |
| `created_after` | datetime | no | Return issues created on or after the given time |
| `created_before` | datetime | no | Return issues created on or before the given time |
| `updated_after` | datetime | no | Return issues updated on or after the given time |
| `updated_before` | datetime | no | Return issues updated on or before the given time |
-| `confidential ` | Boolean | no | Filter confidential or public issues. |
+| `confidential` | Boolean | no | Filter confidential or public issues. |
```bash
curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/groups/4/issues_statistics
@@ -141,22 +141,21 @@ GET /projects/:id/issues_statistics?confidential=true
| 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 |
-| `iids[]` | Array[integer] | no | Return only the milestone having the given `iid` |
+| `iids[]` | integer array | no | Return only the milestone having the given `iid` |
| `labels` | string | no | Comma-separated list of label names, issues must have all labels to be returned. `None` lists all issues with no labels. `Any` lists all issues with at least one label. |
| `milestone` | string | no | The milestone title. `None` lists all issues with no milestone. `Any` lists all issues that have an assigned milestone. |
| `scope` | string | no | Return issues for the given scope: `created_by_me`, `assigned_to_me` or `all`. |
| `author_id` | integer | no | Return issues created by the given user `id`. Mutually exclusive with `author_username`. Combine with `scope=all` or `scope=assigned_to_me`. |
| `author_username` | string | no | Return issues created by the given `username`. Similar to `author_id` and mutually exclusive with `author_id`. |
| `assignee_id` | integer | no | Return issues assigned to the given user `id`. Mutually exclusive with `assignee_username`. `None` returns unassigned issues. `Any` returns issues with an assignee. |
-| `assignee_username` | Array[String] | no | Return issues assigned to the given `username`. Similar to `assignee_id` and mutually exclusive with `assignee_id`. In CE version `assignee_username` array should only contain a single value or an invalid param error will be returned otherwise. |
+| `assignee_username` | string array | no | Return issues assigned to the given `username`. Similar to `assignee_id` and mutually exclusive with `assignee_id`. In CE version `assignee_username` array should only contain a single value or an invalid param error will be returned otherwise. |
| `my_reaction_emoji` | string | no | Return issues reacted by the authenticated user by the given `emoji`. `None` returns issues not given a reaction. `Any` returns issues given at least one reaction. |
| `search` | string | no | Search project issues against their `title` and `description` |
| `created_after` | datetime | no | Return issues created on or after the given time |
| `created_before` | datetime | no | Return issues created on or before the given time |
| `updated_after` | datetime | no | Return issues updated on or after the given time |
| `updated_before` | datetime | no | Return issues updated on or before the given time |
-| `confidential ` | Boolean | no | Filter confidential or public issues. |
-
+| `confidential` | Boolean | no | Filter confidential or public issues. |
```bash
curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/4/issues_statistics
diff --git a/doc/api/jobs.md b/doc/api/jobs.md
index 72973b69117..1add5f432ac 100644
--- a/doc/api/jobs.md
+++ b/doc/api/jobs.md
@@ -14,7 +14,7 @@ GET /projects/:id/jobs
| `scope` | string **or** array of strings | no | Scope of jobs to show. Either one of or an array of the following: `created`, `pending`, `running`, `failed`, `success`, `canceled`, `skipped`, or `manual`. All jobs are returned if `scope` is not provided. |
```sh
-curl --header "PRIVATE-TOKEN: <your_access_token>" 'https://gitlab.example.com/api/v4/projects/1/jobs?scope[]=pending&scope[]=running'
+curl --globoff --header "PRIVATE-TOKEN: <your_access_token>" 'https://gitlab.example.com/api/v4/projects/1/jobs?scope[]=pending&scope[]=running'
```
Example of response
@@ -359,7 +359,7 @@ GET /projects/:id/jobs/:job_id/artifacts
|-------------|----------------|----------|-------------------------------------------------------------------------------------------------------------------------------------------------|
| `id` | integer/string | yes | ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user. |
| `job_id` | integer | yes | ID of a job. |
-| `job_token` **[PREMIUM]** | string | no | To be used with [triggers] for multi-project pipelines. It should be invoked only inside `.gitlab-ci.yml`. Its value is always `$CI_JOB_TOKEN`. |
+| `job_token` **(PREMIUM)** | string | no | To be used with [triggers] for multi-project pipelines. It should be invoked only inside `.gitlab-ci.yml`. Its value is always `$CI_JOB_TOKEN`. |
Example request using the `PRIVATE-TOKEN` header:
@@ -368,7 +368,7 @@ curl --output artifacts.zip --header "PRIVATE-TOKEN: <your_access_token>" "https
```
To use this in a [`script` definition](../ci/yaml/README.md#script) inside
-`.gitlab-ci.yml` **[PREMIUM]**, you can use either:
+`.gitlab-ci.yml` **(PREMIUM)**, you can use either:
- The `JOB-TOKEN` header with the GitLab-provided `CI_JOB_TOKEN` variable.
For example, the following job will download the artifacts of the job with ID
@@ -425,7 +425,7 @@ Parameters
| `id` | integer/string | yes | ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user. |
| `ref_name` | string | yes | Branch or tag name in repository. HEAD or SHA references are not supported. |
| `job` | string | yes | The name of the job. |
-| `job_token` **[PREMIUM]** | string | no | To be used with [triggers] for multi-project pipelines. It should be invoked only inside `.gitlab-ci.yml`. Its value is always `$CI_JOB_TOKEN`. |
+| `job_token` **(PREMIUM)** | string | no | To be used with [triggers] for multi-project pipelines. It should be invoked only inside `.gitlab-ci.yml`. Its value is always `$CI_JOB_TOKEN`. |
Example request using the `PRIVATE-TOKEN` header:
@@ -434,7 +434,7 @@ curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/a
```
To use this in a [`script` definition](../ci/yaml/README.md#script) inside
-`.gitlab-ci.yml` **[PREMIUM]**, you can use either:
+`.gitlab-ci.yml` **(PREMIUM)**, you can use either:
- The `JOB-TOKEN` header with the GitLab-provided `CI_JOB_TOKEN` variable.
For example, the following job will download the artifacts of the `test` job
@@ -485,7 +485,7 @@ Parameters
| Attribute | Type | Required | Description |
|-----------------|----------------|----------|------------------------------------------------------------------------------------------------------------------|
| `id` | integer/string | yes | ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user. |
-| `job_id ` | integer | yes | The unique job identifier. |
+| `job_id` | integer | yes | The unique job identifier. |
| `artifact_path` | string | yes | Path to a file inside the artifacts archive. |
Example request:
@@ -782,7 +782,6 @@ DELETE /projects/:id/jobs/:job_id/artifacts
| `id` | integer/string | yes | ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
| `job_id` | integer | yes | ID of a job. |
-
Example request:
```sh
diff --git a/doc/api/license.md b/doc/api/license.md
index 2a8de64bdbf..12f1d03d576 100644
--- a/doc/api/license.md
+++ b/doc/api/license.md
@@ -1,4 +1,4 @@
-# License **[CORE ONLY]**
+# License **(CORE ONLY)**
In order to interact with license endpoints, you need to authenticate yourself
as an admin.
@@ -131,7 +131,6 @@ Returns:
- `201 Created` if the license is successfully added.
- `400 Bad Request` if the license couldn't be added, with an error message explaining the reason.
-
## Delete a license
```
diff --git a/doc/api/lint.md b/doc/api/lint.md
index 71c09d35b8c..b9b49f3df27 100644
--- a/doc/api/lint.md
+++ b/doc/api/lint.md
@@ -22,30 +22,30 @@ Example responses:
- Valid content:
- ```json
- {
- "status": "valid",
- "errors": []
- }
- ```
+ ```json
+ {
+ "status": "valid",
+ "errors": []
+ }
+ ```
- Invalid content:
- ```json
- {
- "status": "invalid",
- "errors": [
- "variables config should be a hash of key value pairs"
- ]
- }
- ```
+ ```json
+ {
+ "status": "invalid",
+ "errors": [
+ "variables config should be a hash of key value pairs"
+ ]
+ }
+ ```
- Without the content attribute:
- ```json
- {
- "error": "content is missing"
- }
- ```
+ ```json
+ {
+ "error": "content is missing"
+ }
+ ```
[ce-5953]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/5953
diff --git a/doc/api/managed_licenses.md b/doc/api/managed_licenses.md
index 47b193111b6..1af7567626f 100644
--- a/doc/api/managed_licenses.md
+++ b/doc/api/managed_licenses.md
@@ -1,4 +1,4 @@
-# Managed Licenses API **[ULTIMATE]**
+# Managed Licenses API **(ULTIMATE)**
## List managed licenses
@@ -105,7 +105,7 @@ DELETE /projects/:id/managed_licenses/:managed_license_id
curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/1/managed_licenses/4"
```
-When successful, it replies with an HTTP 204 response.
+When successful, it replies with an HTTP 204 response.
## Edit an existing managed license
diff --git a/doc/api/merge_request_approvals.md b/doc/api/merge_request_approvals.md
index 49aaac06b46..c211916464a 100644
--- a/doc/api/merge_request_approvals.md
+++ b/doc/api/merge_request_approvals.md
@@ -1,4 +1,4 @@
-# Merge request approvals API **[STARTER]**
+# Merge request approvals API **(STARTER)**
Configuration for approvals on all Merge Requests (MR) in the project. Must be authenticated for all endpoints.
@@ -178,7 +178,6 @@ PUT /projects/:id/approvers
}
```
-
## Merge Request-level MR approvals
Configuration for approvals on a specific Merge Request. Must be authenticated for all endpoints.
@@ -250,7 +249,6 @@ POST /projects/:id/merge_requests/:merge_request_iid/approvals
| `merge_request_iid` | integer | yes | The IID of MR |
| `approvals_required` | integer | yes | Approvals required before MR can be merged |
-
```json
{
"id": 5,
@@ -359,7 +357,7 @@ POST /projects/:id/merge_requests/:merge_request_iid/approve
| `id` | integer | yes | The ID of a project |
| `merge_request_iid` | integer | yes | The IID of MR |
| `sha` | string | no | The HEAD of the MR |
-| `approval_password` **[STARTER]** | string | no | Current user's password. Required if [**Require user password to approve**](../user/project/merge_requests/merge_request_approvals.md#require-authentication-when-approving-a-merge-request-starter) is enabled in the project settings. |
+| `approval_password` **(STARTER)** | string | no | Current user's password. Required if [**Require user password to approve**](../user/project/merge_requests/merge_request_approvals.md#require-authentication-when-approving-a-merge-request-starter) is enabled in the project settings. |
The `sha` parameter works in the same way as
when [accepting a merge request](merge_requests.md#accept-mr): if it is passed, then it must
diff --git a/doc/api/merge_requests.md b/doc/api/merge_requests.md
index 85a07589956..de87e4a0aee 100644
--- a/doc/api/merge_requests.md
+++ b/doc/api/merge_requests.md
@@ -29,27 +29,28 @@ GET /merge_requests?search=foo&in=title
Parameters:
-| Attribute | Type | Required | Description |
-| ------------------- | -------- | -------- | ---------------------------------------------------------------------------------------------------------------------- |
-| `state` | string | no | Return all merge requests or just those that are `opened`, `closed`, `locked`, or `merged` |
-| `order_by` | string | no | Return requests ordered by `created_at` or `updated_at` fields. Default is `created_at` |
-| `sort` | string | no | Return requests sorted in `asc` or `desc` order. Default is `desc` |
-| `milestone` | string | no | Return merge requests for a specific milestone. `None` returns merge requests with no milestone. `Any` returns merge requests that have an assigned milestone. |
-| `view` | string | no | If `simple`, returns the `iid`, URL, title, description, and basic state of merge request |
-| `labels` | string | no | Return merge requests matching a comma separated list of labels. `None` lists all merge requests with no labels. `Any` lists all merge requests with at least one label. `No+Label` (Deprecated) lists all merge requests with no labels. Predefined names are case-insensitive. |
-| `created_after` | datetime | no | Return merge requests created on or after the given time |
-| `created_before` | datetime | no | Return merge requests created on or before the given time |
-| `updated_after` | datetime | no | Return merge requests updated on or after the given time |
-| `updated_before` | datetime | no | Return merge requests updated on or before the given time |
-| `scope` | string | no | Return merge requests for the given scope: `created_by_me`, `assigned_to_me` or `all`. Defaults to `created_by_me`<br> For versions before 11.0, use the now deprecated `created-by-me` or `assigned-to-me` scopes instead. |
-| `author_id` | integer | no | Returns merge requests created by the given user `id`. Combine with `scope=all` or `scope=assigned_to_me` |
-| `assignee_id` | integer | no | Returns merge requests assigned to the given user `id`. `None` returns unassigned merge requests. `Any` returns merge requests with an assignee. |
-| `my_reaction_emoji` | string | no | Return merge requests reacted by the authenticated user by the given `emoji`. `None` returns issues not given a reaction. `Any` returns issues given at least one reaction. _([Introduced][ce-14016] in GitLab 10.0)_ |
-| `source_branch` | string | no | Return merge requests with the given source branch |
-| `target_branch` | string | no | Return merge requests with the given target branch |
-| `search` | string | no | Search merge requests against their `title` and `description` |
-| `in` | string | no | Modify the scope of the `search` attribute. `title`, `description`, or a string joining them with comma. Default is `title,description` |
-| `wip` | string | no | Filter merge requests against their `wip` status. `yes` to return *only* WIP merge requests, `no` to return *non* WIP merge requests |
+| Attribute | Type | Required | Description |
+| ------------------- | -------- | -------- | ---------------------------------------------------------------------------------------------------------------------- |
+| `state` | string | no | Return all merge requests or just those that are `opened`, `closed`, `locked`, or `merged` |
+| `order_by` | string | no | Return requests ordered by `created_at` or `updated_at` fields. Default is `created_at` |
+| `sort` | string | no | Return requests sorted in `asc` or `desc` order. Default is `desc` |
+| `milestone` | string | no | Return merge requests for a specific milestone. `None` returns merge requests with no milestone. `Any` returns merge requests that have an assigned milestone. |
+| `view` | string | no | If `simple`, returns the `iid`, URL, title, description, and basic state of merge request |
+| `labels` | string | no | Return merge requests matching a comma separated list of labels. `None` lists all merge requests with no labels. `Any` lists all merge requests with at least one label. `No+Label` (Deprecated) lists all merge requests with no labels. Predefined names are case-insensitive. |
+| `created_after` | datetime | no | Return merge requests created on or after the given time |
+| `created_before` | datetime | no | Return merge requests created on or before the given time |
+| `updated_after` | datetime | no | Return merge requests updated on or after the given time |
+| `updated_before` | datetime | no | Return merge requests updated on or before the given time |
+| `scope` | string | no | Return merge requests for the given scope: `created_by_me`, `assigned_to_me` or `all`. Defaults to `created_by_me`<br> For versions before 11.0, use the now deprecated `created-by-me` or `assigned-to-me` scopes instead. |
+| `author_id` | integer | no | Returns merge requests created by the given user `id`. Combine with `scope=all` or `scope=assigned_to_me` |
+| `assignee_id` | integer | no | Returns merge requests assigned to the given user `id`. `None` returns unassigned merge requests. `Any` returns merge requests with an assignee. |
+| `approver_ids` **(STARTER)** | Array[integer] | no | Returns merge requests which have specified all the users with the given `id`s as individual approvers. `None` returns merge requests without approvers. `Any` returns merge requests with an approver. |
+| `my_reaction_emoji` | string | no | Return merge requests reacted by the authenticated user by the given `emoji`. `None` returns issues not given a reaction. `Any` returns issues given at least one reaction. _([Introduced][ce-14016] in GitLab 10.0)_ |
+| `source_branch` | string | no | Return merge requests with the given source branch |
+| `target_branch` | string | no | Return merge requests with the given target branch |
+| `search` | string | no | Search merge requests against their `title` and `description` |
+| `in` | string | no | Modify the scope of the `search` attribute. `title`, `description`, or a string joining them with comma. Default is `title,description` |
+| `wip` | string | no | Filter merge requests against their `wip` status. `yes` to return *only* WIP merge requests, `no` to return *non* WIP merge requests |
```json
[
@@ -147,6 +148,20 @@ Parameters:
]
```
+Users on GitLab [Starter, Bronze, or higher](https://about.gitlab.com/pricing/) will also see
+the `approvals_before_merge` parameter:
+
+```json
+[
+ {
+ "id": 1,
+ "title": "test1",
+ "approvals_before_merge": null
+ ...
+ }
+]
+```
+
## List project merge requests
Get all merge requests for this project.
@@ -177,7 +192,7 @@ Parameters:
| Attribute | Type | Required | Description |
| ------------------- | -------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------ |
| `id` | integer | yes | The ID of a project |
-| `iids[]` | Array[integer] | no | Return the request having the given `iid` |
+| `iids[]` | integer array | no | Return the request having the given `iid` |
| `state` | string | no | Return all merge requests or just those that are `opened`, `closed`, `locked`, or `merged` |
| `order_by` | string | no | Return requests ordered by `created_at` or `updated_at` fields. Default is `created_at` |
| `sort` | string | no | Return requests sorted in `asc` or `desc` order. Default is `desc` |
@@ -191,6 +206,7 @@ Parameters:
| `scope` | string | no | Return merge requests for the given scope: `created_by_me`, `assigned_to_me` or `all`.<br> For versions before 11.0, use the now deprecated `created-by-me` or `assigned-to-me` scopes instead.<br> _([Introduced][ce-13060] in GitLab 9.5. [Changed to snake_case][ce-18935] in GitLab 11.0)_ |
| `author_id` | integer | no | Returns merge requests created by the given user `id` _([Introduced][ce-13060] in GitLab 9.5)_ |
| `assignee_id` | integer | no | Returns merge requests assigned to the given user `id`. `None` returns unassigned merge requests. `Any` returns merge requests with an assignee. _([Introduced][ce-13060] in GitLab 9.5)_ |
+| `approver_ids` **(STARTER)** | Array[integer] | no | Returns merge requests which have specified all the users with the given `id`s as individual approvers. `None` returns merge requests without approvers. `Any` returns merge requests with an approver. |
| `my_reaction_emoji` | string | no | Return merge requests reacted by the authenticated user by the given `emoji`. `None` returns issues not given a reaction. `Any` returns issues given at least one reaction. _([Introduced][ce-14016] in GitLab 10.0)_ |
| `source_branch` | string | no | Return merge requests with the given source branch |
| `target_branch` | string | no | Return merge requests with the given target branch |
@@ -293,6 +309,20 @@ Parameters:
]
```
+Users on GitLab [Starter, Bronze, or higher](https://about.gitlab.com/pricing/) will also see
+the `approvals_before_merge` parameter:
+
+```json
+[
+ {
+ "id": 1,
+ "title": "test1",
+ "approvals_before_merge": null
+ ...
+ }
+]
+```
+
## List group merge requests
Get all merge requests for this group and its subgroups.
@@ -328,6 +358,7 @@ Parameters:
| `scope` | string | no | Return merge requests for the given scope: `created_by_me`, `assigned_to_me` or `all`.<br> |
| `author_id` | integer | no | Returns merge requests created by the given user `id` _([Introduced][ce-13060] in GitLab 9.5)_ |
| `assignee_id` | integer | no | Returns merge requests assigned to the given user `id`. `None` returns unassigned merge requests. `Any` returns merge requests with an assignee. _([Introduced][ce-13060] in GitLab 9.5)_ |
+| `approver_ids` **(STARTER)** | Array[integer] | no | Returns merge requests which have specified all the users with the given `id`s as individual approvers. `None` returns merge requests without approvers. `Any` returns merge requests with an approver. |
| `my_reaction_emoji` | string | no | Return merge requests reacted by the authenticated user by the given `emoji`. `None` returns issues not given a reaction. `Any` returns issues given at least one reaction. _([Introduced][ce-14016] in GitLab 10.0)_ |
| `source_branch` | string | no | Return merge requests with the given source branch |
| `target_branch` | string | no | Return merge requests with the given target branch |
@@ -427,6 +458,20 @@ Parameters:
]
```
+Users on GitLab [Starter, Bronze, or higher](https://about.gitlab.com/pricing/) will also see
+the `approvals_before_merge` parameter:
+
+```json
+[
+ {
+ "id": 1,
+ "title": "test1",
+ "approvals_before_merge": null
+ ...
+ }
+]
+```
+
## Get single MR
Shows information about a single merge request.
@@ -565,6 +610,18 @@ Parameters:
}
```
+Users on GitLab [Starter, Bronze, or higher](https://about.gitlab.com/pricing/) will also see
+the `approvals_before_merge` parameter:
+
+```json
+{
+ "id": 1,
+ "title": "test1",
+ "approvals_before_merge": null
+ ...
+}
+```
+
## Get single MR participants
Get a list of merge request participants.
@@ -767,18 +824,19 @@ Parameters:
## Create MR
Creates a new merge request.
+
```
POST /projects/:id/merge_requests
```
| 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 |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
| `source_branch` | string | yes | The source branch |
| `target_branch` | string | yes | The target branch |
| `title` | string | yes | Title of MR |
| `assignee_id` | integer | no | Assignee user ID |
-| `assignee_ids` | Array[integer] | no | The ID of the user(s) to assign the MR to. Set to `0` or provide an empty value to unassign all assignees. |
+| `assignee_ids` | integer array | no | The ID of the user(s) to assign the MR to. Set to `0` or provide an empty value to unassign all assignees. |
| `description` | string | no | Description of MR |
| `target_project_id` | integer | no | The target project (numeric id) |
| `labels` | string | no | Labels for MR as a comma-separated list |
@@ -788,6 +846,15 @@ POST /projects/:id/merge_requests
| `allow_maintainer_to_push` | boolean | no | Deprecated, see allow_collaboration |
| `squash` | boolean | no | Squash commits into a single commit when merging |
+If `approvals_before_merge` **(STARTER)** is not provided, it inherits the value from the
+target project. If it is provided, then the following conditions must hold in
+order for it to take effect:
+
+1. The target project's `approvals_before_merge` must be greater than zero. A
+ value of zero disables approvals for that project.
+1. The provided value of `approvals_before_merge` must be greater than the
+ target project's `approvals_before_merge`.
+
```json
{
"id": 1,
@@ -893,6 +960,18 @@ POST /projects/:id/merge_requests
}
```
+Users on GitLab [Starter, Bronze, or higher](https://about.gitlab.com/pricing/) will also see
+the `approvals_before_merge` parameter:
+
+```json
+{
+ "id": 1,
+ "title": "test1",
+ "approvals_before_merge": null
+ ...
+}
+```
+
## Update MR
Updates an existing merge request. You can change the target branch, title, or even close the MR.
@@ -908,7 +987,7 @@ PUT /projects/:id/merge_requests/:merge_request_iid
| `target_branch` | string | no | The target branch |
| `title` | string | no | Title of MR |
| `assignee_id` | integer | no | The ID of the user to assign the merge request to. Set to `0` or provide an empty value to unassign all assignees. |
-| `assignee_ids` | Array[integer] | no | The ID of the user(s) to assign the MR to. Set to `0` or provide an empty value to unassign all assignees. |
+| `assignee_ids` | integer array | no | The ID of the user(s) to assign the MR to. Set to `0` or provide an empty value to unassign all assignees. |
| `milestone_id` | integer | no | The global ID of a milestone to assign the merge request to. Set to `0` or provide an empty value to unassign a milestone.|
| `labels` | string | no | Comma-separated label names for a merge request. Set to an empty string to unassign all labels. |
| `description` | string | no | Description of MR |
@@ -1034,6 +1113,18 @@ Must include at least one non-required attribute from above.
}
```
+Users on GitLab [Starter, Bronze, or higher](https://about.gitlab.com/pricing/) will also see
+the `approvals_before_merge` parameter:
+
+```json
+{
+ "id": 1,
+ "title": "test1",
+ "approvals_before_merge": null
+ ...
+}
+```
+
## Delete a merge request
Only for admins and project owners. Soft deletes the merge request in question.
@@ -1191,9 +1282,21 @@ Parameters:
}
```
-## Returns the up to date merge-ref HEAD commit
+Users on GitLab [Starter, Bronze, or higher](https://about.gitlab.com/pricing/) will also see
+the `approvals_before_merge` parameter:
-Merge the changes between the merge request source and target branches into `refs/merge-requests/:iid/merge`
+```json
+{
+ "id": 1,
+ "title": "test1",
+ "approvals_before_merge": null
+ ...
+}
+```
+
+## Merge to default merge ref path
+
+Merge the changes between the merge request source and target branches into `refs/merge-requests/:iid/merge`
ref, of the target project repository, if possible. This ref will have the state the target branch would have if
a regular merge action was taken.
@@ -1349,6 +1452,18 @@ Parameters:
}
```
+Users on GitLab [Starter, Bronze, or higher](https://about.gitlab.com/pricing/) will also see
+the `approvals_before_merge` parameter:
+
+```json
+{
+ "id": 1,
+ "title": "test1",
+ "approvals_before_merge": null
+ ...
+}
+```
+
## Rebase a merge request
Automatically rebase the `source_branch` of the merge request against its
@@ -1370,8 +1485,14 @@ PUT /projects/:id/merge_requests/:merge_request_iid/rebase
curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/76/merge_requests/1/rebase
```
-This is an asynchronous request. The API will return an empty `202 Accepted`
-response if the request is enqueued successfully.
+This is an asynchronous request. The API will return a `202 Accepted` response
+if the request is enqueued successfully, with a response containing:
+
+```json
+{
+ "rebase_in_progress": true
+}
+```
You can poll the [Get single MR](#get-single-mr) endpoint with the
`include_rebase_in_progress` parameter to check the status of the
@@ -1616,6 +1737,18 @@ Example response:
}
```
+Users on GitLab [Starter, Bronze, or higher](https://about.gitlab.com/pricing/) will also see
+the `approvals_before_merge` parameter:
+
+```json
+{
+ "id": 1,
+ "title": "test1",
+ "approvals_before_merge": null
+ ...
+}
+```
+
## Unsubscribe from a merge request
Unsubscribes the authenticated user from a merge request to not receive
@@ -1749,6 +1882,18 @@ Example response:
}
```
+Users on GitLab [Starter, Bronze, or higher](https://about.gitlab.com/pricing/) will also see
+the `approvals_before_merge` parameter:
+
+```json
+{
+ "id": 1,
+ "title": "test1",
+ "approvals_before_merge": null
+ ...
+}
+```
+
## Create a todo
Manually creates a todo for the current user on a merge request.
@@ -1970,6 +2115,7 @@ Example response:
}]
}
```
+
## Set a time estimate for a merge request
Sets an estimated time of work for this merge request.
@@ -2114,3 +2260,7 @@ Example response:
[ce-14016]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/14016
[ce-15454]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/15454
[ce-18935]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/18935
+
+## Approvals **(STARTER)**
+
+For approvals, please see [Merge Request Approvals](merge_request_approvals.md)
diff --git a/doc/api/milestones.md b/doc/api/milestones.md
index 90d8c033cd6..a6ded7d3bd2 100644
--- a/doc/api/milestones.md
+++ b/doc/api/milestones.md
@@ -16,13 +16,13 @@ GET /projects/:id/milestones?search=version
Parameters:
-| 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 |
-| `iids[]` | Array[integer] | optional | Return only the milestones having the given `iid` |
-| `state` | string | optional | Return only `active` or `closed` milestones |
-| `title` | string | optional | Return only the milestones having the given `title` |
-| `search` | string | optional | Return only milestones with a title or description matching the provided string |
+| 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 |
+| `iids[]` | integer array | optional | Return only the milestones having the given `iid` |
+| `state` | string | optional | Return only `active` or `closed` milestones |
+| `title` | string | optional | Return only the milestones having the given `title` |
+| `search` | string | optional | Return only milestones with a title or description matching the provided string |
```bash
curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/milestones
@@ -147,3 +147,18 @@ Parameters:
- `id` (required) - The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user
- `milestone_id` (required) - The ID of a project milestone
+
+## Get all burndown chart events for a single milestone **(STARTER)**
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/4737) in GitLab 12.1
+
+Gets all burndown chart events for a single milestone.
+
+```
+GET /projects/:id/milestones/:milestone_id/burndown_events
+```
+
+Parameters:
+
+- `id` (required) - The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user
+- `milestone_id` (required) - The ID of a project milestone
diff --git a/doc/api/namespaces.md b/doc/api/namespaces.md
index b66a3198ffb..2b6eddf78a1 100644
--- a/doc/api/namespaces.md
+++ b/doc/api/namespaces.md
@@ -54,7 +54,21 @@ Example response:
]
```
-**Note**: `members_count_with_descendants` are presented only for group maintainers/owners.
+Users on GitLab.com [Bronze or higher](https://about.gitlab.com/pricing/#gitlab-com) may also see
+the `plan` parameter associated with a namespace:
+
+```json
+[
+ {
+ "id": 1,
+ "name": "user1",
+ "plan": "bronze",
+ ...
+ }
+]
+```
+
+NOTE: **Note:** Only group maintainers/owners are presented with `members_count_with_descendants`, as well as `plan` **(BRONZE ONLY)**.
## Search for namespace
diff --git a/doc/api/notes.md b/doc/api/notes.md
index c09129c22d4..acbf0334563 100644
--- a/doc/api/notes.md
+++ b/doc/api/notes.md
@@ -5,7 +5,7 @@ Notes are comments on:
- Snippets
- Issues
- Merge requests
-- Epics **[ULTIMATE]**
+- Epics **(ULTIMATE)**
This includes system notes, which are notes about changes to the object (for example, when a milestone changes, there will be a corresponding system note). Label notes are not part of this API, but recorded as separate events in [resource label events](resource_label_events.md).
@@ -396,7 +396,7 @@ Parameters:
curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/merge_requests/7/notes/1602
```
-## Epics **[ULTIMATE]**
+## Epics **(ULTIMATE)**
### List all epic notes
diff --git a/doc/api/notification_settings.md b/doc/api/notification_settings.md
index e21e73c7dac..c6667784617 100644
--- a/doc/api/notification_settings.md
+++ b/doc/api/notification_settings.md
@@ -1,8 +1,8 @@
# Notification settings API
->**Note:** This feature was [introduced][ce-5632] in GitLab 8.12.
+> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/5632) in GitLab 8.12.
-**Valid notification levels**
+## Valid notification levels
The notification levels are defined in the `NotificationSetting.level` model enumeration. Currently, these levels are recognized:
@@ -17,22 +17,21 @@ custom
If the `custom` level is used, specific email events can be controlled. Available events are returned by `NotificationSetting.email_events`. Currently, these events are recognized:
-```
-new_note
-new_issue
-reopen_issue
-close_issue
-reassign_issue
-issue_due
-new_merge_request
-push_to_merge_request
-reopen_merge_request
-close_merge_request
-reassign_merge_request
-merge_merge_request
-failed_pipeline
-success_pipeline
-```
+- `new_note`
+- `new_issue`
+- `reopen_issue`
+- `close_issue`
+- `reassign_issue`
+- `issue_due`
+- `new_merge_request`
+- `push_to_merge_request`
+- `reopen_merge_request`
+- `close_merge_request`
+- `reassign_merge_request`
+- `merge_merge_request`
+- `failed_pipeline`
+- `success_pipeline`
+- `new_epic` **(ULTIMATE)**
## Global notification settings
@@ -85,6 +84,7 @@ curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.
| `merge_merge_request` | boolean | no | Enable/disable this notification |
| `failed_pipeline` | boolean | no | Enable/disable this notification |
| `success_pipeline` | boolean | no | Enable/disable this notification |
+| `new_epic` | boolean | no | Enable/disable this notification ([Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/6626) in 11.3) **(ULTIMATE)** |
Example response:
@@ -153,6 +153,7 @@ curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.
| `merge_merge_request` | boolean | no | Enable/disable this notification |
| `failed_pipeline` | boolean | no | Enable/disable this notification |
| `success_pipeline` | boolean | no | Enable/disable this notification |
+| `new_epic` | boolean | no | Enable/disable this notification ([Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/6626) in 11.3) **(ULTIMATE)** |
Example responses:
@@ -182,4 +183,17 @@ Example responses:
}
```
-[ce-5632]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/5632
+Users on GitLab [Ultimate or Gold](https://about.gitlab.com/pricing/) will also see
+the `new_epic` parameter:
+
+```json
+{
+ "level": "custom",
+ "events": {
+ "new_note": true,
+ "new_issue": false,
+ "new_epic": false,
+ ...
+ }
+}
+```
diff --git a/doc/api/oauth2.md b/doc/api/oauth2.md
index dfe62554852..76e3a0fa1a4 100644
--- a/doc/api/oauth2.md
+++ b/doc/api/oauth2.md
@@ -192,7 +192,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 behalf of a user.
You can pass the token either as GET parameter:
diff --git a/doc/api/packages.md b/doc/api/packages.md
index 618e5c3056a..ca90771b085 100644
--- a/doc/api/packages.md
+++ b/doc/api/packages.md
@@ -1,4 +1,4 @@
-# Packages API **[PREMIUM]**
+# Packages API **(PREMIUM)**
This is the API docs of [GitLab Packages](../administration/packages.md).
@@ -76,7 +76,7 @@ Example response:
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/9305) in GitLab 11.8.
-Get a list of package files of a single package.
+Get a list of package files of a single package.
```
GET /projects/:id/packages/:package_id/package_files
diff --git a/doc/api/pages_domains.md b/doc/api/pages_domains.md
index 70fbe24099f..9678203eb40 100644
--- a/doc/api/pages_domains.md
+++ b/doc/api/pages_domains.md
@@ -1,6 +1,6 @@
# Pages domains API
-Endpoints for connecting custom domain(s) and TLS certificates in [GitLab Pages](https://about.gitlab.com/features/pages/).
+Endpoints for connecting custom domain(s) and TLS certificates in [GitLab Pages](https://about.gitlab.com/product/pages/).
The GitLab Pages feature must be enabled to use these endpoints. Find out more about [administering](../administration/pages/index.md) and [using](../user/project/pages/index.md) the feature.
diff --git a/doc/api/pipeline_schedules.md b/doc/api/pipeline_schedules.md
index 470e55425f8..acf1ac90315 100644
--- a/doc/api/pipeline_schedules.md
+++ b/doc/api/pipeline_schedules.md
@@ -108,9 +108,9 @@ POST /projects/:id/pipeline_schedules
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
| `description` | string | yes | The description of pipeline schedule |
| `ref` | string | yes | The branch/tag name will be triggered |
-| `cron ` | string | yes | The cron (e.g. `0 1 * * *`) ([Cron syntax](https://en.wikipedia.org/wiki/Cron)) |
-| `cron_timezone ` | string | no | The timezone supported by `ActiveSupport::TimeZone` (e.g. `Pacific Time (US & Canada)`) (default: `'UTC'`) |
-| `active ` | boolean | no | The activation of pipeline schedule. If false is set, the pipeline schedule will deactivated initially (default: `true`) |
+| `cron` | string | yes | The cron (e.g. `0 1 * * *`) ([Cron syntax](https://en.wikipedia.org/wiki/Cron)) |
+| `cron_timezone` | string | no | The timezone supported by `ActiveSupport::TimeZone` (e.g. `Pacific Time (US & Canada)`) (default: `'UTC'`) |
+| `active` | boolean | no | The activation of pipeline schedule. If false is set, the pipeline schedule will deactivated initially (default: `true`) |
```sh
curl --request POST --header "PRIVATE-TOKEN: k5ESFgWY2Qf5xEvDcFxZ" --form description="Build packages" --form ref="master" --form cron="0 1 * * 5" --form cron_timezone="UTC" --form active="true" "https://gitlab.example.com/api/v4/projects/29/pipeline_schedules"
@@ -153,9 +153,9 @@ PUT /projects/:id/pipeline_schedules/:pipeline_schedule_id
| `pipeline_schedule_id` | integer | yes | The pipeline schedule id |
| `description` | string | no | The description of pipeline schedule |
| `ref` | string | no | The branch/tag name will be triggered |
-| `cron ` | string | no | The cron (e.g. `0 1 * * *`) ([Cron syntax](https://en.wikipedia.org/wiki/Cron)) |
-| `cron_timezone ` | string | no | The timezone supported by `ActiveSupport::TimeZone` (e.g. `Pacific Time (US & Canada)`) or `TZInfo::Timezone` (e.g. `America/Los_Angeles`) |
-| `active ` | boolean | no | The activation of pipeline schedule. If false is set, the pipeline schedule will deactivated initially. |
+| `cron` | string | no | The cron (e.g. `0 1 * * *`) ([Cron syntax](https://en.wikipedia.org/wiki/Cron)) |
+| `cron_timezone` | string | no | The timezone supported by `ActiveSupport::TimeZone` (e.g. `Pacific Time (US & Canada)`) or `TZInfo::Timezone` (e.g. `America/Los_Angeles`) |
+| `active` | boolean | no | The activation of pipeline schedule. If false is set, the pipeline schedule will deactivated initially. |
```sh
curl --request PUT --header "PRIVATE-TOKEN: k5ESFgWY2Qf5xEvDcFxZ" --form cron="0 2 * * *" "https://gitlab.example.com/api/v4/projects/29/pipeline_schedules/13"
diff --git a/doc/api/pipelines.md b/doc/api/pipelines.md
index 753faec3cc8..e36f74e7c77 100644
--- a/doc/api/pipelines.md
+++ b/doc/api/pipelines.md
@@ -132,11 +132,11 @@ Example of response
POST /projects/:id/pipeline
```
-| 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 |
-| `ref` | string | yes | Reference to commit |
-| `variables` | array | no | An array containing the variables available in the pipeline, matching the structure [{ 'key' => 'UPLOAD_TO_S3', 'variable_type' => 'file', 'value' => 'true' }] |
+| 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 |
+| `ref` | string | yes | Reference to commit |
+| `variables` | array | no | An array containing the variables available in the pipeline, matching the structure `[{ 'key' => 'UPLOAD_TO_S3', 'variable_type' => 'file', 'value' => 'true' }]` |
```
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/1/pipeline?ref=master"
diff --git a/doc/api/project_aliases.md b/doc/api/project_aliases.md
index 65845579409..271632b61c3 100644
--- a/doc/api/project_aliases.md
+++ b/doc/api/project_aliases.md
@@ -1,4 +1,4 @@
-# Project Aliases API **[PREMIUM ONLY]**
+# Project Aliases API **(PREMIUM ONLY)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/3264) in [GitLab Premium](https://about.gitlab.com/pricing/) 12.1.
@@ -68,13 +68,19 @@ Add a new alias for a project. Responds with a 201 when successful,
POST /project_aliases
```
-| Attribute | Type | Required | Description |
-|--------------|--------|----------|-----------------------------------------------|
-| `project_id` | string | yes | The ID or URL-encoded path of the project. |
-| `name` | string | yes | The name of the alias. Must be unique. |
+| Attribute | Type | Required | Description |
+|--------------|----------------|----------|----------------------------------------|
+| `project_id` | integer/string | yes | The ID or path of the project. |
+| `name` | string | yes | The name of the alias. Must be unique. |
```
-curl --request POST "https://gitlab.example.com/api/v4/project_aliases" --form "project_id=gitlab-org%2Fgitlab-ee" --form "name=gitlab-ee"
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/project_aliases" --form "project_id=1" --form "name=gitlab-ee"
+```
+
+or
+
+```
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/project_aliases" --form "project_id=gitlab-org/gitlab-ee" --form "name=gitlab-ee"
```
Example response:
diff --git a/doc/api/project_badges.md b/doc/api/project_badges.md
index 3a7b3d8975e..1c382232837 100644
--- a/doc/api/project_badges.md
+++ b/doc/api/project_badges.md
@@ -91,7 +91,7 @@ POST /projects/:id/badges
| 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 |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
| `link_url` | string | yes | URL of the badge link |
| `image_url` | string | yes | URL of the badge image |
diff --git a/doc/api/project_clusters.md b/doc/api/project_clusters.md
index 327781f6c93..614ea41d572 100644
--- a/doc/api/project_clusters.md
+++ b/doc/api/project_clusters.md
@@ -167,7 +167,7 @@ Parameters:
| `platform_kubernetes_attributes[ca_cert]` | String | no | TLS certificate (needed if API is using a self-signed TLS certificate |
| `platform_kubernetes_attributes[namespace]` | String | no | The unique namespace related to the project |
| `platform_kubernetes_attributes[authorization_type]` | String | no | The cluster authorization type: `rbac`, `abac` or `unknown_authorization`. Defaults to `rbac`. |
-| `environment_scope` | String | no | The associated environment to the cluster. Defaults to `*` **[PREMIUM]** |
+| `environment_scope` | String | no | The associated environment to the cluster. Defaults to `*` **(PREMIUM)** |
Example request:
@@ -257,7 +257,7 @@ Parameters:
| `platform_kubernetes_attributes[token]` | String | no | The token to authenticate against Kubernetes |
| `platform_kubernetes_attributes[ca_cert]` | String | no | TLS certificate (needed if API is using a self-signed TLS certificate |
| `platform_kubernetes_attributes[namespace]` | String | no | The unique namespace related to the project |
-| `environment_scope` | String | no | The associated environment to the cluster **[PREMIUM]** |
+| `environment_scope` | String | no | The associated environment to the cluster **(PREMIUM)** |
NOTE: **Note:**
`name`, `api_url`, `ca_cert` and `token` can only be updated if the cluster was added
diff --git a/doc/api/project_level_variables.md b/doc/api/project_level_variables.md
index 66a749e4811..eab905bbc5f 100644
--- a/doc/api/project_level_variables.md
+++ b/doc/api/project_level_variables.md
@@ -74,7 +74,7 @@ POST /projects/:id/variables
| `variable_type` | string | no | The type of a variable. Available types are: `env_var` (default) and `file` |
| `protected` | boolean | no | Whether the variable is protected |
| `masked` | boolean | no | Whether the variable is masked |
-| `environment_scope` | string | no | The `environment_scope` of the variable **[PREMIUM]** |
+| `environment_scope` | string | no | The `environment_scope` of the variable **(PREMIUM)** |
```
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/1/variables" --form "key=NEW_VARIABLE" --form "value=new value"
@@ -108,7 +108,7 @@ PUT /projects/:id/variables/:key
| `variable_type` | string | no | The type of a variable. Available types are: `env_var` (default) and `file` |
| `protected` | boolean | no | Whether the variable is protected |
| `masked` | boolean | no | Whether the variable is masked |
-| `environment_scope` | string | no | The `environment_scope` of the variable **[PREMIUM]** |
+| `environment_scope` | string | no | The `environment_scope` of the variable **(PREMIUM)** |
```
curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/1/variables/NEW_VARIABLE" --form "value=updated value"
diff --git a/doc/api/project_snippets.md b/doc/api/project_snippets.md
index 0ccb0517e08..c1588f2292a 100644
--- a/doc/api/project_snippets.md
+++ b/doc/api/project_snippets.md
@@ -1,6 +1,6 @@
# Project snippets
-### Snippet visibility level
+## Snippet visibility level
Snippets in GitLab can be either private, internal or public.
You can set it with the `visibility` field in the snippet.
@@ -13,6 +13,12 @@ Constants for snippet visibility levels are:
| `internal` | The snippet is visible for any logged in user |
| `public` | The snippet can be accessed without any authentication |
+NOTE: **Note:**
+From July 2019, the `Internal` visibility setting is disabled for new projects, groups,
+and snippets on GitLab.com. Existing projects, groups, and snippets using the `Internal`
+visibility setting keep this setting. You can read more about the change in the
+[relevant issue](https://gitlab.com/gitlab-org/gitlab-ee/issues/12388).
+
## List snippets
Get a list of project snippets.
diff --git a/doc/api/project_statistics.md b/doc/api/project_statistics.md
index 34d73abfcbf..2732fa47fa0 100644
--- a/doc/api/project_statistics.md
+++ b/doc/api/project_statistics.md
@@ -14,7 +14,7 @@ GET /projects/:id/statistics
| Attribute | Type | Required | Description |
| ---------- | ------ | -------- | ----------- |
-| `id ` | integer / string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
+| `id` | integer / string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
Example response:
diff --git a/doc/api/project_templates.md b/doc/api/project_templates.md
index 0a94a8d47ae..cc932e3ef58 100644
--- a/doc/api/project_templates.md
+++ b/doc/api/project_templates.md
@@ -16,7 +16,7 @@ Support will be added for [Issue and Merge Request templates](../user/project/de
in a future release.
Support for [Group-level file templates](../user/group/index.md#group-file-templates-premium)
-**[PREMIUM]** was [added](https://gitlab.com/gitlab-org/gitlab-ee/issues/5987)
+**(PREMIUM)** was [added](https://gitlab.com/gitlab-org/gitlab-ee/issues/5987)
in GitLab 11.5
## Get all templates of a particular type
@@ -27,7 +27,7 @@ GET /projects/:id/templates/:type
| Attribute | Type | Required | Description |
| ---------- | ------ | -------- | ----------- |
-| `id ` | integer / string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
+| `id` | integer / string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
| `type` | string | yes| The type `(dockerfiles|gitignores|gitlab_ci_ymls|licenses)` of the template |
Example response (licenses):
@@ -93,7 +93,7 @@ GET /projects/:id/templates/:type/:key
| Attribute | Type | Required | Description |
| ---------- | ------ | -------- | ----------- |
-| `id ` | integer / string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
+| `id` | integer / string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
| `type` | string | yes| The type `(dockerfiles|gitignores|gitlab_ci_ymls|licenses)` of the template |
| `key` | string | yes | The key of the template, as obtained from the collection endpoint |
| `project` | string | no | The project name to use when expanding placeholders in the template. Only affects licenses |
diff --git a/doc/api/projects.md b/doc/api/projects.md
index 1d58e390d9e..6468d73e0af 100644
--- a/doc/api/projects.md
+++ b/doc/api/projects.md
@@ -14,7 +14,7 @@ Values for the project visibility level are:
The project can be cloned by any logged in user.
- `public`:
- The project can be cloned without any authentication.
+ The project can be accessed without any authentication.
## Project merge method
@@ -41,23 +41,23 @@ GET /projects
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
-| `archived` | boolean | no | Limit by archived status |
-| `visibility` | string | no | Limit by visibility `public`, `internal`, or `private` |
-| `order_by` | string | no | Return projects ordered by `id`, `name`, `path`, `created_at`, `updated_at`, or `last_activity_at` fields. Default is `created_at` |
-| `sort` | string | no | Return projects sorted in `asc` or `desc` order. Default is `desc` |
-| `search` | string | no | Return list of projects matching the search criteria |
-| `simple` | boolean | no | Return only limited fields for each project. This is a no-op without authentication as then _only_ simple fields are returned. |
-| `owned` | boolean | no | Limit by projects explicitly owned by the current user |
-| `membership` | boolean | no | Limit by projects that the current user is a member of |
-| `starred` | boolean | no | Limit by projects starred by the current user |
-| `statistics` | boolean | no | Include project statistics |
-| `with_custom_attributes` | boolean | no | Include [custom attributes](custom_attributes.md) in response (admins only) |
-| `with_issues_enabled` | boolean | no | Limit by enabled issues feature |
+| `archived` | boolean | no | Limit by archived status |
+| `visibility` | string | no | Limit by visibility `public`, `internal`, or `private` |
+| `order_by` | string | no | Return projects ordered by `id`, `name`, `path`, `created_at`, `updated_at`, or `last_activity_at` fields. Default is `created_at` |
+| `sort` | string | no | Return projects sorted in `asc` or `desc` order. Default is `desc` |
+| `search` | string | no | Return list of projects matching the search criteria |
+| `simple` | boolean | no | Return only limited fields for each project. This is a no-op without authentication as then _only_ simple fields are returned. |
+| `owned` | boolean | no | Limit by projects explicitly owned by the current user |
+| `membership` | boolean | no | Limit by projects that the current user is a member of |
+| `starred` | boolean | no | Limit by projects starred by the current user |
+| `statistics` | boolean | no | Include project statistics |
+| `with_custom_attributes` | boolean | no | Include [custom attributes](custom_attributes.md) in response (admins only) |
+| `with_issues_enabled` | boolean | no | Limit by enabled issues feature |
| `with_merge_requests_enabled` | boolean | no | Limit by enabled merge requests feature |
-| `with_programming_language` | string | no | Limit by projects which use the given programming language |
-| `wiki_checksum_failed` | boolean | no | Limit projects where the wiki checksum calculation has failed _([Introduced][ee-6137] in [GitLab Premium][eep] 11.2)_ |
-| `repository_checksum_failed` | boolean | no | Limit projects where the repository checksum calculation has failed _([Introduced][ee-6137] in [GitLab Premium][eep] 11.2)_ |
-| `min_access_level` | integer | no | Limit by current user minimal [access level](members.md) |
+| `with_programming_language` | string | no | Limit by projects which use the given programming language |
+| `wiki_checksum_failed` | boolean | no | **(PREMIUM)** Limit projects where the wiki checksum calculation has failed ([Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/6137) in [GitLab Premium](https://about.gitlab.com/pricing/) 11.2) |
+| `repository_checksum_failed` | boolean | no | **(PREMIUM)** Limit projects where the repository checksum calculation has failed ([Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/6137) in [GitLab Premium](https://about.gitlab.com/pricing/) 11.2) |
+| `min_access_level` | integer | no | Limit by current user minimal [access level](members.md) |
When `simple=true` or the user is unauthenticated this returns something like:
@@ -156,7 +156,8 @@ When the user is authenticated and `simple` is not set this returns something li
"repository_size": 1038090,
"wiki_size" : 0,
"lfs_objects_size": 0,
- "job_artifacts_size": 0
+ "job_artifacts_size": 0,
+ "packages_size": 0
},
"_links": {
"self": "http://example.com/api/v4/projects",
@@ -239,7 +240,8 @@ When the user is authenticated and `simple` is not set this returns something li
"repository_size": 2066080,
"wiki_size" : 0,
"lfs_objects_size": 0,
- "job_artifacts_size": 0
+ "job_artifacts_size": 0,
+ "packages_size": 0
},
"_links": {
"self": "http://example.com/api/v4/projects",
@@ -254,6 +256,20 @@ When the user is authenticated and `simple` is not set this returns something li
]
```
+Users on GitLab [Starter, Bronze, or higher](https://about.gitlab.com/pricing/) will also see
+the `approvals_before_merge` parameter:
+
+```json
+[
+ {
+ "id": 4,
+ "description": null,
+ "approvals_before_merge": 0,
+ ...
+ }
+]
+```
+
You can filter by [custom attributes](custom_attributes.md) with:
```
@@ -349,7 +365,8 @@ GET /users/:user_id/projects
"repository_size": 1038090,
"wiki_size" : 0,
"lfs_objects_size": 0,
- "job_artifacts_size": 0
+ "job_artifacts_size": 0,
+ "packages_size": 0
},
"_links": {
"self": "http://example.com/api/v4/projects",
@@ -432,7 +449,8 @@ GET /users/:user_id/projects
"repository_size": 2066080,
"wiki_size" : 0,
"lfs_objects_size": 0,
- "job_artifacts_size": 0
+ "job_artifacts_size": 0,
+ "packages_size": 0
},
"_links": {
"self": "http://example.com/api/v4/projects",
@@ -548,6 +566,7 @@ GET /projects/:id
"group_access_level": 10
}
],
+ "repository_storage": "default",
"only_allow_merge_if_pipeline_succeeds": false,
"only_allow_merge_if_all_discussions_are_resolved": false,
"printing_merge_requests_link_enabled": true,
@@ -559,7 +578,8 @@ GET /projects/:id
"repository_size": 1038090,
"wiki_size" : 0,
"lfs_objects_size": 0,
- "job_artifacts_size": 0
+ "job_artifacts_size": 0,
+ "packages_size": 0
},
"_links": {
"self": "http://example.com/api/v4/projects",
@@ -573,6 +593,18 @@ GET /projects/:id
}
```
+Users on GitLab [Starter, Bronze, or higher](https://about.gitlab.com/pricing/) will also see
+the `approvals_before_merge` parameter:
+
+```json
+{
+ "id": 3,
+ "description": null,
+ "approvals_before_merge": 0,
+ ...
+}
+```
+
**Note**: The `web_url` and `avatar_url` attributes on `namespace` were [introduced][ce-27427] in GitLab 11.11.
If the project is a fork, and you provide a valid token to authenticate, the
@@ -674,6 +706,7 @@ POST /projects
| `name` | string | yes if path is not provided | The name of the new project. Equals path if not provided. |
| `path` | string | yes if name is not provided | Repository name for new project. Generated based on name if not provided (generated lowercased with dashes). |
| `namespace_id` | integer | no | Namespace for the new project (defaults to the current user's namespace) |
+| `default_branch` | string | no | `master` by default |
| `description` | string | no | Short project description |
| `issues_enabled` | boolean | no | Enable issues for this project |
| `merge_requests_enabled` | boolean | no | Enable merge requests for this project |
@@ -695,8 +728,16 @@ POST /projects
| `avatar` | mixed | no | Image file for avatar of the project |
| `printing_merge_request_link_enabled` | boolean | no | Show link to create/view merge request when pushing from the command line |
| `ci_config_path` | string | no | The path to CI config file |
+| `repository_storage` | string | no | Which storage shard the repository is on. Available only to admins |
+| `approvals_before_merge` | integer | no | **(STARTER)** How many approvers should approve merge requests by default |
+| `mirror` | boolean | no | **(STARTER)** Enables pull mirroring in a project |
+| `mirror_trigger_builds` | boolean | no | **(STARTER)** Pull mirroring triggers builds |
| `initialize_with_readme` | boolean | no | `false` by default |
+NOTE: **Note:** If your HTTP repository is not publicly accessible,
+add authentication information to the URL: `https://username:password@gitlab.company.com/group/project.git`
+where `password` is a public access key with the `api` scope enabled.
+
## Create project for user
Creates a new project owned by the specified user. Available only for admins.
@@ -710,7 +751,6 @@ POST /projects/user/:user_id
| `user_id` | integer | yes | The user ID of the project owner |
| `name` | string | yes | The name of the new project |
| `path` | string | no | Custom repository name for new project. By default generated based on name |
-| `default_branch` | string | no | `master` by default |
| `namespace_id` | integer | no | Namespace for the new project (defaults to the current user's namespace) |
| `description` | string | no | Short project description |
| `issues_enabled` | boolean | no | Enable issues for this project |
@@ -733,6 +773,15 @@ POST /projects/user/:user_id
| `avatar` | mixed | no | Image file for avatar of the project |
| `printing_merge_request_link_enabled` | boolean | no | Show link to create/view merge request when pushing from the command line |
| `ci_config_path` | string | no | The path to CI config file |
+| `repository_storage` | string | no | Which storage shard the repository is on. Available only to admins |
+| `approvals_before_merge` | integer | no | **(STARTER)** How many approvers should approve merge requests by default |
+| `external_authorization_classification_label` | string | no | **(CORE ONLY)** The classification label for the project |
+| `mirror` | boolean | no | **(STARTER)** Enables pull mirroring in a project |
+| `mirror_trigger_builds` | boolean | no | **(STARTER)** Pull mirroring triggers builds |
+
+NOTE: **Note:** If your HTTP repository is not publicly accessible,
+add authentication information to the URL: `https://username:password@gitlab.company.com/group/project.git`
+where `password` is a public access key with the `api` scope enabled.
## Edit project
@@ -769,6 +818,19 @@ PUT /projects/:id
| `avatar` | mixed | no | Image file for avatar of the project |
| `ci_config_path` | string | no | The path to CI config file |
| `ci_default_git_depth` | integer | no | Default number of revisions for [shallow cloning](../user/project/pipelines/settings.md#git-shallow-clone) |
+| `repository_storage` | string | no | Which storage shard the repository is on. Available only to admins |
+| `approvals_before_merge` | integer | no | **(STARTER)** How many approvers should approve merge request by default |
+| `external_authorization_classification_label` | string | no | **(CORE ONLY)** The classification label for the project |
+| `mirror` | boolean | no | **(STARTER)** Enables pull mirroring in a project |
+| `mirror_user_id` | integer | no | **(STARTER)** User responsible for all the activity surrounding a pull mirror event |
+| `mirror_trigger_builds` | boolean | no | **(STARTER)** Pull mirroring triggers builds |
+| `only_mirror_protected_branches` | boolean | no | **(STARTER)** Only mirror protected branches |
+| `mirror_overwrites_diverged_branches` | boolean | no | **(STARTER)** Pull mirror overwrites diverged branches |
+| `packages_enabled` | boolean | no | **(PREMIUM ONLY)** Enable or disable packages repository feature |
+
+NOTE: **Note:** If your HTTP repository is not publicly accessible,
+add authentication information to the URL: `https://username:password@gitlab.company.com/group/project.git`
+where `password` is a public access key with the `api` scope enabled.
## Fork project
@@ -1292,7 +1354,7 @@ Example response:
## Remove project
-Removes a project including all associated resources (issues, merge requests etc.)
+Removes a project including all associated resources (issues, merge requests etc).
```
DELETE /projects/:id
@@ -1548,9 +1610,114 @@ POST /projects/:id/housekeeping
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
+| `id` | integer/string | yes | The ID of the project or NAMESPACE/PROJECT_NAME |
+
+## Push Rules **(STARTER)**
+
+### Get project push rules
+
+Get the push rules of a project.
+
+```
+GET /projects/:id/push_rule
+```
+
+| Attribute | Type | Required | Description |
+| --------- | ---- | -------- | ----------- |
+| `id` | integer/string | yes | The ID of the project or NAMESPACE/PROJECT_NAME |
+
+```json
+{
+ "id": 1,
+ "project_id": 3,
+ "commit_message_regex": "Fixes \d+\..*",
+ "commit_message_negative_regex": "ssh\:\/\/",
+ "branch_name_regex": "",
+ "deny_delete_tag": false,
+ "created_at": "2012-10-12T17:04:47Z",
+ "member_check": false,
+ "prevent_secrets": false,
+ "author_email_regex": "",
+ "file_name_regex": "",
+ "max_file_size": 5,
+ "commit_committer_check": false
+}
+```
+
+Users on GitLab [Premium, Silver, or higher](https://about.gitlab.com/pricing/) will also see
+the `commit_committer_check` parameter:
+
+```json
+{
+ "id": 1,
+ "project_id": 3,
+ "commit_committer_check": false
+ ...
+}
+```
+
+### Add project push rule
+
+Adds a push rule to a specified project.
+
+```
+POST /projects/:id/push_rule
+```
+
+| Attribute | Type | Required | Description |
+| --------------------------------------------- | -------------- | -------- | ----------- |
+| `id` | integer/string | yes | The ID of the project or NAMESPACE/PROJECT_NAME |
+| `deny_delete_tag` **(STARTER)** | boolean | no | Deny deleting a tag |
+| `member_check` **(STARTER)** | boolean | no | Restrict commits by author (email) to existing GitLab users |
+| `prevent_secrets` **(STARTER)** | boolean | no | GitLab will reject any files that are likely to contain secrets |
+| `commit_message_regex` **(STARTER)** | string | no | All commit messages must match this, e.g. `Fixed \d+\..*` |
+| `commit_message_negative_regex` **(STARTER)** | string | no | No commit message is allowed to match this, e.g. `ssh\:\/\/` |
+| `branch_name_regex` **(STARTER)** | string | no | All branch names must match this, e.g. `(feature|hotfix)\/*` |
+| `author_email_regex` **(STARTER)** | string | no | All commit author emails must match this, e.g. `@my-company.com$` |
+| `file_name_regex` **(STARTER)** | string | no | All commited filenames must **not** match this, e.g. `(jar|exe)$` |
+| `max_file_size` **(STARTER)** | integer | no | Maximum file size (MB) |
+| `commit_committer_check` **(PREMIUM)** | boolean | no | Users can only push commits to this repository that were committed with one of their own verified emails. |
+
+### Edit project push rule
+
+Edits a push rule for a specified project.
+
+```
+PUT /projects/:id/push_rule
+```
+
+| Attribute | Type | Required | Description |
+| --------------------------------------------- | -------------- | -------- | ----------- |
+| `id` | integer/string | yes | The ID of the project or NAMESPACE/PROJECT_NAME |
+| `deny_delete_tag` **(STARTER)** | boolean | no | Deny deleting a tag |
+| `member_check` **(STARTER)** | boolean | no | Restrict commits by author (email) to existing GitLab users |
+| `prevent_secrets` **(STARTER)** | boolean | no | GitLab will reject any files that are likely to contain secrets |
+| `commit_message_regex` **(STARTER)** | string | no | All commit messages must match this, e.g. `Fixed \d+\..*` |
+| `commit_message_negative_regex` **(STARTER)** | string | no | No commit message is allowed to match this, e.g. `ssh\:\/\/` |
+| `branch_name_regex` **(STARTER)** | string | no | All branch names must match this, e.g. `(feature|hotfix)\/*` |
+| `author_email_regex` **(STARTER)** | string | no | All commit author emails must match this, e.g. `@my-company.com$` |
+| `file_name_regex` **(STARTER)** | string | no | All commited filenames must **not** match this, e.g. `(jar|exe)$` |
+| `max_file_size` **(STARTER)** | integer | no | Maximum file size (MB) |
+| `commit_committer_check` **(PREMIUM)** | boolean | no | Users can only push commits to this repository that were committed with one of their own verified emails. |
+
+### Delete project push rule
+
+> Introduced in [GitLab Starter](https://about.gitlab.com/pricing/) 9.0.
+
+Removes a push rule from a project. This is an idempotent method and can be called multiple times.
+Either the push rule is available or not.
+
+```
+DELETE /projects/:id/push_rule
+```
+
+| Attribute | Type | Required | Description |
+| --------- | ---- | -------- | ----------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
-### Transfer a project to a new namespace
+## Transfer a project to a new namespace
+
+> Introduced in GitLab 11.1.
```
PUT /projects/:id/transfer
@@ -1572,6 +1739,22 @@ Read more in the [Project import/export](project_import_export.md) documentation
Read more in the [Project members](members.md) documentation.
+## Start the pull mirroring process for a Project **(STARTER)**
+
+> Introduced in [GitLab Starter](https://about.gitlab.com/pricing) 10.3.
+
+```
+POST /projects/:id/mirror/pull
+```
+
+| Attribute | Type | Required | Description |
+| --------- | ---- | -------- | ----------- |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
+
+```bash
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/:id/mirror/pull
+```
+
## Project badges
Read more in the [Project Badges](project_badges.md) documentation.
@@ -1602,6 +1785,4 @@ GET /projects/:id/snapshot
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
| `wiki` | boolean | no | Whether to download the wiki, rather than project, repository |
-[eep]: https://about.gitlab.com/pricing/ "Available only in GitLab Premium"
-[ee-6137]: https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/6137
[ce-27427]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/27427
diff --git a/doc/api/protected_branches.md b/doc/api/protected_branches.md
index a261bb75be5..9309306ba05 100644
--- a/doc/api/protected_branches.md
+++ b/doc/api/protected_branches.md
@@ -10,6 +10,7 @@ The access levels are defined in the `ProtectedRefAccess.allowed_access_levels`
0 => No access
30 => Developer access
40 => Maintainer access
+60 => Admin access
```
## List protected branches
@@ -51,6 +52,36 @@ Example response:
]
```
+Users on GitLab [Starter, Bronze, or higher](https://about.gitlab.com/pricing/) will also see
+the `user_id` and `group_id` parameters:
+
+Example response:
+
+```json
+[
+ {
+ "name": "master",
+ "push_access_levels": [
+ {
+ "access_level": 40,
+ "user_id": null,
+ "group_id": null,
+ "access_level_description": "Maintainers"
+ }
+ ],
+ "merge_access_levels": [
+ {
+ "access_level": null,
+ "user_id": null,
+ "group_id": 1234,
+ "access_level_description": "Example Merge Group"
+ }
+ ]
+ },
+ ...
+]
+```
+
## Get a single protected branch or wildcard protected branch
Gets a single protected branch or wildcard protected branch.
@@ -88,6 +119,33 @@ Example response:
}
```
+Users on GitLab [Starter, Bronze, or higher](https://about.gitlab.com/pricing/) will also see
+the `user_id` and `group_id` parameters:
+
+Example response:
+
+```json
+{
+ "name": "master",
+ "push_access_levels": [
+ {
+ "access_level": 40,
+ "user_id": null,
+ "group_id": null,
+ "access_level_description": "Maintainers"
+ }
+ ],
+ "merge_access_levels": [
+ {
+ "access_level": null,
+ "user_id": null,
+ "group_id": 1234,
+ "access_level_description": "Example Merge Group"
+ }
+ ]
+}
+```
+
## Protect repository branches
Protects a single repository branch or several project repository
@@ -98,15 +156,47 @@ POST /projects/:id/protected_branches
```
```bash
-curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" 'https://gitlab.example.com/api/v4/projects/5/protected_branches?name=*-stable&push_access_level=30&merge_access_level=30'
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" 'https://gitlab.example.com/api/v4/projects/5/protected_branches?name=*-stable&push_access_level=30&merge_access_level=30&unprotect_access_level=40'
```
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
-| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
-| `name` | string | yes | The name of the branch or wildcard |
-| `push_access_level` | string | no | Access levels allowed to push (defaults: `40`, maintainer access level) |
-| `merge_access_level` | string | no | Access levels allowed to merge (defaults: `40`, maintainer access level) |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
+| `name` | string | yes | The name of the branch or wildcard |
+| `push_access_level` | string | no | Access levels allowed to push (defaults: `40`, maintainer access level) |
+| `merge_access_level` | string | no | Access levels allowed to merge (defaults: `40`, maintainer access level) |
+| `unprotect_access_level` | string | no | Access levels allowed to unprotect (defaults: `40`, maintainer access level) |
+| `allowed_to_push` | array | no | **(STARTER)** Array of access levels allowed to push, with each described by a hash |
+| `allowed_to_merge` | array | no | **(STARTER)** Array of access levels allowed to merge, with each described by a hash |
+| `allowed_to_unprotect` | array | no | **(STARTER)**Array of access levels allowed to unprotect, with each described by a hash |
+
+Example response:
+
+```json
+{
+ "name": "*-stable",
+ "push_access_levels": [
+ {
+ "access_level": 30,
+ "access_level_description": "Developers + Maintainers"
+ }
+ ],
+ "merge_access_levels": [
+ {
+ "access_level": 30,
+ "access_level_description": "Developers + Maintainers"
+ ],
+ "unprotect_access_levels": [
+ {
+ "access_level": 40,
+ "access_level_description": "Maintainers"
+ }
+ ]
+}
+```
+
+Users on GitLab [Starter, Bronze, or higher](https://about.gitlab.com/pricing/) will also see
+the `user_id` and `group_id` parameters:
Example response:
@@ -116,13 +206,65 @@ Example response:
"push_access_levels": [
{
"access_level": 30,
+ "user_id": null,
+ "group_id": null,
"access_level_description": "Developers + Maintainers"
}
],
"merge_access_levels": [
{
"access_level": 30,
+ "user_id": null,
+ "group_id": null,
"access_level_description": "Developers + Maintainers"
+ ],
+ "unprotect_access_levels": [
+ {
+ "access_level": 40,
+ "user_id": null,
+ "group_id": null,
+ "access_level_description": "Maintainers"
+ }
+ ]
+}
+```
+
+### Example with user / group level access **(STARTER)**
+
+Elements in the `allowed_to_push` / `allowed_to_merge` / `allowed_to_unprotect` array should take the
+form `{user_id: integer}`, `{group_id: integer}` or `{access_level: integer}`. Each user must have access to the project and each group must [have this project shared](../user/project/members/share_project_with_groups.md). These access levels allow [more granular control over protected branch access](../user/project/protected_branches.md#restricting-push-and-merge-access-to-certain-users-starter) and were [added to the API in ][ee-3516] in GitLab 10.3 EE.
+
+```bash
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" 'https://gitlab.example.com/api/v4/projects/5/protected_branches?name=*-stable&allowed_to_push%5B%5D%5Buser_id%5D=1'
+```
+
+Example response:
+
+```json
+{
+ "name":"*-stable",
+ "push_access_levels": [
+ {
+ "access_level":null,
+ "user_id":1,
+ "group_id":null,
+ "access_level_description":"Administrator"
+ }
+ ],
+ "merge_access_levels": [
+ {
+ "access_level":40,
+ "user_id":null,
+ "group_id":null,
+ "access_level_description":"Maintainers"
+ }
+ ],
+ "unprotect_access_levels": [
+ {
+ "access_level":40,
+ "user_id":null,
+ "group_id":null,
+ "access_level_description":"Maintainers"
}
]
}
@@ -144,3 +286,5 @@ curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" 'https://git
| --------- | ---- | -------- | ----------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user |
| `name` | string | yes | The name of the branch |
+
+[ee-3516]: https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/3516 "ProtectedBranches API handles per user/group granularity"
diff --git a/doc/api/repositories.md b/doc/api/repositories.md
index 681dc72c934..ffae5c17310 100644
--- a/doc/api/repositories.md
+++ b/doc/api/repositories.md
@@ -121,9 +121,9 @@ Parameters:
- `id` (required) - The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user
- `sha` (optional) - The commit SHA to download. A tag, branch reference, or SHA can be used. This defaults to the tip of the default branch if not specified. For example:
- ```sh
- curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.com/api/v4/projects/<project_id>/repository/archive?sha=<commit_sha>
- ```
+```sh
+curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.com/api/v4/projects/<project_id>/repository/archive?sha=<commit_sha>
+```
## Compare branches, tags or commits
diff --git a/doc/api/resource_label_events.md b/doc/api/resource_label_events.md
index f0a7ac4e41d..7ad4d78014c 100644
--- a/doc/api/resource_label_events.md
+++ b/doc/api/resource_label_events.md
@@ -88,7 +88,7 @@ Parameters:
curl --request GET --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/5/issues/11/resource_label_events/1
```
-## Epics **[ULTIMATE]**
+## Epics **(ULTIMATE)**
### List group epic label events
diff --git a/doc/api/runners.md b/doc/api/runners.md
index 2d91428d1c1..e6962d17a98 100644
--- a/doc/api/runners.md
+++ b/doc/api/runners.md
@@ -20,10 +20,10 @@ Here's an example of how the two tokens are used in Runner registration:
1. You use that authentication token and add it to the
[Runner's configuration file](https://docs.gitlab.com/runner/commands/#configuration-file):
- ```toml
- [[runners]]
- token = "<authentication_token>"
- ```
+ ```toml
+ [[runners]]
+ token = "<authentication_token>"
+ ```
GitLab and Runner are then connected.
@@ -44,7 +44,7 @@ GET /runners?tag_list=tag1,tag2
| `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` |
-| `tag_list` | Array[String] | no | List of of the runner's tags |
+| `tag_list` | string array | no | List of of the runner's tags |
```
curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/runners"
@@ -95,7 +95,7 @@ GET /runners/all?tag_list=tag1,tag2
| `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` |
-| `tag_list` | Array[String] | no | List of of the runner's tags |
+| `tag_list` | string array | no | List of of the runner's tags |
```
curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/runners/all"
@@ -214,10 +214,10 @@ PUT /runners/:id
| `description` | string | no | The description of a runner |
| `active` | boolean | no | The state of a runner; can be set to `true` or `false` |
| `tag_list` | array | no | The list of tags for a runner; put array of tags, that should be finally assigned to a runner |
-| `run_untagged` | boolean | no | Flag indicating the runner can execute untagged jobs |
-| `locked` | boolean | no | Flag indicating the runner is locked |
-| `access_level` | string | no | The access_level of the runner; `not_protected` or `ref_protected` |
-| `maximum_timeout` | integer | no | Maximum timeout set when this Runner will handle the job |
+| `run_untagged`| boolean | no | Flag indicating the runner can execute untagged jobs |
+| `locked` | boolean | no | Flag indicating the runner is locked |
+| `access_level` | string | no | The access_level of the runner; `not_protected` or `ref_protected` |
+| `maximum_timeout` | integer | no | Maximum timeout set when this Runner will handle the job |
```
curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/runners/6" --form "description=test-1-20150125-test" --form "tag_list=ruby,mysql,tag1,tag2"
@@ -291,6 +291,8 @@ GET /runners/:id/jobs
|-----------|---------|----------|---------------------|
| `id` | integer | yes | The ID of a runner |
| `status` | string | no | Status of the job; one of: `running`, `success`, `failed`, `canceled` |
+| `order_by`| string | no | Order jobs by `id`. |
+| `sort` | string | no | Sort jobs in `asc` or `desc` order (default: `desc`) |
```
curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/runners/1/jobs?status=running"
@@ -385,7 +387,7 @@ GET /projects/:id/runners?tag_list=tag1,tag2
| `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` |
-| `tag_list` | Array[String] | no | List of of the runner's tags |
+| `tag_list` | string array | no | List of of the runner's tags |
```
curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/9/runners"
@@ -477,17 +479,17 @@ Register a new Runner for the instance.
POST /runners
```
-| Attribute | Type | Required | Description |
-|-------------|---------|----------|---------------------|
-| `token` | string | yes | [Registration token](#registration-and-authentication-tokens). |
-| `description`| string | no | Runner's description|
-| `info` | hash | no | Runner's metadata |
-| `active` | boolean| no | Whether the Runner is active |
-| `locked` | boolean| no | Whether the Runner should be locked for current project |
-| `run_untagged` | boolean | no | Whether the Runner should handle untagged jobs |
-| `tag_list` | Array[String] | no | List of Runner's tags |
-| `access_level` | string | no | The access_level of the runner; `not_protected` or `ref_protected` |
-| `maximum_timeout` | integer | no | Maximum timeout set when this Runner will handle the job |
+| Attribute | Type | Required | Description |
+|--------------|---------|----------|---------------------|
+| `token` | string | yes | [Registration token](#registration-and-authentication-tokens). |
+| `description`| string | no | Runner's description|
+| `info` | hash | no | Runner's metadata |
+| `active` | boolean | no | Whether the Runner is active |
+| `locked` | boolean | no | Whether the Runner should be locked for current project |
+| `run_untagged` | boolean | no | Whether the Runner should handle untagged jobs |
+| `tag_list` | string array | no | List of Runner's tags |
+| `access_level` | string | no | The access_level of the runner; `not_protected` or `ref_protected` |
+| `maximum_timeout` | integer | no | Maximum timeout set when this Runner will handle the job |
```
curl --request POST "https://gitlab.example.com/api/v4/runners" --form "token=<registration_token>" --form "description=test-1-20150125-test" --form "tag_list=ruby,mysql,tag1,tag2"
diff --git a/doc/api/scim.md b/doc/api/scim.md
index 3870ea788e7..ece7f56e394 100644
--- a/doc/api/scim.md
+++ b/doc/api/scim.md
@@ -1,4 +1,4 @@
-# SCIM API **[SILVER ONLY]**
+# SCIM API **(SILVER ONLY)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/9388) in [GitLab Silver](https://about.gitlab.com/pricing/) 11.10.
@@ -6,7 +6,7 @@ The SCIM API implements the [the RFC7644 protocol](https://tools.ietf.org/html/r
NOTE: **Note:**
[Group SSO](../user/group/saml_sso/index.md) and the feature
-flag `:group_scim` must be enabled for the group. For more information, see [SCIM setup documentation](../user/group/saml_sso/scim_setup.md#requirements).
+flag `:group_scim` must be enabled for the group. For more information, see [SCIM setup documentation](../user/group/saml_sso/scim_setup.md#requirements).
## Get a list of SAML users
diff --git a/doc/api/search.md b/doc/api/search.md
index abb77ae05dc..60acf600ac7 100644
--- a/doc/api/search.md
+++ b/doc/api/search.md
@@ -19,7 +19,7 @@ GET /search
Search the expression within the specified scope. Currently these scopes are supported: projects, issues, merge_requests, milestones, snippet_titles, snippet_blobs, users.
-If Elasticsearch is enabled additional scopes available are blobs, wiki_blobs and commits. Find more about [the feature](../integration/elasticsearch.md). **[STARTER]**
+If Elasticsearch is enabled additional scopes available are blobs, wiki_blobs and commits. Find more about [the feature](../integration/elasticsearch.md). **(STARTER)**
The response depends on the requested scope.
@@ -283,7 +283,7 @@ Example response:
]
```
-### Scope: wiki_blobs **[STARTER]**
+### Scope: wiki_blobs **(STARTER)**
This scope is available only if [Elasticsearch](../integration/elasticsearch.md) is enabled.
@@ -308,7 +308,7 @@ Example response:
]
```
-### Scope: commits **[STARTER]**
+### Scope: commits **(STARTER)**
This scope is available only if [Elasticsearch](../integration/elasticsearch.md) is enabled.
@@ -341,7 +341,7 @@ Example response:
]
```
-### Scope: blobs **[STARTER]**
+### Scope: blobs **(STARTER)**
This scope is available only if [Elasticsearch](../integration/elasticsearch.md) is enabled.
@@ -415,7 +415,7 @@ GET /groups/:id/search
Search the expression within the specified scope. Currently these scopes are supported: projects, issues, merge_requests, milestones, users.
-If Elasticsearch is enabled additional scopes available are blobs, wiki_blobs and commits. Find more about [the feature](../integration/elasticsearch.md). **[STARTER]**
+If Elasticsearch is enabled additional scopes available are blobs, wiki_blobs and commits. Find more about [the feature](../integration/elasticsearch.md). **(STARTER)**
The response depends on the requested scope.
@@ -617,7 +617,7 @@ Example response:
]
```
-### Scope: wiki_blobs **[STARTER]**
+### Scope: wiki_blobs **(STARTER)**
This scope is available only if [Elasticsearch](../integration/elasticsearch.md) is enabled.
@@ -642,7 +642,7 @@ Example response:
]
```
-### Scope: commits **[STARTER]**
+### Scope: commits **(STARTER)**
This scope is available only if [Elasticsearch](../integration/elasticsearch.md) is enabled.
@@ -675,7 +675,7 @@ Example response:
]
```
-### Scope: blobs **[STARTER]**
+### Scope: blobs **(STARTER)**
This scope is available only if [Elasticsearch](../integration/elasticsearch.md) is enabled.
diff --git a/doc/api/services.md b/doc/api/services.md
index 2368f36e444..df15e6892b0 100644
--- a/doc/api/services.md
+++ b/doc/api/services.md
@@ -291,7 +291,6 @@ Parameters:
| `merge_requests_events` | boolean | false | Enable notifications for merge request events |
| `tag_push_events` | boolean | false | Enable notifications for tag push events |
-
### Delete Drone CI service
Delete Drone CI service for a project.
@@ -584,7 +583,7 @@ Parameters:
| `username` | string | yes | The username of the user created to be used with GitLab/Jira. |
| `password` | string | yes | The password of the user created to be used with GitLab/Jira. |
| `active` | boolean | no | Activates or deactivates the service. Defaults to false (deactivated). |
-| `jira_issue_transition_id` | string | no | The ID of a transition that moves issues to a closed state. You can find this number under the Jira workflow administration (**Administration > Issues > Workflows**) by selecting **View** under **Operations** of the desired workflow of your project. The ID of each state can be found inside the parenthesis of each transition name under the **Transitions (id)** column ([see screenshot][trans]). By default, this ID is set to `2`. |
+| `jira_issue_transition_id` | string | no | The ID of a transition that moves issues to a closed state. You can find this number under the Jira workflow administration (**Administration > Issues > Workflows**) by selecting **View** under **Operations** of the desired workflow of your project. The ID of each state can be found inside the parenthesis of each transition name under the **Transitions (id)** column. By default, this ID is set to `2`. |
| `commit_events` | boolean | false | Enable notifications for commit events |
| `merge_requests_events` | boolean | false | Enable notifications for merge request events |
@@ -744,7 +743,7 @@ Parameters:
| --------- | ---- | -------- | ----------- |
| `username` | string | yes | The username of a Packagist account |
| `token` | string | yes | API token to the Packagist server |
-| `server` | boolean | no | URL of the Packagist server. Leave blank for default: https://packagist.org |
+| `server` | boolean | no | URL of the Packagist server. Leave blank for default: <https://packagist.org> |
| `push_events` | boolean | false | Enable notifications for push events |
| `merge_requests_events` | boolean | false | Enable notifications for merge request events |
| `tag_push_events` | boolean | false | Enable notifications for tag push events |
@@ -1147,7 +1146,7 @@ Get JetBrains TeamCity CI service settings for a project.
GET /projects/:id/services/teamcity
```
-## Jenkins CI **[STARTER]**
+## Jenkins CI **(STARTER)**
A continuous integration and build server
@@ -1161,7 +1160,7 @@ PUT /projects/:id/services/jenkins
Parameters:
-- `jenkins_url` (**required**) - Jenkins URL like http://jenkins.example.com
+- `jenkins_url` (**required**) - Jenkins URL like `http://jenkins.example.com`
- `project_name` (**required**) - The URL-friendly project name. Example: my_project_name
- `username` (optional) - A user with access to the Jenkins server, if applicable
- `password` (optional) - The password of the user
@@ -1196,7 +1195,7 @@ PUT /projects/:id/services/jenkins-deprecated
Parameters:
-- `project_url` (**required**) - Jenkins project URL like http://jenkins.example.com/job/my-project/
+- `project_url` (**required**) - Jenkins project URL like `http://jenkins.example.com/job/my-project/`
- `multiproject_enabled` (optional) - Multi-project mode is configured in Jenkins GitLab Hook plugin
- `pass_unstable` (optional) - Unstable builds will be treated as passing
diff --git a/doc/api/settings.md b/doc/api/settings.md
index b01cec64837..ff48cac1f47 100644
--- a/doc/api/settings.md
+++ b/doc/api/settings.md
@@ -67,6 +67,19 @@ Example response:
}
```
+Users on GitLab [Premium or Ultimate](https://about.gitlab.com/pricing/) may also see
+the `file_template_project_id` or the `geo_node_allowed_ips` parameters:
+
+```json
+{
+ "id" : 1,
+ "signup_enabled" : true,
+ "file_template_project_id": 1,
+ "geo_node_allowed_ips": "0.0.0.0/0, ::/0"
+ ...
+}
+```
+
## Change application settings
Use an API call to modify GitLab instance
@@ -121,10 +134,33 @@ Example response:
"performance_bar_allowed_group_id": 42,
"instance_statistics_visibility_private": false,
"user_show_add_ssh_key_message": true,
- "local_markdown_version": 0
+ "file_template_project_id": 1,
+ "local_markdown_version": 0,
+ "geo_node_allowed_ips": "0.0.0.0/0, ::/0"
}
```
+Users on GitLab [Premium or Ultimate](https://about.gitlab.com/pricing/) may also see
+these parameters:
+
+- `external_authorization_service_enabled`
+- `external_authorization_service_url`
+- `external_authorization_service_default_label`
+- `external_authorization_service_timeout`
+- `file_template_project_id`
+- `geo_node_allowed_ips`
+
+Example responses: **(PREMIUM ONLY)**
+
+```json
+ "external_authorization_service_enabled": true,
+ "external_authorization_service_url": "https://authorize.me",
+ "external_authorization_service_default_label": "default",
+ "external_authorization_service_timeout": 0.5,
+ "file_template_project_id": 1,
+ "geo_node_allowed_ips": "0.0.0.0/0, ::/0"
+```
+
## List of settings that can be accessed via API calls
In general, all settings are optional. Certain settings though, if enabled, will
@@ -138,10 +174,14 @@ are listed in the descriptions of the relevant settings.
| `after_sign_up_text` | string | no | Text shown to the user after signing up |
| `akismet_api_key` | string | required by: `akismet_enabled` | API key for akismet spam protection. |
| `akismet_enabled` | boolean | no | (**If enabled, requires:** `akismet_api_key`) Enable or disable akismet spam protection. |
+| `allow_group_owners_to_manage_ldap` | boolean | no | **(PREMIUM)** Set to `true` to allow group owners to manage LDAP |
| `allow_local_requests_from_hooks_and_services` | boolean | no | Allow requests to the local network from hooks and services. |
| `authorized_keys_enabled` | boolean | no | By default, we write to the `authorized_keys` file to support Git over SSH without additional configuration. GitLab can be optimized to authenticate SSH keys via the database file. Only disable this if you have configured your OpenSSH server to use the AuthorizedKeysCommand. |
| `auto_devops_domain` | string | no | Specify a domain to use by default for every project's Auto Review Apps and Auto Deploy stages. |
| `auto_devops_enabled` | boolean | no | Enable Auto DevOps for projects by default. It will automatically build, test, and deploy applications based on a predefined CI/CD configuration. |
+| `check_namespace_plan` | boolean | no | **(PREMIUM)** Enabling this will make only licensed EE features available to projects if the project namespace's plan includes the feature or if the project is public. |
+| `clientside_sentry_dsn` | string | required by: `clientside_sentry_enabled` | Clientside Sentry Data Source Name. |
+| `clientside_sentry_enabled` | boolean | no | (**If enabled, requires:** `clientside_sentry_dsn`) Enable Sentry error reporting for the client side. |
| `container_registry_token_expire_delay` | integer | no | Container Registry token duration in minutes. |
| `default_artifacts_expire_in` | string | no | Set the default expiration time for each job's artifacts. |
| `default_branch_protection` | integer | no | Determine if developers can push to master. Can take: `0` _(not protected, both developers and maintainers can push new commits, force push, or delete the branch)_, `1` _(partially protected, developers and maintainers can push new commits, but cannot force push or delete the branch)_ or `2` _(fully protected, developers cannot push new commits, but maintainers can; no-one can force push or delete the branch)_ as a parameter. Default is `2`. |
@@ -156,10 +196,31 @@ are listed in the descriptions of the relevant settings.
| `dsa_key_restriction` | integer | no | The minimum allowed bit length of an uploaded DSA key. Default is `0` (no restriction). `-1` disables DSA keys. |
| `ecdsa_key_restriction` | integer | no | The minimum allowed curve size (in bits) of an uploaded ECDSA key. Default is `0` (no restriction). `-1` disables ECDSA keys. |
| `ed25519_key_restriction` | integer | no | The minimum allowed curve size (in bits) of an uploaded ED25519 key. Default is `0` (no restriction). `-1` disables ED25519 keys. |
+| `elasticsearch_aws` | boolean | no | **(PREMIUM)** Enable the use of AWS hosted Elasticsearch |
+| `elasticsearch_aws_access_key` | string | no | **(PREMIUM)** AWS IAM access key |
+| `elasticsearch_aws_region` | string | no | **(PREMIUM)** The AWS region the elasticsearch domain is configured |
+| `elasticsearch_aws_secret_access_key` | string | no | **(PREMIUM)** AWS IAM secret access key |
+| `elasticsearch_experimental_indexer` | boolean | no | **(PREMIUM)** Use the experimental elasticsearch indexer. More info: <https://gitlab.com/gitlab-org/gitlab-elasticsearch-indexer> |
+| `elasticsearch_indexing` | boolean | no | **(PREMIUM)** Enable Elasticsearch indexing |
+| `elasticsearch_search` | boolean | no | **(PREMIUM)** Enable Elasticsearch search |
+| `elasticsearch_url` | string | no | **(PREMIUM)** The url to use for connecting to Elasticsearch. Use a comma-separated list to support cluster (e.g., `http://localhost:9200, http://localhost:9201"`). If your Elasticsearch instance is password protected, pass the `username:password` in the URL (e.g., `http://<username>:<password>@<elastic_host>:9200/`). |
+| `elasticsearch_limit_indexing` | boolean | no | **(PREMIUM)** Limit Elasticsearch to index certain namespaces and projects |
+| `elasticsearch_project_ids` | array of integers | no | **(PREMIUM)** The projects to index via Elasticsearch if `elasticsearch_limit_indexing` is enabled. |
+| `elasticsearch_namespace_ids` | array of integers | no | **(PREMIUM)** The namespaces to index via Elasticsearch if `elasticsearch_limit_indexing` is enabled. |
+| `email_additional_text` | string | no | **(PREMIUM)** Additional text added to the bottom of every email for legal/auditing/compliance reasons |
| `email_author_in_body` | boolean | no | Some email servers do not support overriding the email sender name. Enable this option to include the name of the author of the issue, merge request or comment in the email body instead. |
| `enabled_git_access_protocol` | string | no | Enabled protocols for Git access. Allowed values are: `ssh`, `http`, and `nil` to allow both protocols. |
| `enforce_terms` | boolean | no | (**If enabled, requires:** `terms`) Enforce application ToS to all users. |
-| `first_day_of_week` | integer | no | Start day of the week for calendar views and date pickers. Valid values are `0` (default) for Sunday, `1` for Monday, and `6` for Saturday. |
+| `external_auth_client_cert` | string | no | **(PREMIUM)** (**If enabled, requires:** `external_auth_client_key`) The certificate to use to authenticate with the external authorization service |
+| `external_auth_client_key` | string | required by: `external_auth_client_cert` | **(PREMIUM)** Private key for the certificate when authentication is required for the external authorization service, this is encrypted when stored |
+| `external_auth_client_key_pass` | string | no | **(PREMIUM)** Passphrase to use for the private key when authenticating with the external service this is encrypted when stored |
+| `external_authorization_service_enabled` | boolean | no | **(PREMIUM)** (**If enabled, requires:** `external_authorization_service_default_label`, `external_authorization_service_timeout` and `external_authorization_service_url` ) Enable using an external authorization service for accessing projects |
+| `external_authorization_service_default_label` | string | required by: `external_authorization_service_enabled` | **(PREMIUM)** The default classification label to use when requesting authorization and no classification label has been specified on the project |
+| `external_authorization_service_timeout` | float | required by: `external_authorization_service_enabled` | **(PREMIUM)** The timeout after which an authorization request is aborted, in seconds. When a request times out, access is denied to the user. (min: 0.001, max: 10, step: 0.001) |
+| `external_authorization_service_url` | string | required by: `external_authorization_service_enabled` | **(PREMIUM)** URL to which authorization requests will be directed |
+| `file_template_project_id` | integer | no | **(PREMIUM)** The ID of a project to load custom file templates from |
+| `first_day_of_week` | integer | no | Start day of the week for calendar views and date pickers. Valid values are `0` (default) for Sunday, `1` for Monday, and `6` for Saturday. |
+| `geo_status_timeout` | integer | no | **(PREMIUM)** The amount of seconds after which a request to get a secondary node status will time out. |
| `gitaly_timeout_default` | integer | no | Default Gitaly timeout, in seconds. This timeout is not enforced for git fetch/push operations or Sidekiq jobs. Set to `0` to disable timeouts. |
| `gitaly_timeout_fast` | integer | no | Gitaly fast operation timeout, in seconds. Some Gitaly operations are expected to be fast. If they exceed this threshold, there may be a problem with a storage shard and 'failing fast' can help maintain the stability of the GitLab instance. Set to `0` to disable timeouts. |
| `gitaly_timeout_medium` | integer | no | Medium Gitaly timeout, in seconds. This should be a value between the Fast and the Default timeout. Set to `0` to disable timeouts. |
@@ -168,6 +229,7 @@ are listed in the descriptions of the relevant settings.
| `help_page_hide_commercial_content` | boolean | no | Hide marketing-related entries from help. |
| `help_page_support_url` | string | no | Alternate support URL for help page. |
| `help_page_text` | string | no | Custom text displayed on the help page. |
+| `help_text` | string | no | **(PREMIUM)** GitLab server administrator information |
| `hide_third_party_offers` | boolean | no | Do not display offers from third parties within GitLab. |
| `home_page_url` | string | no | Redirect to this URL when not logged in. |
| `housekeeping_bitmaps_enabled` | boolean | required by: `housekeeping_enabled` | Enable Git pack file bitmap creation. |
@@ -190,6 +252,9 @@ are listed in the descriptions of the relevant settings.
| `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 set up for projects. If disabled, only admins will be able to set up mirrors in projects. |
+| `mirror_capacity_threshold` | integer | no | **(PREMIUM)** Minimum capacity to be available before scheduling more mirrors preemptively |
+| `mirror_max_capacity` | integer | no | **(PREMIUM)** Maximum number of mirrors that can be synchronizing at the same time. |
+| `mirror_max_delay` | integer | no | **(PREMIUM)** Maximum time (in minutes) between updates that a mirror can have when scheduled to synchronize. |
| `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`. |
@@ -201,21 +266,28 @@ are listed in the descriptions of the relevant settings.
| `polling_interval_multiplier` | decimal | no | Interval multiplier used by endpoints that perform polling. Set to `0` to disable polling. |
| `project_export_enabled` | boolean | no | Enable project export. |
| `prometheus_metrics_enabled` | boolean | no | Enable prometheus metrics. |
+| `pseudonymizer_enabled` | boolean | no | **(PREMIUM)** When enabled, GitLab will run a background job that will produce pseudonymized CSVs of the GitLab database that will be uploaded to your configured object storage directory.
| `recaptcha_enabled` | boolean | no | (**If enabled, requires:** `recaptcha_private_key` and `recaptcha_site_key`) Enable recaptcha. |
| `recaptcha_private_key` | string | required by: `recaptcha_enabled` | Private key for recaptcha. |
| `recaptcha_site_key` | string | required by: `recaptcha_enabled` | Site key for recaptcha. |
| `repository_checks_enabled` | boolean | no | GitLab will periodically run `git fsck` in all project and wiki repositories to look for silent disk corruption issues. |
+| `repository_size_limit` | integer | no | **(PREMIUM)** Size limit per repository (MB) |
| `repository_storages` | array of strings | no | A list of names of enabled storage paths, taken from `gitlab.yml`. New projects will be created in one of these stores, chosen at random. |
| `require_two_factor_authentication` | boolean | no | (**If enabled, requires:** `two_factor_grace_period`) Require all users to set up Two-factor authentication. |
| `restricted_visibility_levels` | array of strings | no | Selected levels cannot be used by non-admin users for groups, projects or snippets. Can take `private`, `internal` and `public` as a parameter. Default is `null` which means there is no restriction. |
| `rsa_key_restriction` | integer | no | The minimum allowed bit length of an uploaded RSA key. Default is `0` (no restriction). `-1` disables RSA keys. |
| `send_user_confirmation_email` | boolean | no | Send confirmation email on sign-up. |
| `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_enabled` | boolean | no | (**If enabled, requires:** `shared_runners_text` and `shared_runners_minutes`) Enable shared runners for new projects. |
+| `shared_runners_minutes` | integer | required by: `shared_runners_enabled` | **(PREMIUM)** Set the maximum number of pipeline minutes that a group can use on shared Runners per month. |
| `shared_runners_text` | string | required by: `shared_runners_enabled` | Shared runners text. |
| `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`. |
+| `slack_app_enabled` | boolean | no | **(PREMIUM)** (**If enabled, requires:** `slack_app_id`, `slack_app_secret` and `slack_app_secret`) Enable Slack app. |
+| `slack_app_id` | string | required by: `slack_app_enabled` | **(PREMIUM)** The app id of the Slack-app. |
+| `slack_app_secret` | string | required by: `slack_app_enabled` | **(PREMIUM)** The app secret of the Slack-app. |
+| `slack_app_verification_token` | string | required by: `slack_app_enabled` | **(PREMIUM)** The verification token of the Slack-app. |
| `terminal_max_session_time` | integer | no | Maximum time for web terminal websocket connection (in seconds). Set to `0` for unlimited time. |
| `terms` | text | required by: `enforce_terms` | (**Required by:** `enforce_terms`) Markdown content for the ToS. |
| `throttle_authenticated_api_enabled` | boolean | no | (**If enabled, requires:** `throttle_authenticated_api_period_in_seconds` and `throttle_authenticated_api_requests_per_period`) Enable authenticated API request rate limit. Helps reduce request volume (e.g. from crawlers or abusive bots). |
@@ -238,3 +310,4 @@ are listed in the descriptions of the relevant settings.
| `user_show_add_ssh_key_message` | boolean | no | When set to `false` disable the "You won't be able to pull or push project code via SSH" warning shown to users with no uploaded SSH key. |
| `version_check_enabled` | boolean | no | Let GitLab inform you when an update is available. |
| `local_markdown_version` | integer | no | Increase this value when any cached markdown should be invalidated. |
+| `geo_node_allowed_ips` | string | yes | **(PREMIUM)** Comma-separated list of IPs and CIDRs of allowed secondary nodes. For example, `1.1.1.1, 2.2.2.0/24`. |
diff --git a/doc/api/users.md b/doc/api/users.md
index 4667a985eb9..213d1865aca 100644
--- a/doc/api/users.md
+++ b/doc/api/users.md
@@ -70,11 +70,11 @@ Username search is case insensitive.
GET /users
```
-| Attribute | Type | Required | Description |
-| --------- | ---- | -------- | ----------- |
-| `order_by` | string | no | Return users ordered by `id`, `name`, `username`, `created_at`, or `updated_at` fields. Default is `id` |
-| `sort` | string | no | Return users sorted in `asc` or `desc` order. Default is `desc` |
-| `two_factor` | string | no | Filter users by Two-factor authentication. Filter values are `enabled` or `disabled`. By default it returns all users |
+| Attribute | Type | Required | Description |
+| ------------ | ------ | -------- | ----------- |
+| `order_by` | string | no | Return users ordered by `id`, `name`, `username`, `created_at`, or `updated_at` fields. Default is `id` |
+| `sort` | string | no | Return users sorted in `asc` or `desc` order. Default is `desc` |
+| `two_factor` | string | no | Filter users by Two-factor authentication. Filter values are `enabled` or `disabled`. By default it returns all users |
```json
[
@@ -147,6 +147,25 @@ GET /users
]
```
+Users on GitLab [Silver or higher](https://about.gitlab.com/pricing/) will also see
+the `group_saml` provider option:
+
+```json
+[
+ {
+ "id": 1,
+ ...
+ "identities": [
+ {"provider": "github", "extern_uid": "2435223452345"},
+ {"provider": "bitbucket", "extern_uid": "john.smith"},
+ {"provider": "google_oauth2", "extern_uid": "8776128412476123468721346"},
+ {"provider": "group_saml", "extern_uid": "123789", "saml_provider_id": 10}
+ ],
+ ...
+ }
+]
+```
+
You can lookup users by external UID and provider:
```
@@ -223,6 +242,8 @@ Parameters:
- `id` (required) - The ID of a user
+Example Responses:
+
```json
{
"id": 1,
@@ -258,9 +279,39 @@ Parameters:
"can_create_project": true,
"two_factor_enabled": true,
"external": false,
- "private_profile": false,
- "shared_runners_minutes_limit": 133
+ "private_profile": false
+}
+```
+
+Users on GitLab [Starter, Bronze, or higher](https://about.gitlab.com/pricing/) will also see
+the `shared_runners_minutes_limit` and `extra_shared_runners_minutes_limit` parameters.
+
+```json
+{
+ "id": 1,
+ "username": "john_smith",
+ "shared_runners_minutes_limit": 133,
+ "extra_shared_runners_minutes_limit": 133
+ ...
+}
+```
+
+Users on GitLab.com [Silver, or higher](https://about.gitlab.com/pricing/) will also
+see the `group_saml` option:
+
+```json
+{
+ "id": 1,
+ "username": "john_smith",
+ "shared_runners_minutes_limit": 133,
"extra_shared_runners_minutes_limit": 133
+ "identities": [
+ {"provider": "github", "extern_uid": "2435223452345"},
+ {"provider": "bitbucket", "extern_uid": "john.smith"},
+ {"provider": "google_oauth2", "extern_uid": "8776128412476123468721346"},
+ {"provider": "group_saml", "extern_uid": "123789", "saml_provider_id": 10}
+ ],
+ ...
}
```
@@ -287,32 +338,30 @@ POST /users
Parameters:
-- `email` (required) - Email
-- `password` (optional) - Password
-- `reset_password` (optional) - Send user password reset link - true or false (default)
-- `force_random_password` (optional) - Set user password to a random value - true or false (default)
-- `username` (required) - Username
-- `name` (required) - Name
-- `skype` (optional) - Skype ID
-- `linkedin` (optional) - LinkedIn
-- `twitter` (optional) - Twitter account
-- `website_url` (optional) - Website URL
-- `organization` (optional) - Organization name
-- `projects_limit` (optional) - Number of projects user can create
-- `extern_uid` (optional) - External UID
-- `provider` (optional) - External provider name
-- `group_id_for_saml` (optional) - ID of group where SAML has been configured
-- `bio` (optional) - User's biography
-- `location` (optional) - User's location
-- `public_email` (optional) - The public email of the user
-- `admin` (optional) - User is admin - true or false (default)
-- `can_create_group` (optional) - User can create groups - true or false
-- `skip_confirmation` (optional) - Skip confirmation - true or false (default)
-- `external` (optional) - Flags the user as external - true or false(default)
-- `avatar` (optional) - Image file for user's avatar
-- `private_profile` (optional) - User's profile is private - true or false
-- `shared_runners_minutes_limit` (optional) - Pipeline minutes quota for this user
-- `extra_shared_runners_minutes_limit` (optional) - Extra pipeline minutes quota for this user
+- `email` (required) - Email
+- `password` (optional) - Password
+- `reset_password` (optional) - Send user password reset link - true or false(default)
+- `username` (required) - Username
+- `name` (required) - Name
+- `skype` (optional) - Skype ID
+- `linkedin` (optional) - LinkedIn
+- `twitter` (optional) - Twitter account
+- `website_url` (optional) - Website URL
+- `organization` (optional) - Organization name
+- `projects_limit` (optional) - Number of projects user can create
+- `extern_uid` (optional) - External UID
+- `provider` (optional) - External provider name
+- `bio` (optional) - User's biography
+- `location` (optional) - User's location
+- `public_email` (optional) - The public email of the user
+- `admin` (optional) - User is admin - true or false (default)
+- `can_create_group` (optional) - User can create groups - true or false
+- `skip_confirmation` (optional) - Skip confirmation - true or false (default)
+- `external` (optional) - Flags the user as external - true or false(default)
+- `avatar` (optional) - Image file for user's avatar
+- `private_profile` (optional) - User's profile is private - true or false
+- `shared_runners_minutes_limit` (optional) - Pipeline minutes quota for this user **(STARTER)**
+- `extra_shared_runners_minutes_limit` (optional) - Extra pipeline minutes quota for this user **(STARTER)**
## User modification
@@ -348,6 +397,8 @@ Parameters:
- `extra_shared_runners_minutes_limit` (optional) - Extra pipeline minutes quota for this user
- `avatar` (optional) - Image file for user's avatar
- `private_profile` (optional) - User's profile is private - true or false
+- `shared_runners_minutes_limit` (optional) - Pipeline minutes quota for this user **(STARTER)**
+- `extra_shared_runners_minutes_limit` (optional) - Extra pipeline minutes quota for this user **(STARTER)**
On password update, user will be forced to change it upon next login.
Note, at the moment this method does only return a `404` error,
@@ -370,9 +421,7 @@ Parameters:
[moved to the ghost user](../user/profile/account/delete_account.md#associated-records)
will be deleted instead, as well as groups owned solely by this user.
-## User
-
-### For normal users
+## List current user (for normal users)
Gets currently authenticated user.
@@ -418,7 +467,7 @@ GET /user
}
```
-### For admins
+## List current user (for admins)
Parameters:
@@ -497,9 +546,9 @@ Get the status of a user.
GET /users/:id_or_username/status
```
-| Attribute | Type | Required | Description |
-| --------- | ---- | -------- | ----------- |
-| `id_or_username` | string | yes | The id or username of the user to get a status of |
+| Attribute | Type | Required | Description |
+| ---------------- | ------ | -------- | ----------- |
+| `id_or_username` | string | yes | The id or username of the user to get a status of |
```bash
curl "https://gitlab.example.com/users/janedoe/status"
@@ -523,8 +572,8 @@ Set the status of the current user.
PUT /user/status
```
-| Attribute | Type | Required | Description |
-| --------- | ---- | -------- | ----------- |
+| Attribute | Type | Required | Description |
+| --------- | ------ | -------- | ----------- |
| `emoji` | string | no | The name of the emoji to use as status, if omitted `speech_balloon` is used. Emoji name can be one of the specified names in the [Gemojione index][gemojione-index]. |
| `message` | string | no | The message to set as a status. It can also contain emoji codes. |
@@ -544,9 +593,33 @@ Example responses
}
```
+## User counts
+
+Get the counts (same as in top right menu) of the currently signed in user.
+
+| Attribute | Type | Description |
+| --------- | ---- | ----------- |
+| `merge_requests` | number | Merge requests that are active and assigned to current user. |
+
+```
+GET /user_counts
+```
+
+```bash
+curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/user_counts"
+```
+
+Example response:
+
+```json
+{
+ "merge_requests": 4
+}
+```
+
## List user projects
-Please refer to the [List of user projects ](projects.md#list-user-projects).
+Please refer to the [List of user projects](projects.md#list-user-projects).
## List SSH keys
@@ -722,9 +795,9 @@ GET /user/gpg_keys/:key_id
Parameters:
-| Attribute | Type | Required | Description |
-| --------- | ---- | -------- | ----------- |
-| `key_id` | integer | yes | The ID of the GPG key |
+| Attribute | Type | Required | Description |
+| --------- | ------- | -------- | ----------- |
+| `key_id` | integer | yes | The ID of the GPG key |
```bash
curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/user/gpg_keys/1
@@ -750,9 +823,9 @@ POST /user/gpg_keys
Parameters:
-| Attribute | Type | Required | Description |
-| --------- | ---- | -------- | ----------- |
-| key | string | yes | The new GPG key |
+| Attribute | Type | Required | Description |
+| --------- | ------ | -------- | ----------- |
+| key | string | yes | The new GPG key |
```bash
curl --data "key=-----BEGIN PGP PUBLIC KEY BLOCK-----\r\n\r\nxsBNBFV..." --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/user/gpg_keys
@@ -780,9 +853,9 @@ DELETE /user/gpg_keys/:key_id
Parameters:
-| Attribute | Type | Required | Description |
-| --------- | ---- | -------- | ----------- |
-| `key_id` | integer | yes | The ID of the GPG key |
+| Attribute | Type | Required | Description |
+| --------- | ------- | -------- | ----------- |
+| `key_id` | integer | yes | The ID of the GPG key |
```bash
curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/user/gpg_keys/1
@@ -800,9 +873,9 @@ GET /users/:id/gpg_keys
Parameters:
-| Attribute | Type | Required | Description |
-| --------- | ---- | -------- | ----------- |
-| `id` | integer | yes | The ID of the user |
+| Attribute | Type | Required | Description |
+| --------- | ------- | -------- | ----------- |
+| `id` | integer | yes | The ID of the user |
```bash
curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/users/2/gpg_keys
@@ -830,10 +903,10 @@ GET /users/:id/gpg_keys/:key_id
Parameters:
-| Attribute | Type | Required | Description |
-| --------- | ---- | -------- | ----------- |
-| `id` | integer | yes | The ID of the user |
-| `key_id` | integer | yes | The ID of the GPG key |
+| Attribute | Type | Required | Description |
+| --------- | ------- | -------- | ----------- |
+| `id` | integer | yes | The ID of the user |
+| `key_id` | integer | yes | The ID of the GPG key |
```bash
curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/users/2/gpg_keys/1
@@ -859,10 +932,10 @@ POST /users/:id/gpg_keys
Parameters:
-| Attribute | Type | Required | Description |
-| --------- | ---- | -------- | ----------- |
-| `id` | integer | yes | The ID of the user |
-| `key_id` | integer | yes | The ID of the GPG key |
+| Attribute | Type | Required | Description |
+| --------- | ------- | -------- | ----------- |
+| `id` | integer | yes | The ID of the user |
+| `key_id` | integer | yes | The ID of the GPG key |
```bash
curl --data "key=-----BEGIN PGP PUBLIC KEY BLOCK-----\r\n\r\nxsBNBFV..." --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/users/2/gpg_keys
@@ -890,10 +963,10 @@ DELETE /users/:id/gpg_keys/:key_id
Parameters:
-| Attribute | Type | Required | Description |
-| --------- | ---- | -------- | ----------- |
-| `id` | integer | yes | The ID of the user |
-| `key_id` | integer | yes | The ID of the GPG key |
+| Attribute | Type | Required | Description |
+| --------- | ------- | -------- | ----------- |
+| `id` | integer | yes | The ID of the user |
+| `key_id` | integer | yes | The ID of the GPG key |
```bash
curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/users/2/gpg_keys/1
@@ -1074,10 +1147,10 @@ GET /users/:user_id/impersonation_tokens
Parameters:
-| Attribute | Type | Required | Description |
-| --------- | ---- | -------- | ----------- |
-| `user_id` | integer | yes | The ID of the user |
-| `state` | string | no | filter tokens based on state (`all`, `active`, `inactive`) |
+| Attribute | Type | Required | Description |
+| --------- | ------- | -------- | ---------------------------------------------------------- |
+| `user_id` | integer | yes | The ID of the user |
+| `state` | string | no | filter tokens based on state (`all`, `active`, `inactive`) |
```
curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/users/42/impersonation_tokens
@@ -1126,10 +1199,10 @@ GET /users/:user_id/impersonation_tokens/:impersonation_token_id
Parameters:
-| Attribute | Type | Required | Description |
-| --------- | ---- | -------- | ----------- |
-| `user_id` | integer | yes | The ID of the user |
-| `impersonation_token_id` | integer | yes | The ID of the impersonation token |
+| Attribute | Type | Required | Description |
+| ------------------------ | ------- | -------- | --------------------------------- |
+| `user_id` | integer | yes | The ID of the user |
+| `impersonation_token_id` | integer | yes | The ID of the impersonation token |
```
curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/users/42/impersonation_tokens/2
@@ -1155,7 +1228,6 @@ Example response:
## Create an impersonation token
> Requires admin permissions.
-
> Token values are returned once. Make sure you save it - you won't be able to access it again.
It creates a new impersonation token. Note that only administrators can do this.
@@ -1167,12 +1239,12 @@ settings page.
POST /users/:user_id/impersonation_tokens
```
-| Attribute | Type | Required | Description |
-| --------- | ---- | -------- | ----------- |
-| `user_id` | integer | yes | The ID of the user |
-| `name` | string | yes | The name of the impersonation token |
-| `expires_at` | date | no | The expiration date of the impersonation token in ISO format (`YYYY-MM-DD`)|
-| `scopes` | array | yes | The array of scopes of the impersonation token (`api`, `read_user`) |
+| Attribute | Type | Required | Description |
+| ------------ | ------- | -------- | ----------- |
+| `user_id` | integer | yes | The ID of the user |
+| `name` | string | yes | The name of the impersonation token |
+| `expires_at` | date | no | The expiration date of the impersonation token in ISO format (`YYYY-MM-DD`)|
+| `scopes` | array | yes | The array of scopes of the impersonation token (`api`, `read_user`) |
```
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" --data "name=mytoken" --data "expires_at=2017-04-04" --data "scopes[]=api" https://gitlab.example.com/api/v4/users/42/impersonation_tokens
@@ -1219,15 +1291,15 @@ Parameters:
### Get user activities (admin only)
->**Note:** This API endpoint is only available on 8.15 (EE) and 9.1 (CE) and above.
+NOTE: **Note:** This API endpoint is only available on 8.15 (EE) and 9.1 (CE) and above.
Get the last activity date for all users, sorted from oldest to newest.
The activities that update the timestamp are:
- - Git HTTP/SSH activities (such as clone, push)
- - User logging in into GitLab
- - User visiting pages related to Dashboards, Projects, Issues and Merge Requests ([introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/54947) in GitLab 11.8)
+- Git HTTP/SSH activities (such as clone, push)
+- User logging in into GitLab
+- User visiting pages related to Dashboards, Projects, Issues and Merge Requests ([introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/54947) in GitLab 11.8)
By default, it shows the activity for all users in the last 6 months, but this can be
amended by using the `from` parameter.
@@ -1270,4 +1342,4 @@ Example response:
Please note that `last_activity_at` is deprecated, please use `last_activity_on`.
-[gemojione-index]: https://github.com/jonathanwiesel/gemojione/blob/master/config/index.json \ No newline at end of file
+[gemojione-index]: https://github.com/jonathanwiesel/gemojione/blob/master/config/index.json
diff --git a/doc/api/v3_to_v4.md b/doc/api/v3_to_v4.md
index 5752fb7c078..5f875528a6c 100644
--- a/doc/api/v3_to_v4.md
+++ b/doc/api/v3_to_v4.md
@@ -9,7 +9,7 @@ The V3 API documentation is still
Below are the changes made between V3 and V4.
-### 8.17
+## 8.17
- Removed `GET /projects/:search` (use: `GET /projects?search=x`) [!8877](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/8877)
- `iid` filter has been removed from `GET /projects/:id/issues` [!8967](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/8967)
@@ -18,7 +18,7 @@ Below are the changes made between V3 and V4.
- Project snippets do not return deprecated field `expires_at` [!8723](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/8723)
- Endpoints under `GET /projects/:id/keys` have been removed (use `GET /projects/:id/deploy_keys`) [!8716](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/8716)
-### 9.0
+## 9.0
- Status 409 returned for `POST /projects/:id/members` when a member already exists [!9093](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/9093)
- Moved `DELETE /projects/:id/star` to `POST /projects/:id/unstar` [!9328](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/9328)
diff --git a/doc/api/vulnerabilities.md b/doc/api/vulnerabilities.md
index 390d0966244..cc6e5d3960b 100644
--- a/doc/api/vulnerabilities.md
+++ b/doc/api/vulnerabilities.md
@@ -1,4 +1,4 @@
-# Vulnerabilities API **[ULTIMATE]**
+# Vulnerabilities API **(ULTIMATE)**
Every API call to vulnerabilities must be authenticated.
@@ -32,13 +32,13 @@ GET /projects/:id/vulnerabilities?severity=high
GET /projects/:id/vulnerabilities?confidence=unknown,experimental
```
-| 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. |
-| `report_type` | Array[string] | no | Returns vulnerabilities belonging to specified report type. Valid values: `sast`, `dast`, `dependency_scanning`, or `container_scanning`. |
-| `scope` | string | no | Returns vulnerabilities for the given scope: `all` or `dismissed`. Defaults to `dismissed` |
-| `severity` | Array[string] | no | Returns vulnerabilities belonging to specified severity level: `undefined`, `info`, `unknown`, `low`, `medium`, `high`, or `critical`. Defaults to all' |
-| `confidence` | Array[string] | no | Returns vulnerabilities belonging to specified confidence level: `undefined`, `ignore`, `unknown`, `experimental`, `low`, `medium`, `high`, or `confirmed`. Defaults to all |
+| 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. |
+| `report_type` | string array | no | Returns vulnerabilities belonging to specified report type. Valid values: `sast`, `dast`, `dependency_scanning`, or `container_scanning`. |
+| `scope` | string | no | Returns vulnerabilities for the given scope: `all` or `dismissed`. Defaults to `dismissed` |
+| `severity` | string array | no | Returns vulnerabilities belonging to specified severity level: `undefined`, `info`, `unknown`, `low`, `medium`, `high`, or `critical`. Defaults to all' |
+| `confidence` | string array | no | Returns vulnerabilities belonging to specified confidence level: `undefined`, `ignore`, `unknown`, `experimental`, `low`, `medium`, `high`, or `confirmed`. Defaults to all |
```bash
curl --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/4/vulnerabilities
diff --git a/doc/ci/README.md b/doc/ci/README.md
index da864a0b3cc..7048ceaac41 100644
--- a/doc/ci/README.md
+++ b/doc/ci/README.md
@@ -81,6 +81,7 @@ GitLab CI/CD supports numerous configuration options:
| [Git submodules for CI/CD](git_submodules.md) | Configure jobs for using Git submodules.|
| [SSH keys for CI/CD](ssh_keys/README.md) | Using SSH keys in your CI pipelines. |
| [Pipelines triggers](triggers/README.md) | Trigger pipelines through the API. |
+| [Pipelines for Merge Requests](merge_request_pipelines/index.md) | Design a pipeline structure for running a pipeline in merge requests. |
| [Integrate with Kubernetes clusters](../user/project/clusters/index.md) | Connect your project to Google Kubernetes Engine (GKE) or an existing Kubernetes cluster. |
| [GitLab Runner](https://docs.gitlab.com/runner/) | Configure your own GitLab Runners to execute your scripts. |
| [Optimize GitLab and Runner for large repositories](large_repositories/index.md) | Recommended strategies for handling large repos. |
@@ -103,27 +104,27 @@ Its feature set is listed on the table below according to DevOps stages.
| **Verify** ||
| [Browser Performance Testing](../user/project/merge_requests/browser_performance_testing.md) | Quickly determine the performance impact of pending code changes. |
| [CI services](services/README.md) | Link Docker containers with your base image.|
-| [Code Quality](../user/project/merge_requests/code_quality.md) **[STARTER]** | Analyze your source code quality. |
-| [GitLab CI/CD for external repositories](ci_cd_for_external_repos/index.md) **[PREMIUM]** | Get the benefits of GitLab CI/CD combined with repositories in GitHub and BitBucket Cloud. |
-| [Interactive Web Terminals](interactive_web_terminal/index.md) **[CORE ONLY]** | Open an interactive web terminal to debug the running jobs. |
+| [Code Quality](../user/project/merge_requests/code_quality.md) **(STARTER)** | Analyze your source code quality. |
+| [GitLab CI/CD for external repositories](ci_cd_for_external_repos/index.md) **(PREMIUM)** | Get the benefits of GitLab CI/CD combined with repositories in GitHub and BitBucket Cloud. |
+| [Interactive Web Terminals](interactive_web_terminal/index.md) **(CORE ONLY)** | Open an interactive web terminal to debug the running jobs. |
| [JUnit tests](junit_test_reports.md) | Identify script failures directly on merge requests. |
| [Using Docker images](docker/using_docker_images.md) | Use GitLab and GitLab Runner with Docker to build and test applications. |
|---+---|
| **Release** ||
| [Auto Deploy](../topics/autodevops/index.md#auto-deploy) | Deploy your application to a production environment in a Kubernetes cluster. |
| [Building Docker images](docker/using_docker_build.md) | Maintain Docker-based projects using GitLab CI/CD. |
-| [Canary Deployments](../user/project/canary_deployments.md) **[PREMIUM]** | Ship features to only a portion of your pods and let a percentage of your user base to visit the temporarily deployed feature. |
-| [Deploy Boards](../user/project/deploy_boards.md) **[PREMIUM]** | Check the current health and status of each CI/CD environment running on Kubernetes. |
-| [Feature Flags](../user/project/operations/feature_flags.md) **[PREMIUM]** | Deploy your features behind Feature Flags. |
+| [Canary Deployments](../user/project/canary_deployments.md) **(PREMIUM)** | Ship features to only a portion of your pods and let a percentage of your user base to visit the temporarily deployed feature. |
+| [Deploy Boards](../user/project/deploy_boards.md) **(PREMIUM)** | Check the current health and status of each CI/CD environment running on Kubernetes. |
+| [Feature Flags](../user/project/operations/feature_flags.md) **(PREMIUM)** | Deploy your features behind Feature Flags. |
| [GitLab Pages](../user/project/pages/index.md) | Deploy static websites. |
| [GitLab Releases](../user/project/releases/index.md) | Add release notes to Git tags. |
| [Review Apps](review_apps/index.md) | Configure GitLab CI/CD to preview code changes. |
|---+---|
| **Secure** ||
-| [Container Scanning](../user/application_security/container_scanning/index.md) **[ULTIMATE]** | Check your Docker containers for known vulnerabilities.|
-| [Dependency Scanning](../user/application_security/dependency_scanning/index.md) **[ULTIMATE]** | Analyze your dependencies for known vulnerabilities. |
-| [License Management](../user/application_security/license_management/index.md) **[ULTIMATE]** | Search your project dependencies for their licenses. |
-| [Security Test reports](../user/project/merge_requests/index.md#security-reports-ultimate) **[ULTIMATE]** | Check for app vulnerabilities. |
+| [Container Scanning](../user/application_security/container_scanning/index.md) **(ULTIMATE)** | Check your Docker containers for known vulnerabilities.|
+| [Dependency Scanning](../user/application_security/dependency_scanning/index.md) **(ULTIMATE)** | Analyze your dependencies for known vulnerabilities. |
+| [License Management](../user/application_security/license_management/index.md) **(ULTIMATE)** | Search your project dependencies for their licenses. |
+| [Security Test reports](../user/project/merge_requests/index.md#security-reports-ultimate) **(ULTIMATE)** | Check for app vulnerabilities. |
## Examples
@@ -132,7 +133,7 @@ on the [CI Examples](examples/README.md) page.
GitLab also provides [example projects](https://gitlab.com/gitlab-examples) pre-configured to use GitLab CI/CD.
-## Administration **[CORE ONLY]**
+## Administration **(CORE ONLY)**
As a GitLab administrator, you can change the default behavior
of GitLab CI/CD for:
diff --git a/doc/ci/ci_cd_for_external_repos/bitbucket_integration.md b/doc/ci/ci_cd_for_external_repos/bitbucket_integration.md
index bbb25c78ec5..b3110b435db 100644
--- a/doc/ci/ci_cd_for_external_repos/bitbucket_integration.md
+++ b/doc/ci/ci_cd_for_external_repos/bitbucket_integration.md
@@ -2,7 +2,7 @@
type: howto
---
-# Using GitLab CI/CD with a Bitbucket Cloud repository **[PREMIUM]**
+# Using GitLab CI/CD with a Bitbucket Cloud repository **(PREMIUM)**
GitLab CI/CD can be used with Bitbucket Cloud by:
diff --git a/doc/ci/ci_cd_for_external_repos/github_integration.md b/doc/ci/ci_cd_for_external_repos/github_integration.md
index 53b36181062..0bb3aa35ed0 100644
--- a/doc/ci/ci_cd_for_external_repos/github_integration.md
+++ b/doc/ci/ci_cd_for_external_repos/github_integration.md
@@ -2,7 +2,7 @@
type: howto
---
-# Using GitLab CI/CD with a GitHub repository **[PREMIUM]**
+# Using GitLab CI/CD with a GitHub repository **(PREMIUM)**
GitLab CI/CD can be used with **GitHub.com** and **GitHub Enterprise** by
creating a [CI/CD project](index.md) to connect your GitHub repository to
@@ -109,7 +109,7 @@ your repository:
new commits.
The web hook URL should be set to the GitLab API to
- [trigger pull mirroring](https://docs.gitlab.com/ee/api/projects.html#start-the-pull-mirroring-process-for-a-project-starter),
+ [trigger pull mirroring](../../api/projects.md#start-the-pull-mirroring-process-for-a-project-starter),
using the GitLab personal access token we just created.
```
diff --git a/doc/ci/ci_cd_for_external_repos/index.md b/doc/ci/ci_cd_for_external_repos/index.md
index d46e451c609..02b8eb7daa7 100644
--- a/doc/ci/ci_cd_for_external_repos/index.md
+++ b/doc/ci/ci_cd_for_external_repos/index.md
@@ -2,7 +2,7 @@
type: index, howto
---
-# GitLab CI/CD for external repositories **[PREMIUM]**
+# GitLab CI/CD for external repositories **(PREMIUM)**
>[Introduced][ee-4642] in [GitLab Premium][eep] 10.6.
diff --git a/doc/ci/docker/using_docker_images.md b/doc/ci/docker/using_docker_images.md
index f752f942e24..2d7fb323d79 100644
--- a/doc/ci/docker/using_docker_images.md
+++ b/doc/ci/docker/using_docker_images.md
@@ -463,8 +463,6 @@ that runner.
> support for using private registries, which required manual configuration
> of credentials on runner's host. We recommend to upgrade your Runner to
> at least version **1.8** if you want to use private registries.
-> - If the repository is private you need to authenticate your GitLab Runner in the
-> registry. Learn more about how [GitLab Runner works in this case][runner-priv-reg].
To access private container registries, the GitLab Runner process can use:
@@ -489,6 +487,19 @@ it's provided as an environment variable. This is because GitLab Runnner uses **
runtime.
### Using statically-defined credentials
+There are two approaches that you can take in order to access a
+private registry. Both require setting the environment variable
+`DOCKER_AUTH_CONFIG` with appropriate authentication info.
+
+1. Per-job: To configure one job to access a private registry, add
+ `DOCKER_AUTH_CONFIG` as a job variable.
+1. Per-runner: To configure a Runner so all its jobs can access a
+ private registry, add `DOCKER_AUTH_CONFIG` to the environment in the
+ Runner's configuration.
+
+See below for examples of each.
+
+#### Determining your `DOCKER_AUTH_CONFIG` data
As an example, let's assume that you want to use the `registry.example.com:5000/private/image:latest`
image which is private and requires you to login into a private container registry.
@@ -501,30 +512,41 @@ Let's also assume that these are the login credentials:
| username | `my_username` |
| password | `my_password` |
-To configure access for `registry.example.com:5000`, follow these steps:
+There are two ways to determine the value of `DOCKER_AUTH_CONFIG`:
+
+- **First way -** Do a `docker login` on your local machine:
-1. Find what the value of `DOCKER_AUTH_CONFIG` should be. There are two ways to
- accomplish this:
- - **First way -** Do a `docker login` on your local machine:
+ ```bash
+ docker login registry.example.com:5000 --username my_username --password my_password
+ ```
- ```bash
- docker login registry.example.com:5000 --username my_username --password my_password
- ```
+ Then copy the content of `~/.docker/config.json`.
- Then copy the content of `~/.docker/config.json`.
- - **Second way -** In some setups, it's possible that Docker client will use
- the available system keystore to store the result of `docker login`. In
- that case, it's impossible to read `~/.docker/config.json`, so you will
- need to prepare the required base64-encoded version of
- `${username}:${password}` manually. Open a terminal and execute the
- following command:
+ If you don't need access to the registry from your computer, you
+ can do a `docker logout`:
+
+ ```bash
+ docker logout registry.example.com:5000
+ ```
+
+- **Second way -** In some setups, it's possible that Docker client
+ will use the available system keystore to store the result of `docker
+ login`. In that case, it's impossible to read `~/.docker/config.json`,
+ so you will need to prepare the required base64-encoded version of
+ `${username}:${password}` manually. Open a terminal and execute the
+ following command:
+
+ ```bash
+ echo -n "my_username:my_password" | base64
+
+ # Example output to copy
+ bXlfdXNlcm5hbWU6bXlfcGFzc3dvcmQ=
+ ```
- ```bash
- echo -n "my_username:my_password" | base64
+#### Configuring a job
- # Example output to copy
- bXlfdXNlcm5hbWU6bXlfcGFzc3dvcmQ=
- ```
+To configure a single job with access for `registry.example.com:5000`,
+follow these steps:
1. Create a [variable](../variables/README.md#gitlab-cicd-environment-variables) `DOCKER_AUTH_CONFIG` with the content of the
Docker configuration file as the value:
@@ -539,14 +561,6 @@ To configure access for `registry.example.com:5000`, follow these steps:
}
```
-1. Optionally,if you followed the first way of finding the `DOCKER_AUTH_CONFIG`
- value, do a `docker logout` on your computer if you don't need access to the
- registry from it:
-
- ```bash
- docker logout registry.example.com:5000
- ```
-
1. You can now use any private image from `registry.example.com:5000` defined in
`image` and/or `services` in your `.gitlab-ci.yml` file:
@@ -567,6 +581,38 @@ for the Runner to match the `DOCKER_AUTH_CONFIG`. For example, if
then the `DOCKER_AUTH_CONFIG` must also specify `registry.example.com:5000`.
Specifying only `registry.example.com` will not work.
+### Configuring a Runner
+
+If you have many pipelines that access the same registry, it'll
+probably be better to setup registry access at the runner level. This
+allows pipeline authors to have access to a private registry just by
+running a job on the appropriate runner. It also makes registry
+changes and credential rotations much simpler.
+
+Of course this means that any job on that runner can access the
+registry with the same privilege, even across projects. If you need to
+control access to the registry, you'll need to be sure to control
+access to the runner.
+
+To add `DOCKER_AUTH_CONFIG` to a Runner:
+
+1. Modify the Runner's `config.toml` file as follows:
+
+ ```toml
+ [[runners]]
+ environment = ["DOCKER_AUTH_CONFIG={\"auths\":{\"registry.example.com:5000\":{\"auth\":\"bXlfdXNlcm5hbWU6bXlfcGFzc3dvcmQ=\"}}}"]
+ ```
+
+1. Restart the Runner service.
+
+NOTE: **Note:** The double quotes included in the `DOCKER_AUTH_CONFIG`
+data must be escaped with backslashes. This prevents them from being
+interpreted as TOML.
+
+NOTE: **Note:** The `environment` option is a list. So your Runner may
+have existing entries and you should add this to the list, not replace
+it.
+
### Using Credentials Store
> Support for using Credentials Store was added in GitLab Runner 9.5.
@@ -741,7 +787,6 @@ creation.
[tutum/wordpress]: https://hub.docker.com/r/tutum/wordpress/
[postgres-hub]: https://hub.docker.com/r/_/postgres/
[mysql-hub]: https://hub.docker.com/r/_/mysql/
-[runner-priv-reg]: https://docs.gitlab.com/runner/configuration/advanced-configuration.html#using-a-private-container-registry
[entrypoint]: https://docs.docker.com/engine/reference/builder/#entrypoint
[cmd]: https://docs.docker.com/engine/reference/builder/#cmd
[register]: https://docs.gitlab.com/runner/register/
diff --git a/doc/ci/environments.md b/doc/ci/environments.md
index a32dbc11a33..f86ca8f74f2 100644
--- a/doc/ci/environments.md
+++ b/doc/ci/environments.md
@@ -673,7 +673,7 @@ fetch line:
fetch = +refs/environments/*:refs/remotes/origin/environments/*
```
-### Scoping environments with specs **[PREMIUM]**
+### Scoping environments with specs **(PREMIUM)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/2112) in [GitLab Premium](https://about.gitlab.com/pricing/) 9.4.
@@ -692,7 +692,7 @@ with `review/` would have that particular variable.
Some GitLab features can behave differently for each environment.
For example, you can
-[create a secret variable to be injected only into a production environment](variables/README.md#limiting-environment-scopes-of-environment-variables-premium). **[PREMIUM]**
+[create a secret variable to be injected only into a production environment](variables/README.md#limiting-environment-scopes-of-environment-variables-premium). **(PREMIUM)**
In most cases, these features use the _environment specs_ mechanism, which offers
an efficient way to implement scoping within each environment group.
@@ -734,7 +734,7 @@ Below are some links you may find interesting:
- [The `.gitlab-ci.yml` definition of environments](yaml/README.md#environment)
- [A blog post on Deployments & Environments](https://about.gitlab.com/2016/08/26/ci-deployment-and-environments/)
- [Review Apps - Use dynamic environments to deploy your code for every branch](review_apps/index.md)
-- [Deploy Boards for your applications running on Kubernetes](../user/project/deploy_boards.md) **[PREMIUM]**
+- [Deploy Boards for your applications running on Kubernetes](../user/project/deploy_boards.md) **(PREMIUM)**
<!-- ## Troubleshooting
diff --git a/doc/ci/environments/protected_environments.md b/doc/ci/environments/protected_environments.md
index b72ebe838b8..e5213881862 100644
--- a/doc/ci/environments/protected_environments.md
+++ b/doc/ci/environments/protected_environments.md
@@ -2,7 +2,7 @@
type: concepts, howto
---
-# Protected Environments **[PREMIUM]**
+# Protected Environments **(PREMIUM)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/6303) in [GitLab Premium](https://about.gitlab.com/pricing/) 11.3.
diff --git a/doc/ci/examples/README.md b/doc/ci/examples/README.md
index 2b4fe321cb3..5a302392c54 100644
--- a/doc/ci/examples/README.md
+++ b/doc/ci/examples/README.md
@@ -42,10 +42,10 @@ The following table lists examples with step-by-step tutorials that are containe
Contributions are welcome! You can help your favorite programming
language users and GitLab by sending a merge request with a guide for that language.
-You may want to apply for the [GitLab Community Writers Program](https://about.gitlab.com/community-writers/)
+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.
-## Adding templates to your GitLab installation **[PREMIUM ONLY]**
+## Adding templates to your GitLab installation **(PREMIUM ONLY)**
If you want to have customized examples and templates for your own self-managed GitLab instance available to your team, your GitLab administrator can [designate an instance template repository](../../user/admin_area/settings/instance_template_repository.md) that contains examples and templates specific to your enterprise.
diff --git a/doc/ci/examples/artifactory_and_gitlab/index.md b/doc/ci/examples/artifactory_and_gitlab/index.md
index 2117b342903..c9f700ed190 100644
--- a/doc/ci/examples/artifactory_and_gitlab/index.md
+++ b/doc/ci/examples/artifactory_and_gitlab/index.md
@@ -13,7 +13,7 @@ date: 2017-08-15
## Introduction
In this article, we will show how you can leverage the power of [GitLab CI/CD](https://about.gitlab.com/product/continuous-integration/)
-to build a [Maven](https://maven.apache.org/) project, deploy it to [Artifactory](https://www.jfrog.com/artifactory/), and then use it from another Maven application as a dependency.
+to build a [Maven](https://maven.apache.org/) project, deploy it to [Artifactory](https://jfrog.com/artifactory/), and then use it from another Maven application as a dependency.
You'll create two different projects:
diff --git a/doc/ci/examples/end_to_end_testing_webdriverio/index.md b/doc/ci/examples/end_to_end_testing_webdriverio/index.md
index 7f1beb96bbf..38fcf05f519 100644
--- a/doc/ci/examples/end_to_end_testing_webdriverio/index.md
+++ b/doc/ci/examples/end_to_end_testing_webdriverio/index.md
@@ -32,7 +32,7 @@ through the process of setting up GitLab CI/CD for end-to-end testing Javascript
with WebdriverIO, but the general strategy should carry over to other languages.
We assume you are familiar with GitLab, [GitLab CI/CD](../../README.md), [Review Apps](../../review_apps/index.md), and running your app locally, e.g., on `localhost:8000`.
-### What to test
+## What to test
In the widely-used [testing pyramid strategy](https://martinfowler.com/bliki/TestPyramid.html), end-to-end tests act more like a
safeguard: [most of your code should be covered by
@@ -40,9 +40,9 @@ unit tests](https://vincenttunru.com/100-percent-coverage/) that allow you to ea
will likely want to
[limit the number of end-to-end tests](https://testing.googleblog.com/2015/04/just-say-no-to-more-end-to-end-tests.html)
to just enough to give you the confidence that the deployment went as intended, that your
-infrastructure is up and running, and that your units of code work well together.
+infrastructure is up and running, and that your units of code work well together.
-### Selenium and WebdriverIO
+## Selenium and WebdriverIO
[Selenium](http://www.seleniumhq.org/) is a piece of software that can control web browsers, e.g., to make them
visit a specific URL or interact with elements on the page. It can be programmatically controlled
@@ -65,7 +65,7 @@ describe('A visitor without account', function(){
expect(browser.getUrl()).toMatch('page-that-does-not-exist');
browser.element('.content a[href="/"]').click();
-
+
expect(browser.getUrl()).not.toMatch('page-that-does-not-exist');
});
});
diff --git a/doc/ci/examples/php.md b/doc/ci/examples/php.md
index c459bb7001f..0b9e9e93e55 100644
--- a/doc/ci/examples/php.md
+++ b/doc/ci/examples/php.md
@@ -64,7 +64,7 @@ docker-php-ext-install pdo_mysql
You might wonder what `docker-php-ext-install` is. In short, it is a script
provided by the official php docker image that you can use to easily install
extensions. For more information read the documentation at
-<https://hub.docker.com/r/_/php/>.
+<https://hub.docker.com/_/php>.
Now that we created the script that contains all prerequisites for our build
environment, let's add it in `.gitlab-ci.yml`:
@@ -96,7 +96,7 @@ Finally, commit your files and push them to GitLab to see your build succeeding
The final `.gitlab-ci.yml` should look similar to this:
```yaml
-# Select image from https://hub.docker.com/r/_/php/
+# Select image from https://hub.docker.com/_/php
image: php:5.6
before_script:
@@ -286,7 +286,7 @@ that runs on [GitLab.com](https://gitlab.com) using our publicly available
Want to hack on it? Simply fork it, commit, and push your changes. Within a few
moments the changes will be picked by a public runner and the job will begin.
-[php-hub]: https://hub.docker.com/r/_/php/
+[php-hub]: https://hub.docker.com/_/php
[phpenv]: https://github.com/phpenv/phpenv
[phpenv-installation]: https://github.com/phpenv/phpenv#installation
[php-example-repo]: https://gitlab.com/gitlab-examples/php
diff --git a/doc/ci/examples/test-clojure-application.md b/doc/ci/examples/test-clojure-application.md
index 5cda8702b56..6ea38f22bca 100644
--- a/doc/ci/examples/test-clojure-application.md
+++ b/doc/ci/examples/test-clojure-application.md
@@ -35,7 +35,7 @@ test:
- lein test
```
-In `before_script`, we install JRE and [Leiningen](http://leiningen.org/).
+In `before_script`, we install JRE and [Leiningen](https://leiningen.org/).
The sample project uses the [migratus](https://github.com/yogthos/migratus) library to manage database migrations, and
we have added a database migration as the last step of `before_script`.
diff --git a/doc/ci/examples/test-scala-application.md b/doc/ci/examples/test-scala-application.md
index bd899240307..7d039ab1aeb 100644
--- a/doc/ci/examples/test-scala-application.md
+++ b/doc/ci/examples/test-scala-application.md
@@ -46,7 +46,7 @@ deploy:
In the above configuration:
-- The `before_script` installs [SBT](http://www.scala-sbt.org/) and
+- The `before_script` installs [SBT](https://www.scala-sbt.org/) and
displays the version that is being used.
- The `test` stage executes SBT to compile and test the project.
- [sbt-scoverage](https://github.com/scoverage/sbt-scoverage) is used as an SBT
diff --git a/doc/ci/examples/test_phoenix_app_with_gitlab_ci_cd/index.md b/doc/ci/examples/test_phoenix_app_with_gitlab_ci_cd/index.md
index ec25ca1bfc3..a5fed00972f 100644
--- a/doc/ci/examples/test_phoenix_app_with_gitlab_ci_cd/index.md
+++ b/doc/ci/examples/test_phoenix_app_with_gitlab_ci_cd/index.md
@@ -404,14 +404,14 @@ other reasons][ci-reasons] to keep using GitLab CI/CD. The benefits to our teams
[phoenix-learning-guide]: https://hexdocs.pm/phoenix/learning.html "Phoenix Learning Guide"
[phoenix-install]: https://hexdocs.pm/phoenix/installation.html "Phoenix Installation"
[phoenix-mysql]: https://hexdocs.pm/phoenix/ecto.html#using-mysql "Phoenix with MySQL"
-[elixir-site]: http://elixir-lang.org/ "Elixir"
-[elixir-mix]: http://elixir-lang.org/getting-started/mix-otp/introduction-to-mix.html "Introduction to mix"
-[elixir-docs]: http://elixir-lang.org/getting-started/introduction.html "Elixir Documentation"
+[elixir-site]: https://elixir-lang.org/ "Elixir"
+[elixir-mix]: https://elixir-lang.org/getting-started/mix-otp/introduction-to-mix.html "Introduction to mix"
+[elixir-docs]: https://elixir-lang.org/getting-started/introduction.html "Elixir Documentation"
[elixir-install]: https://elixir-lang.org/install.html "Elixir Installation"
-[ecto]: http://hexdocs.pm/ecto "Ecto"
+[ecto]: https://hexdocs.pm/ecto/Ecto.html "Ecto"
[ecto-repo]: https://hexdocs.pm/ecto/Ecto.html#module-repositories "Ecto Repositories"
[mix-ecto]: https://hexdocs.pm/ecto/Mix.Tasks.Ecto.Create.html "mix and Ecto"
-[iex]: http://elixir-lang.org/getting-started/introduction.html#interactive-mode "Interactive Mode"
+[iex]: https://elixir-lang.org/getting-started/introduction.html#interactive-mode "Interactive Mode"
[ci-lint]: https://gitlab.com/ci/lint "CI Lint Tool"
[ci-reasons]: https://about.gitlab.com/2015/02/03/7-reasons-why-you-should-be-using-ci/ "7 Reasons Why You Should Be Using CI"
[ci-guide]: https://about.gitlab.com/2015/12/14/getting-started-with-gitlab-and-gitlab-ci/ "Getting Started With GitLab And GitLab CI/CD"
diff --git a/doc/ci/git_submodules.md b/doc/ci/git_submodules.md
index 551044dd76f..1354a26d6e2 100644
--- a/doc/ci/git_submodules.md
+++ b/doc/ci/git_submodules.md
@@ -79,14 +79,14 @@ correctly with your CI jobs:
1. If you are using an older version of `gitlab-runner`, then use
`git submodule sync/update` in `before_script`:
- ```yaml
- before_script:
- - git submodule sync --recursive
- - git submodule update --init --recursive
- ```
-
- `--recursive` should be used in either both or none (`sync/update`) depending on
- whether you have recursive submodules.
+ ```yaml
+ before_script:
+ - git submodule sync --recursive
+ - git submodule update --init --recursive
+ ```
+
+ `--recursive` should be used in either both or none (`sync/update`) depending on
+ whether you have recursive submodules.
The rationale to set the `sync` and `update` in `before_script` is because of
the way Git submodules work. On a fresh Runner workspace, Git will set the
diff --git a/doc/ci/interactive_web_terminal/index.md b/doc/ci/interactive_web_terminal/index.md
index 1387d4df500..6c73cbbf8d7 100644
--- a/doc/ci/interactive_web_terminal/index.md
+++ b/doc/ci/interactive_web_terminal/index.md
@@ -59,7 +59,7 @@ close the terminal window.
![finished job with terminal open](img/finished_job_with_terminal_open.png)
-## Interactive Web Terminals for the Web IDE **[ULTIMATE ONLY]**
+## Interactive Web Terminals for the Web IDE **(ULTIMATE ONLY)**
Read the Web IDE docs to learn how to run [Interactive Terminals through the Web IDE](../../user/project/web_ide/index.md).
diff --git a/doc/ci/introduction/index.md b/doc/ci/introduction/index.md
index ef9f9a9973c..fc89f0fc94f 100644
--- a/doc/ci/introduction/index.md
+++ b/doc/ci/introduction/index.md
@@ -177,22 +177,22 @@ according to each stage (Verify, Package, Release).
1. **Verify**:
- Automatically build and test your application with Continuous Integration.
- - Analyze your source code quality with [GitLab Code Quality](../../user/project/merge_requests/code_quality.md). **[STARTER]**
- - Determine the performance impact of code changes with [Browser Performance Testing](../../user/project/merge_requests/browser_performance_testing.md). **[PREMIUM]**
- - Perform a series of tests, such as [Container Scanning](../../user/application_security/container_scanning/index.md) **[ULTIMATE]**, [Dependency Scanning](../../user/application_security/dependency_scanning/index.md) **[ULTIMATE]**, and [JUnit tests](../junit_test_reports.md).
+ - Analyze your source code quality with [GitLab Code Quality](../../user/project/merge_requests/code_quality.md). **(STARTER)**
+ - Determine the performance impact of code changes with [Browser Performance Testing](../../user/project/merge_requests/browser_performance_testing.md). **(PREMIUM)**
+ - Perform a series of tests, such as [Container Scanning](../../user/application_security/container_scanning/index.md) **(ULTIMATE)**, [Dependency Scanning](../../user/application_security/dependency_scanning/index.md) **(ULTIMATE)**, and [JUnit tests](../junit_test_reports.md).
- Deploy your changes with [Review Apps](../review_apps/index.md) to preview the app changes on every branch.
1. **Package**:
- Store Docker images with [Container Registry](../../user/project/container_registry.md).
- - Store NPM packages with [NPM Registry](../../user/project/packages/npm_registry.md). **[PREMIUM]**
- - Store Maven artifacts with [Maven Repository](../../user/project/packages/maven_repository.md). **[PREMIUM]**
+ - Store NPM packages with [NPM Registry](../../user/project/packages/npm_registry.md). **(PREMIUM)**
+ - Store Maven artifacts with [Maven Repository](../../user/project/packages/maven_repository.md). **(PREMIUM)**
1. **Release**:
- Continuous Deployment, automatically deploying your app to production.
- Continuous Delivery, manually click to deploy your app to production.
- Deploy static websites with [GitLab Pages](../../user/project/pages/index.md).
- - Ship features to only a portion of your pods and let a percentage of your user base to visit the temporarily deployed feature with [Canary Deployments](../../user/project/canary_deployments.md). **[PREMIUM]**
- - Deploy your features behind [Feature Flags](../../user/project/operations/feature_flags.md). **[PREMIUM]**
+ - Ship features to only a portion of your pods and let a percentage of your user base to visit the temporarily deployed feature with [Canary Deployments](../../user/project/canary_deployments.md). **(PREMIUM)**
+ - Deploy your features behind [Feature Flags](../../user/project/operations/feature_flags.md). **(PREMIUM)**
- Add release notes to any Git tag with [GitLab Releases](../../user/project/releases/index.md).
- - View of the current health and status of each CI environment running on Kubernetes with [Deploy Boards](../../user/project/deploy_boards.md). **[PREMIUM]**
+ - View of the current health and status of each CI environment running on Kubernetes with [Deploy Boards](../../user/project/deploy_boards.md). **(PREMIUM)**
- Deploy your application to a production environment in a Kubernetes cluster with [Auto Deploy](../../topics/autodevops/index.md#auto-deploy).
With GitLab CI/CD you can also:
@@ -201,7 +201,7 @@ With GitLab CI/CD you can also:
- Deploy your app to different [environments](../environments.md).
- Install your own [GitLab Runner](https://docs.gitlab.com/runner/).
- [Schedule pipelines](../../user/project/pipelines/schedules.md).
-- Check for app vulnerabilities with [Security Test reports](../../user/project/merge_requests/index.md#security-reports-ultimate). **[ULTIMATE]**
+- Check for app vulnerabilities with [Security Test reports](../../user/project/merge_requests/index.md#security-reports-ultimate). **(ULTIMATE)**
To see all CI/CD features, navigate back to the [CI/CD index](../README.md).
diff --git a/doc/ci/merge_request_pipelines/index.md b/doc/ci/merge_request_pipelines/index.md
index c3dbcf6a19f..72a9a876037 100644
--- a/doc/ci/merge_request_pipelines/index.md
+++ b/doc/ci/merge_request_pipelines/index.md
@@ -1,8 +1,9 @@
---
-type: reference
+type: reference, index
+last_update: 2019-07-03
---
-# Pipelines for merge requests
+# Pipelines for Merge Requests
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/15310) in GitLab 11.6.
@@ -75,135 +76,13 @@ when a merge request was created or updated. For example:
![Merge request page](img/merge_request.png)
-## Pipelines for merged results **[PREMIUM]**
+## Pipelines for Merged Results **(PREMIUM)**
-> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/7380) in [GitLab Premium](https://about.gitlab.com/pricing/) 11.10.
-> This feature is disabled by default until we resolve issues with [contention handling](https://gitlab.com/gitlab-org/gitlab-ee/issues/11222), but [can be enabled manually](#enabling-pipelines-for-merged-results).
+Read the [documentation on Pipelines for Merged Results](pipelines_for_merged_results/index.md).
-It's possible for your source and target branches to diverge, which can result
-in the scenario that source branch's pipeline was green, the target's pipeline was green,
-but the combined output fails.
+### Merge Trains **(PREMIUM)**
-By having your merge request pipeline automatically
-create a new ref that contains the merge result of the source and target branch
-(then running a pipeline on that ref), we can better test that the combined result
-is also valid.
-
-GitLab can run pipelines for merge requests
-on this merged result. That is, where the source and target branches are combined into a
-new ref and a pipeline for this ref validates the result prior to merging.
-
-![Merge request pipeline as the head pipeline](img/merge_request_pipeline.png)
-
-There are some cases where creating a combined ref is not possible or not wanted.
-For example, a source branch that has conflicts with the target branch
-or a merge request that is still in WIP status. In this case, the merge request pipeline falls back to a "detached" state
-and runs on the source branch ref as if it was a regular pipeline.
-
-The detached state serves to warn you that you are working in a situation
-subjected to merge problems, and helps to highlight that you should
-get out of WIP status or resolve merge conflicts as soon as possible.
-
-### Requirements and limitations
-
-Pipelines for merged results require:
-
-- [GitLab Runner](https://gitlab.com/gitlab-org/gitlab-runner) 11.9 or newer.
-- [Gitaly](https://gitlab.com/gitlab-org/gitaly) 1.21.0 or newer.
-
-In addition, pipelines for merged results have the following limitations:
-
-- Forking/cross-repo workflows are not currently supported. To follow progress,
- see [#9713](https://gitlab.com/gitlab-org/gitlab-ee/issues/9713).
-- This feature is not available for
- [fast forward merges](../../user/project/merge_requests/fast_forward_merge.md) yet.
- To follow progress, see [#58226](https://gitlab.com/gitlab-org/gitlab-ce/issues/58226).
-
-### Enabling Pipelines for merged results
-
-To enable pipelines on merged results at the project level:
-
-1. Visit your project's **Settings > General** and expand **Merge requests**.
-1. Check **Merge pipelines will try to validate the post-merge result prior to merging**.
-1. Click **Save changes** button.
-
-![Merge request pipeline config](img/merge_request_pipeline_config.png)
-
-CAUTION: **Warning:**
-Make sure your `gitlab-ci.yml` file is [configured properly for pipelines for merge requests](#configuring-pipelines-for-merge-requests),
-otherwise pipelines for merged results won't run and your merge requests will be stuck in an unresolved state.
-
-## Merge Trains **[PREMIUM]**
-
-> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/9186) in [GitLab Premium](https://about.gitlab.com/pricing/) 12.0.
-> This feature is disabled by default, but [can be enabled manually](#enabling-merge-trains).
-
-[Pipelines for merged results](#pipelines-for-merged-results-premium) introduces
-running a build on the result of the merged code prior to merging, as a way to keep master green.
-
-There's a scenario, however, for teams with a high number of changes in the target branch (typically master) where in many or even all cases,
-by the time the merged code is validated another commit has made it to master, invalidating the merged result.
-You'd need some kind of queuing, cancellation or retry mechanism for these scenarios
-in order to ensure an orderly flow of changes into the target branch.
-
-Each MR that joins a merge train joins as the last item in the train,
-just as it works in the current state. However, instead of queuing and waiting,
-each item takes the completed state of the previous (pending) merge ref, adds its own changes,
-and starts the pipeline immediately in parallel under the assumption that everything is going to pass.
-
-In this way, if all the pipelines in the train merge successfully, no pipeline time is wasted either queuing or retrying.
-If the button is subsequently pressed in a different MR, instead of creating a new pipeline for the target branch,
-it creates a new pipeline targeting the merge result of the previous MR plus the target branch.
-Pipelines invalidated through failures are immediately canceled and requeued.
-
-### Requirements and limitations
-
-Merge trains have the following requirements and limitations:
-
-- This feature requires that
- [pipelines for merged results](#pipelines-for-merged-results-premium) are
- **configured properly**.
-- Each merge train can generate a merge ref and run a pipeline **one at a time**.
- We plan to make the pipelines for merged results
- [run in parallel](https://gitlab.com/gitlab-org/gitlab-ee/issues/11222) in a
- future release.
-
-### Enabling Merge Trains
-
-To enable merge trains at the project level:
-
-1. Visit your project's **Settings > General** and expand **Merge requests**.
-1. Check **Allow merge trains**.
-1. Click **Save changes** button.
-
-![Merge request pipeline config](img/merge_train_config.png)
-
-### How to add a merge request to a merge train
-
-To add a merge request to a merge train:
-
-1. Click "Start/Add merge train" button in a merge request
-
-![Start merge train](img/merge_train_start.png)
-
-### How to remove a merge request from a merge train
-
-1. Click "Remove from merge train" button in the merge request widget.
-
-![Cancel merge train](img/merge_train_cancel.png)
-
-### Tips: Start/Add to merge train when pipeline succeeds
-
-You can add a merge request to a merge train only when the latest pipeline in the
-merge request finished. While the pipeline is running or pending, you cannot add
-the merge request to a train because the current change of the merge request may
-be broken thus it could affect the following merge requests.
-
-In this case, you can schedule to add the merge request to a merge train **when the latest
-pipeline succeeds**. You can see the following button instead of the regular "Start/Add merge train"
-button while the latest pipeline is running.
-
-![Add to merge train when pipeline succeeds](img/merge_train_start_when_pipeline_succeeds.png)
+Read the [documentation on Merge Trains](pipelines_for_merged_results/merge_trains/index.md).
## Excluding certain jobs
@@ -289,3 +168,15 @@ to integrate your job with [GitLab Merge Request API](../../api/merge_requests.m
You can find the list of available variables in [the reference sheet](../variables/predefined_variables.md).
The variable names begin with the `CI_MERGE_REQUEST_` prefix.
+
+<!-- ## Troubleshooting
+
+Include any troubleshooting steps that you can foresee. If you know beforehand what issues
+one might have when setting this up, or when something is changed, or on upgrading, it's
+important to describe those, too. Think of things that may go wrong and include them here.
+This is important to minimize requests for support, and to avoid doc comments with
+questions that you know someone might ask.
+
+Each scenario can be a third-level heading, e.g. `### Getting error message X`.
+If you have none to add when creating a doc, leave this section in place
+but commented out to help encourage others to add to it in the future. -->
diff --git a/doc/ci/merge_request_pipelines/img/merge_request_pipeline.png b/doc/ci/merge_request_pipelines/pipelines_for_merged_results/img/merge_request_pipeline.png
index 58d5581f628..58d5581f628 100644
--- a/doc/ci/merge_request_pipelines/img/merge_request_pipeline.png
+++ b/doc/ci/merge_request_pipelines/pipelines_for_merged_results/img/merge_request_pipeline.png
Binary files differ
diff --git a/doc/ci/merge_request_pipelines/img/merge_request_pipeline_config.png b/doc/ci/merge_request_pipelines/pipelines_for_merged_results/img/merge_request_pipeline_config.png
index 0a84e61d284..0a84e61d284 100644
--- a/doc/ci/merge_request_pipelines/img/merge_request_pipeline_config.png
+++ b/doc/ci/merge_request_pipelines/pipelines_for_merged_results/img/merge_request_pipeline_config.png
Binary files differ
diff --git a/doc/ci/merge_request_pipelines/pipelines_for_merged_results/index.md b/doc/ci/merge_request_pipelines/pipelines_for_merged_results/index.md
new file mode 100644
index 00000000000..a13857bee25
--- /dev/null
+++ b/doc/ci/merge_request_pipelines/pipelines_for_merged_results/index.md
@@ -0,0 +1,78 @@
+---
+type: reference
+last_update: 2019-07-03
+---
+
+# Pipelines for Merged Results **(PREMIUM)**
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/7380) in [GitLab Premium](https://about.gitlab.com/pricing/) 11.10.
+> This feature is disabled by default until we resolve issues with [contention handling](https://gitlab.com/gitlab-org/gitlab-ee/issues/11222), but [can be enabled manually](#enabling-pipelines-for-merged-results).
+
+It's possible for your source and target branches to diverge, which can result
+in the scenario that source branch's pipeline was green, the target's pipeline was green,
+but the combined output fails.
+
+By having your merge request pipeline automatically
+create a new ref that contains the merge result of the source and target branch
+(then running a pipeline on that ref), we can better test that the combined result
+is also valid.
+
+GitLab can run pipelines for merge requests
+on this merged result. That is, where the source and target branches are combined into a
+new ref and a pipeline for this ref validates the result prior to merging.
+
+![Merge request pipeline as the head pipeline](img/merge_request_pipeline.png)
+
+There are some cases where creating a combined ref is not possible or not wanted.
+For example, a source branch that has conflicts with the target branch
+or a merge request that is still in WIP status. In this case, the merge request pipeline falls back to a "detached" state
+and runs on the source branch ref as if it was a regular pipeline.
+
+The detached state serves to warn you that you are working in a situation
+subjected to merge problems, and helps to highlight that you should
+get out of WIP status or resolve merge conflicts as soon as possible.
+
+## Requirements and limitations
+
+Pipelines for merged results require:
+
+- [GitLab Runner](https://gitlab.com/gitlab-org/gitlab-runner) 11.9 or newer.
+- [Gitaly](https://gitlab.com/gitlab-org/gitaly) 1.21.0 or newer.
+
+In addition, pipelines for merged results have the following limitations:
+
+- Forking/cross-repo workflows are not currently supported. To follow progress,
+ see [#9713](https://gitlab.com/gitlab-org/gitlab-ee/issues/9713).
+- This feature is not available for
+ [fast forward merges](../../../user/project/merge_requests/fast_forward_merge.md) yet.
+ To follow progress, see [#58226](https://gitlab.com/gitlab-org/gitlab-ce/issues/58226).
+
+## Enabling Pipelines for Merged Results
+
+To enable pipelines on merged results at the project level:
+
+1. Visit your project's **Settings > General** and expand **Merge requests**.
+1. Check **Merge pipelines will try to validate the post-merge result prior to merging**.
+1. Click **Save changes** button.
+
+![Merge request pipeline config](img/merge_request_pipeline_config.png)
+
+CAUTION: **Warning:**
+Make sure your `gitlab-ci.yml` file is [configured properly for pipelines for merge requests](../index.md#configuring-pipelines-for-merge-requests),
+otherwise pipelines for merged results won't run and your merge requests will be stuck in an unresolved state.
+
+## Merge Trains **(PREMIUM)**
+
+Read the [documentation on Merge Trains](merge_trains/index.md).
+
+<!-- ## Troubleshooting
+
+Include any troubleshooting steps that you can foresee. If you know beforehand what issues
+one might have when setting this up, or when something is changed, or on upgrading, it's
+important to describe those, too. Think of things that may go wrong and include them here.
+This is important to minimize requests for support, and to avoid doc comments with
+questions that you know someone might ask.
+
+Each scenario can be a third-level heading, e.g. `### Getting error message X`.
+If you have none to add when creating a doc, leave this section in place
+but commented out to help encourage others to add to it in the future. -->
diff --git a/doc/ci/merge_request_pipelines/img/merge_train_cancel.png b/doc/ci/merge_request_pipelines/pipelines_for_merged_results/merge_trains/img/merge_train_cancel_v12_0.png
index 1561fdcc7a5..1561fdcc7a5 100644
--- a/doc/ci/merge_request_pipelines/img/merge_train_cancel.png
+++ b/doc/ci/merge_request_pipelines/pipelines_for_merged_results/merge_trains/img/merge_train_cancel_v12_0.png
Binary files differ
diff --git a/doc/ci/merge_request_pipelines/img/merge_train_config.png b/doc/ci/merge_request_pipelines/pipelines_for_merged_results/merge_trains/img/merge_train_config_v12_0.png
index fb0af43556e..fb0af43556e 100644
--- a/doc/ci/merge_request_pipelines/img/merge_train_config.png
+++ b/doc/ci/merge_request_pipelines/pipelines_for_merged_results/merge_trains/img/merge_train_config_v12_0.png
Binary files differ
diff --git a/doc/ci/merge_request_pipelines/img/merge_train_start.png b/doc/ci/merge_request_pipelines/pipelines_for_merged_results/merge_trains/img/merge_train_start_v12_0.png
index f20108157d2..f20108157d2 100644
--- a/doc/ci/merge_request_pipelines/img/merge_train_start.png
+++ b/doc/ci/merge_request_pipelines/pipelines_for_merged_results/merge_trains/img/merge_train_start_v12_0.png
Binary files differ
diff --git a/doc/ci/merge_request_pipelines/img/merge_train_start_when_pipeline_succeeds.png b/doc/ci/merge_request_pipelines/pipelines_for_merged_results/merge_trains/img/merge_train_start_when_pipeline_succeeds_v12_0.png
index 62c2f2f5ff5..62c2f2f5ff5 100644
--- a/doc/ci/merge_request_pipelines/img/merge_train_start_when_pipeline_succeeds.png
+++ b/doc/ci/merge_request_pipelines/pipelines_for_merged_results/merge_trains/img/merge_train_start_when_pipeline_succeeds_v12_0.png
Binary files differ
diff --git a/doc/ci/merge_request_pipelines/pipelines_for_merged_results/merge_trains/index.md b/doc/ci/merge_request_pipelines/pipelines_for_merged_results/merge_trains/index.md
new file mode 100644
index 00000000000..57358434c02
--- /dev/null
+++ b/doc/ci/merge_request_pipelines/pipelines_for_merged_results/merge_trains/index.md
@@ -0,0 +1,88 @@
+---
+type: reference
+last_update: 2019-07-03
+---
+
+# Merge Trains **(PREMIUM)**
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/9186) in [GitLab Premium](https://about.gitlab.com/pricing/) 12.0.
+> This feature is disabled by default, but [can be enabled manually](#enabling-merge-trains).
+
+[Pipelines for merged results](../index.md#pipelines-for-merged-results-premium) introduces
+running a build on the result of the merged code prior to merging, as a way to keep master green.
+
+There's a scenario, however, for teams with a high number of changes in the target branch (typically master) where in many or even all cases,
+by the time the merged code is validated another commit has made it to master, invalidating the merged result.
+You'd need some kind of queuing, cancellation or retry mechanism for these scenarios
+in order to ensure an orderly flow of changes into the target branch.
+
+Each MR that joins a merge train joins as the last item in the train,
+just as it works in the current state. However, instead of queuing and waiting,
+each item takes the completed state of the previous (pending) merge ref, adds its own changes,
+and starts the pipeline immediately in parallel under the assumption that everything is going to pass.
+
+In this way, if all the pipelines in the train merge successfully, no pipeline time is wasted either queuing or retrying.
+If the button is subsequently pressed in a different MR, instead of creating a new pipeline for the target branch,
+it creates a new pipeline targeting the merge result of the previous MR plus the target branch.
+Pipelines invalidated through failures are immediately canceled and requeued.
+
+## Requirements and limitations
+
+Merge trains have the following requirements and limitations:
+
+- This feature requires that
+ [pipelines for merged results](../index.md#pipelines-for-merged-results-premium) are
+ **configured properly**.
+- Each merge train can generate a merge ref and run a pipeline **one at a time**.
+ We plan to make the pipelines for merged results
+ [run in parallel](https://gitlab.com/gitlab-org/gitlab-ee/issues/11222) in a
+ future release.
+
+## Enabling Merge Trains
+
+To enable merge trains at the project level:
+
+1. Visit your project's **Settings > General** and expand **Merge requests**.
+1. Check **Allow merge trains**.
+1. Click **Save changes** button.
+
+![Merge request pipeline config](img/merge_train_config_v12_0.png)
+
+## How to add a merge request to a merge train
+
+To add a merge request to a merge train:
+
+1. Click "Start/Add merge train" button in a merge request
+
+![Start merge train](img/merge_train_start_v12_0.png)
+
+## How to remove a merge request from a merge train
+
+1. Click "Remove from merge train" button in the merge request widget.
+
+![Cancel merge train](img/merge_train_cancel_v12_0.png)
+
+## Start/Add to merge train when pipeline succeeds
+
+You can add a merge request to a merge train only when the latest pipeline in the
+merge request finished. While the pipeline is running or pending, you cannot add
+the merge request to a train because the current change of the merge request may
+be broken thus it could affect the following merge requests.
+
+In this case, you can schedule to add the merge request to a merge train **when the latest
+pipeline succeeds**. You can see the following button instead of the regular "Start/Add merge train"
+button while the latest pipeline is running.
+
+![Add to merge train when pipeline succeeds](img/merge_train_start_when_pipeline_succeeds_v12_0.png)
+
+<!-- ## Troubleshooting
+
+Include any troubleshooting steps that you can foresee. If you know beforehand what issues
+one might have when setting this up, or when something is changed, or on upgrading, it's
+important to describe those, too. Think of things that may go wrong and include them here.
+This is important to minimize requests for support, and to avoid doc comments with
+questions that you know someone might ask.
+
+Each scenario can be a third-level heading, e.g. `### Getting error message X`.
+If you have none to add when creating a doc, leave this section in place
+but commented out to help encourage others to add to it in the future. -->
diff --git a/doc/ci/metrics_reports.md b/doc/ci/metrics_reports.md
index f9cfc0892a7..4d3f5a143f7 100644
--- a/doc/ci/metrics_reports.md
+++ b/doc/ci/metrics_reports.md
@@ -2,9 +2,9 @@
type: reference
---
-# Metrics Reports **[PREMIUM]**
+# Metrics Reports **(PREMIUM)**
-> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/9788) in [GitLab Premium](https://about.gitlab.com/pricing) 11.10.
+> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/9788) in [GitLab Premium](https://about.gitlab.com/pricing/) 11.10.
Requires GitLab Runner 11.10 and above.
## Overview
diff --git a/doc/ci/multi_project_pipelines.md b/doc/ci/multi_project_pipelines.md
index 50c8d82602b..463b9194c58 100644
--- a/doc/ci/multi_project_pipelines.md
+++ b/doc/ci/multi_project_pipelines.md
@@ -2,7 +2,7 @@
type: reference
---
-# Multi-project pipelines **[PREMIUM]**
+# Multi-project pipelines **(PREMIUM)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/2121) in
[GitLab Premium 9.3](https://about.gitlab.com/2017/06/22/gitlab-9-3-released/#multi-project-pipeline-graphs).
diff --git a/doc/ci/pipelines.md b/doc/ci/pipelines.md
index 4a07aa31f8a..06a81c3d0c7 100644
--- a/doc/ci/pipelines.md
+++ b/doc/ci/pipelines.md
@@ -234,7 +234,7 @@ Pipeline status and test coverage report badges are available and configurable f
For information on adding pipeline badges to projects, see [Pipeline badges](../user/project/pipelines/settings.md#pipeline-badges).
-## Multi-project pipelines **[PREMIUM]**
+## Multi-project pipelines **(PREMIUM)**
Pipelines for different projects can be combined and visualized together.
diff --git a/doc/ci/quick_start/README.md b/doc/ci/quick_start/README.md
index 11bcfd5dc2c..0480b83d183 100644
--- a/doc/ci/quick_start/README.md
+++ b/doc/ci/quick_start/README.md
@@ -233,7 +233,7 @@ CI with various languages.
[runner-install]: https://docs.gitlab.com/runner/install/
[blog-ci]: https://about.gitlab.com/2015/05/06/why-were-replacing-gitlab-ci-jobs-with-gitlab-ci-dot-yml/
[examples]: ../examples/README.md
-[ci]: https://about.gitlab.com/gitlab-ci/
+[ci]: https://about.gitlab.com/product/continuous-integration/
[yaml]: ../yaml/README.md
[runner]: ../runners/README.md
[enabled]: ../enable_or_disable_ci.md
diff --git a/doc/ci/review_apps/img/toolbar_feeback_form.png b/doc/ci/review_apps/img/toolbar_feeback_form.png
index d147981a387..fe1c7e6e611 100644
--- a/doc/ci/review_apps/img/toolbar_feeback_form.png
+++ b/doc/ci/review_apps/img/toolbar_feeback_form.png
Binary files differ
diff --git a/doc/ci/review_apps/index.md b/doc/ci/review_apps/index.md
index 70934e074a0..9b89988bf42 100644
--- a/doc/ci/review_apps/index.md
+++ b/doc/ci/review_apps/index.md
@@ -27,7 +27,7 @@ In the above example:
- Once the review as passed, `topic branch` is merged into `master` where it's deploy to staging.
- After been approved in staging, the changes that were merged into `master` are deployed in to production.
-### How Review Apps work
+## How Review Apps work
A Review App is a mapping of a branch with an [environment](../environments.md).
Access to the Review App is made available as a link on the [merge request](../../user/project/merge_requests.md) relevant to the branch.
@@ -41,27 +41,34 @@ In this example, a branch was:
- Successfully built.
- Deployed under a dynamic environment that can be reached by clicking on the **View app** button.
+After adding Review Apps to your workflow, you follow the branched Git flow. That is:
+
+1. Push a branch and let the Runner deploy the Review App based on the `script` definition of the dynamic environment job.
+1. Wait for the Runner to build and deploy your web application.
+1. Click on the link provided in the merge request related to the branch to see the changes live.
+
## Configuring Review Apps
Review Apps are built on [dynamic environments](../environments.md#configuring-dynamic-environments), which allow you to dynamically create a new environment for each branch.
The process of configuring Review Apps is as follows:
-1. Set up the infrastructure to host and deploy the Review Apps.
+1. Set up the infrastructure to host and deploy the Review Apps (check the [examples](#review-apps-examples) below).
1. [Install](https://docs.gitlab.com/runner/install/) and [configure](https://docs.gitlab.com/runner/commands/) a Runner to do deployment.
1. Set up a job in `.gitlab-ci.yml` that uses the [predefined CI environment variable](../variables/README.md) `${CI_COMMIT_REF_NAME}` to create dynamic environments and restrict it to run only on branches.
1. Optionally, set a job that [manually stops](../environments.md#stopping-an-environment) the Review Apps.
-### Examples
+## Review Apps examples
The following are example projects that demonstrate Review App configuration:
- [NGINX](https://gitlab.com/gitlab-examples/review-apps-nginx).
- [OpenShift](https://gitlab.com/gitlab-examples/review-apps-openshift).
+<i class="fa fa-youtube-play youtube" aria-hidden="true"></i>
See also the video [Demo: Cloud Native Development with GitLab](https://www.youtube.com/watch?v=jfIyQEwrocw), which includes a Review Apps example.
-### Route Maps
+## Route Maps
> Introduced in GitLab 8.17. In GitLab 11.5, the file links are available in the merge request widget.
@@ -82,7 +89,7 @@ To set up a route map, add a a file inside the repository at `.gitlab/route-map.
which contains a YAML array that maps `source` paths (in the repository) to `public`
paths (on the website).
-#### Route Maps example
+### Route Maps example
The following is an example of a route map for [Middleman](https://middlemanapp.com),
a static site generator (SSG) used to build [GitLab's website](https://about.gitlab.com),
@@ -146,51 +153,102 @@ Once you have the route mapping set up, it will take effect in the following loc
!["View on env" button in file view](img/view_on_env_blob.png)
-## Working with Review Apps
-
-After adding Review Apps to your workflow, you follow the branched Git flow. That is:
-
-1. Push a branch and let the Runner deploy the Review App based on the `script` definition of the dynamic environment job.
-1. Wait for the Runner to build and deploy your web application.
-1. Click on the link that provided in the merge request related to the branch to see the changes live.
-
-### Visual Reviews **[STARTER]**
+## Visual Reviews **(STARTER)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/10761) in GitLab Starter 12.0.
-The Visual Reviews feedback form can be added to a Review App to enable reviewers to post comments
-directly from the app back to the merge request that spawned the Review App.
+With Visual Reviews, you can provide a feedback form to your Review Apps so
+that reviewers can post comments directly from the app back to the merge request
+that spawned the Review App.
-For example, a form like the following can be configured to post the contents of the
-text field into the discussion thread of a merge request:
+### Configuring Visual Reviews
-![feedback form](img/toolbar_feeback_form.png)
+The feedback form is served through a script you add to pages in your Review App.
+If you have [Developer permissions](../../user/permissions.md) to the project,
+you can access it by clicking the **Review** button in the **Pipeline** section
+of the merge request.
-#### Using Visual Reviews
+![review button](img/review_button.png)
-If Visual Reviews has been [enabled](#configuring-visual-reviews) for the Review App, the Visual Reviews feedback form is overlaid on the app's pages at the bottom-right corner.
+The provided script should be added to the `<head>` of you application and
+consists of some project and merge request specific values. Here's what it
+looks like:
+
+```html
+<script
+ data-project-id='11790219'
+ data-merge-request-id='1'
+ data-mr-url='https://gitlab.example.com'
+ data-project-path='sarah/review-app-tester'
+ id='review-app-toolbar-script'
+ src='https://gitlab.example.com/assets/webpack/visual_review_toolbar.js'>
+</script>
+```
-To use the feedback form, you will need to create a [personal access token](../../user/profile/personal_access_tokens.md) with the API scope selected.
+Ideally, you should use [environment variables](../variables/predefined_variables.md)
+to replace those values at runtime when each review app is created:
+
+- `data-project-id` is the project ID, which can be found by the `CI_PROJECT_ID`
+ variable.
+- `data-merge-request-id` is the merge request ID, which can be found by the
+ `CI_MERGE_REQUEST_IID` variable. `CI_MERGE_REQUEST_IID` is available only if
+ [`only: [merge_requests]`](../merge_request_pipelines/index.md)
+ is used and the merge request is created.
+- `data-mr-url` is the URL of the GitLab instance and will be the same for all
+ review apps.
+- `data-project-path` is the project's path, which can be found by `CI_PROJECT_PATH`.
+- `id` is always `review-app-toolbar-script`, you don't need to change that.
+- `src` is the source of the review toolbar script, which resides in the
+ respective GitLab instance and will be the same for all review apps.
+
+For example, in a Ruby application, you would need to have this script:
+
+```html
+<script
+ data-project-id="ENV['CI_PROJECT_ID']"
+ data-merge-request-id="ENV['CI_MERGE_REQUEST_IID']"
+ data-mr-url='https://gitlab.example.com'
+ data-project-path="ENV['CI_PROJECT_PATH']"
+ id='review-app-toolbar-script'
+ src='https://gitlab.example.com/assets/webpack/visual_review_toolbar.js'>
+</script>
+```
-Paste the token into the feedback box, when prompted. If you select **Remember me**, your browser stores the token so that future visits to Review Apps at the same URL will not require you to re-enter the token. To clear the token, click **Log out**.
+Then, when your app is deployed via GitLab CI/CD, those variables should get
+replaced with their real values.
-Because tokens must be entered on a per-domain basis and they can only be accessed once, you can save the token to your password manager specifically for the purpose of Visual Reviews. This way, you will not need to create additional tokens for each merge request.
+NOTE: **Note:**
+Future enhancements [are planned](https://gitlab.com/gitlab-org/gitlab-ee/issues/11322)
+to make this process even easier.
-Comments can make use of all the [Markdown annotations](../../user/markdown.md)
-available in merge request comment boxes.
+### Using Visual Reviews
-#### Configuring Visual Reviews
+After Visual Reviews has been [enabled](#configuring-visual-reviews) for the
+Review App, the Visual Reviews feedback form is overlaid on the app's pages at
+the bottom-right corner.
-The feedback form is served through a script you add to pages in your Review App.
-To access the code to include the script, click the **Review** button in the **Pipeline** section of the merge request.
+![Visual review feedback form](img/toolbar_feeback_form.png)
-![review button](img/review_button.png)
+To use the feedback form:
+
+1. Create a [personal access token](../../user/profile/personal_access_tokens.md)
+ with the API scope selected.
+1. Paste the token into the feedback box when prompted. If you select **Remember me**,
+ your browser stores the token so that future visits to Review Apps at the same URL
+ will not require you to re-enter the token. To clear the token, click **Log out**.
+1. Make a comment on the visual review. You can make use of all the
+ [Markdown annotations](../../user/markdown.md) that are also available in
+ merge request comments.
+1. Finally, click **Send feedback**.
-The provided script hardcodes the project and merge request IDs. You may want to consider
-using features of your programming language to use environment variables or other
-means to inject these at runtime.
+After you make and submit a comment in the visual review box, it will appear
+automatically in the respective merge request.
-Future enhancements [are planned](https://gitlab.com/gitlab-org/gitlab-ee/issues/11322) to make this process even easier.
+TIP: **Tip:**
+Because tokens must be entered on a per-domain basis and they can only be accessed
+once, different review apps will not remember your token. You can save the token
+to your password manager specifically for the purpose of Visual Reviews. This way,
+you will not need to create additional tokens for each merge request.
## Limitations
diff --git a/doc/ci/services/postgres.md b/doc/ci/services/postgres.md
index 211eea26eb0..960346ac11a 100644
--- a/doc/ci/services/postgres.md
+++ b/doc/ci/services/postgres.md
@@ -114,5 +114,5 @@ available [shared runners](../runners/README.md).
Want to hack on it? Simply fork it, commit and push your changes. Within a few
moments the changes will be picked by a public runner and the job will begin.
-[hub-pg]: https://hub.docker.com/r/_/postgres/
+[hub-pg]: https://hub.docker.com/_/postgres
[postgres-example-repo]: https://gitlab.com/gitlab-examples/postgres
diff --git a/doc/ci/triggers/README.md b/doc/ci/triggers/README.md
index 04c541fefe7..d1f9aa03b6b 100644
--- a/doc/ci/triggers/README.md
+++ b/doc/ci/triggers/README.md
@@ -32,7 +32,7 @@ to protect trigger tokens.
You can use the `CI_JOB_TOKEN` [variable][predef] (used to authenticate
with the [GitLab Container Registry][registry]) in the following cases.
-#### When used with multi-project pipelines **[PREMIUM]**
+#### When used with multi-project pipelines **(PREMIUM)**
> **Note**:
The use of `CI_JOB_TOKEN` for multi-project pipelines was [introduced][ee-2017]
@@ -56,7 +56,7 @@ Pipelines triggered that way also expose a special variable:
Read more about the [pipelines trigger API][trigapi].
-#### When a pipeline depends on the artifacts of another pipeline **[PREMIUM]**
+#### When a pipeline depends on the artifacts of another pipeline **(PREMIUM)**
> The use of `CI_JOB_TOKEN` in the artifacts download API was [introduced][ee-2346]
in [GitLab Premium][ee] 9.5.
diff --git a/doc/ci/variables/README.md b/doc/ci/variables/README.md
index 1b50273eca2..42dd4f08ed8 100644
--- a/doc/ci/variables/README.md
+++ b/doc/ci/variables/README.md
@@ -389,7 +389,7 @@ Protected variables can be added by going to your project's
Once you set them, they will be available for all subsequent pipelines.
-### Limiting environment scopes of environment variables **[PREMIUM]**
+### Limiting environment scopes of environment variables **(PREMIUM)**
You can limit the environment scope of a variable by
[defining which environments][envs] it can be available for.
diff --git a/doc/ci/variables/predefined_variables.md b/doc/ci/variables/predefined_variables.md
index 7dbb9af2869..e911e97d3c8 100644
--- a/doc/ci/variables/predefined_variables.md
+++ b/doc/ci/variables/predefined_variables.md
@@ -78,7 +78,7 @@ future GitLab releases.**
| `CI_PIPELINE_ID` | 8.10 | all | The unique id of the current pipeline that GitLab CI uses internally |
| `CI_PIPELINE_IID` | 11.0 | all | The unique id of the current pipeline scoped to project |
| `CI_PIPELINE_SOURCE` | 10.0 | all | Indicates how the pipeline was triggered. Possible options are: `push`, `web`, `trigger`, `schedule`, `api`, and `pipeline`. For pipelines created before GitLab 9.5, this will show as `unknown` |
-| `CI_PIPELINE_TRIGGERED` | all | all | The flag to indicate that job was [triggered] |
+| `CI_PIPELINE_TRIGGERED` | all | all | The flag to indicate that job was [triggered](../triggers/README.md) |
| `CI_PIPELINE_URL` | 11.1 | 0.5 | Pipeline details URL |
| `CI_PROJECT_DIR` | all | all | The full path where the repository is cloned and where the job is run. If the GitLab Runner `builds_dir` parameter is set, this variable is set relative to the value of `builds_dir`. For more information, see [Advanced configuration](https://docs.gitlab.com/runner/configuration/advanced-configuration.html#the-runners-section) for GitLab Runner. |
| `CI_PROJECT_ID` | all | all | The unique id of the current project that GitLab CI uses internally |
diff --git a/doc/ci/yaml/README.md b/doc/ci/yaml/README.md
index 2759f1c5160..474db05de06 100644
--- a/doc/ci/yaml/README.md
+++ b/doc/ci/yaml/README.md
@@ -973,6 +973,8 @@ review_app:
stop_review_app:
stage: deploy
+ variables:
+ GIT_STRATEGY: none
script: make delete-app
when: manual
environment:
@@ -987,6 +989,10 @@ Once the `review_app` job is successfully finished, it will trigger the
set it up to `manual` so it will need a [manual action](#whenmanual) via
GitLab's web interface in order to run.
+Also in the example, `GIT_STRATEGY` is set to `none` so that GitLab Runner won’t
+try to check out the code after the branch is deleted when the `stop_review_app`
+job is [automatically triggered](../environments.md#automatically-stopping-an-environment).
+
The `stop_review_app` job is **required** to have the following keywords defined:
- `when` - [reference](#when)
@@ -1051,7 +1057,7 @@ globally and all jobs will use that definition.
#### `cache:paths`
Use the `paths` directive to choose which files or directories will be cached.
-Wildcards can be used as well.
+Wildcards can be used that follow the [glob](https://en.wikipedia.org/wiki/Glob_(programming)) patterns and [filepath.Match](https://golang.org/pkg/path/filepath/#Match).
Cache all files in `binaries` that end in `.apk` and the `.config` file:
@@ -1213,8 +1219,10 @@ be available for download in the GitLab UI.
#### `artifacts:paths`
-You can only use paths that are within the project workspace. To pass artifacts
-between different jobs, see [dependencies](#dependencies).
+You can only use paths that are within the project workspace.
+Wildcards can be used that follow the [glob](https://en.wikipedia.org/wiki/Glob_(programming)) patterns and [filepath.Match](https://golang.org/pkg/path/filepath/#Match).
+
+To pass artifacts between different jobs, see [dependencies](#dependencies).
Send all files in `binaries` and `.config`:
@@ -1469,7 +1477,7 @@ 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]`).
-##### `artifacts:reports:codequality` **[STARTER]**
+##### `artifacts:reports:codequality` **(STARTER)**
> Introduced in GitLab 11.5. Requires GitLab Runner 11.5 and above.
@@ -1479,7 +1487,7 @@ as artifacts.
The collected Code Quality report will be uploaded to GitLab as an artifact and will
be automatically shown in merge requests.
-##### `artifacts:reports:sast` **[ULTIMATE]**
+##### `artifacts:reports:sast` **(ULTIMATE)**
> Introduced in GitLab 11.5. Requires GitLab Runner 11.5 and above.
@@ -1490,7 +1498,7 @@ The collected SAST report will be uploaded to GitLab as an artifact and will
be automatically shown in merge requests, pipeline view and provide data for security
dashboards.
-##### `artifacts:reports:dependency_scanning` **[ULTIMATE]**
+##### `artifacts:reports:dependency_scanning` **(ULTIMATE)**
> Introduced in GitLab 11.5. Requires GitLab Runner 11.5 and above.
@@ -1501,7 +1509,7 @@ The collected Dependency Scanning report will be uploaded to GitLab as an artifa
be automatically shown in merge requests, pipeline view and provide data for security
dashboards.
-##### `artifacts:reports:container_scanning` **[ULTIMATE]**
+##### `artifacts:reports:container_scanning` **(ULTIMATE)**
> Introduced in GitLab 11.5. Requires GitLab Runner 11.5 and above.
@@ -1512,7 +1520,7 @@ The collected Container Scanning report will be uploaded to GitLab as an artifac
be automatically shown in merge requests, pipeline view and provide data for security
dashboards.
-##### `artifacts:reports:dast` **[ULTIMATE]**
+##### `artifacts:reports:dast` **(ULTIMATE)**
> Introduced in GitLab 11.5. Requires GitLab Runner 11.5 and above.
@@ -1523,7 +1531,7 @@ The collected DAST report will be uploaded to GitLab as an artifact and will
be automatically shown in merge requests, pipeline view and provide data for security
dashboards.
-##### `artifacts:reports:license_management` **[ULTIMATE]**
+##### `artifacts:reports:license_management` **(ULTIMATE)**
> Introduced in GitLab 11.5. Requires GitLab Runner 11.5 and above.
@@ -1534,7 +1542,7 @@ The collected License Management report will be uploaded to GitLab as an artifac
be automatically shown in merge requests, pipeline view and provide data for security
dashboards.
-##### `artifacts:reports:performance` **[PREMIUM]**
+##### `artifacts:reports:performance` **(PREMIUM)**
> Introduced in GitLab 11.5. Requires GitLab Runner 11.5 and above.
@@ -1544,7 +1552,7 @@ as artifacts.
The collected Performance report will be uploaded to GitLab as an artifact and will
be automatically shown in merge requests.
-##### `artifacts:reports:metrics` **[PREMIUM]**
+##### `artifacts:reports:metrics` **(PREMIUM)**
> Introduced in GitLab 11.10.
@@ -1741,7 +1749,7 @@ test:
parallel: 5
```
-### `trigger` **[PREMIUM]**
+### `trigger` **(PREMIUM)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/8997) in [GitLab Premium](https://about.gitlab.com/pricing/) 11.8.
diff --git a/doc/customization/index.md b/doc/customization/index.md
index 71e87b3f111..0198059297f 100644
--- a/doc/customization/index.md
+++ b/doc/customization/index.md
@@ -2,7 +2,7 @@
description: Learn how to customize GitLab's appearance for self-managed installations.
---
-# Customizing GitLab's appearance **[CORE ONLY]**
+# Customizing GitLab's appearance **(CORE ONLY)**
For GitLab self-managed instances, it's possible to customize
a few pages.
diff --git a/doc/customization/issue_closing.md b/doc/customization/issue_closing.md
index 680c51e7524..9333f55ca9c 100644
--- a/doc/customization/issue_closing.md
+++ b/doc/customization/issue_closing.md
@@ -1,3 +1,5 @@
---
-redirect_to: '../user/project/issues/automatic_issue_closing.md'
+redirect_to: '../user/project/issues/managing_issues.md#closing-issues-automatically'
---
+
+This document was moved to [another location](../user/project/issues/managing_issues.md#closing-issues-automatically).
diff --git a/doc/customization/libravatar.md b/doc/customization/libravatar.md
index 18aaeb5a712..e618f3be2fe 100644
--- a/doc/customization/libravatar.md
+++ b/doc/customization/libravatar.md
@@ -6,12 +6,12 @@ Libravatar is a service which delivers your avatar (profile picture) to other we
This means that it is not complicated to switch to Libravatar avatar service or even self hosted Libravatar server.
-# Configuration
+## Configuration
In [gitlab.yml gravatar section](https://gitlab.com/gitlab-org/gitlab-ce/blob/672bd3902d86b78d730cea809fce312ec49d39d7/config/gitlab.yml.example#L122) set
the configuration options as follows:
-## For HTTP
+### For HTTP
```yml
gravatar:
@@ -20,7 +20,7 @@ the configuration options as follows:
plain_url: "http://cdn.libravatar.org/avatar/%{hash}?s=%{size}&d=identicon"
```
-## For HTTPS
+### For HTTPS
```yml
gravatar:
@@ -29,7 +29,7 @@ the configuration options as follows:
ssl_url: "https://seccdn.libravatar.org/avatar/%{hash}?s=%{size}&d=identicon"
```
-## Self-hosted
+### Self-hosted
If you are [running your own libravatar service](https://wiki.libravatar.org/running_your_own/) the URL will be different in the configuration
but the important part is to provide the same placeholders so GitLab can parse the URL correctly.
@@ -38,7 +38,7 @@ For example, you host a service on `http://libravatar.example.com` the `plain_ur
`http://libravatar.example.com/avatar/%{hash}?s=%{size}&d=identicon`
-## Omnibus-gitlab example
+### Omnibus-gitlab example
In `/etc/gitlab/gitlab.rb`:
@@ -67,7 +67,7 @@ For example, you can use `retro` set in which case the URL would look like: `pla
## Usage examples
-#### For Microsoft Office 365
+### For Microsoft Office 365
If your users are Office 365-users, the "GetPersonaPhoto" service can be used. Note that this service requires login, so this use case is
most useful in a corporate installation, where all users have access to Office 365.
diff --git a/doc/customization/system_header_and_footer_messages.md b/doc/customization/system_header_and_footer_messages.md
index 9d6931c730d..15830be4e8a 100644
--- a/doc/customization/system_header_and_footer_messages.md
+++ b/doc/customization/system_header_and_footer_messages.md
@@ -1,14 +1,15 @@
# Adding a system message to every page
-> [Introduced][ee-1283] in [GitLab Premium][eep] 10.7.
+> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/5023) in [GitLab Premium](https://about.gitlab.com/pricing/) 10.7.
+> [Added](https://gitlab.com/gitlab-org/gitlab-ce/issues/55057) to [GitLab Core](https://about.gitlab.com/pricing/) in 11.9.
Navigate to the **Admin** area and go to the **Appearance** page.
Under **System header and footer** insert your header message and/or footer message.
Both background and font color of the header and footer are customizable.
-You can also apply the header and footer messages to gitlab emails,
-by checking the **Enable header and footer in emails** checkbox.
+You can also apply the header and footer messages to gitlab emails,
+by checking the **Enable header and footer in emails** checkbox.
Note that color settings will only be applied within the app interface and not to emails
![appearance](system_header_and_footer_messages/appearance.png)
diff --git a/doc/development/README.md b/doc/development/README.md
index 5df6ec5fd56..1566173992a 100644
--- a/doc/development/README.md
+++ b/doc/development/README.md
@@ -82,6 +82,7 @@ description: 'Learn how to contribute to GitLab.'
- [Understanding EXPLAIN plans](understanding_explain_plans.md)
- [explain.depesz.com](https://explain.depesz.com/) for visualising the output
of `EXPLAIN`
+- [pgFormatter](http://sqlformat.darold.net/) a PostgreSQL SQL syntax beautifier
### Migrations
diff --git a/doc/development/api_graphql_styleguide.md b/doc/development/api_graphql_styleguide.md
index aeddad14995..c83a0427c98 100644
--- a/doc/development/api_graphql_styleguide.md
+++ b/doc/development/api_graphql_styleguide.md
@@ -2,13 +2,14 @@
## Deep Dive
-In March 2019, Nick Thomas hosted a [Deep Dive] on GitLab's [GraphQL API] to share his domain specific knowledge with anyone who may work in this part of the code base in the future. You can find the [recording on YouTube], and the slides on [Google Slides] and in [PDF]. Everything covered in this deep dive was accurate as of GitLab 11.9, and while specific details may have changed since then, it should still serve as a good introduction.
-
-[Deep Dive]: https://gitlab.com/gitlab-org/create-stage/issues/1
-[Pull Repository Mirroring functionality]: ../api/graphql/
-[recording on YouTube]: https://www.youtube.com/watch?v=-9L_1MWrjkg
-[Google Slides]: https://docs.google.com/presentation/d/1qOTxpkTdHIp1CRjuTvO-aXg0_rUtzE3ETfLUdnBB5uQ/edit
-[PDF]: https://gitlab.com/gitlab-org/create-stage/uploads/8e78ea7f326b2ef649e7d7d569c26d56/GraphQL_Deep_Dive__Create_.pdf
+In March 2019, Nick Thomas hosted a [Deep Dive](https://gitlab.com/gitlab-org/create-stage/issues/1)
+on GitLab's [GraphQL API](../api/graphql/index.md) to share his domain specific knowledge
+with anyone who may work in this part of the code base in the future. You can find the
+[recording on YouTube](https://www.youtube.com/watch?v=-9L_1MWrjkg), and the slides on
+[Google Slides](https://docs.google.com/presentation/d/1qOTxpkTdHIp1CRjuTvO-aXg0_rUtzE3ETfLUdnBB5uQ/edit)
+and in [PDF](https://gitlab.com/gitlab-org/create-stage/uploads/8e78ea7f326b2ef649e7d7d569c26d56/GraphQL_Deep_Dive__Create_.pdf).
+Everything covered in this deep dive was accurate as of GitLab 11.9, and while specific
+details may have changed since then, it should still serve as a good introduction.
## Authentication
diff --git a/doc/development/api_styleguide.md b/doc/development/api_styleguide.md
index 4fc38a460f8..0866d3baeeb 100644
--- a/doc/development/api_styleguide.md
+++ b/doc/development/api_styleguide.md
@@ -53,7 +53,7 @@ allowed.
### Exclude params from parent namespaces!
-> By default `declared(params) `includes parameters that were defined in all
+> By default `declared(params)`includes parameters that were defined in all
parent namespaces.
– <https://github.com/ruby-grape/grape#include-parent-namespaces>
diff --git a/doc/development/architecture.md b/doc/development/architecture.md
index 87735751c4a..b645a72567c 100644
--- a/doc/development/architecture.md
+++ b/doc/development/architecture.md
@@ -40,7 +40,7 @@ A complete architecture diagram is available in our
![Simplified Component Overview](img/architecture_simplified.png)
-<!--
+<!--
To update this diagram, GitLab team members can edit this source file:
https://docs.google.com/drawings/d/1fBzAyklyveF-i-2q-OHUIqDkYfjjxC4mq5shwKSZHLs/edit.
-->
@@ -267,7 +267,7 @@ GitLab CI is the open-source continuous integration service included with GitLab
#### Gitlab Workhorse
- [Project page](https://gitlab.com/gitlab-org/gitlab-workhorse/blob/master/README.md)
-- Configuration: [Omnibus][gitlab-workhorse-omnibus], [Charts][gitlab-workhorse-charts], [Source][workhorse-source]
+- Configuration: [Omnibus][workhorse-omnibus], [Charts][workhorse-charts], [Source][workhorse-source]
- Layer: Core Service (Processor)
- Process: `gitlab-workhorse`
@@ -304,7 +304,7 @@ GitLab is comprised of a large number of services that all log. We started bundl
- Configuration: [Omnibus][mattermost-omnibus], [Charts][mattermost-charts]
- Layer: Core Service (Processor)
-Mattermost is an open source, private cloud, Slack-alternative from https://mattermost.com.
+Mattermost is an open source, private cloud, Slack-alternative from <https://mattermost.com>.
#### MinIO
@@ -321,7 +321,7 @@ MinIO is an object storage server released under Apache License v2.0. It is comp
- Layer: Core Service (Processor)
- Process: `nginx`
-Nginx as an ingress port for all HTTP requests and routes them to the approriate sub-systems within GitLab. We are bundling an unmodified version of the popular open source webserver.
+Nginx as an ingress port for all HTTP requests and routes them to the appropriate sub-systems within GitLab. We are bundling an unmodified version of the popular open source webserver.
#### Node Exporter
@@ -484,9 +484,11 @@ When making a request to an HTTP Endpoint (think `/users/sign_in`) the request w
Below we describe the different pathing that HTTP vs. SSH Git requests will take. There is some overlap with the Web Request Cycle but also some differences.
### Web Request (80/443)
+
TODO
### SSH Request (22)
+
TODO
## System Layout
@@ -505,7 +507,9 @@ To summarize here's the [directory structure of the `git` user home directory](.
### Processes
- ps aux | grep '^git'
+```sh
+ps aux | grep '^git'
+```
GitLab has several components to operate. As a system user (i.e. any user that is not the `git` user) it requires a persistent database (MySQL/PostreSQL) and redis database. It also uses Apache httpd or Nginx to proxypass Unicorn. As the `git` user it starts Sidekiq and Unicorn (a simple ruby HTTP server running on port `8080` by default). Under the GitLab user there are normally 4 processes: `unicorn_rails master` (1 process), `unicorn_rails worker` (2 processes), `sidekiq` (1 process).
@@ -681,7 +685,7 @@ We've also detailed [our architecture of GitLab.com](https://about.gitlab.com/ha
[pgbouncer-exporter-omnibus]: ../administration/monitoring/prometheus/pgbouncer_exporter.md
[pgbouncer-exporter-charts]: https://docs.gitlab.com/charts/installation/deployment.html#postgresql
[gitlab-monitor-omnibus]: ../administration/monitoring/prometheus/gitlab_monitor_exporter.md
-[gitab-monitor-charts]: https://docs.gitlab.com/charts/charts/gitlab/gitlab-monitor/index.html
+[gitlab-monitor-charts]: https://docs.gitlab.com/charts/charts/gitlab/gitlab-monitor/index.html
[node-exporter-omnibus]: ../administration/monitoring/prometheus/node_exporter.md
[node-exporter-charts]: https://gitlab.com/charts/gitlab/issues/1332
[mattermost-omnibus]: https://docs.gitlab.com/omnibus/gitlab-mattermost/
diff --git a/doc/development/automatic_ce_ee_merge.md b/doc/development/automatic_ce_ee_merge.md
index 3ca841353e6..423b35a9e3a 100644
--- a/doc/development/automatic_ce_ee_merge.md
+++ b/doc/development/automatic_ce_ee_merge.md
@@ -115,7 +115,7 @@ Now, every time you create an MR for CE and EE:
1. Continue cherry-picking: `git cherry-pick --continue`
1. Push to EE: `git push origin branch-example-ee`
1. Create the EE-equivalent MR and link to the CE MR from the
- description "Ports [CE-MR-LINK] to EE"
+ description `Ports [CE-MR-LINK] to EE`
1. Once all the jobs are passing in both CE and EE, you've addressed the
feedback from your own team, and got them approved, the merge requests can be merged.
1. When both MRs are ready, the EE merge request will be merged first, and the
@@ -125,42 +125,43 @@ Now, every time you create an MR for CE and EE:
- The commit SHA can be easily found from the GitLab UI. From a merge request,
open the tab **Commits** and click the copy icon to copy the commit SHA.
-- To cherry-pick a **commit range**, such as [A > B > C > D] use:
+- To cherry-pick a **commit range**, such as (A > B > C > D) use:
- ```shell
- git cherry-pick "oldest-commit-SHA^..newest-commit-SHA"
- ```
+ ```shell
+ git cherry-pick "oldest-commit-SHA^..newest-commit-SHA"
+ ```
- For example, suppose the commit A is the oldest, and its SHA is `4f5e4018c09ed797fdf446b3752f82e46f5af502`,
- and the commit D is the newest, and its SHA is `80e1c9e56783bd57bd7129828ec20b252ebc0538`.
- The cherry-pick command will be:
+ For example, suppose the commit A is the oldest, and its SHA is `4f5e4018c09ed797fdf446b3752f82e46f5af502`,
+ and the commit D is the newest, and its SHA is `80e1c9e56783bd57bd7129828ec20b252ebc0538`.
+ The cherry-pick command will be:
- ```shell
- git cherry-pick "4f5e4018c09ed797fdf446b3752f82e46f5af502^..80e1c9e56783bd57bd7129828ec20b252ebc0538"
- ```
+ ```shell
+ git cherry-pick "4f5e4018c09ed797fdf446b3752f82e46f5af502^..80e1c9e56783bd57bd7129828ec20b252ebc0538"
+ ```
- To cherry-pick a **merge commit**, use the flag `-m 1`. For example, suppose that the
merge commit SHA is `138f5e2f20289bb376caffa0303adb0cac859ce1`:
- ```shell
- git cherry-pick -m 1 138f5e2f20289bb376caffa0303adb0cac859ce1
- ```
-- To cherry-pick multiple commits, such as B and D in a range [A > B > C > D], use:
+ ```shell
+ git cherry-pick -m 1 138f5e2f20289bb376caffa0303adb0cac859ce1
+ ```
- ```shell
- git cherry-pick commit-B-SHA commit-D-SHA
- ```
+- To cherry-pick multiple commits, such as B and D in a range (A > B > C > D), use:
- For example, suppose commit B SHA = `4f5e4018c09ed797fdf446b3752f82e46f5af502`,
- and the commit D SHA = `80e1c9e56783bd57bd7129828ec20b252ebc0538`.
- The cherry-pick command will be:
+ ```shell
+ git cherry-pick commit-B-SHA commit-D-SHA
+ ```
- ```shell
- git cherry-pick 4f5e4018c09ed797fdf446b3752f82e46f5af502 80e1c9e56783bd57bd7129828ec20b252ebc0538
- ```
+ For example, suppose commit B SHA = `4f5e4018c09ed797fdf446b3752f82e46f5af502`,
+ and the commit D SHA = `80e1c9e56783bd57bd7129828ec20b252ebc0538`.
+ The cherry-pick command will be:
- This case is particularly useful when you have a merge commit in a sequence of
- commits and you want to cherry-pick all but the merge commit.
+ ```shell
+ git cherry-pick 4f5e4018c09ed797fdf446b3752f82e46f5af502 80e1c9e56783bd57bd7129828ec20b252ebc0538
+ ```
+
+ This case is particularly useful when you have a merge commit in a sequence of
+ commits and you want to cherry-pick all but the merge commit.
- If you push more commits to the CE branch, you can safely repeat the procedure
to cherry-pick them to the EE-equivalent branch. You can do that as many times as
diff --git a/doc/development/changelog.md b/doc/development/changelog.md
index 45b3d5a23a1..3ed586f07e9 100644
--- a/doc/development/changelog.md
+++ b/doc/development/changelog.md
@@ -35,7 +35,7 @@ the `author` field. GitLab team members **should not**.
- Any user-facing change **should** have a changelog entry. Example: "GitLab now
uses system fonts for all text."
-- Any change behind a feature flag **should not** have a changelog entry. The entry should be added [in the merge request removing the feature flags](https://docs.gitlab.com/ee/development/feature_flags.html#developing-with-feature-flags).
+- Any change behind a feature flag **should not** have a changelog entry. The entry should be added [in the merge request removing the feature flags](feature_flags/development.md).
- A fix for a regression introduced and then fixed in the same release (i.e.,
fixing a bug introduced during a monthly release candidate) **should not**
have a changelog entry.
@@ -62,7 +62,7 @@ making it both concise and descriptive, err on the side of descriptive.
The first example provides no context of where the change was made, or why, or
how it benefits the user.
-- **Bad:** Copy [some text] to clipboard.
+- **Bad:** Copy (some text) to clipboard.
- **Good:** Update the "Copy to clipboard" tooltip to indicate what's being
copied.
@@ -144,7 +144,7 @@ If you're working on the GitLab EE repository, the entry will be added to
| [`--type`](#--type-or--t) | `-t` | The category of the change, valid options are: `added`, `fixed`, `changed`, `deprecated`, `removed`, `security`, `performance`, `other` |
| `--help` | `-h` | Print help message |
-##### `--amend`
+#### `--amend`
You can pass the **`--amend`** argument to automatically stage the generated
file and amend it to the previous commit.
@@ -166,7 +166,7 @@ author:
type:
```
-##### `--force` or `-f`
+#### `--force` or `-f`
Use **`--force`** or **`-f`** to overwrite an existing changelog entry if it
already exists.
@@ -184,7 +184,7 @@ author:
type:
```
-##### `--merge-request` or `-m`
+#### `--merge-request` or `-m`
Use the **`--merge-request`** or **`-m`** argument to provide the
`merge_request` value:
@@ -199,7 +199,7 @@ author:
type:
```
-##### `--dry-run` or `-n`
+#### `--dry-run` or `-n`
Use the **`--dry-run`** or **`-n`** argument to prevent actually writing or
committing anything:
@@ -216,7 +216,7 @@ type:
$ ls changelogs/unreleased/
```
-##### `--git-username` or `-u`
+#### `--git-username` or `-u`
Use the **`--git-username`** or **`-u`** argument to automatically fill in the
`author` value with your configured Git `user.name` value:
@@ -234,7 +234,7 @@ author: Jane Doe
type:
```
-##### `--type` or `-t`
+#### `--type` or `-t`
Use the **`--type`** or **`-t`** argument to provide the `type` value:
diff --git a/doc/development/chatops_on_gitlabcom.md b/doc/development/chatops_on_gitlabcom.md
index a7b402c3fb0..3b681880401 100644
--- a/doc/development/chatops_on_gitlabcom.md
+++ b/doc/development/chatops_on_gitlabcom.md
@@ -13,10 +13,10 @@ tasks such as:
To request access to Chatops on GitLab.com:
1. Log into <https://ops.gitlab.net/users/sign_in> using the same username as for GitLab.com.
-1. Ask [anyone in the `chatops` project](https://gitlab.com/gitlab-com/chatops/project_members) to add you by running `/chatops run member add <username> gitlab-com/chatops --ops`.
+1. Ask [anyone in the `chatops` project](https://gitlab.com/gitlab-com/chatops/-/project_members) to add you by running `/chatops run member add <username> gitlab-com/chatops --ops`.
## See also
- - [Chatops Usage](https://docs.gitlab.com/ee/ci/chatops/README.html)
- - [Understanding EXPLAIN plans](understanding_explain_plans.md)
- - [Feature Groups](feature_flags/development.md#feature-groups)
+- [Chatops Usage](../ci/chatops/README.md)
+- [Understanding EXPLAIN plans](understanding_explain_plans.md)
+- [Feature Groups](feature_flags/development.md#feature-groups)
diff --git a/doc/development/code_comments.md b/doc/development/code_comments.md
index 36962eb46d4..827a610efa2 100644
--- a/doc/development/code_comments.md
+++ b/doc/development/code_comments.md
@@ -1,11 +1,11 @@
# Code comments
-Whenever you add comment to the code that is expected to be addressed at any time
-in future, please create a technical debt issue for it. Then put a link to it
+Whenever you add comment to the code that is expected to be addressed at any time
+in future, please create a technical debt issue for it. Then put a link to it
to the code comment you've created. This will allow other developers to quickly
check if a comment is still relevant and what needs to be done to address it.
-Examples:
+Examples:
```rb
# Deprecated scope until code_owner column has been migrated to rule_type.
diff --git a/doc/development/code_review.md b/doc/development/code_review.md
index 6123f9f845a..e60800f1ab7 100644
--- a/doc/development/code_review.md
+++ b/doc/development/code_review.md
@@ -319,7 +319,7 @@ reviewee.
### GitLab-specific concerns
GitLab is used in a lot of places. Many users use
-our [Omnibus packages](https://about.gitlab.com/installation/), but some use
+our [Omnibus packages](https://about.gitlab.com/install/), but some use
the [Docker images](https://docs.gitlab.com/omnibus/docker/), some are
[installed from source](../install/installation.md),
and there are other installation methods available. GitLab.com itself is a large
diff --git a/doc/development/contributing/community_roles.md b/doc/development/contributing/community_roles.md
index b9c369286d2..3296cb173d7 100644
--- a/doc/development/contributing/community_roles.md
+++ b/doc/development/contributing/community_roles.md
@@ -4,8 +4,8 @@ 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/) |
+| Maintainer | Accepts merge requests on several GitLab projects | Added to the [team page](https://about.gitlab.com/company/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/company/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 |
diff --git a/doc/development/contributing/index.md b/doc/development/contributing/index.md
index 59cf5014da4..853882e8642 100644
--- a/doc/development/contributing/index.md
+++ b/doc/development/contributing/index.md
@@ -4,7 +4,7 @@ Thank you for your interest in contributing to GitLab. This guide details how
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/).
+["Contributing to GitLab"](https://about.gitlab.com/community/contribute/).
Looking for something to work on? Look for issues with the label [`Accepting merge requests`](#i-want-to-contribute).
diff --git a/doc/development/contributing/issue_workflow.md b/doc/development/contributing/issue_workflow.md
index d9595bd7bba..910f9f4bf7a 100644
--- a/doc/development/contributing/issue_workflow.md
+++ b/doc/development/contributing/issue_workflow.md
@@ -1,21 +1,24 @@
# 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
+and [labels](https://gitlab.com/gitlab-org/gitlab-ce/-/labels). Leads and product managers handle most of the
scheduling into milestones. Labelling is a task for everyone.
Most issues will have labels for at least one of the following:
-- Type: ~feature, ~bug, ~customer, etc.
-- Subject: ~wiki, ~"Container Registry", ~ldap, ~api, ~frontend, etc.
-- Team: ~Plan, ~Manage, ~Quality, etc.
-- Stage: ~"devops:plan", ~"devops:create", etc.
+- Type: ~feature, ~bug, ~backstage, etc.
+- Subject: ~wiki, ~"Container Registry", ~ldap, ~api, etc.
+- Team: ~Documentation, ~Delivery, etc.
+- Stage: ~"devops::plan", ~"devops::create", etc.
+- Group: ~"group::source code" ~"group::knowledge" ~"group::editor", etc.
+- Department: ~UX, ~Quality
+- Specialization: ~frontend, ~backend
- Release Scoping: ~Deliverable, ~Stretch, ~"Next Patch Release"
- Priority: ~P1, ~P2, ~P3, ~P4
- Severity: ~S1, ~S2, ~S3, ~S4
All labels, their meaning and priority are defined on the
-[labels page][labels-page].
+[labels page](https://gitlab.com/gitlab-org/gitlab-ce/-/labels).
If you come across an issue that has none of these, and you're allowed to set
labels, you can _always_ add the team and type, and often also the subject.
@@ -27,8 +30,7 @@ labels, you can _always_ add the team and type, and often also the subject.
Type labels are very important. They define what kind of issue this is. Every
issue should have one or more.
-Examples of type labels are ~feature, ~bug, ~customer, ~security,
-and ~direction.
+Examples of type labels are ~feature, ~bug, ~backstage and ~security
A number of type labels have a priority assigned to them, which automatically
makes them float to the top, depending on their importance.
@@ -36,7 +38,7 @@ makes them float to the top, depending on their importance.
Type labels are always lowercase, and can have any color, besides blue (which is
already reserved for subject labels).
-The descriptions on the [labels page][labels-page] explain what falls under each type label.
+The descriptions on the [labels page](https://gitlab.com/gitlab-org/gitlab-ce/-/labels) explain what falls under each type label.
## Subject labels
@@ -56,19 +58,20 @@ issue is labeled with a subject label corresponding to your expertise.
Subject labels are always all-lowercase.
-## Team labels
+## Team labels
+
+**Important**: Most of the team labels will be soon deprecated in favor of [Group labels](#group-labels).
Team labels specify what team is responsible for this issue.
Assigning a team label makes sure issues get the attention of the appropriate
people.
-The current team labels are:
+The team labels planned for deprecation are:
- ~Configure
- ~Create
- ~Defend
- ~Distribution
-- ~Documentation
- ~Ecosystem
- ~Geo
- ~Gitaly
@@ -77,13 +80,16 @@ The current team labels are:
- ~Memory
- ~Monitor
- ~Plan
-- ~Quality
- ~Release
- ~Secure
-- ~UX
- ~Verify
-The descriptions on the [labels page][labels-page] explain what falls under the
+The following team labels are **true** teams per our [organization structure](https://about.gitlab.com/company/team/structure/#organizational-structure) which will remain post deprecation.
+
+- ~Delivery
+- ~Documentation
+
+The descriptions on the [labels page](https://gitlab.com/gitlab-org/gitlab-ce/-/labels) explain what falls under the
responsibility of each team.
Within those team labels, we also have the ~backend and ~frontend labels to
@@ -92,6 +98,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.
+
## Stage labels
Stage labels specify which [DevOps stage][devops-stages] the issue belongs to.
@@ -132,10 +139,44 @@ The Stage labels are used to generate the [direction pages][direction-pages] aut
Group labels specify which [groups][structure-groups] the issue belongs to.
-Examples include:
-
-- ~"group::control"
-- ~"group::editor"
+The current group labels are:
+
+* ~"group::access"
+* ~"group::measure"
+* ~"group::source code"
+* ~"group::knowledge"
+* ~"group::editor"
+* ~"group::gitaly"
+* ~"group::gitter"
+* ~"group::team planning"
+* ~"group::enterprise planning"
+* ~"group::certify"
+* ~"group::ci and runner"
+* ~"group::testing"
+* ~"group::package"
+* ~"group::progressive delivery"
+* ~"group::release management"
+* ~"group::autodevops and kubernetes"
+* ~"group::serverless and paas"
+* ~"group::apm"
+* ~"group::health"
+* ~"group::static analysis"
+* ~"group::dynamic analysis"
+* ~"group::software composition analysis"
+* ~"group::runtime application security"
+* ~"group::threat management"
+* ~"group::application infrastructure security"
+* ~"group::activation"
+* ~"group::adoption"
+* ~"group::upsell"
+* ~"group::retention"
+* ~"group::fulfillment"
+* ~"group::telemetry"
+* ~"group::distribution"
+* ~"group::geo"
+* ~"group::memory"
+* ~"group::ecosystem"
+
These labels are [scoped labels](../../user/project/labels.md#scoped-labels-premium)
and thus are mutually exclusive.
@@ -147,6 +188,20 @@ can be applied to a single issue. You can find the groups listed in the
[structure-groups]: https://about.gitlab.com/company/team/structure/#groups
[product-categories]: https://about.gitlab.com/handbook/product/categories/
+## Department labels
+
+The current department labels are:
+
+* ~UX
+* ~Quality
+
+## Specialization labels
+
+These labels narrow the [specialization](https://about.gitlab.com/company/team/structure/#specialist) on a unit of work.
+
+* ~frontend
+* ~backend
+
## Release Scoping labels
Release Scoping labels help us clearly communicate expectations of the work for the
@@ -290,7 +345,7 @@ For feature proposals for EE, open an issue on the
In order to help track the feature proposals, we have created a
[`feature`][fl] label. For the time being, users that are not members
-of the project cannot add labels. You can instead ask one of the [core team]
+of the project cannot add labels. You can instead ask one of the [core team](https://about.gitlab.com/community/core-team/)
members to add the label ~feature to the issue or add the following
code snippet right after your description in a new line: `~feature`.
@@ -301,7 +356,7 @@ Please submit Feature Proposals using the ['Feature Proposal' issue template](ht
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
-need to ask one of the [core team] members to add the label, if you do not have permissions to do it by yourself.
+need to ask one of the [core team](https://about.gitlab.com/community/core-team/) members to add the label, if you do not have permissions to do it by yourself.
If you want to create something yourself, consider opening an issue first to
discuss whether it is interesting to include this in GitLab.
@@ -445,7 +500,6 @@ A recent example of this was the issue for
[Return to Contributing documentation](index.md)
-[labels-page]: https://gitlab.com/gitlab-org/gitlab-ce/labels
[ce-tracker]: https://gitlab.com/gitlab-org/gitlab-ce/issues
[ee-tracker]: https://gitlab.com/gitlab-org/gitlab-ee/issues
[inferred-labels]: https://gitlab.com/gitlab-org/quality/triage-ops/merge_requests/155
diff --git a/doc/development/contributing/merge_request_workflow.md b/doc/development/contributing/merge_request_workflow.md
index 6064f59ed10..3f61ad7cb13 100644
--- a/doc/development/contributing/merge_request_workflow.md
+++ b/doc/development/contributing/merge_request_workflow.md
@@ -65,7 +65,7 @@ request is as follows:
1. If you are contributing documentation, choose `Documentation` from the
"Choose a template" menu and fill in the description according to the template.
1. Mention the issue(s) your merge request solves, using the `Solves #XXX` or
- `Closes #XXX` syntax to [auto-close](../../user/project/issues/automatic_issue_closing.md)
+ `Closes #XXX` syntax to [auto-close](../../user/project/issues/managing_issues.md#closing-issues-automatically)
the issue(s) once the merge request is merged.
1. If you're allowed to (Core team members, for example), set a relevant milestone
and [labels](issue_workflow.md).
@@ -193,6 +193,7 @@ requirements.
1. [Changelog entry added](../changelog.md), if necessary.
1. Reviewed by relevant (UX/FE/BE/tech writing) reviewers and all concerns are addressed.
1. Merged by a project maintainer.
+1. Confirmed to be working in the [Canary stage](https://about.gitlab.com/handbook/engineering/#canary-testing) or on GitLab.com once the contribution is deployed.
1. Added to the [release post](https://about.gitlab.com/handbook/marketing/blog/release-posts/),
if relevant.
1. Added to [the website](https://gitlab.com/gitlab-com/www-gitlab-com/blob/master/data/features.yml), if relevant.
diff --git a/doc/development/contributing/style_guides.md b/doc/development/contributing/style_guides.md
index 87e61a7476f..5c6ea1f469d 100644
--- a/doc/development/contributing/style_guides.md
+++ b/doc/development/contributing/style_guides.md
@@ -1,11 +1,11 @@
# Style guides
-1. [Ruby](https://github.com/bbatsov/ruby-style-guide).
+1. [Ruby](https://github.com/rubocop-hq/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. [Rails](https://github.com/rubocop-hq/rails-style-guide)
1. [Newlines styleguide][newlines-styleguide]
1. [Testing][testing]
1. [JavaScript styleguide][js-styleguide]
@@ -13,7 +13,7 @@
1. [Shell commands (Ruby)](../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. [Markdown](https://cirosantilli.com/markdown-style-guide/)
1. [Documentation styleguide](../documentation/styleguide.md)
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
@@ -25,7 +25,7 @@
1. [Python](../python_guide/index.md)
This is also the style used by linting tools such as
-[RuboCop](https://github.com/bbatsov/rubocop) and [Hound CI](https://houndci.com).
+[RuboCop](https://github.com/rubocop-hq/rubocop) and [Hound CI](https://houndci.com).
---
diff --git a/doc/development/database_debugging.md b/doc/development/database_debugging.md
index de2c5b43411..0311eda1ff1 100644
--- a/doc/development/database_debugging.md
+++ b/doc/development/database_debugging.md
@@ -3,7 +3,7 @@
This section is to help give some copy-pasta you can use as a reference when you
run into some head-banging database problems.
-An easy first step is to search for your error in Slack or google "GitLab <my error>".
+An easy first step is to search for your error in Slack or google "GitLab (my error)".
---
diff --git a/doc/development/documentation/site_architecture/global_nav.md b/doc/development/documentation/site_architecture/global_nav.md
index a441ede6e42..20eeebf444f 100644
--- a/doc/development/documentation/site_architecture/global_nav.md
+++ b/doc/development/documentation/site_architecture/global_nav.md
@@ -4,8 +4,9 @@ description: "Learn how GitLab docs' global navigation works and how to add new
# Global navigation
-> [Introduced](https://gitlab.com/gitlab-com/gitlab-docs/merge_requests/362)
-in November 2018 for GitLab 11.6.
+> - [Introduced](https://gitlab.com/gitlab-com/gitlab-docs/merge_requests/362)
+in GitLab 11.6.
+> - [Updated](https://gitlab.com/gitlab-com/gitlab-docs/merge_requests/482) in GitLab 12.1.
The global nav adds to the left sidebar the ability to
navigate and explore the contents of GitLab's documentation.
@@ -217,13 +218,13 @@ and the following syntax rules.
- Always use relative paths against the home of CE and EE. Examples:
- For `https://docs.gitlab.com/ee/README.html`, the relative URL is `README.html`.
- For `https://docs.gitlab.com/ee/user/project/cycle_analytics.html`, the relative
- URL is `user/project/cycle_analytics.html`
+ URL is `user/project/cycle_analytics.html`.
- For `README.html` files, add the complete path `path/to/README.html`.
- For `index.html` files, use the clean (canonical) URL: `path/to/`.
- For EE-only docs, use the same relative path, but add the attribute `ee_only: true` below
- the `doc_url` or `category_url`, as explained above. This will guarantee that when
- the user is looking at the CE docs, it will link to the EE docs. It also displays
- an "info" icon on the CE nav to make the user aware that it's a different link.
+ the `doc_url` or `category_url`, as explained above. This displays
+ an "info" icon on the nav to make the user aware that the feature is
+ EE-only.
DANGER: **Important!**
All links present on the data file must end in `.html`, not `.md`. Do not
@@ -293,7 +294,7 @@ point to `/ee/` docs.
On the other hand, if the user is looking at `/ce/` docs,
all the links in the CE nav should link internally to `/ce/`
-files, except for [`ee-only` docs](#ee-only-docs).
+files.
```html
<% if dir != 'ce' %>
@@ -314,21 +315,12 @@ categories (`cat[:category_url]`), and docs (`doc[:doc_url]`) URLs.
#### `ee-only` docs
-If the user is looking at the CE nav, a given doc is present only
-in `/ee/`, it's tagged in the data file by `ee-only`, linking it
-directly to `/ee/`.
+Docs for features present only in GitLab EE are tagged
+in the data file by `ee-only` and an icon is displayed on the nav
+link indicating that the `ee-only` feature is not available in CE.
-```html
-<% if dir == 'ce' && cat[:ee_only] %>
- <a href="/ee/<%= cat[:category_url] %>">...</a>
-<% end %>
-```
-
-To make it clear that it it's a different link, an icon is displayed
-on the nav link indicating that the `ee-only` doc is not available in CE.
-
-The `ee-only` attribute is available for `categories` (`<% if dir == 'ce' && cat[:ee_only] %>`)
-and `docs` (`<% if dir == 'ce' && doc[:ee_only] %>`), but not for `sections`.
+The `ee-only` attribute is available for `categories` (`<% if cat[:ee_only] %>`)
+and `docs` (`<% if doc[:ee_only] %>`), but not for `sections`.
### CSS classes
diff --git a/doc/development/documentation/styleguide.md b/doc/development/documentation/styleguide.md
index 0d82f905bf3..d9cea0614c3 100644
--- a/doc/development/documentation/styleguide.md
+++ b/doc/development/documentation/styleguide.md
@@ -151,7 +151,7 @@ The table below shows what kind of documentation goes where.
applies to images.
1. For image files, do not exceed 100KB.
1. Do not upload video files to the product repositories.
-[Link or embed videos](#videos) instead.
+ [Link or embed videos](#videos) instead.
1. There are four main directories, `user`, `administration`, `api` and `development`.
1. The `doc/user/` directory has five main subdirectories: `project/`, `group/`,
`profile/`, `dashboard/` and `admin_area/`.
@@ -179,7 +179,7 @@ The table below shows what kind of documentation goes where.
If you are unsure where a document or a content addition should live, this should
not stop you from authoring and contributing. You can use your best judgment and
then ask the reviewer of your MR to confirm your decision, and/or ask a technical writer
-at any stage in the process. The techncial writing team will review all documentation
+at any stage in the process. The technical writing team will review all documentation
changes, regardless, and can move content if there is a better place for it.
### Avoid duplication
@@ -393,7 +393,7 @@ Instead:
Example:
```md
-For more information, see the [confidential issue](https://docs.gitlab.com/ee/user/project/issues/confidential_issues.html) `https://gitlab.com/gitlab-org/gitlab-ce/issues/<issue_number>`.
+For more information, see the [confidential issue](../../user/project/issues/confidential_issues.md) `https://gitlab.com/gitlab-org/gitlab-ce/issues/<issue_number>`.
```
### Unlinking emails
@@ -476,7 +476,7 @@ Do not upload videos to the product repositories. [Link](#link-to-video) or [emb
### Link to video
-To link out to a video, include a YouTube icon so that readers can
+To link out to a video, include a YouTube icon so that readers can
quickly and easily scan the page for videos before reading:
```md
@@ -518,7 +518,7 @@ you have your MR reviewed and approved by a technical writer.
```html
leave a blank line here
<div class="video-fallback">
- See the video: [Video title](https://www.youtube.com/watch?v=MqL6BMOySIQ).
+ See the video: <a href="https://www.youtube.com/watch?v=MqL6BMOySIQ">Video title</a>.
</div>
<figure class="video-container">
<iframe src="https://www.youtube.com/embed/MqL6BMOySIQ" frameborder="0" allowfullscreen="true"> </iframe>
@@ -529,7 +529,7 @@ leave a blank line here
This is how it renders on docs.gitlab.com:
<div class="video-fallback">
- See the video: [What is GitLab](https://www.youtube.com/watch?v=enMumwvLAug).
+ See the video: <a href="https://www.youtube.com/watch?v=enMumwvLAug">What is GitLab</a>.
</div>
<figure class="video-container">
<iframe src="https://www.youtube.com/embed/MqL6BMOySIQ" frameborder="0" allowfullscreen="true"> </iframe>
@@ -767,24 +767,24 @@ Other text includes deprecation notices and version-specific how-to information.
When a feature is available in EE-only tiers, add the corresponding tier according to the
feature availability:
-- For GitLab Starter and GitLab.com Bronze: `**[STARTER]**`.
-- For GitLab Premium and GitLab.com Silver: `**[PREMIUM]**`.
-- For GitLab Ultimate and GitLab.com Gold: `**[ULTIMATE]**`.
-- For GitLab Core and GitLab.com Free: `**[CORE]**`.
+- For GitLab Starter and GitLab.com Bronze: `**(STARTER)**`.
+- For GitLab Premium and GitLab.com Silver: `**(PREMIUM)**`.
+- For GitLab Ultimate and GitLab.com Gold: `**(ULTIMATE)**`.
+- For GitLab Core and GitLab.com Free: `**(CORE)**`.
To exclude GitLab.com tiers (when the feature is not available in GitLab.com), add the
keyword "only":
-- For GitLab Core: `**[CORE ONLY]**`.
-- For GitLab Starter: `**[STARTER ONLY]**`.
-- For GitLab Premium: `**[PREMIUM ONLY]**`.
-- For GitLab Ultimate: `**[ULTIMATE ONLY]**`.
+- For GitLab Core: `**(CORE ONLY)**`.
+- For GitLab Starter: `**(STARTER ONLY)**`.
+- For GitLab Premium: `**(PREMIUM ONLY)**`.
+- For GitLab Ultimate: `**(ULTIMATE ONLY)**`.
For GitLab.com only tiers (when the feature is not available for self-hosted instances):
-- For GitLab Bronze and higher tiers: `**[BRONZE ONLY]**`.
-- For GitLab Silver and higher tiers: `**[SILVER ONLY]**`.
-- For GitLab Gold: `**[GOLD ONLY]**`.
+- For GitLab Bronze and higher tiers: `**(BRONZE ONLY)**`.
+- For GitLab Silver and higher tiers: `**(SILVER ONLY)**`.
+- For GitLab Gold: `**(GOLD ONLY)**`.
The tier should be ideally added to headers, so that the full badge will be displayed.
However, it can be also mentioned from paragraphs, list items, and table cells. For these cases,
@@ -792,9 +792,9 @@ the tier mention will be represented by an orange question mark that will show t
For example:
-- `**[STARTER]**` renders as **[STARTER]**
-- `**[STARTER ONLY]**` renders as **[STARTER ONLY]**
-- `**[SILVER ONLY]**` renders as **[SILVER ONLY]**
+- `**(STARTER)**` renders as **(STARTER)**
+- `**(STARTER ONLY)**` renders as **(STARTER ONLY)**
+- `**(SILVER ONLY)**` renders as **(SILVER ONLY)**
The absence of tiers' mentions mean that the feature is available in GitLab Core,
GitLab.com Free, and all higher tiers.
@@ -802,7 +802,7 @@ GitLab.com Free, and all higher tiers.
### How it works
Introduced by [!244](https://gitlab.com/gitlab-com/gitlab-docs/merge_requests/244),
-the special markup `**[STARTER]**` will generate a `span` element to trigger the
+the special markup `**(STARTER)**` will generate a `span` element to trigger the
badges and tooltips (`<span class="badge-trigger starter">`). When the keyword
"only" is added, the corresponding GitLab.com badge will not be displayed.
diff --git a/doc/development/ee_features.md b/doc/development/ee_features.md
index 34d41cf4958..7131b717353 100644
--- a/doc/development/ee_features.md
+++ b/doc/development/ee_features.md
@@ -182,52 +182,52 @@ There are a few gotchas with it:
pattern](https://en.wikipedia.org/wiki/Template_method_pattern).
For example, given this base:
- ```ruby
- class Base
- def execute
- return unless enabled?
+ ```ruby
+ class Base
+ def execute
+ return unless enabled?
- # ...
- # ...
- end
+ # ...
+ # ...
end
- ```
+ end
+ ```
- Instead of just overriding `Base#execute`, we should update it and extract
- the behaviour into another method:
+ Instead of just overriding `Base#execute`, we should update it and extract
+ the behaviour into another method:
- ```ruby
- class Base
- def execute
- return unless enabled?
+ ```ruby
+ class Base
+ def execute
+ return unless enabled?
- do_something
- end
+ do_something
+ end
- private
+ private
- def do_something
- # ...
- # ...
- end
+ def do_something
+ # ...
+ # ...
end
- ```
+ end
+ ```
- Then we're free to override that `do_something` without worrying about the
- guards:
+ Then we're free to override that `do_something` without worrying about the
+ guards:
- ```ruby
- module EE::Base
- extend ::Gitlab::Utils::Override
+ ```ruby
+ module EE::Base
+ extend ::Gitlab::Utils::Override
- override :do_something
- def do_something
- # Follow the above pattern to call super and extend it
- end
+ override :do_something
+ def do_something
+ # Follow the above pattern to call super and extend it
end
- ```
+ end
+ ```
- This would require updating CE first, or make sure this is back ported to CE.
+ This would require updating CE first, or make sure this is back ported to CE.
When prepending, place them in the `ee/` specific sub-directory, and
wrap class or module in `module EE` to avoid naming conflicts.
@@ -446,7 +446,6 @@ The disadvantage of this:
port `render_if_exists` to CE.
- If we have typos in the partial name, it would be silently ignored.
-
##### Caveats
The `render_if_exists` view path argument must be relative to `app/views/` and `ee/app/views`.
@@ -973,7 +972,7 @@ For regular JS files, the approach is similar.
1. An EE file should be created with the EE only code, and it should extend the CE counterpart.
1. For code inside functions that can't be extended, the code should be moved into a new file and we should use `ee_else_ce` helper:
-##### Example:
+#### Example:
```javascript
import eeCode from 'ee_else_ce/ee_code';
@@ -1000,7 +999,7 @@ styles are usually kept in stylesheet that is common for both CE and EE, and it
to isolate such ruleset from rest of CE rules (along with adding comment describing the same)
to avoid conflicts during CE to EE merge.
-#### Bad
+### Bad
```scss
.section-body {
@@ -1016,7 +1015,7 @@ to avoid conflicts during CE to EE merge.
}
```
-#### Good
+### Good
```scss
.section-body {
@@ -1034,9 +1033,16 @@ to avoid conflicts during CE to EE merge.
// EE-specific end
```
-### Backporting changes from EE to CE
+## Backporting changes from EE to CE
+
+Until the work completed to merge the ce and ee codebases, which is tracked on [epic &802](https://gitlab.com/groups/gitlab-org/-/epics/802), there exists times in which some changes for EE require specific changes to the CE
+code base. Examples of backports include the following:
+
+- Features intended or originally built for EE that are later decided to move to CE
+- Sometimes some code in CE may impact the EE feature
+
+Here is a workflow to make sure those changes end up backported safely into CE too.
-When working in EE-specific features, you might have to tweak a few files that are not EE-specific. Here is a workflow to make sure those changes end up backported safely into CE too.
(This approach does not refer to changes introduced via [csslab](https://gitlab.com/gitlab-org/csslab/).)
1. **Make your changes in the EE branch.** If possible, keep a separated commit (to be squashed) to help backporting and review.
diff --git a/doc/development/elasticsearch.md b/doc/development/elasticsearch.md
index 05e64b33eec..0965db29557 100644
--- a/doc/development/elasticsearch.md
+++ b/doc/development/elasticsearch.md
@@ -1,4 +1,4 @@
-# Elasticsearch knowledge **[STARTER ONLY]**
+# Elasticsearch knowledge **(STARTER ONLY)**
This area is to maintain a compendium of useful information when working with elasticsearch.
@@ -65,7 +65,7 @@ Search queries are generated by the concerns found in [ee/app/models/concerns/el
## Existing Analyzers/Tokenizers/Filters
-These are all defined in https://gitlab.com/gitlab-org/gitlab-ee/blob/master/ee/lib/elasticsearch/git/model.rb
+These are all defined in <https://gitlab.com/gitlab-org/gitlab-ee/blob/master/ee/lib/elasticsearch/git/model.rb>
### Analyzers
@@ -150,7 +150,7 @@ Uses an [Edge NGram token filter](https://www.elastic.co/guide/en/elasticsearch/
## Troubleshooting
-### Getting "flood stage disk watermark [95%] exceeded"
+### Getting `flood stage disk watermark [95%] exceeded`
You might get an error such as
diff --git a/doc/development/emails.md b/doc/development/emails.md
index 8baf343b133..e6af075a282 100644
--- a/doc/development/emails.md
+++ b/doc/development/emails.md
@@ -26,57 +26,57 @@ See the [Rails guides] for more info.
feature and fill in the details for your specific IMAP server and email
account:
- Configuration for Gmail / Google Apps, assumes mailbox gitlab-incoming@gmail.com
-
- ```yaml
- incoming_email:
- enabled: true
-
- # The email address including the `%{key}` placeholder that will be replaced to reference the item being replied to.
- # The placeholder can be omitted but if present, it must appear in the "user" part of the address (before the `@`).
- address: "gitlab-incoming+%{key}@gmail.com"
-
- # Email account username
- # With third party providers, this is usually the full email address.
- # With self-hosted email servers, this is usually the user part of the email address.
- user: "gitlab-incoming@gmail.com"
- # Email account password
- password: "[REDACTED]"
-
- # IMAP server host
- host: "imap.gmail.com"
- # IMAP server port
- port: 993
- # Whether the IMAP server uses SSL
- ssl: true
- # Whether the IMAP server uses StartTLS
- start_tls: false
-
- # The mailbox where incoming mail will end up. Usually "inbox".
- mailbox: "inbox"
- # The IDLE command timeout.
- idle_timeout: 60
- ```
-
- As mentioned, the part after `+` is ignored, and this will end up in the mailbox for `gitlab-incoming@gmail.com`.
+ Configuration for Gmail / Google Apps, assumes mailbox `gitlab-incoming@gmail.com`:
+
+ ```yaml
+ incoming_email:
+ enabled: true
+
+ # The email address including the `%{key}` placeholder that will be replaced to reference the item being replied to.
+ # The placeholder can be omitted but if present, it must appear in the "user" part of the address (before the `@`).
+ address: "gitlab-incoming+%{key}@gmail.com"
+
+ # Email account username
+ # With third party providers, this is usually the full email address.
+ # With self-hosted email servers, this is usually the user part of the email address.
+ user: "gitlab-incoming@gmail.com"
+ # Email account password
+ password: "[REDACTED]"
+
+ # IMAP server host
+ host: "imap.gmail.com"
+ # IMAP server port
+ port: 993
+ # Whether the IMAP server uses SSL
+ ssl: true
+ # Whether the IMAP server uses StartTLS
+ start_tls: false
+
+ # The mailbox where incoming mail will end up. Usually "inbox".
+ mailbox: "inbox"
+ # The IDLE command timeout.
+ idle_timeout: 60
+ ```
+
+ As mentioned, the part after `+` is ignored, and this will end up in the mailbox for `gitlab-incoming@gmail.com`.
1. Run this command in the GitLab root directory to launch `mail_room`:
- ```sh
- bundle exec mail_room -q -c config/mail_room.yml
- ```
+ ```sh
+ bundle exec mail_room -q -c config/mail_room.yml
+ ```
1. Verify that everything is configured correctly:
- ```sh
- bundle exec rake gitlab:incoming_email:check RAILS_ENV=development
- ```
+ ```sh
+ bundle exec rake gitlab:incoming_email:check RAILS_ENV=development
+ ```
1. Reply by email should now be working.
## Email namespace
-As of GitLab 11.7, we support a new format for email handler addresses. This was done to
+As of GitLab 11.7, we support a new format for email handler addresses. This was done to
support catch-all mailboxes.
If you need to implement a feature which requires a new email handler, follow these rules
@@ -91,10 +91,10 @@ for the format of the email key:
Examples of valid email keys:
- - `gitlab-org-gitlab-ce-20-Author_Token12345678-issue` (create a new issue)
- - `gitlab-org-gitlab-ce-20-Author_Token12345678-merge-request` (create a new merge request)
- - `1234567890abcdef1234567890abcdef-unsubscribe` (unsubscribe from a conversation)
- - `1234567890abcdef1234567890abcdef` (reply to a conversation)
+- `gitlab-org-gitlab-ce-20-Author_Token12345678-issue` (create a new issue)
+- `gitlab-org-gitlab-ce-20-Author_Token12345678-merge-request` (create a new merge request)
+- `1234567890abcdef1234567890abcdef-unsubscribe` (unsubscribe from a conversation)
+- `1234567890abcdef1234567890abcdef` (reply to a conversation)
Please note that the action `-issue-` is used in GitLab Premium as the handler for the Service Desk feature.
@@ -103,10 +103,10 @@ Please note that the action `-issue-` is used in GitLab Premium as the handler f
Although we continue to support the older legacy format, no new features should use a legacy format.
These are the only valid legacy formats for an email handler:
- - `path/to/project+namespace`
- - `path/to/project+namespace+action`
- - `namespace`
- - `namespace+action`
+- `path/to/project+namespace`
+- `path/to/project+namespace+action`
+- `namespace`
+- `namespace+action`
Please note that `path/to/project` is used in GitLab Premium as handler for the Service Desk feature.
diff --git a/doc/development/fe_guide/architecture.md b/doc/development/fe_guide/architecture.md
index c67389b169e..49b74b5ebcf 100644
--- a/doc/development/fe_guide/architecture.md
+++ b/doc/development/fe_guide/architecture.md
@@ -11,7 +11,7 @@ Architectural decisions should be accessible to everyone, so please document
them in the relevant Merge Request discussion or by updating our documentation
when appropriate.
-You can find the Frontend Architecture experts on the [team page](https://about.gitlab.com/team).
+You can find the Frontend Architecture experts on the [team page](https://about.gitlab.com/company/team).
## Examples
diff --git a/doc/development/fe_guide/development_process.md b/doc/development/fe_guide/development_process.md
index f3fdaa3b883..ae0e2361840 100644
--- a/doc/development/fe_guide/development_process.md
+++ b/doc/development/fe_guide/development_process.md
@@ -12,8 +12,7 @@ This checklist is intended to help us during development of bigger features/refa
Please use your best judgement when to use it and please contribute new points through merge requests if something comes to your mind.
----
-
+```
### Frontend development
#### Planning development
@@ -24,15 +23,15 @@ Please use your best judgement when to use it and please contribute new points t
- [ ] Are all necessary UX specifications available that you will need in order to implement? Are there new UX components/patterns in the designs? Then contact the UI component team early on. How should error messages or validation be handled?
- [ ] **Library usage** Use Vuex as soon as you have even a medium state to manage, use Vue router if you need to have different views internally and want to link from the outside. Check what libraries we already have for which occasions.
- [ ] **Plan your implementation:**
- - [ ] **Architecture plan:** Create a plan aligned with GitLab's architecture, how you are going to do the implementation, for example Vue application setup and its components (through [onion skinning](https://gitlab.com/gitlab-org/gitlab-ce/issues/35873#note_39994091)), Store structure and data flow, which existing Vue components can you reuse. It's a good idea to go through your plan with another engineer to refine it.
- - [ ] **Backend:** The best way is to kickoff the implementation in a call and discuss with the assigned Backend engineer what you will need from the backend and also when. Can you reuse existing API's? How is the performance with the planned architecture? Maybe create together a JSON mock object to already start with development.
- - [ ] **Communication:** It also makes sense to have for bigger features an own slack channel (normally called #f_{feature_name}) and even weekly demo calls with all people involved.
- - [ ] **Dependency Plan:** Are there big dependencies in the plan between you and others, then maybe create an execution diagram to show what is blocking which part and the order of the different parts.
- - [ ] **Task list:** Create a simple checklist of the subtasks that are needed for the implementation, also consider creating even sub issues. (for example show a comment, delete a comment, update a comment, etc.). This helps you and also everyone else following the implementation
+ - [ ] **Architecture plan:** Create a plan aligned with GitLab's architecture, how you are going to do the implementation, for example Vue application setup and its components (through [onion skinning](https://gitlab.com/gitlab-org/gitlab-ce/issues/35873#note_39994091)), Store structure and data flow, which existing Vue components can you reuse. It's a good idea to go through your plan with another engineer to refine it.
+ - [ ] **Backend:** The best way is to kickoff the implementation in a call and discuss with the assigned Backend engineer what you will need from the backend and also when. Can you reuse existing API's? How is the performance with the planned architecture? Maybe create together a JSON mock object to already start with development.
+ - [ ] **Communication:** It also makes sense to have for bigger features an own slack channel (normally called #f_{feature_name}) and even weekly demo calls with all people involved.
+ - [ ] **Dependency Plan:** Are there big dependencies in the plan between you and others, then maybe create an execution diagram to show what is blocking which part and the order of the different parts.
+ - [ ] **Task list:** Create a simple checklist of the subtasks that are needed for the implementation, also consider creating even sub issues. (for example show a comment, delete a comment, update a comment, etc.). This helps you and also everyone else following the implementation
- [ ] **Keep it small** To make it easier for you and also all reviewers try to keep merge requests small and merge into a feature branch if needed. To accomplish that you need to plan that from the start. Different methods are:
- - [ ] **Skeleton based plan** Start with an MR that has the skeleton of the components with placeholder content. In following MRs you can fill the components with interactivity. This also makes it easier to spread out development on multiple people.
- - [ ] **Cookie Mode** Think about hiding the feature behind a cookie flag if the implementation is on top of existing features
- - [ ] **New route** Are you refactoring something big then you might consider adding a new route where you implement the new feature and when finished delete the current route and rename the new one. (for example 'merge_request' and 'new_merge_request')
+ - [ ] **Skeleton based plan** Start with an MR that has the skeleton of the components with placeholder content. In following MRs you can fill the components with interactivity. This also makes it easier to spread out development on multiple people.
+ - [ ] **Cookie Mode** Think about hiding the feature behind a cookie flag if the implementation is on top of existing features
+ - [ ] **New route** Are you refactoring something big then you might consider adding a new route where you implement the new feature and when finished delete the current route and rename the new one. (for example 'merge_request' and 'new_merge_request')
- [ ] **Setup** Is there any specific setup needed for your implementation (for example a kubernetes cluster)? Then let everyone know if it is not already mentioned where they can find documentation (if it doesn't exist - create it)
- [ ] **Security** Are there any new security relevant implementations? Then please contact the security team for an app security review. If you are not sure ask our [domain expert](https://about.gitlab.com/handbook/engineering/frontend/#frontend-domain-experts)
@@ -57,8 +56,7 @@ Please use your best judgement when to use it and please contribute new points t
- [ ] Are there any big changes on how and especially how frequently we use the API then let production know about it
- [ ] Smoke test of the RC on dev., staging., canary deployments and .com
- [ ] Follow up on issues that came out of the review. Create issues for discovered edge cases that should be covered in future iterations.
-
----
+```
### Share your work early
@@ -66,7 +64,7 @@ Please use your best judgement when to use it and please contribute new points t
GitLab's architecture.
1. Add a diagram to the issue and ask a frontend architect in the slack channel `#fe_architectural` about it.
- ![Diagram of Issue Boards Architecture](img/boards_diagram.png)
+ ![Diagram of Issue Boards Architecture](img/boards_diagram.png)
1. Don't take more than one week between starting work on a feature and
sharing a Merge Request with a reviewer or a maintainer.
diff --git a/doc/development/fe_guide/emojis.md b/doc/development/fe_guide/emojis.md
index 38794c47965..6d324d4c4a0 100644
--- a/doc/development/fe_guide/emojis.md
+++ b/doc/development/fe_guide/emojis.md
@@ -3,10 +3,10 @@
GitLab supports native unicode emojis and fallsback to image-based emojis selectively
when your platform does not support it.
-# How to update Emojis
+## How to update Emojis
1. Update the `gemojione` gem
- 1. Update `fixtures/emojis/index.json` from [Gemojione](https://github.com/jonathanwiesel/gemojione/blob/master/config/index.json).
+ 1. Update `fixtures/emojis/index.json` from [Gemojione](https://github.com/bonusly/gemojione/blob/master/config/index.json).
In the future, we could grab the file directly from the gem.
We should probably make a PR on the Gemojione project to get access to
all emojis after being parsed or just a raw path to the `json` file itself.
diff --git a/doc/development/fe_guide/graphql.md b/doc/development/fe_guide/graphql.md
index 9fcd32fddfa..55b719227e5 100644
--- a/doc/development/fe_guide/graphql.md
+++ b/doc/development/fe_guide/graphql.md
@@ -55,7 +55,6 @@ It is possible to manage an application state with Apollo by passing
in a resolvers object when creating the default client. The default state can be set by writing
to the cache after setting up the default client.
-
```javascript
import Vue from 'vue';
import VueApollo from 'vue-apollo';
@@ -115,13 +114,12 @@ defaultClient.query(query)
.then(result => console.log(result));
```
-Read more about the [Apollo] client in the [Apollo documentation][apollo-client-docs].
+Read more about the [Apollo] client in the [Apollo documentation](https://www.apollographql.com/docs/tutorial/client/).
[Apollo]: https://www.apollographql.com/
[vue-apollo]: https://github.com/Akryum/vue-apollo/
[vue-apollo-docs]: https://akryum.github.io/vue-apollo/
[feature-flags]: ../feature_flags.md
[default-client]: https://gitlab.com/gitlab-org/gitlab-ce/blob/master/app/assets/javascripts/lib/graphql.js
-[apollo-client-docs]: https://www.apollographql.com/docs/tutorial/client.html
[vue-test-utils]: https://vue-test-utils.vuejs.org/
[apollo-link-state]: https://www.apollographql.com/docs/link/links/state.html
diff --git a/doc/development/fe_guide/security.md b/doc/development/fe_guide/security.md
index 83bb449e54d..47ac87fc895 100644
--- a/doc/development/fe_guide/security.md
+++ b/doc/development/fe_guide/security.md
@@ -1,5 +1,6 @@
# Security
-### Resources
+
+## Resources
[Mozilla’s HTTP Observatory CLI][observatory-cli] and the
[Qualys SSL Labs Server Test][qualys-ssl] are good resources for finding
@@ -56,7 +57,7 @@ Some resources on implementing Subresource Integrity:
-->
-### Including external resources
+## Including external resources
External fonts, CSS, and JavaScript should never be used with the exception of
Google Analytics and Piwik - and only when the instance has enabled it. Assets
@@ -64,7 +65,7 @@ should always be hosted and served locally from the GitLab instance. Embedded
resources via `iframes` should never be used except in certain circumstances
such as with ReCaptcha, which cannot be used without an `iframe`.
-### Avoiding inline scripts and styles
+## Avoiding inline scripts and styles
In order to protect users from [XSS vulnerabilities][xss], we will disable
inline scripts in the future using Content Security Policy.
diff --git a/doc/development/fe_guide/style_guide_scss.md b/doc/development/fe_guide/style_guide_scss.md
index b25dce65ffe..5220c9eeea3 100644
--- a/doc/development/fe_guide/style_guide_scss.md
+++ b/doc/development/fe_guide/style_guide_scss.md
@@ -6,6 +6,7 @@ easy to maintain, and performant for the end-user.
## Rules
### Utility Classes
+
As part of the effort for [cleaning up our CSS and moving our components into GitLab-UI](https://gitlab.com/groups/gitlab-org/-/epics/950)
led by the [GitLab UI WG](https://gitlab.com/gitlab-com/www-gitlab-com/merge_requests/20623) we prefer the use of utility classes over adding new CSS. However, complex CSS can be addressed by adding component classes.
@@ -31,12 +32,12 @@ New utility classes should be added to [`utilities.scss`](https://gitlab.com/git
#### When should I create component classes?
-We recommend a "utility-first" approach.
+We recommend a "utility-first" approach.
1. Start with utility classes.
2. If composing utility classes into a component class removes code duplication and encapsulates a clear responsibility, do it.
-This encourages an organic growth of component classes and prevents the creation of one-off unreusable classes. Also, the kind of classes that emerge from "utility-first" tend to be design-centered (e.g. `.button`, `.alert`, `.card`) rather than domain-centered (e.g. `.security-report-widget`, `.commit-header-icon`).
+This encourages an organic growth of component classes and prevents the creation of one-off unreusable classes. Also, the kind of classes that emerge from "utility-first" tend to be design-centered (e.g. `.button`, `.alert`, `.card`) rather than domain-centered (e.g. `.security-report-widget`, `.commit-header-icon`).
Examples of component classes that were created using "utility-first" include:
@@ -45,8 +46,8 @@ Examples of component classes that were created using "utility-first" include:
Inspiration:
-- https://tailwindcss.com/docs/utility-first
-- https://tailwindcss.com/docs/extracting-components
+- <https://tailwindcss.com/docs/utility-first>
+- <https://tailwindcss.com/docs/extracting-components>
### Naming
diff --git a/doc/development/fe_guide/vue.md b/doc/development/fe_guide/vue.md
index 020eede8a03..6c7572352ec 100644
--- a/doc/development/fe_guide/vue.md
+++ b/doc/development/fe_guide/vue.md
@@ -49,7 +49,9 @@ provided as a prop to the main component.
Be sure to read about [page-specific JavaScript][page_specific_javascript].
### Bootstrapping Gotchas
+
#### Providing data from HAML to JavaScript
+
While mounting a Vue application may be a need to provide data from Rails to JavaScript.
To do that, provide the data through `data` attributes in the HTML element and query them while mounting the application.
@@ -83,7 +85,8 @@ document.addEventListener('DOMContentLoaded', () => new Vue({
```
#### Accessing the `gl` object
-When we need to query the `gl` object for data that won't change during the application's life cyle, we should do it in the same place where we query the DOM.
+
+When we need to query the `gl` object for data that won't change during the application's life cycle, we should do it in the same place where we query the DOM.
By following this practice, we can avoid the need to mock the `gl` object, which will make tests easier.
It should be done while initializing our Vue instance, and the data should be provided as `props` to the main component:
@@ -118,6 +121,7 @@ You can read more about components in Vue.js site, [Component System][component-
### A folder for the Store
#### Vuex
+
Check this [page](vuex.md) for more details.
### Mixing Vue and jQuery
@@ -212,6 +216,7 @@ describe('Todos App', () => {
```
### `mountComponent` helper
+
There is a helper in `spec/javascripts/helpers/vue_mount_component_helper.js` that allows you to mount a component with the given props:
```javascript
@@ -225,10 +230,12 @@ const vm = mountComponent(Component, data);
```
### Test the component's output
+
The main return value of a Vue component is the rendered output. In order to test the component we
need to test the rendered output. [Vue][vue-test] guide's to unit test show us exactly that:
## Vue.js Expert Role
+
One should apply to be a Vue.js expert by opening an MR when the Merge Request's they create and review show:
- Deep understanding of Vue and Vuex reactivy
diff --git a/doc/development/feature_flags/controls.md b/doc/development/feature_flags/controls.md
index c67467b7c11..739f4207e27 100644
--- a/doc/development/feature_flags/controls.md
+++ b/doc/development/feature_flags/controls.md
@@ -5,7 +5,7 @@ GitLab Inc. provided environments such as staging and production, you need to
have access to the chatops bot. Chatops bot is currently running on the ops instance,
which is different from GitLab.com or dev.gitlab.org.
-Follow the Chatops document to [request access](https://docs.gitlab.com/ee/development/chatops_on_gitlabcom.html#requesting-access).
+Follow the Chatops document to [request access](../chatops_on_gitlabcom.md#requesting-access).
Once you are added to the project test if your access propagated,
run:
@@ -112,7 +112,7 @@ 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, make sure to also add the
appropriate "Pick into X" label (e.g. "Pick into XX.X").
-See [the process document](https://docs.gitlab.com/ee/development/feature_flags/process.html#including-a-feature-behind-feature-flag-in-the-final-release) for further details.
+See [the process document](process.md#including-a-feature-behind-feature-flag-in-the-final-release) for further details.
When a feature gate has been removed from the code base, the value still exists
in the database.
diff --git a/doc/development/feature_flags/development.md b/doc/development/feature_flags/development.md
index 238052529d9..98773026122 100644
--- a/doc/development/feature_flags/development.md
+++ b/doc/development/feature_flags/development.md
@@ -57,7 +57,7 @@ the feature flag check will default to `true`.
As an example, if you were to ship the backend half of a feature behind a flag,
you'd want to explicitly disable that flag until the frontend half is also ready
-to be shipped. [You can do this via Chatops](https://docs.gitlab.com/ee/development/feature_flags/controls.html):
+to be shipped. [You can do this via Chatops](controls.md):
```
/chatops run feature set some_feature 0
diff --git a/doc/development/feature_flags/process.md b/doc/development/feature_flags/process.md
index ee142b0da66..28d6080ce87 100644
--- a/doc/development/feature_flags/process.md
+++ b/doc/development/feature_flags/process.md
@@ -1,4 +1,5 @@
# Feature flags process
+
## Feature flags for user applications
This document only covers feature flags used in the development of GitLab
@@ -12,12 +13,12 @@ should be leveraged:
- By default, the feature flags should be **off**.
- Feature flags should remain in the codebase for as short period as possible
-to reduce the need for feature flag accounting.
+ to reduce the need for feature flag accounting.
- The person operating with feature flags is responsible for clearly communicating
-the status of a feature behind the feature flag with responsible stakeholders.
+ the status of a feature behind the feature flag with responsible stakeholders.
- Merge requests that make changes hidden behind a feature flag, or remove an
-existing feature flag because a feature is deemed stable must have the
-~"feature flag" label assigned.
+ existing feature flag because a feature is deemed stable must have the
+ ~"feature flag" label assigned.
One might be tempted to think that feature flags will delay the release of a
feature by at least one month (= one release). This is not the case. A feature
@@ -64,12 +65,12 @@ to be included in the final self-managed release.
In addition to this, the feature behind feature flag should:
- Run in all GitLab.com environments for a sufficient period of time. This time
-period depends on the feature behind the feature flag, but as a general rule of
-thumb 2-4 working days should be sufficient to gather enough feedback.
+ period depends on the feature behind the feature flag, but as a general rule of
+ thumb 2-4 working days should be sufficient to gather enough feedback.
- The feature should be exposed to all users within the GitLab.com plan during
-the above mentioned period of time. Exposing the feature to a smaller percentage
-or only a group of users might not expose a sufficient amount of information to aid in
-making a decision on feature stability.
+ the above mentioned period of time. Exposing the feature to a smaller percentage
+ or only a group of users might not expose a sufficient amount of information to aid in
+ making a decision on feature stability.
While rare, release managers may decide to reject picking or revert a change in
a stable branch, even when feature flags are used. This might be necessary if
diff --git a/doc/development/file_storage.md b/doc/development/file_storage.md
index 18e4dc2ca0c..02874d18a30 100644
--- a/doc/development/file_storage.md
+++ b/doc/development/file_storage.md
@@ -33,9 +33,9 @@ they are still not 100% standardized. You can see them below:
| User avatars | yes | uploads/-/system/user/avatar/:id/:filename | `AvatarUploader` | User |
| User snippet attachments | yes | uploads/-/system/personal_snippet/:id/:random_hex/:filename | `PersonalFileUploader` | Snippet |
| Project avatars | yes | uploads/-/system/project/avatar/:id/:filename | `AvatarUploader` | Project |
-| Issues/MR/Notes Markdown attachments | yes | uploads/:project_path_with_namespace/:random_hex/:filename | `FileUploader` | Project |
-| Issues/MR/Notes Legacy Markdown attachments | no | uploads/-/system/note/attachment/:id/:filename | `AttachmentUploader` | Note |
-| CI Artifacts (CE) | yes | shared/artifacts/:disk_hash[0..1]/:disk_hash[2..3]/:disk_hash/:year_:month_:date/:job_id/:job_artifact_id (:disk_hash is SHA256 digest of project_id) | `JobArtifactUploader` | Ci::JobArtifact |
+| Issues/MR/Notes Markdown attachments | yes | uploads/:project_path_with_namespace/:random_hex/:filename | `FileUploader` | Project |
+| Issues/MR/Notes Legacy Markdown attachments | no | uploads/-/system/note/attachment/:id/:filename | `AttachmentUploader` | Note |
+| CI Artifacts (CE) | yes | `shared/artifacts/:disk_hash[0..1]/:disk_hash[2..3]/:disk_hash/:year_:month_:date/:job_id/:job_artifact_id` (:disk_hash is SHA256 digest of project_id) | `JobArtifactUploader` | Ci::JobArtifact |
| LFS Objects (CE) | yes | shared/lfs-objects/:hex/:hex/:object_hash | `LfsObjectUploader` | LfsObject |
| External merge request diffs | yes | shared/external-diffs/merge_request_diffs/mr-:parent_id/diff-:id | `ExternalDiffUploader` | MergeRequestDiff |
diff --git a/doc/development/geo.md b/doc/development/geo.md
index a10f13b069f..685d4e44ad3 100644
--- a/doc/development/geo.md
+++ b/doc/development/geo.md
@@ -1,4 +1,4 @@
-# Geo (development) **[PREMIUM ONLY]**
+# Geo (development) **(PREMIUM ONLY)**
Geo connects GitLab instances together. One GitLab instance is
designated as a **primary** node and can be run with multiple
diff --git a/doc/development/git_object_deduplication.md b/doc/development/git_object_deduplication.md
index b512d7611d3..c103a4527ff 100644
--- a/doc/development/git_object_deduplication.md
+++ b/doc/development/git_object_deduplication.md
@@ -113,7 +113,7 @@ are as follows:
(`pool.source_project`)
> TODO Fix invalid SQL data for pools created prior to GitLab 11.11
-> https://gitlab.com/gitlab-org/gitaly/issues/1653.
+> <https://gitlab.com/gitlab-org/gitaly/issues/1653>.
### Assumptions
@@ -157,7 +157,7 @@ are as follows:
repository.
> TODO should forks of forks be deduplicated?
-> https://gitlab.com/gitlab-org/gitaly/issues/1532
+> <https://gitlab.com/gitlab-org/gitaly/issues/1532>
### Consequences
@@ -215,4 +215,4 @@ the secondary, at which stage Git objects will get deduplicated.
> TODO How do we handle the edge case where at the time the Geo
> secondary tries to create the pool repository, the source project does
-> not exist? https://gitlab.com/gitlab-org/gitaly/issues/1533
+> not exist? <https://gitlab.com/gitlab-org/gitaly/issues/1533>
diff --git a/doc/development/go_guide/index.md b/doc/development/go_guide/index.md
index 4dad8815fcb..f09339eb3a4 100644
--- a/doc/development/go_guide/index.md
+++ b/doc/development/go_guide/index.md
@@ -41,7 +41,7 @@ of possible security breaches in our code:
Remember to run
[SAST](../../user/application_security/sast/index.md)
-**[ULTIMATE]** on your project (or at least the [gosec
+**(ULTIMATE)** on your project (or at least the [gosec
analyzer](https://gitlab.com/gitlab-org/security-products/analyzers/gosec)),
and to follow our [Security
requirements](../code_review.md#security-requirements).
@@ -82,7 +82,7 @@ go lint:
image: golang:1.11
script:
- go get -u golang.org/x/lint/golint
- - golint -set_exit_status
+ - golint -set_exit_status $(go list ./... | grep -v "vendor/")
```
Once [recursive includes](https://gitlab.com/gitlab-org/gitlab-ce/issues/56836)
@@ -95,9 +95,9 @@ Dependencies should be kept to the minimum. The introduction of a new
dependency should be argued in the merge request, as per our [Approval
Guidelines](../code_review.md#approval-guidelines). Both [License
Management](../../user/project/merge_requests/license_management.md)
-**[ULTIMATE]** and [Dependency
+**(ULTIMATE)** and [Dependency
Scanning](../../user/application_security/dependency_scanning/index.md)
-**[ULTIMATE]** should be activated on all projects to ensure new dependencies
+**(ULTIMATE)** should be activated on all projects to ensure new dependencies
security status and license compatibility.
### Modules
diff --git a/doc/development/gotchas.md b/doc/development/gotchas.md
index 1b9ebb50c29..13dda17bb7d 100644
--- a/doc/development/gotchas.md
+++ b/doc/development/gotchas.md
@@ -101,10 +101,10 @@ end
in a prepended module, which is very likely the case in EE. We could see
error like this:
- ```
- 1.1) Failure/Error: expect_any_instance_of(ApplicationSetting).to receive_messages(messages)
- Using `any_instance` to stub a method (elasticsearch_indexing) that has been defined on a prepended module (EE::ApplicationSetting) is not supported.
- ```
+ ```
+ 1.1) Failure/Error: expect_any_instance_of(ApplicationSetting).to receive_messages(messages)
+ Using `any_instance` to stub a method (elasticsearch_indexing) that has been defined on a prepended module (EE::ApplicationSetting) is not supported.
+ ```
### Alternative: `expect_next_instance_of`
diff --git a/doc/development/integrations/jira_connect.md b/doc/development/integrations/jira_connect.md
index 5bf43d320c6..9ba3b922fd8 100644
--- a/doc/development/integrations/jira_connect.md
+++ b/doc/development/integrations/jira_connect.md
@@ -4,7 +4,7 @@ The following are required to install and test the app:
1. A Jira Cloud instance
- Atlassian provides free instances for development and testing. [Click here to sign up](http://go.atlassian.com/cloud-dev).
+ Atlassian provides free instances for development and testing. [Click here to sign up](https://developer.atlassian.com/platform/marketplace/getting-started/#free-developer-instances-to-build-and-test-your-app).
1. A GitLab instance available over the internet
@@ -15,7 +15,7 @@ The following are required to install and test the app:
> This feature is currently behind the `:jira_connect_app` feature flag
-# Installing the app in Jira
+## Installing the app in Jira
1. Enable Jira development mode to install apps that are not from the Atlassian Marketplace
diff --git a/doc/development/licensed_feature_availability.md b/doc/development/licensed_feature_availability.md
index 6f3dd59b2c3..80ec7b8c0cf 100644
--- a/doc/development/licensed_feature_availability.md
+++ b/doc/development/licensed_feature_availability.md
@@ -1,18 +1,18 @@
-# Licensed feature availability **[STARTER]**
+# Licensed feature availability **(STARTER)**
-As of GitLab 9.4, we've been supporting a simplified version of licensed
-feature availability checks via `ee/app/models/license.rb`, both for
+As of GitLab 9.4, we've been supporting a simplified version of licensed
+feature availability checks via `ee/app/models/license.rb`, both for
on-premise or GitLab.com plans and features.
## Restricting features scoped by namespaces or projects
GitLab.com plans are persisted on user groups and namespaces, therefore, if you're adding a
-feature such as [Related issues](../user/project/issues/related_issues.md) or
-[Service desk](../user/project/service_desk.md),
+feature such as [Related issues](../user/project/issues/related_issues.md) or
+[Service desk](../user/project/service_desk.md),
it should be restricted on namespace scope.
-1. Add the feature symbol on `EES_FEATURES`, `EEP_FEATURES` or `EEU_FEATURES` constants in
- `ee/app/models/license.rb`. Note on `ee/app/models/ee/namespace.rb` that _Bronze_ GitLab.com
+1. Add the feature symbol on `EES_FEATURES`, `EEP_FEATURES` or `EEU_FEATURES` constants in
+ `ee/app/models/license.rb`. Note on `ee/app/models/ee/namespace.rb` that _Bronze_ GitLab.com
features maps to on-premise _EES_, _Silver_ to _EEP_ and _Gold_ to _EEU_.
2. Check using:
@@ -22,12 +22,12 @@ project.feature_available?(:feature_symbol)
## Restricting global features (instance)
-However, for features such as [Geo](../administration/geo/replication/index.md) and
-[Load balancing](../administration/database_load_balancing.md), which cannot be restricted
-to only a subset of projects or namespaces, the check will be made directly in
+However, for features such as [Geo](../administration/geo/replication/index.md) and
+[Load balancing](../administration/database_load_balancing.md), which cannot be restricted
+to only a subset of projects or namespaces, the check will be made directly in
the instance license.
-1. Add the feature symbol on `EES_FEATURES`, `EEP_FEATURES` or `EEU_FEATURES` constants in
+1. Add the feature symbol on `EES_FEATURES`, `EEP_FEATURES` or `EEU_FEATURES` constants in
`ee/app/models/license.rb`.
2. Add the same feature symbol to `GLOBAL_FEATURES`
3. Check using:
diff --git a/doc/development/logging.md b/doc/development/logging.md
index d61441813b2..4f63c84fc0e 100644
--- a/doc/development/logging.md
+++ b/doc/development/logging.md
@@ -30,8 +30,8 @@ Completed 200 OK in 166ms (Views: 117.4ms | ActiveRecord: 27.2ms)
These logs suffer from a number of problems:
1. They often lack timestamps or other contextual information (e.g. project ID, user)
-2. They may span multiple lines, which make them hard to find via Elasticsearch.
-3. They lack a common structure, which make them hard to parse by log
+1. They may span multiple lines, which make them hard to find via Elasticsearch.
+1. They lack a common structure, which make them hard to parse by log
forwarders, such as Logstash or Fluentd. This also makes them hard to
search.
@@ -67,46 +67,46 @@ importer progresses. Here's what to do:
make it easy for people to search pertinent logs in one place. For
example, `geo.log` contains all logs pertaining to GitLab Geo.
To create a new file:
- 1. Choose a filename (e.g. `importer_json.log`).
- 1. Create a new subclass of `Gitlab::JsonLogger`:
-
- ```ruby
- module Gitlab
- module Import
- class Logger < ::Gitlab::JsonLogger
- def self.file_name_noext
- 'importer'
- end
+ 1. Choose a filename (e.g. `importer_json.log`).
+ 1. Create a new subclass of `Gitlab::JsonLogger`:
+
+ ```ruby
+ module Gitlab
+ module Import
+ class Logger < ::Gitlab::JsonLogger
+ def self.file_name_noext
+ 'importer'
end
- end
- end
- ```
+ end
+ end
+ end
+ ```
- 1. In your class where you want to log, you might initialize the logger as an instance variable:
+ 1. In your class where you want to log, you might initialize the logger as an instance variable:
- ```ruby
- attr_accessor :logger
+ ```ruby
+ attr_accessor :logger
- def initialize
- @logger = Gitlab::Import::Logger.build
- end
- ```
+ def initialize
+ @logger = Gitlab::Import::Logger.build
+ end
+ ```
- Note that it's useful to memoize this because creating a new logger
- each time you log will open a file, adding unnecessary overhead.
+ Note that it's useful to memoize this because creating a new logger
+ each time you log will open a file, adding unnecessary overhead.
1. Now insert log messages into your code. When adding logs,
make sure to include all the context as key-value pairs:
- ```ruby
- # BAD
- logger.info("Unable to create project #{project.id}")
- ```
+ ```ruby
+ # BAD
+ logger.info("Unable to create project #{project.id}")
+ ```
- ```ruby
- # GOOD
- logger.info(message: "Unable to create project", project_id: project.id)
- ```
+ ```ruby
+ # GOOD
+ logger.info(message: "Unable to create project", project_id: project.id)
+ ```
1. Be sure to create a common base structure of your log messages. For example,
all messages might have `current_user_id` and `project_id` to make it easier
@@ -116,16 +116,16 @@ importer progresses. Here's what to do:
logs properly if you [mix integer and string
types](https://www.elastic.co/guide/en/elasticsearch/guide/current/mapping.html#_avoiding_type_gotchas):
- ```ruby
- # BAD
- logger.info(message: "Import error", error: 1)
- logger.info(message: "Import error", error: "I/O failure")
- ```
+ ```ruby
+ # BAD
+ logger.info(message: "Import error", error: 1)
+ logger.info(message: "Import error", error: "I/O failure")
+ ```
- ```ruby
- # GOOD
- logger.info(message: "Import error", error_code: 1, error: "I/O failure")
- ```
+ ```ruby
+ # GOOD
+ logger.info(message: "Import error", error_code: 1, error: "I/O failure")
+ ```
## Additional steps with new log files
diff --git a/doc/development/migration_style_guide.md b/doc/development/migration_style_guide.md
index 9b26f691b55..0c7601b415e 100644
--- a/doc/development/migration_style_guide.md
+++ b/doc/development/migration_style_guide.md
@@ -21,7 +21,7 @@ When downtime is necessary the migration has to be approved by:
1. A Database Specialist
An up-to-date list of people holding these titles can be found at
-<https://about.gitlab.com/team/>.
+<https://about.gitlab.com/company/team/>.
When writing your migrations, also consider that databases might have stale data
or inconsistencies and guard for that. Try to make as few assumptions as
diff --git a/doc/development/new_fe_guide/development/components.md b/doc/development/new_fe_guide/development/components.md
index 963ce53423b..cebdc87eab9 100644
--- a/doc/development/new_fe_guide/development/components.md
+++ b/doc/development/new_fe_guide/development/components.md
@@ -13,7 +13,7 @@ D3 is very popular across many projects outside of GitLab:
- [The New York Times](https://archive.nytimes.com/www.nytimes.com/interactive/2012/02/13/us/politics/2013-budget-proposal-graphic.html)
- [plot.ly](https://plot.ly/)
-- [Droptask](https://www.droptask.com/)
+- [Droptask](https://www.ayoa.com/previously-droptask/)
Within GitLab, D3 has been used for the following notable features
diff --git a/doc/development/new_fe_guide/development/performance.md b/doc/development/new_fe_guide/development/performance.md
index 640a8d64176..c54b8305991 100644
--- a/doc/development/new_fe_guide/development/performance.md
+++ b/doc/development/new_fe_guide/development/performance.md
@@ -2,10 +2,10 @@
## Monitoring
-We have a performance dashboard available in one of our [grafana instances](https://dashboards.gitlab.net/d/1EBTz3Dmz/sitespeed-page-summary?orgId=1). This dashboard automatically aggregates metric data from [sitespeed.io](https://sitespeed.io) every 6 hours. These changes are displayed after a set number of pages are aggregated.
+We have a performance dashboard available in one of our [grafana instances](https://dashboards.gitlab.net/d/1EBTz3Dmz/sitespeed-page-summary?orgId=1). This dashboard automatically aggregates metric data from [sitespeed.io](https://www.sitespeed.io/) every 6 hours. These changes are displayed after a set number of pages are aggregated.
These pages can be found inside a text file in the gitlab-build-images [repository](https://gitlab.com/gitlab-org/gitlab-build-images) called [gitlab.txt](https://gitlab.com/gitlab-org/gitlab-build-images/blob/master/scripts/gitlab.txt)
-Any frontend engineer can contribute to this dashboard. They can contribute by adding or removing urls of pages from this text file. Please have a [frontend monitoring expert](https://about.gitlab.com/team) review your changes before assigning to a maintainer of the `gitlab-build-images` project. The changes will go live on the next scheduled run after the changes are merged into `master`.
+Any frontend engineer can contribute to this dashboard. They can contribute by adding or removing urls of pages from this text file. Please have a [frontend monitoring expert](https://about.gitlab.com/company/team) review your changes before assigning to a maintainer of the `gitlab-build-images` project. The changes will go live on the next scheduled run after the changes are merged into `master`.
There are 3 recommended high impact metrics to review on each page:
diff --git a/doc/development/new_fe_guide/development/testing.md b/doc/development/new_fe_guide/development/testing.md
index 8441089418e..2b62c2a41fe 100644
--- a/doc/development/new_fe_guide/development/testing.md
+++ b/doc/development/new_fe_guide/development/testing.md
@@ -261,7 +261,7 @@ scenario 'successfully', :js do
end
```
-The steps of each test are written using capybara methods ([documentation](http://www.rubydoc.info/gems/capybara/2.15.1)).
+The steps of each test are written using capybara methods ([documentation](https://www.rubydoc.info/gems/capybara/2.15.1)).
Bear in mind <abbr title="XMLHttpRequest">XHR</abbr> calls might require you to use `wait_for_requests` in between steps, like so:
@@ -277,7 +277,7 @@ expect(page).not_to have_selector('.card')
### Vuex Helper: `testAction`
-We have a helper available to make testing actions easier, as per [official documentation](https://vuex.vuejs.org/en/testing.html):
+We have a helper available to make testing actions easier, as per [official documentation](https://vuex.vuejs.org/guide/testing.html):
```
testAction(
diff --git a/doc/development/new_fe_guide/style/html.md b/doc/development/new_fe_guide/style/html.md
index e8c9c2ccebf..1445da3f0e1 100644
--- a/doc/development/new_fe_guide/style/html.md
+++ b/doc/development/new_fe_guide/style/html.md
@@ -16,7 +16,7 @@ Button tags requires a `type` attribute according to the [W3C HTML specification
### Button role
-If an HTML element has an `onClick` handler but is not a button, it should have `role="button"`. This is [more accessible](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Techniques/Using_the_button_role).
+If an HTML element has an `onClick` handler but is not a button, it should have `role="button"`. This is [more accessible](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/button_role).
```html
// bad
diff --git a/doc/development/newlines_styleguide.md b/doc/development/newlines_styleguide.md
index 5f7210020b6..a13adc2f13e 100644
--- a/doc/development/newlines_styleguide.md
+++ b/doc/development/newlines_styleguide.md
@@ -11,7 +11,7 @@ def method
issue.save
- render json: issue
+ render json: issue
end
```
@@ -21,7 +21,7 @@ def method
issue = Issue.new
issue.save
- render json: issue
+ render json: issue
end
```
diff --git a/doc/development/packages.md b/doc/development/packages.md
index ab0c5f9904d..08aa0b08525 100644
--- a/doc/development/packages.md
+++ b/doc/development/packages.md
@@ -1,15 +1,15 @@
-# Packages **[PREMIUM]**
+# Packages **(PREMIUM)**
This document will guide you through adding another [package management system](../administration/packages.md) support to GitLab.
See already supported package types in [Packages documentation](../administration/packages.md)
Since GitLab packages' UI is pretty generic, it is possible to add new
-package system support by solely backend changes. This guide is superficial and does
-not cover the way the code should be written. However, you can find a good example
-by looking at existing merge requests with Maven and NPM support:
+package system support by solely backend changes. This guide is superficial and does
+not cover the way the code should be written. However, you can find a good example
+by looking at existing merge requests with Maven and NPM support:
-- [NPM registry support](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/8673).
+- [NPM registry support](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/8673).
- [Maven repository](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/6607).
- [Instance level endpoint for Maven repository](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/8757)
@@ -17,44 +17,44 @@ by looking at existing merge requests with Maven and NPM support:
The existing database model requires the following:
-- Every package belongs to a project.
+- Every package belongs to a project.
- Every package file belongs to a package.
- A package can have one or more package files.
- The package model is based on storing information about the package and its version.
## API endpoints
-Package systems work with GitLab via API. For example `ee/lib/api/npm_packages.rb`
-implements API endpoints to work with NPM clients. So, the first thing to do is to
-add a new `ee/lib/api/your_name_packages.rb` file with API endpoints that are
-necessary to make the package system client to work. Usually that means having
-endpoints like:
+Package systems work with GitLab via API. For example `ee/lib/api/npm_packages.rb`
+implements API endpoints to work with NPM clients. So, the first thing to do is to
+add a new `ee/lib/api/your_name_packages.rb` file with API endpoints that are
+necessary to make the package system client to work. Usually that means having
+endpoints like:
- GET package information.
- GET package file content.
- PUT upload package.
Since the packages belong to a project, it's expected to have project-level endpoint
-for uploading and downloading them. For example:
+for uploading and downloading them. For example:
```
GET https://gitlab.com/api/v4/projects/<your_project_id>/packages/npm/
PUT https://gitlab.com/api/v4/projects/<your_project_id>/packages/npm/
```
-Group-level and instance-level endpoints are good to have but are optional.
+Group-level and instance-level endpoints are good to have but are optional.
NOTE: **Note:**
-To avoid name conflict for instance-level endpoints we use
+To avoid name conflict for instance-level endpoints we use
[the package naming convention](../user/project/packages/npm_registry.md#package-naming-convention)
## Configuration
-GitLab has a `packages` section in its configuration file (`gitlab.rb`).
-It applies to all package systems supported by GitLab. Usually you don't need
-to add anything there.
+GitLab has a `packages` section in its configuration file (`gitlab.rb`).
+It applies to all package systems supported by GitLab. Usually you don't need
+to add anything there.
-Packages can be configured to use object storage, therefore your code must support it.
+Packages can be configured to use object storage, therefore your code must support it.
## Database
@@ -63,6 +63,6 @@ Every time you upload a new package, you can either create a new record of `Pack
or add files to existing record. `PackageFile` should be able to store all file-related
information like the file `name`, `side`, `sha1`, etc.
-If there is specific data necessary to be stored for only one package system support,
-consider creating a separate metadata model. See `packages_maven_metadata` table
+If there is specific data necessary to be stored for only one package system support,
+consider creating a separate metadata model. See `packages_maven_metadata` table
and `Packages::MavenMetadatum` model as example for package specific data.
diff --git a/doc/development/performance.md b/doc/development/performance.md
index 0e21d45f57c..c034f4a344b 100644
--- a/doc/development/performance.md
+++ b/doc/development/performance.md
@@ -424,7 +424,7 @@ might find using these gems more convenient:
### Examples
You may find some useful examples in this snippet:
-https://gitlab.com/gitlab-org/gitlab-ce/snippets/33946
+<https://gitlab.com/gitlab-org/gitlab-ce/snippets/33946>
[#15607]: https://gitlab.com/gitlab-org/gitlab-ce/issues/15607
[yorickpeterse]: https://gitlab.com/yorickpeterse
diff --git a/doc/development/profiling.md b/doc/development/profiling.md
index 795523b82aa..e1d1d2e33fa 100644
--- a/doc/development/profiling.md
+++ b/doc/development/profiling.md
@@ -95,7 +95,9 @@ Sherlock is a custom profiling tool built into GitLab. Sherlock is _only_
available when running GitLab in development mode _and_ when setting the
environment variable `ENABLE_SHERLOCK` to a non empty value. For example:
- ENABLE_SHERLOCK=1 bundle exec rails s
+```sh
+ENABLE_SHERLOCK=1 bundle exec rails s
+```
Recorded transactions can be found by navigating to `/sherlock/transactions`.
@@ -106,7 +108,9 @@ Bullet adds quite a bit of logging noise it's disabled by default. To enable
Bullet, set the environment variable `ENABLE_BULLET` to a non-empty value before
starting GitLab. For example:
- ENABLE_BULLET=true bundle exec rails s
+```sh
+ENABLE_BULLET=true bundle exec rails s
+```
Bullet will log query problems to both the Rails log as well as the Chrome
console.
diff --git a/doc/development/pry_debugging.md b/doc/development/pry_debugging.md
index de5e1323e6a..17d8428b0c0 100644
--- a/doc/development/pry_debugging.md
+++ b/doc/development/pry_debugging.md
@@ -73,7 +73,7 @@ Similar to source browsing, is [Documentation browsing](https://github.com/pry/p
### Command history
-With <kdb>Ctrl+R</kbd> you can search your [command history](https://github.com/pry/pry/wiki/History).
+With **Ctrl+R** you can search your [command history](https://github.com/pry/pry/wiki/History).
## Stepping
diff --git a/doc/development/python_guide/index.md b/doc/development/python_guide/index.md
index 6025dc9ebf2..a80bee27d4a 100644
--- a/doc/development/python_guide/index.md
+++ b/doc/development/python_guide/index.md
@@ -36,7 +36,7 @@ You can read more about it in: <https://github.com/pyenv/pyenv-installer#prerequ
Pyenv installation will add required changes to Bash. If you use a different shell,
check for any additional steps required for it.
-For Fish, you can install a plugin for [Fisherman](https://github.com/fisherman/fisherman):
+For Fish, you can install a plugin for [Fisher](https://github.com/jorgebucaran/fisher):
```bash
fisher add fisherman/pyenv
@@ -76,4 +76,3 @@ pipenv shell
After running that command, you can run GitLab on the same shell and it will be using the Python and dependencies
installed from the `pipenv install` command.
-
diff --git a/doc/development/query_recorder.md b/doc/development/query_recorder.md
index 2167ed57428..a6b60149ea4 100644
--- a/doc/development/query_recorder.md
+++ b/doc/development/query_recorder.md
@@ -1,6 +1,6 @@
# QueryRecorder
-QueryRecorder is a tool for detecting the [N+1 queries problem](http://guides.rubyonrails.org/active_record_querying.html#eager-loading-associations) from tests.
+QueryRecorder is a tool for detecting the [N+1 queries problem](https://guides.rubyonrails.org/active_record_querying.html#eager-loading-associations) from tests.
> Implemented in [spec/support/query_recorder.rb](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/spec/support/helpers/query_recorder.rb) via [9c623e3e](https://gitlab.com/gitlab-org/gitlab-ce/commit/9c623e3e5d7434f2e30f7c389d13e5af4ede770a)
@@ -86,4 +86,4 @@ QueryRecorder SQL: SELECT COUNT(*) FROM "issues" WHERE "issues"."deleted_at" IS
- [Bullet](profiling.md#Bullet) For finding `N+1` query problems
- [Performance guidelines](performance.md)
-- [Merge request performance guidelines](merge_request_performance_guidelines.md#query-counts) \ No newline at end of file
+- [Merge request performance guidelines](merge_request_performance_guidelines.md#query-counts)
diff --git a/doc/development/rake_tasks.md b/doc/development/rake_tasks.md
index 4fc10b6af5c..c97e179910b 100644
--- a/doc/development/rake_tasks.md
+++ b/doc/development/rake_tasks.md
@@ -28,7 +28,7 @@ bin/rake "gitlab:seed:issues[group-path/project-path]"
By default, this seeds an average of 2 issues per week for the last 5 weeks per
project.
-#### Seeding issues for Insights charts **[ULTIMATE]**
+#### Seeding issues for Insights charts **(ULTIMATE)**
You can seed issues specifically for working with the
[Insights charts](../user/group/insights/index.md) with the
diff --git a/doc/development/routing.md b/doc/development/routing.md
index e9c0ad8d4e8..a25eb48b73c 100644
--- a/doc/development/routing.md
+++ b/doc/development/routing.md
@@ -7,11 +7,15 @@ support subgroups, GitLab project and group routes use the wildcard
character to match project and group routes. For example, we might have
a path such as:
- /gitlab-com/customer-success/north-america/west/customerA
+```
+/gitlab-com/customer-success/north-america/west/customerA
+```
However, paths can be ambiguous. Consider the following example:
- /gitlab-com/edit
+```
+/gitlab-com/edit
+```
It's ambiguous whether there is a subgroup named `edit` or whether
this is a special endpoint to edit the `gitlab-com` group.
@@ -25,8 +29,10 @@ number of [reserved names](../user/reserved_names.md).
We have a number of global routes. For example:
- /-/health
- /-/metrics
+```
+/-/health
+/-/metrics
+```
## Group routes
@@ -34,10 +40,12 @@ Every group route must be under the `/-/` scope.
Examples:
- gitlab-org/-/edit
- gitlab-org/-/activity
- gitlab-org/-/security/dashboard
- gitlab-org/serverless/-/activity
+```
+gitlab-org/-/edit
+gitlab-org/-/activity
+gitlab-org/-/security/dashboard
+gitlab-org/serverless/-/activity
+```
To achieve that, use the `scope '-'` method.
@@ -48,10 +56,12 @@ client or other software requires something different.
Examples:
- gitlab-org/gitlab-ce/-/activity
- gitlab-org/gitlab-ce/-/jobs/123
- gitlab-org/gitlab-ce/-/settings/repository
- gitlab-org/serverless/runtimes/-/settings/repository
+```
+gitlab-org/gitlab-ce/-/activity
+gitlab-org/gitlab-ce/-/jobs/123
+gitlab-org/gitlab-ce/-/settings/repository
+gitlab-org/serverless/runtimes/-/settings/repository
+```
Currently, only some project routes are placed under the `/-/` scope. However,
you can help us migrate more of them! To migrate project routes:
diff --git a/doc/development/sql.md b/doc/development/sql.md
index edeca7fb298..a256fd46c09 100644
--- a/doc/development/sql.md
+++ b/doc/development/sql.md
@@ -94,7 +94,9 @@ on the amount of data indexed).
To keep naming of these indexes consistent please use the following naming
pattern:
- index_TABLE_on_COLUMN_trigram
+```
+index_TABLE_on_COLUMN_trigram
+```
For example, a GIN/trigram index for `issues.title` would be called
`index_issues_on_title_trigram`.
diff --git a/doc/development/testing_guide/best_practices.md b/doc/development/testing_guide/best_practices.md
index 71e3b7740cb..448d9fd01c4 100644
--- a/doc/development/testing_guide/best_practices.md
+++ b/doc/development/testing_guide/best_practices.md
@@ -327,7 +327,7 @@ However, if a spec makes direct Redis calls, it should mark itself with the
`:clean_gitlab_redis_queues` traits as appropriate.
Sidekiq jobs are typically not run in specs, but this behaviour can be altered
-in each spec through the use of `Sidekiq::Testing.inline!` blocks. Any spec that
+in each spec through the use of `perform_enqueued_jobs` blocks. Any spec that
causes Sidekiq jobs to be pushed to Redis should use the `:sidekiq` trait, to
ensure that they are removed once the spec completes.
diff --git a/doc/development/testing_guide/ci.md b/doc/development/testing_guide/ci.md
index 7a7fca46534..87d48726268 100644
--- a/doc/development/testing_guide/ci.md
+++ b/doc/development/testing_guide/ci.md
@@ -1,6 +1,6 @@
# GitLab tests in the Continuous Integration (CI) context
-### Test suite parallelization on the CI
+## Test suite parallelization on the CI
Our current CI parallelization setup is as follows:
@@ -26,7 +26,7 @@ Our current CI parallelization setup is as follows:
After that, the next pipeline will use the up-to-date
`knapsack/${CI_PROJECT_NAME}/rspec_report-master.json` file.
-### Monitoring
+## Monitoring
The GitLab test suite is [monitored] for the `master` branch, and any branch
that includes `rspec-profile` in their name.
diff --git a/doc/development/testing_guide/end_to_end/index.md b/doc/development/testing_guide/end_to_end/index.md
index 527cd350633..59eb3ecfd7e 100644
--- a/doc/development/testing_guide/end_to_end/index.md
+++ b/doc/development/testing_guide/end_to_end/index.md
@@ -79,7 +79,7 @@ subgraph gitlab-ce/ee pipeline
end
subgraph omnibus-gitlab pipeline
- A2[<b>`Trigger-docker` stage</b></b><br />`Trigger:gitlab-docker` job] -->|once done| B2
+ A2[<b>`Trigger-docker` stage</b><br />`Trigger:gitlab-docker` job] -->|once done| B2
end
subgraph gitlab-qa pipeline
diff --git a/doc/development/testing_guide/end_to_end/quick_start_guide.md b/doc/development/testing_guide/end_to_end/quick_start_guide.md
index 041bdf716b3..064fb0e31dd 100644
--- a/doc/development/testing_guide/end_to_end/quick_start_guide.md
+++ b/doc/development/testing_guide/end_to_end/quick_start_guide.md
@@ -394,15 +394,15 @@ end
By defining the `api_get_path` method, we allow the [`ApiFabricator`](https://gitlab.com/gitlab-org/gitlab-ee/blob/master/qa/qa/resource/api_fabricator.rb) module to know which path to use to get a single issue.
-> This `GET` path can be found in the [public API documentation](https://docs.gitlab.com/ee/api/issues.html#single-issue).
+> This `GET` path can be found in the [public API documentation](../../../api/issues.md#single-issue).
By defining the `api_post_path` method, we allow the [`ApiFabricator`](https://gitlab.com/gitlab-org/gitlab-ee/blob/master/qa/qa/resource/api_fabricator.rb) module to know which path to use to create a new issue in a specific project.
-> This `POST` path can be found in the [public API documentation](https://docs.gitlab.com/ee/api/issues.html#new-issue).
+> This `POST` path can be found in the [public API documentation](../../../api/issues.md#new-issue).
By defining the `api_post_body` method, we allow the [`ApiFabricator.api_post`](https://gitlab.com/gitlab-org/gitlab-ee/blob/a9177ca1812bac57e2b2fa4560e1d5dd8ffac38b/qa/qa/resource/api_fabricator.rb#L68) method to know which data to send when making the `POST` request.
-> Notice that we pass both `labels` and `title` attributes in the `api_post_body`, where `labels` receives an array of labels, and [`title` is required](https://docs.gitlab.com/ee/api/issues.html#new-issue). Also, notice that we keep them alphabetically organized.
+> Notice that we pass both `labels` and `title` attributes in the `api_post_body`, where `labels` receives an array of labels, and [`title` is required](../../../api/issues.md#new-issue). Also, notice that we keep them alphabetically organized.
**Label resource**
@@ -441,7 +441,7 @@ By defining the `api_post_path` method, we allow for the [`ApiFabricator `](http
By defining the `api_post_body` method, we we allow for the [`ApiFabricator.api_post`](https://gitlab.com/gitlab-org/gitlab-ee/blob/a9177ca1812bac57e2b2fa4560e1d5dd8ffac38b/qa/qa/resource/api_fabricator.rb#L68) method to know which data to send when making the `POST` request.
-> Notice that we pass both `color` and `name` attributes in the `api_post_body` since [those are required](https://docs.gitlab.com/ee/api/labels.html#create-a-new-label). Also, notice that we keep them alphabetically organized.
+> Notice that we pass both `color` and `name` attributes in the `api_post_body` since [those are required](../../../api/labels.md#create-a-new-label). Also, notice that we keep them alphabetically organized.
### 8. Page Objects
diff --git a/doc/development/testing_guide/frontend_testing.md b/doc/development/testing_guide/frontend_testing.md
index 28ebb6f0f64..98df0b5ea7c 100644
--- a/doc/development/testing_guide/frontend_testing.md
+++ b/doc/development/testing_guide/frontend_testing.md
@@ -560,7 +560,6 @@ end
[vue-test]: https://docs.gitlab.com/ce/development/fe_guide/vue.html#testing-vue-components
[rspec]: https://github.com/rspec/rspec-rails#feature-specs
[capybara]: https://github.com/teamcapybara/capybara
-[karma]: http://karma-runner.github.io/
[jasmine]: https://jasmine.github.io/
---
diff --git a/doc/development/testing_guide/index.md b/doc/development/testing_guide/index.md
index 93ee2a6371a..aadbea1a540 100644
--- a/doc/development/testing_guide/index.md
+++ b/doc/development/testing_guide/index.md
@@ -11,7 +11,7 @@ importance.
## Overview
-GitLab is built on top of [Ruby on Rails][rails], and we're using [RSpec] for all
+GitLab is built on top of [Ruby on Rails](https://rubyonrails.org/), and we're using [RSpec] for all
the backend tests, with [Capybara] for end-to-end integration testing.
On the frontend side, we're using [Karma] and [Jasmine] for JavaScript unit and
integration testing.
@@ -80,9 +80,6 @@ Everything you should know about how to run end-to-end tests using
[Return to Development documentation](../README.md)
-[^1]: /ci/yaml/README.html#dependencies
-
-[rails]: http://rubyonrails.org/
[RSpec]: https://github.com/rspec/rspec-rails#feature-specs
[Capybara]: https://github.com/teamcapybara/capybara
[Karma]: http://karma-runner.github.io/
diff --git a/doc/development/understanding_explain_plans.md b/doc/development/understanding_explain_plans.md
index bfbb7be70e3..11aafd7b639 100644
--- a/doc/development/understanding_explain_plans.md
+++ b/doc/development/understanding_explain_plans.md
@@ -654,7 +654,6 @@ and related tools such as:
- <https://explain.depesz.com/>
- <http://tatiyants.com/postgres-query-plan-visualization/>
-
## Producing query plans
There are a few ways to get the output of a query plan. Of course you
diff --git a/doc/development/ux_guide/resources.md b/doc/development/ux_guide/resources.md
index baec235a8dd..ae092246d05 100644
--- a/doc/development/ux_guide/resources.md
+++ b/doc/development/ux_guide/resources.md
@@ -1,5 +1,5 @@
---
-redirect_to: 'https://design.gitlab.com/resources/design-resources'
+redirect_to: 'https://design.gitlab.com/resources/design-resources/'
---
-The content of this document was moved into the [GitLab Design System](https://design.gitlab.com/).
+The content of this document was moved into the [GitLab Design System](https://design.gitlab.com/resources/design-resources/).
diff --git a/doc/downgrade_ee_to_ce/README.md b/doc/downgrade_ee_to_ce/README.md
index a187b3cbb07..a3f6f2b327c 100644
--- a/doc/downgrade_ee_to_ce/README.md
+++ b/doc/downgrade_ee_to_ce/README.md
@@ -81,7 +81,7 @@ To downgrade an Omnibus installation, it is sufficient to install the Community
Edition package on top of the currently installed one. You can do this manually,
by directly [downloading the package](https://packages.gitlab.com/gitlab/gitlab-ce)
you need, or by adding our CE package repository and following the
-[CE installation instructions](https://about.gitlab.com/installation/?version=ce).
+[CE installation instructions](https://about.gitlab.com/install/?version=ce).
**Source Installation**
diff --git a/doc/gitlab-basics/README.md b/doc/gitlab-basics/README.md
index 0c268eff9f1..fd16047b8e4 100644
--- a/doc/gitlab-basics/README.md
+++ b/doc/gitlab-basics/README.md
@@ -22,7 +22,7 @@ The following are guides to basic GitLab functionality:
- [Fork a project](fork-project.md), to duplicate projects so they can be worked on in parallel.
- [Add a file](add-file.md), to add new files to a project's repository.
- [Add an image](add-image.md), to add new images to a project's repository.
-- [Create an issue](../user/project/issues/create_new_issue.md), to start collaborating within a project.
+- [Create an issue](../user/project/issues/managing_issues.md#create-a-new-issue), to start collaborating within a project.
- [Create a merge request](add-merge-request.md), to request changes made in a branch be merged into a project's repository.
- See how these features come together in the [GitLab Flow introduction video](https://youtu.be/InKNIvky2KE) and [GitLab Flow page](../workflow/gitlab_flow.md).
diff --git a/doc/gitlab-basics/create-issue.md b/doc/gitlab-basics/create-issue.md
index 6e2a09fc030..5fa5f1bf2e2 100644
--- a/doc/gitlab-basics/create-issue.md
+++ b/doc/gitlab-basics/create-issue.md
@@ -1,5 +1,5 @@
---
-redirect_to: '../user/project/issues/index.md#issue-actions'
+redirect_to: '../user/project/issues/index.md#viewing-and-managing-issues'
---
-This document was moved to [another location](../user/project/issues/index.md#issue-actions).
+This document was moved to [another location](../user/project/issues/index.md#viewing-and-managing-issues).
diff --git a/doc/gitlab-basics/create-project.md b/doc/gitlab-basics/create-project.md
index a9ae4fb23f9..ccba72f0ef8 100644
--- a/doc/gitlab-basics/create-project.md
+++ b/doc/gitlab-basics/create-project.md
@@ -16,7 +16,7 @@ To create a project in GitLab:
- [Import a project](../user/project/import/index.md) from a different repository,
if enabled on your GitLab instance. Contact your GitLab admin if this
is unavailable.
- - Run [CI/CD pipelines for external repositories](../ci/ci_cd_for_external_repos/index.md). **[PREMIUM]**
+ - Run [CI/CD pipelines for external repositories](../ci/ci_cd_for_external_repos/index.md). **(PREMIUM)**
## Blank projects
@@ -69,7 +69,7 @@ TIP: **Tip:**
You can improve the existing built-in templates or contribute new ones on the
[`project-templates`](https://gitlab.com/gitlab-org/project-templates) and [`pages`](https://gitlab.com/pages) groups.
-### Custom project templates **[PREMIUM ONLY]**
+### Custom project templates **(PREMIUM ONLY)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/6860) in
[GitLab Premium](https://about.gitlab.com/pricing) 11.2.
diff --git a/doc/install/README.md b/doc/install/README.md
index 9cc21412898..af98791c8e9 100644
--- a/doc/install/README.md
+++ b/doc/install/README.md
@@ -4,7 +4,7 @@ description: Read through the GitLab installation methods.
type: index
---
-# Installation **[CORE ONLY]**
+# Installation **(CORE ONLY)**
GitLab can be installed in most GNU/Linux distributions and in a number
of cloud providers. To get the best experience from GitLab you need to balance
diff --git a/doc/install/google_cloud_platform/index.md b/doc/install/google_cloud_platform/index.md
index 77c61acbfd4..14bf7012c01 100644
--- a/doc/install/google_cloud_platform/index.md
+++ b/doc/install/google_cloud_platform/index.md
@@ -55,7 +55,7 @@ After a few seconds, the instance will be created and available to log in. The n
![GitLab first sign in](img/ssh_terminal.png)
-1. Next, follow the instructions for installing GitLab for the operating system you choose, at <https://about.gitlab.com/installation/>. You can use the IP address from the step above, as the hostname.
+1. Next, follow the instructions for installing GitLab for the operating system you choose, at <https://about.gitlab.com/install/>. You can use the IP address from the step above, as the hostname.
1. Congratulations! GitLab is now installed and you can access it via your browser. To finish installation, open the URL in your browser and provide the initial administrator password. The username for this account is `root`.
@@ -128,9 +128,9 @@ GitLab can be configured to authenticate with other OAuth providers, LDAP, SAML,
Kerberos, etc. Here are some documents you might be interested in reading:
- [Omnibus GitLab documentation](https://docs.gitlab.com/omnibus/)
-- [Integration documentation](https://docs.gitlab.com/ce/integration/)
-- [GitLab Pages configuration](https://docs.gitlab.com/ce/administration/pages/index.html)
-- [GitLab Container Registry configuration](https://docs.gitlab.com/ce/administration/container_registry.html)
+- [Integration documentation](../../integration/README.md)
+- [GitLab Pages configuration](../../administration/pages/index.md)
+- [GitLab Container Registry configuration](../../administration/container_registry.md)
[freetrial]: https://console.cloud.google.com/freetrial "GCP free trial"
[ip]: https://cloud.google.com/compute/docs/configure-instance-ip-addresses#promote_ephemeral_ip "Configuring an Instance's IP Addresses"
diff --git a/doc/install/installation.md b/doc/install/installation.md
index 4c1021d097f..e9206469e5d 100644
--- a/doc/install/installation.md
+++ b/doc/install/installation.md
@@ -167,7 +167,7 @@ cd pcre2-10.33
chmod +x configure
./configure --prefix=/usr --enable-jit
make
-make install
+sudo make install
# Download and compile from source
cd /tmp
@@ -560,7 +560,7 @@ NOTE: **Note:**
If you want to use HTTPS, see [Using HTTPS](#using-https) for the additional steps.
NOTE: **Note:**
-Make sure your hostname can be resolved on the machine itself by either a proper DNS record or an additional line in `/etc/hosts` ("127.0.0.1 hostname"). This might be necessary, for example, if you set up GitLab behind a reverse proxy. If the hostname cannot be resolved, the final installation check will fail with "Check GitLab API access: FAILED. code: 401" and pushing commits will be rejected with "[remote rejected] master -> master (hook declined)".
+Make sure your hostname can be resolved on the machine itself by either a proper DNS record or an additional line in `/etc/hosts` ("127.0.0.1 hostname"). This might be necessary, for example, if you set up GitLab behind a reverse proxy. If the hostname cannot be resolved, the final installation check will fail with `Check GitLab API access: FAILED. code: 401` and pushing commits will be rejected with `[remote rejected] master -> master (hook declined)`.
NOTE: **Note:**
GitLab Shell application startup time can be greatly reduced by disabling RubyGems. This can be done in several ways:
@@ -634,8 +634,8 @@ Gitaly must be running for the next section.
gitlab_path=/home/git/gitlab
gitaly_path=/home/git/gitaly
-sudo -u git -H $gitlab_path/bin/daemon_with_pidfile $gitlab_path/tmp/pids/gitaly.pid \
- $gitaly_path/gitaly $gitaly_path/config.toml >> $gitlab_path/log/gitaly.log 2>&1 &
+sudo -u git -H sh -c "$gitlab_path/bin/daemon_with_pidfile $gitlab_path/tmp/pids/gitaly.pid \
+ $gitaly_path/gitaly $gitaly_path/config.toml >> $gitlab_path/log/gitaly.log 2>&1 &"
```
### Initialize Database and Activate Advanced Features
diff --git a/doc/install/kubernetes/gitlab_chart.md b/doc/install/kubernetes/gitlab_chart.md
index 43655767002..d067c341be8 100644
--- a/doc/install/kubernetes/gitlab_chart.md
+++ b/doc/install/kubernetes/gitlab_chart.md
@@ -1,5 +1,5 @@
---
-redirect_to: https://docs.gitlab.com/charts/
+redirect_to: 'https://docs.gitlab.com/charts/'
---
This document was moved to [another location](https://docs.gitlab.com/charts/).
diff --git a/doc/install/kubernetes/gitlab_omnibus.md b/doc/install/kubernetes/gitlab_omnibus.md
index 43655767002..d067c341be8 100644
--- a/doc/install/kubernetes/gitlab_omnibus.md
+++ b/doc/install/kubernetes/gitlab_omnibus.md
@@ -1,5 +1,5 @@
---
-redirect_to: https://docs.gitlab.com/charts/
+redirect_to: 'https://docs.gitlab.com/charts/'
---
This document was moved to [another location](https://docs.gitlab.com/charts/).
diff --git a/doc/install/kubernetes/gitlab_runner_chart.md b/doc/install/kubernetes/gitlab_runner_chart.md
index 08ccf2cf9ad..be58c957166 100644
--- a/doc/install/kubernetes/gitlab_runner_chart.md
+++ b/doc/install/kubernetes/gitlab_runner_chart.md
@@ -1,5 +1,5 @@
---
-redirect_to: https://docs.gitlab.com/runner/install/kubernetes.html
+redirect_to: 'https://docs.gitlab.com/runner/install/kubernetes.html'
---
This document was moved to [another location](https://docs.gitlab.com/runner/install/kubernetes.html).
diff --git a/doc/install/kubernetes/index.md b/doc/install/kubernetes/index.md
index 43655767002..d067c341be8 100644
--- a/doc/install/kubernetes/index.md
+++ b/doc/install/kubernetes/index.md
@@ -1,5 +1,5 @@
---
-redirect_to: https://docs.gitlab.com/charts/
+redirect_to: 'https://docs.gitlab.com/charts/'
---
This document was moved to [another location](https://docs.gitlab.com/charts/).
diff --git a/doc/install/kubernetes/preparation/connect.md b/doc/install/kubernetes/preparation/connect.md
index db55e03d3d4..839461c982c 100644
--- a/doc/install/kubernetes/preparation/connect.md
+++ b/doc/install/kubernetes/preparation/connect.md
@@ -1,5 +1,5 @@
---
-redirect_to: https://docs.gitlab.com/charts/installation/cloud/
+redirect_to: 'https://docs.gitlab.com/charts/installation/cloud/'
---
This document was moved to [another location](https://docs.gitlab.com/charts/installation/cloud/).
diff --git a/doc/install/kubernetes/preparation/eks.md b/doc/install/kubernetes/preparation/eks.md
index 975d35c11c6..c3f53c2f580 100644
--- a/doc/install/kubernetes/preparation/eks.md
+++ b/doc/install/kubernetes/preparation/eks.md
@@ -1,5 +1,5 @@
---
-redirect_to: https://docs.gitlab.com/charts/installation/cloud/eks.html
+redirect_to: 'https://docs.gitlab.com/charts/installation/cloud/eks.html'
---
This document was moved to [another location](https://docs.gitlab.com/charts/installation/cloud/eks.html).
diff --git a/doc/install/kubernetes/preparation/networking.md b/doc/install/kubernetes/preparation/networking.md
index 2af16a752dc..7e88bbd3cd1 100644
--- a/doc/install/kubernetes/preparation/networking.md
+++ b/doc/install/kubernetes/preparation/networking.md
@@ -1,5 +1,5 @@
---
-redirect_to: https://docs.gitlab.com/charts/installation/deployment.html#networking-and-dns
+redirect_to: 'https://docs.gitlab.com/charts/installation/deployment.html#networking-and-dns'
---
This document was moved to [another location](https://docs.gitlab.com/charts/installation/deployment.html#networking-and-dns).
diff --git a/doc/install/kubernetes/preparation/rbac.md b/doc/install/kubernetes/preparation/rbac.md
index f94e7c24cdc..fc18b91641c 100644
--- a/doc/install/kubernetes/preparation/rbac.md
+++ b/doc/install/kubernetes/preparation/rbac.md
@@ -1,5 +1,5 @@
---
-redirect_to: https://docs.gitlab.com/charts/installation/deployment.html#rbac
+redirect_to: 'https://docs.gitlab.com/charts/installation/deployment.html#rbac'
---
This document was moved to [another location](https://docs.gitlab.com/charts/installation/deployment.html#rbac).
diff --git a/doc/install/kubernetes/preparation/tiller.md b/doc/install/kubernetes/preparation/tiller.md
index 66d6c8faece..c1c7910703e 100644
--- a/doc/install/kubernetes/preparation/tiller.md
+++ b/doc/install/kubernetes/preparation/tiller.md
@@ -1,5 +1,5 @@
---
-redirect_to: https://docs.gitlab.com/charts/installation/tools.html
+redirect_to: 'https://docs.gitlab.com/charts/installation/tools.html'
---
This document was moved to [another location](https://docs.gitlab.com/charts/installation/tools.html).
diff --git a/doc/install/kubernetes/preparation/tools_installation.md b/doc/install/kubernetes/preparation/tools_installation.md
index 66d6c8faece..c1c7910703e 100644
--- a/doc/install/kubernetes/preparation/tools_installation.md
+++ b/doc/install/kubernetes/preparation/tools_installation.md
@@ -1,5 +1,5 @@
---
-redirect_to: https://docs.gitlab.com/charts/installation/tools.html
+redirect_to: 'https://docs.gitlab.com/charts/installation/tools.html'
---
This document was moved to [another location](https://docs.gitlab.com/charts/installation/tools.html).
diff --git a/doc/install/openshift_and_gitlab/index.md b/doc/install/openshift_and_gitlab/index.md
index 45d07ec5d11..e4a2d9ecd68 100644
--- a/doc/install/openshift_and_gitlab/index.md
+++ b/doc/install/openshift_and_gitlab/index.md
@@ -13,8 +13,8 @@ for details.
## Introduction
-[OpenShift Origin][openshift] is an open source container application
-platform created by [RedHat], based on [kubernetes] and [Docker]. That means
+[OpenShift Origin](https://www.okd.io/) (**Note:** renamed to OKD in Aug 2018) is an open source container application
+platform created by [RedHat], based on [kubernetes](https://kubernetes.io/) and [Docker]. That means
you can host your own PaaS for free and almost with no hassle.
In this tutorial, we will see how to deploy GitLab in OpenShift using GitLab's
@@ -27,8 +27,11 @@ For a video demonstration on installing GitLab on OpenShift, check the article [
## Prerequisites
-OpenShift 3 is not yet deployed on RedHat's offered Online platform ([openshift.com]),
-so in order to test it, we will use an [all-in-one Virtualbox image][vm] that is
+CAUTION: **Caution:** This information is no longer up to date, as the current versions
+have changed and products have been renamed.
+
+OpenShift 3 is not yet deployed on RedHat's offered Online platform, [openshift.com](https://www.openshift.com/),
+so in order to test it, we will use an [all-in-one Virtualbox image](https://www.okd.io/minishift/) that is
offered by the OpenShift developers and managed by Vagrant. If you haven't done
already, go ahead and install the following components as they are essential to
test OpenShift easily:
@@ -458,7 +461,7 @@ OpenShift's website about [autoscaling].
## Current limitations
-As stated in the [all-in-one VM][vm] page:
+As stated in the [all-in-one VM](https://www.okd.io/minishift/) page:
> By default, OpenShift will not allow a container to run as root or even a
non-random container assigned userid. Most Docker images in the Dockerhub do not
@@ -506,12 +509,8 @@ is capable of. As always, you can refer to the detailed
PaaS and managing your applications with the ease of containers.
[RedHat]: https://www.redhat.com/en "RedHat website"
-[openshift]: https://www.openshift.org "OpenShift Origin website"
-[vm]: https://www.openshift.org/vm/ "OpenShift All-in-one VM"
[vm-new]: https://app.vagrantup.com/openshift/boxes/origin-all-in-one "Official OpenShift Vagrant box on Vagrant Cloud"
[template]: https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/docker/openshift-template.json "OpenShift template for GitLab"
-[openshift.com]: https://openshift.com "OpenShift Online"
-[kubernetes]: http://kubernetes.io/ "Kubernetes website"
[Docker]: https://www.docker.com "Docker website"
[oc]: https://docs.openshift.org/latest/cli_reference/get_started_cli.html "Documentation - oc CLI documentation"
[VirtualBox]: https://www.virtualbox.org/wiki/Downloads "VirtualBox downloads"
diff --git a/doc/install/pivotal/index.md b/doc/install/pivotal/index.md
index f068572f1e9..6a4b361c842 100644
--- a/doc/install/pivotal/index.md
+++ b/doc/install/pivotal/index.md
@@ -1,4 +1,4 @@
-# GitLab Pivotal Tile **[PREMIUM ONLY]**
+# GitLab Pivotal Tile **(PREMIUM ONLY)**
CAUTION: **Discontinued:**
As of September 13, 2017, the GitLab Enterprise Plus for Pivotal Cloud Foundry
diff --git a/doc/install/requirements.md b/doc/install/requirements.md
index 68c1bcbc801..25ab608de3a 100644
--- a/doc/install/requirements.md
+++ b/doc/install/requirements.md
@@ -30,7 +30,7 @@ For the installations options, see [the main installation page](README.md).
- macOS
Installation of GitLab on these operating systems is possible, but not supported.
-Please see the [installation from source guide](installation.md) and the [installation guides](https://about.gitlab.com/installation/) for more information.
+Please see the [installation from source guide](installation.md) and the [installation guides](https://about.gitlab.com/install/) for more information.
### Microsoft Windows
diff --git a/doc/integration/akismet.md b/doc/integration/akismet.md
index 4f7be70baf2..cb8f25d2895 100644
--- a/doc/integration/akismet.md
+++ b/doc/integration/akismet.md
@@ -3,7 +3,7 @@
> *Note:* Before 8.11 only issues submitted via the API and for non-project
members were submitted to Akismet.
-GitLab leverages [Akismet](http://akismet.com) to protect against spam. Currently
+GitLab leverages [Akismet](https://akismet.com/) to protect against spam. Currently
GitLab uses Akismet to prevent the creation of spam issues on public projects. Issues
created via the WebUI or the API can be submitted to Akismet for review.
diff --git a/doc/integration/azure.md b/doc/integration/azure.md
index 7a6d4bb143f..a9468f201ef 100644
--- a/doc/integration/azure.md
+++ b/doc/integration/azure.md
@@ -2,21 +2,21 @@
To enable the Microsoft Azure OAuth2 OmniAuth provider you must register your application with Azure. Azure will generate a client ID and secret key for you to use.
-1. Sign in to the [Azure Management Portal](https://manage.windowsazure.com).
+1. Sign in to the [Azure Management Portal](https://portal.azure.com).
-1. Select "Active Directory" on the left and choose the directory you want to use to register GitLab.
+1. Select "Active Directory" on the left and choose the directory you want to use to register GitLab.
-1. Select "Applications" at the top bar and click the "Add" button the bottom.
+1. Select "Applications" at the top bar and click the "Add" button the bottom.
-1. Select "Add an application my organization is developing".
+1. Select "Add an application my organization is developing".
-1. Provide the project information and click the "Next" button.
- - Name: 'GitLab' works just fine here.
- - Type: 'WEB APPLICATION AND/OR WEB API'
+1. Provide the project information and click the "Next" button.
+ - Name: 'GitLab' works just fine here.
+ - Type: 'WEB APPLICATION AND/OR WEB API'
-1. On the "App properties" page enter the needed URI's and click the "Complete" button.
- - SIGN-IN URL: Enter the URL of your GitLab installation (e.g `https://gitlab.mycompany.com/`)
- - APP ID URI: Enter the endpoint URL for Microsoft to use, just has to be unique (e.g `https://mycompany.onmicrosoft.com/gitlab`)
+1. On the "App properties" page enter the needed URI's and click the "Complete" button.
+ - SIGN-IN URL: Enter the URL of your GitLab installation (e.g `https://gitlab.mycompany.com/`)
+ - APP ID URI: Enter the endpoint URL for Microsoft to use, just has to be unique (e.g `https://mycompany.onmicrosoft.com/gitlab`)
1. Select "Configure" in the top menu.
@@ -30,59 +30,59 @@ To enable the Microsoft Azure OAuth2 OmniAuth provider you must register your ap
1. You will see lots of endpoint URLs in the form `https://login.microsoftonline.com/TENANT ID/...`, note down the TENANT ID part of one of those endpoints.
-1. On your GitLab server, open the configuration file.
+1. On your GitLab server, open the configuration file.
- For omnibus package:
+ For omnibus package:
- ```sh
- sudo editor /etc/gitlab/gitlab.rb
- ```
+ ```sh
+ sudo editor /etc/gitlab/gitlab.rb
+ ```
- For installations from source:
+ For installations from source:
- ```sh
- cd /home/git/gitlab
+ ```sh
+ cd /home/git/gitlab
- sudo -u git -H editor config/gitlab.yml
- ```
+ sudo -u git -H editor config/gitlab.yml
+ ```
-1. See [Initial OmniAuth Configuration](omniauth.md#initial-omniauth-configuration) for initial settings.
+1. See [Initial OmniAuth Configuration](omniauth.md#initial-omniauth-configuration) for initial settings.
-1. Add the provider configuration:
+1. Add the provider configuration:
- For omnibus package:
+ For omnibus package:
- ```ruby
- gitlab_rails['omniauth_providers'] = [
- {
- "name" => "azure_oauth2",
- "args" => {
- "client_id" => "CLIENT ID",
- "client_secret" => "CLIENT SECRET",
- "tenant_id" => "TENANT ID",
- }
- }
- ]
- ```
+ ```ruby
+ gitlab_rails['omniauth_providers'] = [
+ {
+ "name" => "azure_oauth2",
+ "args" => {
+ "client_id" => "CLIENT ID",
+ "client_secret" => "CLIENT SECRET",
+ "tenant_id" => "TENANT ID",
+ }
+ }
+ ]
+ ```
- For installations from source:
+ For installations from source:
- ```
- - { name: 'azure_oauth2',
- args: { client_id: "CLIENT ID",
- client_secret: "CLIENT SECRET",
- tenant_id: "TENANT ID" } }
- ```
+ ```
+ - { name: 'azure_oauth2',
+ args: { client_id: "CLIENT ID",
+ client_secret: "CLIENT SECRET",
+ tenant_id: "TENANT ID" } }
+ ```
- The `base_azure_url` is optional and can be added for different locales;
- e.g. `base_azure_url: "https://login.microsoftonline.de"`.
+ The `base_azure_url` is optional and can be added for different locales;
+ e.g. `base_azure_url: "https://login.microsoftonline.de"`.
-1. Replace 'CLIENT ID', 'CLIENT SECRET' and 'TENANT ID' with the values you got above.
+1. Replace 'CLIENT ID', 'CLIENT SECRET' and 'TENANT ID' with the values you got above.
-1. Save the configuration file.
+1. Save the configuration file.
-1. [Reconfigure][] or [restart GitLab][] for the changes to take effect if you
- installed GitLab via Omnibus or from source respectively.
+1. [Reconfigure][] or [restart GitLab][] for the changes to take effect if you
+ installed GitLab via Omnibus or from source respectively.
On the sign in page there should now be a Microsoft icon below the regular sign in form. Click the icon to begin the authentication process. Microsoft will ask the user to sign in and authorize the GitLab application. If everything goes well the user will be returned to GitLab and will be signed in.
diff --git a/doc/integration/elasticsearch.md b/doc/integration/elasticsearch.md
index ea2bdc8a96d..da1df07a75d 100644
--- a/doc/integration/elasticsearch.md
+++ b/doc/integration/elasticsearch.md
@@ -1,4 +1,4 @@
-# Elasticsearch integration **[STARTER ONLY]**
+# Elasticsearch integration **(STARTER ONLY)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/109 "Elasticsearch Merge Request") in GitLab [Starter](https://about.gitlab.com/pricing/) 8.4. Support
> for [Amazon Elasticsearch](http://docs.aws.amazon.com/elasticsearch-service/latest/developerguide/es-gsg.html) was [introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/1305) in GitLab
@@ -130,7 +130,7 @@ The following Elasticsearch settings are available:
| `Elasticsearch indexing` | Enables/disables Elasticsearch indexing. You may want to enable indexing but disable search in order to give the index time to be fully completed, for example. Also, keep in mind that this option doesn't have any impact on existing data, this only enables/disables background indexer which tracks data changes. So by enabling this you will not get your existing data indexed, use special rake task for that as explained in [Adding GitLab's data to the Elasticsearch index](#adding-gitlabs-data-to-the-elasticsearch-index). |
| `Use the new repository indexer (beta)` | Perform repository indexing using [GitLab Elasticsearch Indexer](https://gitlab.com/gitlab-org/gitlab-elasticsearch-indexer). |
| `Search with Elasticsearch enabled` | Enables/disables using Elasticsearch in search. |
-| `URL` | The URL to use for connecting to Elasticsearch. Use a comma-separated list to support clustering (e.g., "http://host1, https://host2:9200"). If your Elasticsearch instance is password protected, pass the `username:password` in the URL (e.g., `http://<username>:<password>@<elastic_host>:9200/`). |
+| `URL` | The URL to use for connecting to Elasticsearch. Use a comma-separated list to support clustering (e.g., `http://host1, https://host2:9200`). If your Elasticsearch instance is password protected, pass the `username:password` in the URL (e.g., `http://<username>:<password>@<elastic_host>:9200/`). |
| `Number of Elasticsearch shards` | Elasticsearch indexes are split into multiple shards for performance reasons. In general, larger indexes need to have more shards. Changes to this value do not take effect until the index is recreated. You can read more about tradeoffs in the [Elasticsearch documentation](https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-create-index.html#create-index-settings) |
| `Number of Elasticsearch replicas` | Each Elasticsearch shard can have a number of replicas. These are a complete copy of the shard, and can provide increased query performance or resilience against hardware failure. Increasing this value will greatly increase total disk space required by the index. |
| `Limit namespaces and projects that can be indexed` | Enabling this will allow you to select namespaces and projects to index. All other namespaces and projects will use database search instead. Please note that if you enable this option but do not select any namespaces or projects, none will be indexed. [Read more below](#limiting-namespaces-and-projects).
@@ -156,7 +156,7 @@ If no namespaces or projects are selected, no Elasticsearch indexing will take p
CAUTION: **Warning**:
If you have already indexed your instance, you will have to regenerate the index in order to delete all existing data
for filtering to work correctly. To do this run the rake tasks `gitlab:elastic:create_empty_index` and
-`gitlab:elastic:clear_index_status` Afterwards, removing a namespace or a projeect from the list will delete the data
+`gitlab:elastic:clear_index_status`. Afterwards, removing a namespace or a project from the list will delete the data
from the Elasticsearch index as expected.
## Disabling Elasticsearch
@@ -167,7 +167,7 @@ To disable the Elasticsearch integration:
1. Find the 'Elasticsearch' section and uncheck 'Search with Elasticsearch enabled'
and 'Elasticsearch indexing'
1. Click **Save** for the changes to take effect
-1. [Optional] Delete the existing index by running the command `sudo gitlab-rake gitlab:elastic:delete_index`
+1. (Optional) Delete the existing index by running the command `sudo gitlab-rake gitlab:elastic:delete_index`
## Adding GitLab's data to the Elasticsearch index
@@ -304,7 +304,7 @@ For Elasticsearch 6.x, before proceeding with the force merge, the index should
```bash
curl --request PUT localhost:9200/gitlab-production/_settings --data '{
"settings": {
- "index.blocks.write": true
+ "index.blocks.write": true
} }'
```
@@ -319,7 +319,7 @@ After this, if your index is in read-only, switch back to read-write:
```bash
curl --request PUT localhost:9200/gitlab-production/_settings --data '{
"settings": {
- "index.blocks.write": false
+ "index.blocks.write": false
} }'
```
@@ -392,9 +392,9 @@ When performing a search, the GitLab index will use the following scopes:
Whenever a change or deletion is made to an indexed GitLab object (a merge request description is changed, a file is deleted from the master branch in a repository, a project is deleted, etc), a document in the index is deleted. However, since these are "soft" deletes, the overall number of "deleted documents", and therefore wasted space, increases. Elasticsearch does intelligent merging of segments in order to remove these deleted documents. However, depending on the amount and type of activity in your GitLab installation, it's possible to see as much as 50% wasted space in the index.
-In general, we recommend simply letting Elasticseach merge and reclaim space automatically, with the default settings. From [Lucene's Handling of Deleted Documents](https://www.elastic.co/blog/lucenes-handling-of-deleted-documents "Lucene's Handling of Deleted Documents"), _"Overall, besides perhaps decreasing the maximum segment size, it is best to leave Lucene's defaults as-is and not fret too much about when deletes are reclaimed."_
+In general, we recommend simply letting Elasticsearch merge and reclaim space automatically, with the default settings. From [Lucene's Handling of Deleted Documents](https://www.elastic.co/blog/lucenes-handling-of-deleted-documents "Lucene's Handling of Deleted Documents"), _"Overall, besides perhaps decreasing the maximum segment size, it is best to leave Lucene's defaults as-is and not fret too much about when deletes are reclaimed."_
-However, some larger installations may wish to tune the merge policy settings:
+However, some larger installations may wish to tune the merge policy settings:
- Consider reducing the `index.merge.policy.max_merged_segment` size from the default 5 GB to maybe 2 GB or 3 GB. Merging only happens when a segment has at least 50% deletions. Smaller segment sizes will allow merging to happen more frequently.
@@ -425,14 +425,14 @@ Here are some common pitfalls and how to overcome them:
- **How can I verify my GitLab instance is using Elasticsearch?**
The easiest method is via the rails console (`sudo gitlab-rails console`) by running the following:
-
+
```ruby
u = User.find_by_username('your-username')
s = SearchService.new(u, {:search => 'search_term'})
pp s.search_objects.class.name
```
-
- If you see `Elasticsearch::Model::Response::Records`, you are using Elasticsearch.
+
+ If you see `Elasticsearch::Model::Response::Records`, you are using Elasticsearch.
- **I updated GitLab and now I can't find anything**
@@ -443,23 +443,23 @@ Here are some common pitfalls and how to overcome them:
- **I indexed all the repositories but I can't find anything**
Make sure you indexed all the database data [as stated above](#adding-gitlabs-data-to-the-elasticsearch-index).
-
+
Beyond that, check via the [Elasticsearch Search API](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-search.html) to see if the data shows up on the Elasticsearch side.
-
+
If it shows up via the [Elasticsearch Search API](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-search.html), check that it shows up via the rails console (`sudo gitlab-rails console`):
-
+
```ruby
u = User.find_by_username('your-username')
s = SearchService.new(u, {:search => 'search_term', :scope => ‘blobs’})
pp s.search_objects.to_a
```
-
+
See [Elasticsearch Index Scopes](elasticsearch.md#elasticsearch-index-scopes) for more information on searching for specific types of data.
- **I indexed all the repositories but then switched Elasticsearch servers and now I can't find anything**
You will need to re-run all the rake tasks to re-index the database, repositories, and wikis.
-
+
- **The indexing process is taking a very long time**
The more data present in your GitLab instance, the longer the indexing process takes.
diff --git a/doc/integration/jenkins.md b/doc/integration/jenkins.md
index e6496ae3a2e..50cb3d50009 100644
--- a/doc/integration/jenkins.md
+++ b/doc/integration/jenkins.md
@@ -1,4 +1,4 @@
-# Jenkins CI service **[STARTER]**
+# Jenkins CI service **(STARTER)**
>**Note:**
In GitLab 8.3, Jenkins integration using the
diff --git a/doc/integration/jira_development_panel.md b/doc/integration/jira_development_panel.md
index 703736eeb3c..60c7bdabf93 100644
--- a/doc/integration/jira_development_panel.md
+++ b/doc/integration/jira_development_panel.md
@@ -1,4 +1,4 @@
-# GitLab Jira development panel integration **[PREMIUM]**
+# GitLab Jira development panel integration **(PREMIUM)**
> [Introduced][ee-2381] in [GitLab Premium][eep] 10.0.
diff --git a/doc/integration/kerberos.md b/doc/integration/kerberos.md
index 44117755b83..cf2ef511264 100644
--- a/doc/integration/kerberos.md
+++ b/doc/integration/kerberos.md
@@ -1,4 +1,4 @@
-# Kerberos integration **[STARTER ONLY]**
+# Kerberos integration **(STARTER ONLY)**
GitLab can integrate with [Kerberos][kerb] as an authentication mechanism.
diff --git a/doc/integration/oauth2_generic.md b/doc/integration/oauth2_generic.md
index 3e72589ce12..3c1a0f2a117 100644
--- a/doc/integration/oauth2_generic.md
+++ b/doc/integration/oauth2_generic.md
@@ -1,7 +1,7 @@
# Sign into GitLab with (almost) any OAuth2 provider
The `omniauth-oauth2-generic` gem allows Single Sign On between GitLab and your own OAuth2 provider
-(or any OAuth2 provider compatible with this gem)
+(or any OAuth2 provider compatible with this gem)
This strategy is designed to allow configuration of the simple OmniAuth SSO process outlined below:
@@ -12,7 +12,7 @@ This strategy is designed to allow configuration of the simple OmniAuth SSO proc
1. Strategy parses user information from the response, using a **configurable** format
1. GitLab finds or creates the returned user and logs them in
-### Limitations of this Strategy:
+## Limitations of this Strategy:
- It can only be used for Single Sign on, and will not provide any other access granted by any OAuth provider
(importing projects or users, etc)
@@ -20,7 +20,7 @@ This strategy is designed to allow configuration of the simple OmniAuth SSO proc
- It is not able to fetch user information from more than one URL
- It has not been tested with user information formats other than JSON
-### Config Instructions
+## Config Instructions
1. Register your application in the OAuth2 provider you wish to authenticate with.
@@ -57,9 +57,9 @@ This strategy is designed to allow configuration of the simple OmniAuth SSO proc
1. Restart GitLab for the changes to take effect
-On the sign in page there should now be a new button below the regular sign in form.
+On the sign in page there should now be a new button below the regular sign in form.
Click the button to begin your provider's authentication process. This will direct
the browser to your OAuth2 Provider's authentication page. If everything goes well
the user will be returned to your GitLab instance and will be signed in.
-[1]: https://gitlab.com/satorix/omniauth-oauth2-generic#gitlab-config-example \ No newline at end of file
+[1]: https://gitlab.com/satorix/omniauth-oauth2-generic#gitlab-config-example
diff --git a/doc/integration/oauth_provider.md b/doc/integration/oauth_provider.md
index c02a29dffb4..b9dc2e123c5 100644
--- a/doc/integration/oauth_provider.md
+++ b/doc/integration/oauth_provider.md
@@ -11,7 +11,7 @@ If you want to use:
## Introduction to OAuth
-[OAuth] provides to client applications a 'secure delegated access' to server
+[OAuth](https://oauth.net/2/) provides to client applications a 'secure delegated access' to server
resources on behalf of a resource owner. In fact, OAuth allows an authorization
server to issue access tokens to third-party clients with the approval of the
resource owner, or the end-user.
@@ -85,5 +85,3 @@ application can perform such as `read_user` and `api`. There are many more scope
available.
At any time you can revoke any access by just clicking **Revoke**.
-
-[oauth]: http://oauth.net/2/ "OAuth website"
diff --git a/doc/integration/openid_connect_provider.md b/doc/integration/openid_connect_provider.md
index a7f907254a1..89f4924d717 100644
--- a/doc/integration/openid_connect_provider.md
+++ b/doc/integration/openid_connect_provider.md
@@ -5,7 +5,7 @@ to sign in to other services.
## Introduction to OpenID Connect
-[OpenID Connect] \(OIDC) is a simple identity layer on top of the
+[OpenID Connect](https://openid.net/connect/) \(OIDC) is a simple identity layer on top of the
OAuth 2.0 protocol. It allows clients to verify the identity of the end-user
based on the authentication performed by GitLab, as well as to obtain
basic profile information about the end-user in an interoperable and
@@ -14,7 +14,7 @@ but does so in a way that is API-friendly, and usable by native and
mobile applications.
On the client side, you can use [omniauth-openid-connect] for Rails
-applications, or any of the other available [client implementations].
+applications, or any of the other available [client implementations](https://openid.net/developers/libraries/#connect).
GitLab's implementation uses the [doorkeeper-openid_connect] gem, refer
to its README for more details about which parts of the specifications
@@ -46,8 +46,6 @@ Currently the following user information is shared with clients:
Only the `sub` and `sub_legacy` claims are included in the ID token, all other claims are available from the `/oauth/userinfo` endpoint used by OIDC clients.
-[OpenID Connect]: http://openid.net/connect/ "OpenID Connect website"
[doorkeeper-openid_connect]: https://github.com/doorkeeper-gem/doorkeeper-openid_connect "Doorkeeper::OpenidConnect website"
[OAuth guide]: oauth_provider.md "GitLab as OAuth2 authentication service provider"
[omniauth-openid-connect]: https://github.com/jjbohn/omniauth-openid-connect/ "OmniAuth::OpenIDConnect website"
-[client implementations]: http://openid.net/developers/libraries#connect "List of available client implementations"
diff --git a/doc/integration/shibboleth.md b/doc/integration/shibboleth.md
index 616f3a76b2c..07c83c1a049 100644
--- a/doc/integration/shibboleth.md
+++ b/doc/integration/shibboleth.md
@@ -5,8 +5,8 @@ This documentation is for enabling shibboleth with omnibus-gitlab package.
In order to enable Shibboleth support in gitlab we need to use Apache instead of Nginx (It may be possible to use Nginx, however this is difficult to configure using the bundled Nginx provided in the omnibus-gitlab package). Apache uses mod_shib2 module for shibboleth authentication and can pass attributes as headers to omniauth-shibboleth provider.
To enable the Shibboleth OmniAuth provider you must configure Apache shibboleth module.
-Installation and configuration of module it self is out of scope of this document.
-Check <https://wiki.shibboleth.net/> for more info.
+The installation and configuration of the module itself is out of the scope of this document.
+Check <https://wiki.shibboleth.net/confluence/display/SP3/Apache> for more info.
You can find Apache config in gitlab-recipes (<https://gitlab.com/gitlab-org/gitlab-recipes/tree/master/web-server/apache>).
diff --git a/doc/integration/twitter.md b/doc/integration/twitter.md
index 1cbfd81dfa9..d8096993885 100644
--- a/doc/integration/twitter.md
+++ b/doc/integration/twitter.md
@@ -2,80 +2,81 @@
To enable the Twitter OmniAuth provider you must register your application with Twitter. Twitter will generate a client ID and secret key for you to use.
-1. Sign in to [Twitter Application Management](https://apps.twitter.com/).
+1. Sign in to [Twitter Application Management](https://developer.twitter.com/apps).
-1. Select "Create new app"
+1. Select "Create new app"
-1. Fill in the application details.
- - Name: This can be anything. Consider something like `<Organization>'s GitLab` or `<Your Name>'s GitLab` or
- something else descriptive.
- - Description: Create a description.
- - Website: The URL to your GitLab installation. `https://gitlab.example.com`
- - Callback URL: `https://gitlab.example.com/users/auth/twitter/callback`
- - Agree to the "Developer Agreement".
+1. Fill in the application details.
+ - Name: This can be anything. Consider something like `<Organization>'s GitLab` or `<Your Name>'s GitLab` or
+ something else descriptive.
+ - Description: Create a description.
+ - Website: The URL to your GitLab installation. `https://gitlab.example.com`
+ - Callback URL: `https://gitlab.example.com/users/auth/twitter/callback`
+ - Agree to the "Developer Agreement".
- ![Twitter App Details](img/twitter_app_details.png)
-1. Select "Create your Twitter application."
+ ![Twitter App Details](img/twitter_app_details.png)
-1. Select the "Settings" tab.
+1. Select "Create your Twitter application."
-1. Underneath the Callback URL check the box next to "Allow this application to be used to Sign in with Twitter."
+1. Select the "Settings" tab.
-1. Select "Update settings" at the bottom to save changes.
+1. Underneath the Callback URL check the box next to "Allow this application to be used to Sign in with Twitter."
-1. Select the "Keys and Access Tokens" tab.
+1. Select "Update settings" at the bottom to save changes.
-1. You should now see an API key and API secret (see screenshot). Keep this page open as you continue configuration.
+1. Select the "Keys and Access Tokens" tab.
- ![Twitter app](img/twitter_app_api_keys.png)
+1. You should now see an API key and API secret (see screenshot). Keep this page open as you continue configuration.
-1. On your GitLab server, open the configuration file.
+ ![Twitter app](img/twitter_app_api_keys.png)
- For omnibus package:
+1. On your GitLab server, open the configuration file.
- ```sh
- sudo editor /etc/gitlab/gitlab.rb
- ```
+ For omnibus package:
- For installations from source:
+ ```sh
+ sudo editor /etc/gitlab/gitlab.rb
+ ```
- ```sh
- cd /home/git/gitlab
+ For installations from source:
- sudo -u git -H editor config/gitlab.yml
- ```
+ ```sh
+ cd /home/git/gitlab
-1. See [Initial OmniAuth Configuration](omniauth.md#initial-omniauth-configuration) for initial settings.
+ sudo -u git -H editor config/gitlab.yml
+ ```
-1. Add the provider configuration:
+1. See [Initial OmniAuth Configuration](omniauth.md#initial-omniauth-configuration) for initial settings.
- For omnibus package:
+1. Add the provider configuration:
- ```ruby
- gitlab_rails['omniauth_providers'] = [
- {
- "name" => "twitter",
- "app_id" => "YOUR_APP_ID",
- "app_secret" => "YOUR_APP_SECRET"
- }
- ]
- ```
+ For omnibus package:
- For installations from source:
+ ```ruby
+ gitlab_rails['omniauth_providers'] = [
+ {
+ "name" => "twitter",
+ "app_id" => "YOUR_APP_ID",
+ "app_secret" => "YOUR_APP_SECRET"
+ }
+ ]
+ ```
- ```
- - { name: 'twitter', app_id: 'YOUR_APP_ID',
- app_secret: 'YOUR_APP_SECRET' }
- ```
+ For installations from source:
-1. Change 'YOUR_APP_ID' to the API key from Twitter page in step 11.
+ ```
+ - { name: 'twitter', app_id: 'YOUR_APP_ID',
+ app_secret: 'YOUR_APP_SECRET' }
+ ```
-1. Change 'YOUR_APP_SECRET' to the API secret from the Twitter page in step 11.
+1. Change 'YOUR_APP_ID' to the API key from Twitter page in step 11.
-1. Save the configuration file.
+1. Change 'YOUR_APP_SECRET' to the API secret from the Twitter page in step 11.
-1. [Reconfigure][] or [restart GitLab][] for the changes to take effect if you
- installed GitLab via Omnibus or from source respectively.
+1. Save the configuration file.
+
+1. [Reconfigure][] or [restart GitLab][] for the changes to take effect if you
+ installed GitLab via Omnibus or from source respectively.
On the sign in page there should now be a Twitter icon below the regular sign in form. Click the icon to begin the authentication process. Twitter will ask the user to sign in and authorize the GitLab application. If everything goes well the user will be returned to GitLab and will be signed in.
diff --git a/doc/intro/README.md b/doc/intro/README.md
index d9c733d4285..33b23372280 100644
--- a/doc/intro/README.md
+++ b/doc/intro/README.md
@@ -15,7 +15,7 @@ Create projects and groups.
Create issues, labels, milestones, cast your vote, and review issues.
-- [Create an issue](../user/project/issues/create_new_issue.md)
+- [Create an issue](../user/project/issues/managing_issues.md#create-a-new-issue)
- [Assign labels to issues](../user/project/labels.md)
- [Use milestones as an overview of your project's tracker](../user/project/milestones/index.md)
- [Use voting to express your like/dislike to issues and merge requests](../workflow/award_emoji.md)
@@ -26,7 +26,7 @@ Create merge requests and review code.
- [Fork a project and contribute to it](../workflow/forking_workflow.md)
- [Create a new merge request](../gitlab-basics/add-merge-request.md)
-- [Automatically close issues from merge requests](../user/project/issues/automatic_issue_closing.md)
+- [Automatically close issues from merge requests](../user/project/issues/managing_issues.md#closing-issues-automatically)
- [Automatically merge when pipeline succeeds](../user/project/merge_requests/merge_when_pipeline_succeeds.md)
- [Revert any commit](../user/project/merge_requests/revert_changes.md)
- [Cherry-pick any commit](../user/project/merge_requests/cherry_pick_changes.md)
@@ -41,6 +41,6 @@ Use the built-in continuous integration in GitLab.
Install and update your GitLab installation.
-- [Install GitLab](https://about.gitlab.com/installation/)
+- [Install GitLab](https://about.gitlab.com/install/)
- [Update GitLab](https://about.gitlab.com/update/)
- [Explore Omnibus GitLab configuration options](https://docs.gitlab.com/omnibus/settings/configuration.html)
diff --git a/doc/policy/maintenance.md b/doc/policy/maintenance.md
index 72bace3d282..018c273c51a 100644
--- a/doc/policy/maintenance.md
+++ b/doc/policy/maintenance.md
@@ -9,7 +9,7 @@ patch and security releases. New releases are usually announced on the [GitLab b
## Versioning
-GitLab uses [Semantic Versioning](http://semver.org/) for its releases:
+GitLab uses [Semantic Versioning](https://semver.org/) for its releases:
`(Major).(Minor).(Patch)` in a [pragmatic way](https://gist.github.com/jashkenas/cbd2b088e20279ae2c8e).
For example, for GitLab version 10.5.7:
diff --git a/doc/public_access/public_access.md b/doc/public_access/public_access.md
index b1637181855..d04428fdbfe 100644
--- a/doc/public_access/public_access.md
+++ b/doc/public_access/public_access.md
@@ -29,6 +29,12 @@ in users.
Any logged in user will have [Guest permissions](../user/permissions.md)
on the repository.
+NOTE: **Note:**
+From July 2019, the `Internal` visibility setting is disabled for new projects, groups,
+and snippets on GitLab.com. Existing projects, groups, and snippets using the `Internal`
+visibility setting keep this setting. You can read more about the change in the
+[relevant issue](https://gitlab.com/gitlab-org/gitlab-ee/issues/12388).
+
### Private projects
Private projects can only be cloned and viewed by project members.
diff --git a/doc/push_rules/push_rules.md b/doc/push_rules/push_rules.md
index 2142f5a5f69..b1754131e76 100644
--- a/doc/push_rules/push_rules.md
+++ b/doc/push_rules/push_rules.md
@@ -2,7 +2,7 @@
type: reference, howto
---
-# Push Rules **[STARTER]**
+# Push Rules **(STARTER)**
Gain additional control over what can and can't be pushed to your repository by using
regular expressions to reject pushes based on commit contents, branch names or file details.
diff --git a/doc/raketasks/README.md b/doc/raketasks/README.md
index 0729875daf8..dcc96507676 100644
--- a/doc/raketasks/README.md
+++ b/doc/raketasks/README.md
@@ -9,10 +9,10 @@ comments: false
- [Cleanup](cleanup.md)
- [Features](features.md)
- [LDAP Maintenance](../administration/raketasks/ldap.md)
-- [General Maintenance](maintenance.md) and self-checks
+- [General Maintenance](../administration/raketasks/maintenance.md) and self-checks
- [User management](user_management.md)
- [Webhooks](web_hooks.md)
- [Import](import.md) of git repositories in bulk
-- [Rebuild authorized_keys file](http://docs.gitlab.com/ce/raketasks/maintenance.html#rebuild-authorized_keys-file) task for administrators
+- [Rebuild authorized_keys file](../administration/raketasks/maintenance.md#rebuild-authorized_keys-file) task for administrators
- [Migrate Uploads](../administration/raketasks/uploads/migrate.md)
- [Sanitize Uploads](../administration/raketasks/uploads/sanitize.md)
diff --git a/doc/raketasks/web_hooks.md b/doc/raketasks/web_hooks.md
index 2c6ae0749dd..a498e9793c1 100644
--- a/doc/raketasks/web_hooks.md
+++ b/doc/raketasks/web_hooks.md
@@ -1,4 +1,4 @@
-# Webhooks administration **[CORE ONLY]**
+# Webhooks administration **(CORE ONLY)**
## Add a webhook for **ALL** projects:
diff --git a/doc/subscriptions/index.md b/doc/subscriptions/index.md
index 1e9c53b9811..745a2253e84 100644
--- a/doc/subscriptions/index.md
+++ b/doc/subscriptions/index.md
@@ -74,7 +74,7 @@ Please note that you need to be a group owner to associate a group to your subsc
To see the status of your GitLab.com subscription, you can click on the Billings
section of the relevant namespace:
-- For individuals, this is located at https://gitlab.com/profile/billings under
+- For individuals, this is located at <https://gitlab.com/profile/billings> under
in your Settings,
- For groups, this is located under the group's Settings dropdown, under Billing.
diff --git a/doc/tools/email.md b/doc/tools/email.md
index a2d677484f0..72a5d094bc9 100644
--- a/doc/tools/email.md
+++ b/doc/tools/email.md
@@ -2,7 +2,7 @@
type: howto, reference
---
-# Email from GitLab **[STARTER ONLY]**
+# Email from GitLab **(STARTER ONLY)**
GitLab provides a simple tool to administrators for emailing all users, or users of
a chosen group or project, right from the admin area. Users will receive the email
diff --git a/doc/topics/application_development_platform/index.md b/doc/topics/application_development_platform/index.md
index 8742606479d..2ea561eb943 100644
--- a/doc/topics/application_development_platform/index.md
+++ b/doc/topics/application_development_platform/index.md
@@ -9,10 +9,10 @@ The GitLab Application Development Platform aims to:
- Reduce and even eliminate the time it takes for an Operations team
to provide a full environment for software developers.
-- Get developers up and running fast so they can focus on writing
+- Get developers up and running fast so they can focus on writing
great applications with a robust development feature set.
-- Provide best-of-breed security features so that applications developed
- with GitLab are not affected by vulnerabilities that may lead to security
+- Provide best-of-breed security features so that applications developed
+ with GitLab are not affected by vulnerabilities that may lead to security
problems and unintended use.
It is comprised of the following high-level elements:
@@ -35,28 +35,28 @@ with various cloud providers.
### Build, test, deploy
In order to provide modern DevOps workflows, our Application Development Platform will rely on
-[Auto DevOps](https://docs.gitlab.com/ee/topics/autodevops/) to provide those workflows. Auto DevOps works with
-any Kubernetes cluster; you're not limited to running on GitLab's infrastructure. Additionally, Auto DevOps offers
-an incremental consumption path. Because it is [composable](https://docs.gitlab.com/ee/topics/autodevops/#using-components-of-auto-devops),
+[Auto DevOps](../autodevops/index.md) to provide those workflows. Auto DevOps works with
+any Kubernetes cluster; you're not limited to running on GitLab's infrastructure. Additionally, Auto DevOps offers
+an incremental consumption path. Because it is [composable](../autodevops/index.md#using-components-of-auto-devops),
you can use as much or as little of the default pipeline as you'd like, and deeply customize without having to integrate a completely different platform.
### Security
-The Application Development Platform helps you ensure that the applications you create are not affected by vulnerabilities
+The Application Development Platform helps you ensure that the applications you create are not affected by vulnerabilities
that may lead to security problems and unintended use. This can be achieved by making use of the embedded security features of Auto DevOps,
-which inform security teams and developers if there is something to consider changing in their apps
+which inform security teams and developers if there is something to consider changing in their apps
before it is too late to create a preventative fix. The following features are included:
-- [Auto SAST (Static Application Security Testing)](https://docs.gitlab.com/ee/topics/autodevops/#auto-sast-ultimate)
-- [Auto Dependency Scanning](https://docs.gitlab.com/ee/topics/autodevops/#auto-dependency-scanning-ultimate)
-- [Auto Container Scanning](https://docs.gitlab.com/ee/topics/autodevops/#auto-container-scanning-ultimate)
-- [Auto DAST (Dynamic Application Security Testing)](https://docs.gitlab.com/ee/topics/autodevops/#auto-dast-ultimate)
+- [Auto SAST (Static Application Security Testing)](../autodevops/index.md#auto-sast-ultimate)
+- [Auto Dependency Scanning](../autodevops/index.md#auto-dependency-scanning-ultimate)
+- [Auto Container Scanning](../autodevops/index.md#auto-container-scanning-ultimate)
+- [Auto DAST (Dynamic Application Security Testing)](../autodevops/index.md#auto-dast-ultimate)
### Observability
Performance is a critical aspect of the user experience, and ensuring your application is responsive and available is everyone's
-responsibility. The Application Development Platform integrates key performance analytics and feedback
+responsibility. The Application Development Platform integrates key performance analytics and feedback
into GitLab, automatically. The following features are included:
-- [Auto Monitoring](https://docs.gitlab.com/ee/topics/autodevops/#auto-monitoring)
-- [In-app Kubernetes Pod Logs](https://docs.gitlab.com/ee/user/project/clusters/kubernetes_pod_logs.html) \ No newline at end of file
+- [Auto Monitoring](../autodevops/index.md#auto-monitoring)
+- [In-app Kubernetes Pod Logs](../../user/project/clusters/kubernetes_pod_logs.md)
diff --git a/doc/topics/authentication/index.md b/doc/topics/authentication/index.md
index 228da2d1f57..8b4a2f1630b 100644
--- a/doc/topics/authentication/index.md
+++ b/doc/topics/authentication/index.md
@@ -17,11 +17,11 @@ This page gathers all the resources for the topic **Authentication** within GitL
## GitLab administrators
- [LDAP (Community Edition)](../../administration/auth/ldap.md)
-- [LDAP (Enterprise Edition)](../../administration/auth/ldap-ee.md) **[STARTER]**
+- [LDAP (Enterprise Edition)](../../administration/auth/ldap-ee.md) **(STARTER)**
- [Enforce Two-factor Authentication (2FA)](../../security/two_factor_authentication.md#enforce-two-factor-authentication-2fa)
- **Articles:**
- [How to Configure LDAP with GitLab CE](../../administration/auth/how_to_configure_ldap_gitlab_ce/index.md)
- - [How to Configure LDAP with GitLab EE](../../administration/auth/how_to_configure_ldap_gitlab_ee/index.md) **[STARTER]**
+ - [How to Configure LDAP with GitLab EE](../../administration/auth/how_to_configure_ldap_gitlab_ee/index.md) **(STARTER)**
- [Feature Highlight: LDAP Integration](https://about.gitlab.com/2014/07/10/feature-highlight-ldap-sync/)
- [Debugging LDAP](https://about.gitlab.com/handbook/support/workflows/support-engineering/ldap/debugging_ldap.html)
- **Integrations:**
@@ -30,10 +30,10 @@ This page gathers all the resources for the topic **Authentication** within GitL
- [Atlassian Crowd OmniAuth Provider](../../administration/auth/crowd.md)
- [CAS OmniAuth Provider](../../integration/cas.md)
- [SAML OmniAuth Provider](../../integration/saml.md)
- - [SAML for GitLab.com Groups](../../user/group/saml_sso/index.md) **[SILVER ONLY]**
- - [SCIM user provisioning for GitLab.com Groups](../../user/group/saml_sso/scim_setup.md) **[SILVER ONLY]**
+ - [SAML for GitLab.com Groups](../../user/group/saml_sso/index.md) **(SILVER ONLY)**
+ - [SCIM user provisioning for GitLab.com Groups](../../user/group/saml_sso/scim_setup.md) **(SILVER ONLY)**
- [Okta SSO provider](../../administration/auth/okta.md)
- - [Kerberos integration (GitLab EE)](../../integration/kerberos.md) **[STARTER]**
+ - [Kerberos integration (GitLab EE)](../../integration/kerberos.md) **(STARTER)**
## API
diff --git a/doc/topics/autodevops/index.md b/doc/topics/autodevops/index.md
index 41d12128e51..e2d51f673b5 100644
--- a/doc/topics/autodevops/index.md
+++ b/doc/topics/autodevops/index.md
@@ -61,15 +61,15 @@ project in a simple and automatic way:
1. [Auto Build](#auto-build)
1. [Auto Test](#auto-test)
-1. [Auto Code Quality](#auto-code-quality-starter) **[STARTER]**
-1. [Auto SAST (Static Application Security Testing)](#auto-sast-ultimate) **[ULTIMATE]**
-1. [Auto Dependency Scanning](#auto-dependency-scanning-ultimate) **[ULTIMATE]**
-1. [Auto License Management](#auto-license-management-ultimate) **[ULTIMATE]**
-1. [Auto Container Scanning](#auto-container-scanning-ultimate) **[ULTIMATE]**
+1. [Auto Code Quality](#auto-code-quality-starter) **(STARTER)**
+1. [Auto SAST (Static Application Security Testing)](#auto-sast-ultimate) **(ULTIMATE)**
+1. [Auto Dependency Scanning](#auto-dependency-scanning-ultimate) **(ULTIMATE)**
+1. [Auto License Management](#auto-license-management-ultimate) **(ULTIMATE)**
+1. [Auto Container Scanning](#auto-container-scanning-ultimate) **(ULTIMATE)**
1. [Auto Review Apps](#auto-review-apps)
-1. [Auto DAST (Dynamic Application Security Testing)](#auto-dast-ultimate) **[ULTIMATE]**
+1. [Auto DAST (Dynamic Application Security Testing)](#auto-dast-ultimate) **(ULTIMATE)**
1. [Auto Deploy](#auto-deploy)
-1. [Auto Browser Performance Testing](#auto-browser-performance-testing-premium) **[PREMIUM]**
+1. [Auto Browser Performance Testing](#auto-browser-performance-testing-premium) **(PREMIUM)**
1. [Auto Monitoring](#auto-monitoring)
As Auto DevOps relies on many different components, it's good to have a basic
@@ -169,14 +169,14 @@ Support for `AUTO_DEVOPS_DOMAIN` was [removed in GitLab
12.0](https://gitlab.com/gitlab-org/gitlab-ce/issues/56959).
-## Using multiple Kubernetes clusters **[PREMIUM]**
+## 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-premium).
-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:
+In the [Auto DevOps template] (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/`)
- `staging`
@@ -354,7 +354,7 @@ you may succeed with a [custom buildpack](#custom-buildpacks). Check the
Auto Test uses tests you already have in your application. If there are no
tests, it's up to you to add them.
-### Auto Code Quality **[STARTER]**
+### Auto Code Quality **(STARTER)**
Auto Code Quality uses the
[Code Quality image](https://gitlab.com/gitlab-org/security-products/codequality) to run
@@ -365,7 +365,7 @@ out.
Any differences between the source and target branches are also
[shown in the merge request widget](../../user/project/merge_requests/code_quality.md).
-### Auto SAST **[ULTIMATE]**
+### Auto SAST **(ULTIMATE)**
> Introduced in [GitLab Ultimate][ee] 10.3.
@@ -380,7 +380,7 @@ check out.
Any security warnings are also shown in the merge request widget. Read more how
[SAST works](../../user/application_security/sast/index.md).
-### Auto Dependency Scanning **[ULTIMATE]**
+### Auto Dependency Scanning **(ULTIMATE)**
> Introduced in [GitLab Ultimate][ee] 10.7.
@@ -397,7 +397,7 @@ check out.
Any security warnings are also shown in the merge request widget. Read more about
[Dependency Scanning](../../user/application_security/dependency_scanning/index.md).
-### Auto License Management **[ULTIMATE]**
+### Auto License Management **(ULTIMATE)**
> Introduced in [GitLab Ultimate][ee] 11.0.
@@ -413,7 +413,7 @@ check out.
Any licenses are also shown in the merge request widget. Read more how
[License Management works](../../user/application_security/license_management/index.md).
-### Auto Container Scanning **[ULTIMATE]**
+### Auto Container Scanning **(ULTIMATE)**
> Introduced in GitLab 10.4.
@@ -468,7 +468,7 @@ deploys with Auto DevOps can undo your changes. Also, if you change something
and want to undo it by deploying again, Helm may not detect that anything changed
in the first place, and thus not realize that it needs to re-apply the old config.
-### Auto DAST **[ULTIMATE]**
+### Auto DAST **(ULTIMATE)**
> Introduced in [GitLab Ultimate][ee] 10.4.
@@ -483,7 +483,7 @@ later download and check out.
Any security warnings are also shown in the merge request widget. Read how
[DAST works](../../user/application_security/dast/index.md).
-### Auto Browser Performance Testing **[PREMIUM]**
+### Auto Browser Performance Testing **(PREMIUM)**
> Introduced in [GitLab Premium][ee] 10.4.
@@ -655,32 +655,39 @@ repo or by specifying a project variable:
- **Project variable** - Create a [project variable](../../ci/variables/README.md#gitlab-cicd-environment-variables)
`AUTO_DEVOPS_CHART` with the URL of a custom chart to use or create two project variables `AUTO_DEVOPS_CHART_REPOSITORY` with the URL of a custom chart repository and `AUTO_DEVOPS_CHART` with the path to the chart.
-### Custom Helm chart per environment **[PREMIUM]**
+### Custom Helm chart per environment **(PREMIUM)**
You can specify the use of a custom Helm chart per environment by scoping the environment variable
to the desired environment. See [Limiting environment scopes of variables](../../ci/variables/README.md#limiting-environment-scopes-of-environment-variables-premium).
### Customizing `.gitlab-ci.yml`
-If you want to modify the CI/CD pipeline used by Auto DevOps, you can copy the
-[Auto DevOps template] into your project's repo and edit as you see fit.
+Everything about Auto DevOps is customizable since the [Auto DevOps template]
+is just an example of a [`.gitlab-ci.yml`](../../ci/yaml/README.md) and uses
+only features that are available to any `.gitlab-ci.yml`.
-Assuming that your project is new or it doesn't have a `.gitlab-ci.yml` file
-present:
+Auto DevOps is completely customizable because the [Auto DevOps template]:
-1. From your project home page, either click on the "Set up CI/CD" button, or click
- on the plus button and (`+`), then "New file"
-1. Pick `.gitlab-ci.yml` as the template type
-1. Select "Auto-DevOps" from the template dropdown
-1. Edit the template or add any jobs needed
-1. Give an appropriate commit message and hit "Commit changes"
+- Is just an implementation of a [`.gitlab-ci.yml`](../../ci/yaml/README.md) file.
+- Uses only features available to any implementation of `.gitlab-ci.yml`.
-TIP: **Tip:** The Auto DevOps template includes useful comments to help you
-customize it. For example, if you want deployments to go to a staging environment
-instead of directly to a production one, you can enable the `staging` job by
-renaming `.staging` to `staging`. Then make sure to uncomment the `when` key of
-the `production` job to turn it into a manual action instead of deploying
-automatically.
+If you want to modify the CI/CD pipeline used by Auto DevOps, you can [`include`
+the template](../../ci/yaml/README.md#includetemplate) and customize as
+needed. To do this, add a `.gitlab-ci.yml` file to the root of your repository
+containing the following:
+
+```yml
+include:
+ - template: Auto-DevOps.gitlab-ci.yml
+```
+
+Then add any extra changes you want. Your additions will be merged with the
+[Auto DevOps template] using the behaviour described for
+[`include`](../../ci/yaml/README.md#include).
+
+It is also possible to copy and paste the contents of the [Auto DevOps
+template] into your project and edit this as needed. You may prefer to do it
+that way if you want to specifically remove any part of it.
### Using components of Auto-DevOps
@@ -896,7 +903,7 @@ If `STAGING_ENABLED` is defined in your project (e.g., set `STAGING_ENABLED` to
to a `staging` environment, and a `production_manual` job will be created for
you when you're ready to manually deploy to production.
-#### Deploy policy for canary environments **[PREMIUM]**
+#### Deploy policy for canary environments **(PREMIUM)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ci-yml/merge_requests/171)
in GitLab 11.0.
@@ -911,7 +918,7 @@ If `CANARY_ENABLED` is defined in your project (e.g., set `CANARY_ENABLED` to
- `production_manual` which is to be used by you when you're ready to manually
deploy to production.
-#### Incremental rollout to production **[PREMIUM]**
+#### Incremental rollout to production **(PREMIUM)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/5415) in GitLab 10.8.
@@ -969,7 +976,7 @@ Before GitLab 11.4 this feature was enabled by the presence of the
`INCREMENTAL_ROLLOUT_ENABLED` environment variable.
This configuration is deprecated and will be removed in the future.
-#### Timed incremental rollout to production **[PREMIUM]**
+#### Timed incremental rollout to production **(PREMIUM)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/7545) in GitLab 11.4.
diff --git a/doc/topics/autodevops/quick_start_guide.md b/doc/topics/autodevops/quick_start_guide.md
index 6717e95266e..c1771a57da0 100644
--- a/doc/topics/autodevops/quick_start_guide.md
+++ b/doc/topics/autodevops/quick_start_guide.md
@@ -159,15 +159,15 @@ In the **test** stage, GitLab runs various checks on the application:
- The `test` job runs unit and integration tests by detecting the language and
framework ([Auto Test](index.md#auto-test))
- The `code_quality` job checks the code quality and is allowed to fail
- ([Auto Code Quality](index.md#auto-code-quality-starter)) **[STARTER]**
+ ([Auto Code Quality](index.md#auto-code-quality-starter)) **(STARTER)**
- The `container_scanning` job checks the Docker container if it has any
vulnerabilities and is allowed to fail ([Auto Container Scanning](index.md#auto-container-scanning-ultimate))
- The `dependency_scanning` job checks if the application has any dependencies
- susceptible to vulnerabilities and is allowed to fail ([Auto Dependency Scanning](index.md#auto-dependency-scanning-ultimate)) **[ULTIMATE]**
+ susceptible to vulnerabilities and is allowed to fail ([Auto Dependency Scanning](index.md#auto-dependency-scanning-ultimate)) **(ULTIMATE)**
- The `sast` job runs static analysis on the current code to check for potential
- security issues and is allowed to fail([Auto SAST](index.md#auto-sast-ultimate)) **[ULTIMATE]**
+ security issues and is allowed to fail([Auto SAST](index.md#auto-sast-ultimate)) **(ULTIMATE)**
- The `license_management` job searches the application's dependencies to determine each of their
- licenses and is allowed to fail ([Auto License Management](index.md#auto-license-management-ultimate)) **[ULTIMATE]**
+ licenses and is allowed to fail ([Auto License Management](index.md#auto-license-management-ultimate)) **(ULTIMATE)**
NOTE: **Note:**
As you might have noticed, all jobs except `test` are allowed to fail in the
@@ -178,7 +178,7 @@ deploys the application in Kubernetes ([Auto Deploy](index.md#auto-deploy)).
Lastly, in the **performance** stage, some performance tests will run
on the deployed application
-([Auto Browser Performance Testing](index.md#auto-browser-performance-testing-premium)). **[PREMIUM]**
+([Auto Browser Performance Testing](index.md#auto-browser-performance-testing-premium)). **(PREMIUM)**
---
@@ -285,8 +285,8 @@ all within GitLab. Despite its automatic nature, Auto DevOps can also be configu
and customized to fit your workflow. Here are some helpful resources for further reading:
1. [Auto DevOps](index.md)
-1. [Multiple Kubernetes clusters](index.md#using-multiple-kubernetes-clusters-premium) **[PREMIUM]**
-1. [Incremental rollout to production](index.md#incremental-rollout-to-production-premium) **[PREMIUM]**
+1. [Multiple Kubernetes clusters](index.md#using-multiple-kubernetes-clusters-premium) **(PREMIUM)**
+1. [Incremental rollout to production](index.md#incremental-rollout-to-production-premium) **(PREMIUM)**
1. [Disable jobs you don't need with environment variables](index.md#environment-variables)
1. [Use a static IP for your cluster](../../user/project/clusters/index.md#using-a-static-ip)
1. [Use your own buildpacks to build your application](index.md#custom-buildpacks)
diff --git a/doc/university/README.md b/doc/university/README.md
index 9d861460618..f696db2df20 100644
--- a/doc/university/README.md
+++ b/doc/university/README.md
@@ -73,7 +73,7 @@ The GitLab University curriculum is composed of GitLab videos, screencasts, pres
- Being part of our Great Community and Contributing to GitLab
1. [Getting Started with the GitLab Development Kit (GDK)](https://about.gitlab.com/2016/06/08/getting-started-with-gitlab-development-kit/)
1. [Contributing Technical Articles to the GitLab Blog](https://about.gitlab.com/2016/01/26/call-for-writers/)
-1. [GitLab Training Workshops](https://docs.gitlab.com/ce/university/training/end-user/)
+1. [GitLab Training Workshops](training/end-user/README.md)
1. [GitLab Professional Services](https://about.gitlab.com/services/)
### 1.8 GitLab Training Material
diff --git a/doc/university/support/README.md b/doc/university/support/README.md
index 2c6e52acfde..fdeba89f9c8 100644
--- a/doc/university/support/README.md
+++ b/doc/university/support/README.md
@@ -45,7 +45,7 @@ It's important to understand how to install GitLab in the same way that our user
Sometimes we need to upgrade customers from old versions of GitLab to latest, so it's good to get some experience of doing that now.
-- [Installation Methods](https://about.gitlab.com/installation/):
+- [Installation Methods](https://about.gitlab.com/install/):
- [Omnibus](https://gitlab.com/gitlab-org/omnibus-gitlab/)
- [Docker](https://gitlab.com/gitlab-org/gitlab-ce/tree/master/docker)
- [Source](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/install/installation.md)
diff --git a/doc/university/training/index.md b/doc/university/training/index.md
index 4c8ae0d9ce8..61fde9d8336 100644
--- a/doc/university/training/index.md
+++ b/doc/university/training/index.md
@@ -6,7 +6,7 @@ type: index
# GitLab Training Material
All GitLab training material is stored in markdown format. Slides are
-generated using [Deskset](http://www.decksetapp.com/).
+generated using [Deskset](https://www.deckset.com/).
All training material is open to public contribution.
@@ -35,8 +35,8 @@ This section contains the following topics:
## Additional Resources
1. [GitLab Documentation](https://docs.gitlab.com)
-1. [GUI Clients](http://git-scm.com/downloads/guis)
-1. [Pro Git book](http://git-scm.com/book)
+1. [GUI Clients](https://git-scm.com/downloads/guis)
+1. [Pro Git book](https://git-scm.com/book/en/v2)
1. [Platzi Course](https://courses.platzi.com/courses/git-gitlab/)
1. [Code School tutorial](http://try.github.io/)
1. Contact us at `subscribers@gitlab.com`
diff --git a/doc/update/mysql_to_postgresql.md b/doc/update/mysql_to_postgresql.md
index 4b13e41ab53..1e424134242 100644
--- a/doc/update/mysql_to_postgresql.md
+++ b/doc/update/mysql_to_postgresql.md
@@ -13,7 +13,7 @@ NOTE: **Note:**
Support for MySQL was removed in GitLab 12.1. This procedure should be performed
**before** installing GitLab 12.1.
-[pgloader](http://pgloader.io) 3.4.1+ is required.
+[pgloader](https://pgloader.io/) 3.4.1+ is required.
You can install it directly from your distribution, for example in
Debian/Ubuntu:
@@ -59,7 +59,7 @@ pgloader within the container as it is not included in the container image.
```
1. Install pgloader:
-
+
``` bash
apt-get update
apt-get -y install pgloader
diff --git a/doc/update/patch_versions.md b/doc/update/patch_versions.md
index 4300d6d56c7..0506d992d4b 100644
--- a/doc/update/patch_versions.md
+++ b/doc/update/patch_versions.md
@@ -100,7 +100,7 @@ sudo -u git -H git checkout v$(</home/git/gitlab/GITLAB_PAGES_VERSION)
sudo -u git -H make
```
-### 8. Install/Update `gitlab-elasticsearch-indexer` (optional) **[STARTER ONLY]**
+### 8. Install/Update `gitlab-elasticsearch-indexer` (optional) **(STARTER ONLY)**
If you're interested in using GitLab's new [elasticsearch repository indexer](../integration/elasticsearch.md#elasticsearch-repository-indexer-beta) (currently in beta)
please follow the instructions on the document linked above and enable the
diff --git a/doc/update/upgrading_from_ce_to_ee.md b/doc/update/upgrading_from_ce_to_ee.md
index 7ae716d2cb3..bea5bcd9dd7 100644
--- a/doc/update/upgrading_from_ce_to_ee.md
+++ b/doc/update/upgrading_from_ce_to_ee.md
@@ -72,7 +72,7 @@ sudo -u git -H bundle exec rake db:migrate RAILS_ENV=production
sudo -u git -H bundle exec rake assets:clean assets:precompile cache:clear RAILS_ENV=production
```
-### 4. Install `gitlab-elasticsearch-indexer` (optional) **[STARTER ONLY]**
+### 4. Install `gitlab-elasticsearch-indexer` (optional) **(STARTER ONLY)**
If you're interested in using GitLab's new [elasticsearch repository
indexer](../integration/elasticsearch.md) (currently in beta) please follow the instructions on the
diff --git a/doc/update/upgrading_from_source.md b/doc/update/upgrading_from_source.md
index 023dc7d6de3..d3b0a3c2829 100644
--- a/doc/update/upgrading_from_source.md
+++ b/doc/update/upgrading_from_source.md
@@ -76,7 +76,7 @@ sudo gem install bundler --no-document --version '< 2'
NOTE: Beginning in GitLab 11.8, we only support node 8 or higher, and dropped
support for node 6. Be sure to upgrade if necessary.
-GitLab utilizes [webpack](http://webpack.js.org) to compile frontend assets.
+GitLab utilizes [webpack](https://webpack.js.org/) to compile frontend assets.
This requires a minimum version of node v8.10.0.
You can check which version you are running with `node -v`. If you are running
diff --git a/doc/user/admin_area/custom_project_templates.md b/doc/user/admin_area/custom_project_templates.md
index e34ba045c54..427f3103cfc 100644
--- a/doc/user/admin_area/custom_project_templates.md
+++ b/doc/user/admin_area/custom_project_templates.md
@@ -1,6 +1,6 @@
-# Custom instance-level project templates **[PREMIUM ONLY]**
+# Custom instance-level project templates **(PREMIUM ONLY)**
-> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/6860) in [GitLab Premium](https://about.gitlab.com/pricing) 11.2.
+> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/6860) in [GitLab Premium](https://about.gitlab.com/pricing/) 11.2.
When you create a new [project](../project/index.md), creating it based on custom project templates is
a convenient bootstrap option.
diff --git a/doc/user/admin_area/geo_nodes.md b/doc/user/admin_area/geo_nodes.md
index d99b87cbc5c..9e7057f93d4 100644
--- a/doc/user/admin_area/geo_nodes.md
+++ b/doc/user/admin_area/geo_nodes.md
@@ -2,7 +2,7 @@
type: howto
---
-# Geo nodes admin area **[PREMIUM ONLY]**
+# Geo nodes admin area **(PREMIUM ONLY)**
You can configure various settings for GitLab Geo nodes. For more information, see
[Geo documentation](../../administration/geo/replication/index.md).
@@ -61,6 +61,12 @@ which is used by users. Internal URL does not need to be a private address.
Internal URL defaults to External URL, but you can customize it under
**Admin area > Geo Nodes**.
+CAUTION: **Warning:**
+We recommend using an HTTPS connection while configuring the Geo nodes. To avoid
+breaking communication between **primary** and **secondary** nodes when using
+HTTPS, customize your Internal URL to point to a Load Balancer with TLS
+termination.
+
## Multiple secondary nodes behind a load balancer
In GitLab 11.11, **secondary** nodes can use identical external URLs as long as
@@ -83,4 +89,4 @@ questions that you know someone might ask.
Each scenario can be a third-level heading, e.g. `### Getting error message X`.
If you have none to add when creating a doc, leave this section in place
-but commented out to help encourage others to add to it in the future. --> \ No newline at end of file
+but commented out to help encourage others to add to it in the future. -->
diff --git a/doc/user/admin_area/index.md b/doc/user/admin_area/index.md
index d2947ae3371..f5e6bff67c5 100644
--- a/doc/user/admin_area/index.md
+++ b/doc/user/admin_area/index.md
@@ -2,7 +2,7 @@
type: reference
---
-# GitLab Admin Area **[CORE ONLY]**
+# GitLab Admin Area **(CORE ONLY)**
The Admin Area provides a web UI for administering some features of GitLab self-managed instances.
@@ -26,9 +26,9 @@ The Admin Area is made up of the following sections:
| System Hooks | Configure [system hooks](../../system_hooks/system_hooks.md) for many events. |
| Applications | Create system [OAuth applications](../../integration/oauth_provider.md) for integrations with other services. |
| Abuse Reports | Manage [abuse reports](abuse_reports.md) submitted by your users. |
-| License **[STARTER ONLY]** | Upload, display, and remove [licenses](license.md). |
-| Push Rules **[STARTER]** | Configure pre-defined git [push rules](../../push_rules/push_rules.md) for projects. |
-| Geo **[PREMIUM ONLY]** | Configure and maintain [Geo nodes](geo_nodes.md). |
+| License **(STARTER ONLY)** | Upload, display, and remove [licenses](license.md). |
+| Push Rules **(STARTER)** | Configure pre-defined git [push rules](../../push_rules/push_rules.md) for projects. |
+| Geo **(PREMIUM ONLY)** | Configure and maintain [Geo nodes](geo_nodes.md). |
| Deploy Keys | Create instance-wide [SSH deploy keys](../../ssh/README.md#deploy-keys). |
| Service Templates | Create [service templates](../project/integrations/services_templates.md) for projects. |
| Labels | Create and maintain [labels](labels.md) for your GitLab instance. |
@@ -289,6 +289,6 @@ The content of each log file is listed in chronological order. To minimize perfo
The **Requests Profiles** page contains the token required for profiling. For more details, see [Request Profiling](../../administration/monitoring/performance/request_profiling.md).
-### Audit Log **[PREMIUM ONLY]**
+### Audit Log **(PREMIUM ONLY)**
The **Audit Log** page lists changes made within the GitLab server. With this information you can control, analyze, and track every change.
diff --git a/doc/user/admin_area/labels.md b/doc/user/admin_area/labels.md
index eba27548f86..1d15be89bd5 100644
--- a/doc/user/admin_area/labels.md
+++ b/doc/user/admin_area/labels.md
@@ -2,7 +2,7 @@
type: reference
---
-# Labels administration **[CORE ONLY]**
+# Labels administration **(CORE ONLY)**
In the Admin Area, you can manage labels for the GitLab instance. For more details, see [Labels](../project/labels.md).
diff --git a/doc/user/admin_area/license.md b/doc/user/admin_area/license.md
index 8ddb9c3d707..bbd04146eb2 100644
--- a/doc/user/admin_area/license.md
+++ b/doc/user/admin_area/license.md
@@ -2,7 +2,7 @@
type: howto
---
-# Activate all GitLab Enterprise Edition functionality with a license **[STARTER ONLY]**
+# Activate all GitLab Enterprise Edition functionality with a license **(STARTER ONLY)**
To activate all GitLab Enterprise Edition (EE) functionality, you need to upload
a license. Once you've received your license from GitLab Inc., you can upload it
diff --git a/doc/user/admin_area/settings/account_and_limit_settings.md b/doc/user/admin_area/settings/account_and_limit_settings.md
index 001e4b6bf48..9968b7349dc 100644
--- a/doc/user/admin_area/settings/account_and_limit_settings.md
+++ b/doc/user/admin_area/settings/account_and_limit_settings.md
@@ -4,7 +4,7 @@ type: reference
# Account and limit settings
-## Repository size limit **[STARTER]**
+## Repository size limit **(STARTER)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/740) in [GitLab Enterprise Edition 8.12](https://about.gitlab.com/2016/09/22/gitlab-8-12-released/#limit-project-size-ee).
> Available in [GitLab Starter](https://about.gitlab.com/pricing/).
@@ -44,10 +44,12 @@ The first push of a new project, including LFS objects, will be checked for size
and **will** be rejected if the sum of their sizes exceeds the maximum allowed
repository size.
+**Note:** The repository size limit includes repository files and LFS, and does not include artifacts.
+
For details on manually purging files, see [reducing the repository size using Git](../../project/repository/reducing_the_repo_size_using_git.md).
NOTE: **Note:**
-For GitLab.com, the repository size limit is 10 GB.
+GitLab.com repository size [is set by GitLab](../../gitlab_com/index.md#repository-size-limit).
<!-- ## Troubleshooting
diff --git a/doc/user/admin_area/settings/continuous_integration.md b/doc/user/admin_area/settings/continuous_integration.md
index 84596ff6a2c..ebbb2472752 100644
--- a/doc/user/admin_area/settings/continuous_integration.md
+++ b/doc/user/admin_area/settings/continuous_integration.md
@@ -2,14 +2,14 @@
type: reference
---
-# Continuous Integration and Deployment Admin settings **[CORE ONLY]**
+# Continuous Integration and Deployment Admin settings **(CORE ONLY)**
In this area, you will find settings for Auto DevOps, Runners and job artifacts.
You can find it in the admin area, under **Settings > Continuous Integration and Deployment**.
![Admin area settings button](../img/admin_area_settings_button.png)
-## Auto DevOps **[CORE ONLY]**
+## Auto DevOps **(CORE ONLY)**
To enable (or disable) [Auto DevOps](../../../topics/autodevops/index.md)
for all projects:
@@ -26,7 +26,7 @@ From now on, every existing project and newly created ones that don't have a
If you want to disable it for a specific project, you can do so in
[its settings](../../../topics/autodevops/index.md#enablingdisabling-auto-devops).
-## Maximum artifacts size **[CORE ONLY]**
+## Maximum artifacts size **(CORE ONLY)**
The maximum size of the [job artifacts](../../../administration/job_artifacts.md)
can be set in the Admin area of your GitLab instance. The value is in *MB* and
@@ -38,7 +38,7 @@ To change it:
1. Change the value of maximum artifacts size (in MB).
1. Hit **Save changes** for the changes to take effect.
-## Default artifacts expiration **[CORE ONLY]**
+## Default artifacts expiration **(CORE ONLY)**
The default expiration time of the [job artifacts](../../../administration/job_artifacts.md)
can be set in the Admin area of your GitLab instance. The syntax of duration is
@@ -54,7 +54,7 @@ This setting is set per job and can be overridden in
[`.gitlab-ci.yml`](../../../ci/yaml/README.md#artifactsexpire_in).
To disable the expiration, set it to `0`. The default unit is in seconds.
-## Shared Runners pipeline minutes quota **[STARTER ONLY]**
+## Shared Runners pipeline minutes quota **(STARTER ONLY)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/1078)
in GitLab Starter 8.16.
@@ -137,7 +137,7 @@ includes a link to [purchase more minutes](https://customers.gitlab.com/plans).
If you are not the owner of the group, you will need to contact them to let them know they need to
[purchase more minutes](https://customers.gitlab.com/plans).
-## Archive jobs **[CORE ONLY]**
+## Archive jobs **(CORE ONLY)**
Archiving jobs is useful for reducing the CI/CD footprint on the system by
removing some of the capabilities of the jobs (metadata needed to run the job),
diff --git a/doc/user/admin_area/settings/email.md b/doc/user/admin_area/settings/email.md
index 9555a695b13..1f07a4dfdc6 100644
--- a/doc/user/admin_area/settings/email.md
+++ b/doc/user/admin_area/settings/email.md
@@ -10,7 +10,7 @@ You can customize some of the content in emails sent from your GitLab instance.
The logo in the header of some emails can be customized, see the [logo customization section](../../../customization/branded_page_and_email_header.md).
-## Custom additional text **[PREMIUM ONLY]**
+## Custom additional text **(PREMIUM ONLY)**
> [Introduced][ee-5031] in [GitLab Premium][eep] 10.7.
diff --git a/doc/user/admin_area/settings/external_authorization.md b/doc/user/admin_area/settings/external_authorization.md
index c1aa04f7bc2..4fde7477490 100644
--- a/doc/user/admin_area/settings/external_authorization.md
+++ b/doc/user/admin_area/settings/external_authorization.md
@@ -2,10 +2,10 @@
type: reference
---
-# External authorization control **[CORE ONLY]**
+# External authorization control **(CORE ONLY)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/4216) in
-> [GitLab Premium](https://about.gitlab.com/pricing) 10.6.
+> [GitLab Premium](https://about.gitlab.com/pricing/) 10.6.
> [Moved](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/27056) to
> [GitLab Core](https://about.gitlab.com/pricing/) in 11.10.
diff --git a/doc/user/admin_area/settings/index.md b/doc/user/admin_area/settings/index.md
index eed087ae52b..5427d04cd7d 100644
--- a/doc/user/admin_area/settings/index.md
+++ b/doc/user/admin_area/settings/index.md
@@ -2,7 +2,7 @@
type: index
---
-# Admin Area settings **[CORE ONLY]**
+# Admin Area settings **(CORE ONLY)**
In the Admin Area **Settings** page, you can find various options for your GitLab
instance like sign-up restrictions, account limits and quota, metrics, etc.
@@ -10,7 +10,7 @@ instance like sign-up restrictions, account limits and quota, metrics, etc.
Navigate to it by going to **Admin Area > Settings**. Some of the settings
include:
-- [Account and limit settings](account_and_limit_settings.md) **[STARTER]**
+- [Account and limit settings](account_and_limit_settings.md) **(STARTER)**
- [Continuous Integration and Deployment](continuous_integration.md)
- [Email](email.md)
- [Sign up restrictions](sign_up_restrictions.md)
@@ -18,7 +18,7 @@ include:
- [Third party offers](third_party_offers.md)
- [Usage statistics](usage_statistics.md)
- [Visibility and access controls](visibility_and_access_controls.md)
-- [Custom templates repository](instance_template_repository.md) **[PREMIUM]**
+- [Custom templates repository](instance_template_repository.md) **(PREMIUM)**
NOTE: **Note:**
You can change the [first day of the week](../../profile/preferences.md) for the entire GitLab instance
diff --git a/doc/user/admin_area/settings/instance_template_repository.md b/doc/user/admin_area/settings/instance_template_repository.md
index 91286a67c31..f2ba131d17b 100644
--- a/doc/user/admin_area/settings/instance_template_repository.md
+++ b/doc/user/admin_area/settings/instance_template_repository.md
@@ -2,10 +2,10 @@
type: reference
---
-# Instance template repository **[PREMIUM ONLY]**
+# Instance template repository **(PREMIUM ONLY)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/5986) in
-> [GitLab Premium](https://about.gitlab.com/pricing) 11.3.
+> [GitLab Premium](https://about.gitlab.com/pricing/) 11.3.
## Overview
diff --git a/doc/user/admin_area/settings/usage_statistics.md b/doc/user/admin_area/settings/usage_statistics.md
index 652d6ad2cdd..f698e0a1608 100644
--- a/doc/user/admin_area/settings/usage_statistics.md
+++ b/doc/user/admin_area/settings/usage_statistics.md
@@ -10,7 +10,7 @@ to perform various actions.
All statistics are opt-out, you can enable/disable them from the admin panel
under **Admin area > Settings > Metrics and profiling > Usage statistics**.
-## Version check **[CORE ONLY]**
+## Version check **(CORE ONLY)**
If enabled, version check will inform you if a new version is available and the
importance of it through a status. This is shown on the help page (i.e. `/help`)
@@ -33,7 +33,7 @@ secure.
If you disable version check, this information will not be collected. Enable or
disable the version check at **Admin area > Settings > Usage statistics**.
-## Usage ping **[CORE ONLY]**
+## Usage ping **(CORE ONLY)**
> [Introduced][ee-557] in GitLab Enterprise Edition 8.10. More statistics
[were added][ee-735] in GitLab Enterprise Edition
@@ -78,7 +78,7 @@ production: &base
usage_ping_enabled: false
```
-## Instance statistics visibility **[CORE ONLY]**
+## Instance statistics visibility **(CORE ONLY)**
Once usage ping is enabled, GitLab will gather data from other instances and
will be able to show [usage statistics](../../instance_statistics/index.md)
diff --git a/doc/user/admin_area/settings/visibility_and_access_controls.md b/doc/user/admin_area/settings/visibility_and_access_controls.md
index 63879935fd8..bf59f49b993 100644
--- a/doc/user/admin_area/settings/visibility_and_access_controls.md
+++ b/doc/user/admin_area/settings/visibility_and_access_controls.md
@@ -12,7 +12,7 @@ GitLab allows administrators to:
- Enable or disable repository mirroring.
- Prevent non-administrators from deleting projects
([introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/5615) in GitLab 12.0).
- **[PREMIUM ONLY]**
+ **(PREMIUM ONLY)**
To access the visibility and access control options:
diff --git a/doc/user/application_security/container_scanning/index.md b/doc/user/application_security/container_scanning/index.md
index 9dfbe326f1d..696446599c8 100644
--- a/doc/user/application_security/container_scanning/index.md
+++ b/doc/user/application_security/container_scanning/index.md
@@ -1,4 +1,4 @@
-# Container Scanning **[ULTIMATE]**
+# Container Scanning **(ULTIMATE)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/3672)
in [GitLab Ultimate](https://about.gitlab.com/pricing/) 10.4.
diff --git a/doc/user/application_security/dast/index.md b/doc/user/application_security/dast/index.md
index 2283efe3a44..936703cce32 100644
--- a/doc/user/application_security/dast/index.md
+++ b/doc/user/application_security/dast/index.md
@@ -1,4 +1,4 @@
-# Dynamic Application Security Testing (DAST) **[ULTIMATE]**
+# Dynamic Application Security Testing (DAST) **(ULTIMATE)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/4348)
in [GitLab Ultimate](https://about.gitlab.com/pricing/) 10.4.
diff --git a/doc/user/application_security/dependency_scanning/analyzers.md b/doc/user/application_security/dependency_scanning/analyzers.md
index 937ded287e5..3b4b341739b 100644
--- a/doc/user/application_security/dependency_scanning/analyzers.md
+++ b/doc/user/application_security/dependency_scanning/analyzers.md
@@ -1,4 +1,4 @@
-# Dependency Scanning Analyzers **[ULTIMATE]**
+# Dependency Scanning Analyzers **(ULTIMATE)**
Dependency Scanning relies on underlying third party tools that are wrapped into
what we call "Analyzers". An analyzer is a
diff --git a/doc/user/application_security/dependency_scanning/index.md b/doc/user/application_security/dependency_scanning/index.md
index 9145e034dcb..2fe8a6f9029 100644
--- a/doc/user/application_security/dependency_scanning/index.md
+++ b/doc/user/application_security/dependency_scanning/index.md
@@ -1,4 +1,4 @@
-# Dependency Scanning **[ULTIMATE]**
+# Dependency Scanning **(ULTIMATE)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/5105)
in [GitLab Ultimate](https://about.gitlab.com/pricing/) 10.7.
diff --git a/doc/user/application_security/index.md b/doc/user/application_security/index.md
index 69fa1ec5da6..91e79f6c23b 100644
--- a/doc/user/application_security/index.md
+++ b/doc/user/application_security/index.md
@@ -1,4 +1,4 @@
-# GitLab Secure **[ULTIMATE]**
+# GitLab Secure **(ULTIMATE)**
Check your application for security vulnerabilities that may lead to unauthorized access,
data leaks, and denial of services. GitLab will perform static and dynamic tests on the
@@ -12,12 +12,12 @@ GitLab can scan and report any vulnerabilities found in your project.
| Secure scanning tool | Description |
|:-----------------------------------------------------------------------------|:-----------------------------------------------------------------------|
-| [Container Scanning](container_scanning/index.md) **[ULTIMATE]** | Scan Docker containers for known vulnerabilities. |
-| [Dependency Scanning](dependency_scanning/index.md) **[ULTIMATE]** | Analyze your dependencies for known vulnerabilities. |
-| [Dynamic Application Security Testing (DAST)](dast/index.md) **[ULTIMATE]** | Analyze running web applications for known vulnerabilities. |
-| [License Management](license_management/index.md) **[ULTIMATE]** | Search your project's dependencies for their licenses. |
-| [Security Dashboard](security_dashboard/index.md) **[ULTIMATE]** | View vulnerabilities in all your projects and groups. |
-| [Static Application Security Testing (SAST)](sast/index.md) **[ULTIMATE]** | Analyze source code for known vulnerabilities. |
+| [Container Scanning](container_scanning/index.md) **(ULTIMATE)** | Scan Docker containers for known vulnerabilities. |
+| [Dependency Scanning](dependency_scanning/index.md) **(ULTIMATE)** | Analyze your dependencies for known vulnerabilities. |
+| [Dynamic Application Security Testing (DAST)](dast/index.md) **(ULTIMATE)** | Analyze running web applications for known vulnerabilities. |
+| [License Management](license_management/index.md) **(ULTIMATE)** | Search your project's dependencies for their licenses. |
+| [Security Dashboard](security_dashboard/index.md) **(ULTIMATE)** | View vulnerabilities in all your projects and groups. |
+| [Static Application Security Testing (SAST)](sast/index.md) **(ULTIMATE)** | Analyze source code for known vulnerabilities. |
## Maintenance and update of the vulnerabilities database
diff --git a/doc/user/application_security/license_management/index.md b/doc/user/application_security/license_management/index.md
index 957c4ede981..8eb231f8359 100644
--- a/doc/user/application_security/license_management/index.md
+++ b/doc/user/application_security/license_management/index.md
@@ -1,4 +1,4 @@
-# License Management **[ULTIMATE]**
+# License Management **(ULTIMATE)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/5483)
in [GitLab Ultimate](https://about.gitlab.com/pricing/) 11.0.
@@ -46,12 +46,19 @@ The following languages and package managers are supported.
| Language | Package managers | Scan Tool |
|------------|-------------------------------------------------------------------|----------------------------------------------------------|
-| JavaScript | [Bower](https://bower.io/), [npm](https://www.npmjs.com/) |[License Finder](https://github.com/pivotal/LicenseFinder)|
-| Go | [Godep](https://github.com/tools/godep), go get |[License Finder](https://github.com/pivotal/LicenseFinder)|
+| JavaScript | [Bower](https://bower.io/), [npm](https://www.npmjs.com/), [yarn](https://yarnpkg.com/) ([experimental support](https://github.com/pivotal/LicenseFinder#experimental-project-types)) |[License Finder](https://github.com/pivotal/LicenseFinder)|
+| Go | [Godep](https://github.com/tools/godep), go get ([experimental support](https://github.com/pivotal/LicenseFinder#experimental-project-types)), gvt ([experimental support](https://github.com/pivotal/LicenseFinder#experimental-project-types)), glide ([experimental support](https://github.com/pivotal/LicenseFinder#experimental-project-types)), dep ([experimental support](https://github.com/pivotal/LicenseFinder#experimental-project-types)), trash ([experimental support](https://github.com/pivotal/LicenseFinder#experimental-project-types)) and govendor ([experimental support](https://github.com/pivotal/LicenseFinder#experimental-project-types)), [go mod](https://github.com/golang/go/wiki/Modules) ([experimental support](https://github.com/pivotal/LicenseFinder#experimental-project-types)) |[License Finder](https://github.com/pivotal/LicenseFinder)|
| Java | [Gradle](https://gradle.org/), [Maven](https://maven.apache.org/) |[License Finder](https://github.com/pivotal/LicenseFinder)|
| .NET | [Nuget](https://www.nuget.org/) |[License Finder](https://github.com/pivotal/LicenseFinder)|
| Python | [pip](https://pip.pypa.io/en/stable/) |[License Finder](https://github.com/pivotal/LicenseFinder)|
| Ruby | [gem](https://rubygems.org/) |[License Finder](https://github.com/pivotal/LicenseFinder)|
+| Erlang | [rebar](https://www.rebar3.org/) ([experimental support](https://github.com/pivotal/LicenseFinder#experimental-project-types))|[License Finder](https://github.com/pivotal/LicenseFinder)|
+| Objective-C, Swift | [Carthage](https://github.com/Carthage/Carthage) , [CocoaPods v0.39 and below](https://cocoapods.org/) ([experimental support](https://github.com/pivotal/LicenseFinder#experimental-project-types)) |[License Finder](https://github.com/pivotal/LicenseFinder)|
+| Elixir | [mix](https://elixir-lang.org/getting-started/mix-otp/introduction-to-mix.html) ([experimental support](https://github.com/pivotal/LicenseFinder#experimental-project-types)) |[License Finder](https://github.com/pivotal/LicenseFinder)|
+| C++/C | [conan](https://conan.io/) ([experimental support](https://github.com/pivotal/LicenseFinder#experimental-project-types))|[License Finder](https://github.com/pivotal/LicenseFinder)|
+| Scala | [sbt](https://www.scala-sbt.org/) ([experimental support](https://github.com/pivotal/LicenseFinder#experimental-project-types))|[License Finder](https://github.com/pivotal/LicenseFinder)|
+| Rust | [cargo](https://crates.io/) ([experimental support](https://github.com/pivotal/LicenseFinder#experimental-project-types))|[License Finder](https://github.com/pivotal/LicenseFinder)|
+| PHP | [composer](https://getcomposer.org/) ([experimental support](https://github.com/pivotal/LicenseFinder#experimental-project-types))|[License Finder](https://github.com/pivotal/LicenseFinder)|
## Requirements
diff --git a/doc/user/application_security/sast/index.md b/doc/user/application_security/sast/index.md
index 9074ac3f4a1..84b45cbe6e6 100644
--- a/doc/user/application_security/sast/index.md
+++ b/doc/user/application_security/sast/index.md
@@ -1,4 +1,4 @@
-# Static Application Security Testing (SAST) **[ULTIMATE]**
+# Static Application Security Testing (SAST) **(ULTIMATE)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/3775)
in [GitLab Ultimate](https://about.gitlab.com/pricing/) 10.3.
diff --git a/doc/user/application_security/security_dashboard/index.md b/doc/user/application_security/security_dashboard/index.md
index 19eeb06a259..3b01fe66e03 100644
--- a/doc/user/application_security/security_dashboard/index.md
+++ b/doc/user/application_security/security_dashboard/index.md
@@ -1,4 +1,4 @@
-# GitLab Security Dashboard **[ULTIMATE]**
+# GitLab Security Dashboard **(ULTIMATE)**
The Security Dashboard is a good place to get an overview of all the security
vulnerabilities in your groups and projects.
diff --git a/doc/user/asciidoc.md b/doc/user/asciidoc.md
index a22b285b114..06cc64b209d 100644
--- a/doc/user/asciidoc.md
+++ b/doc/user/asciidoc.md
@@ -1,12 +1,12 @@
# AsciiDoc
GitLab uses the [Asciidoctor](https://asciidoctor.org) gem to convert AsciiDoc content to HTML5.
-Consult the [Asciidoctor User Manual](https://asciidoctor.org/docs/user-manual) for a complete Asciidoctor reference.
+Consult the [Asciidoctor User Manual](https://asciidoctor.org/docs/user-manual/) for a complete Asciidoctor reference.
## Syntax
Here's a brief reference of the most commonly used AsciiDoc syntax.
-You can find the full documentation for the AsciiDoc syntax at https://asciidoctor.org/docs.
+You can find the full documentation for the AsciiDoc syntax at <https://asciidoctor.org/docs>.
### Paragraphs
diff --git a/doc/user/clusters/applications.md b/doc/user/clusters/applications.md
index b520c4fb579..2246ea8ed5a 100644
--- a/doc/user/clusters/applications.md
+++ b/doc/user/clusters/applications.md
@@ -111,7 +111,7 @@ file.
[Ingress](https://kubernetes.github.io/ingress-nginx/) 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.
+DevOps](../../topics/autodevops/index.md) or deploy your own web apps.
NOTE: **Note:**
The
@@ -251,6 +251,8 @@ The applications below can be uninstalled.
| Application | GitLab version | Notes |
| ----------- | -------------- | ----- |
+| Ingress | 12.1+ | The associated load balancer and IP will be deleted and cannot be restored. Furthermore, it can only be uninstalled if JupyterHub is not installed. |
+| JupyterHub | 12.1+ | All data not committed to GitLab will be deleted and cannot be restored. |
| Prometheus | 11.11+ | All data will be deleted and cannot be restored. |
To uninstall an application:
@@ -287,4 +289,3 @@ To avoid installation errors:
kubectl get secrets/tiller-secret -n gitlab-managed-apps -o "jsonpath={.data['ca\.crt']}" | base64 -d > b.pem
diff a.pem b.pem
```
-
diff --git a/doc/user/discussions/index.md b/doc/user/discussions/index.md
index 20eabdada79..f2156720af7 100644
--- a/doc/user/discussions/index.md
+++ b/doc/user/discussions/index.md
@@ -5,7 +5,7 @@ The ability to contribute conversationally is offered throughout GitLab.
You can leave a comment in the following places:
- issues
-- epics **[ULTIMATE]**
+- epics **(ULTIMATE)**
- merge requests
- snippets
- commits
@@ -282,7 +282,7 @@ edit existing comments. Non-team members are restricted from adding or editing c
Additionally, locked issues and merge requests can not be reopened.
-## Merge Request Reviews **[PREMIUM]**
+## Merge Request Reviews **(PREMIUM)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/4213) in GitLab 11.4.
diff --git a/doc/user/gitlab_com/index.md b/doc/user/gitlab_com/index.md
index 2fb6cec55fa..7858c419e04 100644
--- a/doc/user/gitlab_com/index.md
+++ b/doc/user/gitlab_com/index.md
@@ -1,7 +1,7 @@
# GitLab.com settings
In this page you will find information about the settings that are used on
-[GitLab.com](https://about.gitlab.com/pricing).
+[GitLab.com](https://about.gitlab.com/pricing/).
## SSH host keys fingerprints
@@ -73,9 +73,9 @@ or over the size limit, you can [reduce your repository size with Git](../projec
## IP range
-GitLab.com, CI/CD, and related services are deployed into Google Cloud Platform (GCP). Any
-IP based firewall can be configured by looking up all
-[IP address ranges or CIDR blocks for GCP](https://cloud.google.com/compute/docs/faq#where_can_i_find_product_name_short_ip_ranges).
+GitLab.com, CI/CD, and related services are deployed into Google Cloud Platform (GCP). Any
+IP based firewall can be configured by looking up all
+[IP address ranges or CIDR blocks for GCP](https://cloud.google.com/compute/docs/faq#where_can_i_find_product_name_short_ip_ranges).
[Static endpoints](https://gitlab.com/gitlab-com/gl-infra/infrastructure/issues/5071) are being considered.
@@ -260,7 +260,7 @@ The list of GitLab.com specific settings (and their defaults) is as follows:
| hot_standby_feedback | on | off |
| log_autovacuum_min_duration | 0 | -1 |
| log_checkpoints | on | off |
-| log_line_prefix | `%t [%p]: [%l-1] ` | empty |
+| log_line_prefix | `%t [%p]: [%l-1]` | empty |
| log_min_duration_statement | 1000 | -1 |
| log_temp_files | 0 | -1 |
| maintenance_work_mem | 2048MB | 16 MB |
@@ -352,3 +352,11 @@ High Performance TCP/HTTP Load Balancer:
[unicorn-worker-killer]: https://rubygems.org/gems/unicorn-worker-killer "unicorn-worker-killer"
[4010]: https://gitlab.com/gitlab-com/infrastructure/issues/4010 "Find a good value for maximum timeout for Shared Runners"
[4070]: https://gitlab.com/gitlab-com/infrastructure/issues/4070 "Configure per-runner timeout for shared-runners-manager-X on GitLab.com"
+
+## Group and project settings
+
+On GitLab.com, projects, groups, and snippets created
+after July 2019 have the `Internal` visibility setting disabled.
+
+You can read more about the change in the
+[relevant issue](https://gitlab.com/gitlab-org/gitlab-ee/issues/12388).
diff --git a/doc/user/group/clusters/index.md b/doc/user/group/clusters/index.md
index 8d4ffd93f59..0dffc216f8e 100644
--- a/doc/user/group/clusters/index.md
+++ b/doc/user/group/clusters/index.md
@@ -42,7 +42,7 @@ to the group containing the project if the project's cluster is available and no
In the case of sub-groups, GitLab will use the cluster of the closest ancestor group
to the project, provided the cluster is not disabled.
-## Multiple Kubernetes clusters **[PREMIUM]**
+## Multiple Kubernetes clusters **(PREMIUM)**
With GitLab Premium, you can associate more than one Kubernetes clusters to your
group. That way you can have different clusters for different environments,
@@ -82,7 +82,7 @@ the [Auto DevOps](../../../topics/autodevops/index.md) stages.
The domain should have a wildcard DNS configured to the Ingress IP address.
-## Environment scopes **[PREMIUM]**
+## Environment scopes **(PREMIUM)**
When adding more than one Kubernetes cluster to your project, you need to differentiate
them with an environment scope. The environment scope associates clusters with
diff --git a/doc/user/group/contribution_analytics/index.md b/doc/user/group/contribution_analytics/index.md
index a555b7723df..2d37fc375db 100644
--- a/doc/user/group/contribution_analytics/index.md
+++ b/doc/user/group/contribution_analytics/index.md
@@ -2,7 +2,7 @@
type: reference
---
-# Contribution Analytics **[STARTER]**
+# Contribution Analytics **(STARTER)**
> Introduced in [GitLab Starter](https://about.gitlab.com/pricing/) 8.3.
diff --git a/doc/user/group/custom_project_templates.md b/doc/user/group/custom_project_templates.md
index aa088d2fcdb..8a85c375490 100644
--- a/doc/user/group/custom_project_templates.md
+++ b/doc/user/group/custom_project_templates.md
@@ -2,9 +2,9 @@
type: reference
---
-# Custom group-level project templates **[PREMIUM]**
+# Custom group-level project templates **(PREMIUM)**
-> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/6861) in [GitLab Premium](https://about.gitlab.com/pricing) 11.6.
+> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/6861) in [GitLab Premium](https://about.gitlab.com/pricing/) 11.6.
When you create a new [project](../project/index.md), creating it based on custom project templates is
a convenient bootstrap option.
diff --git a/doc/user/group/dependency_proxy/index.md b/doc/user/group/dependency_proxy/index.md
index 4fc2d8e9509..771468fbba8 100644
--- a/doc/user/group/dependency_proxy/index.md
+++ b/doc/user/group/dependency_proxy/index.md
@@ -1,4 +1,4 @@
-# Dependency Proxy **[PREMIUM]**
+# Dependency Proxy **(PREMIUM)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/7934) in [GitLab Premium](https://about.gitlab.com/pricing/) 11.11.
diff --git a/doc/user/group/epics/index.md b/doc/user/group/epics/index.md
index f53c1dd95d7..601ffd4947b 100644
--- a/doc/user/group/epics/index.md
+++ b/doc/user/group/epics/index.md
@@ -2,7 +2,7 @@
type: reference, howto
---
-# Epics **[ULTIMATE]**
+# Epics **(ULTIMATE)**
> Introduced in [GitLab Ultimate][ee] 10.2.
diff --git a/doc/user/group/index.md b/doc/user/group/index.md
index 7240b8e118b..db348c678eb 100644
--- a/doc/user/group/index.md
+++ b/doc/user/group/index.md
@@ -200,7 +200,7 @@ Alternatively, you can [lock the sharing with group feature](#share-with-group-l
In GitLab Enterprise Edition, it is possible to manage GitLab group memberships using LDAP groups.
See [the GitLab Enterprise Edition documentation](../../integration/ldap.md) for more information.
-## Epics **[ULTIMATE]**
+## Epics **(ULTIMATE)**
> Introduced in [GitLab Ultimate][ee] 10.2.
@@ -210,13 +210,13 @@ milestones.
[Learn more about Epics.](epics/index.md)
-## Group Security Dashboard **[ULTIMATE]**
+## Group Security Dashboard **(ULTIMATE)**
Get an overview of the vulnerabilities of all the projects in a group and its subgroups.
[Learn more about the Group Security Dashboard.](security_dashboard/index.md)
-## Insights **[ULTIMATE]**
+## Insights **(ULTIMATE)**
> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/725) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 12.0.
@@ -307,7 +307,7 @@ To enable this feature, navigate to the group settings page. Select
![Checkbox for share with group lock](img/share_with_group_lock.png)
-#### Member Lock **[STARTER]**
+#### Member Lock **(STARTER)**
Member lock lets a group owner prevent any new project membership to all of the
projects within a group, allowing tighter control over project membership.
@@ -327,7 +327,7 @@ This will disable the option for all users who previously had permissions to
operate project memberships, so no new users can be added. Furthermore, any
request to add a new user to a project through API will not be possible.
-#### IP access restriction **[ULTIMATE]**
+#### IP access restriction **(ULTIMATE)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/1985) in
[GitLab Ultimate](https://about.gitlab.com/pricing/) 12.0.
@@ -346,7 +346,7 @@ Restriction currently applies to UI, API access is not restricted.
To avoid accidental lock-out, admins and group owners are are able to access
the group regardless of the IP restriction.
-#### Group file templates **[PREMIUM]**
+#### Group file templates **(PREMIUM)**
Group file templates allow you to share a set of templates for common file
types with every project in a group. It is analogous to the
@@ -370,7 +370,7 @@ To enable this feature, navigate to the group settings page, expand the
![Group file template settings](img/group_file_template_settings.png)
-#### Group-level project templates **[PREMIUM]**
+#### Group-level project templates **(PREMIUM)**
Define project templates at a group level by setting a group as the template source.
[Learn more about group-level project templates](custom_project_templates.md).
@@ -382,10 +382,10 @@ Define project templates at a group level by setting a group as the template sou
- **Webhooks**: Configure [webhooks](../project/integrations/webhooks.md) for your group.
- **Kubernetes cluster integration**: Connect your GitLab group with [Kubernetes clusters](clusters/index.md).
- **Audit Events**: View [Audit Events](../../administration/audit_events.md)
- for the group. **[STARTER ONLY]**
+ for the group. **(STARTER ONLY)**
- **Pipelines quota**: Keep track of the [pipeline quota](../admin_area/settings/continuous_integration.md) for the group.
-#### Storage usage quota **[STARTER]**
+#### Storage usage quota **(STARTER)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/13294) in [GitLab Starter](https://about.gitlab.com/pricing/) 12.0.
@@ -393,17 +393,17 @@ A group owner can check the aggregated storage usage for all the project in a gr
![Group storage usage quota](img/group_storage_usage_quota.png)
-## User contribution analysis **[STARTER]**
+## User contribution analysis **(STARTER)**
With [GitLab Contribution Analytics](contribution_analytics/index.md),
you have an overview of the contributions (pushes, merge requests,
and issues) performed by your group members.
-## Issues analytics **[PREMIUM]**
+## Issues analytics **(PREMIUM)**
With [GitLab Issues Analytics](issues_analytics/index.md), you can see a bar chart of the number of issues created each month in your groups.
-## Dependency Proxy **[PREMIUM]**
+## Dependency Proxy **(PREMIUM)**
Use GitLab as a [dependency proxy](dependency_proxy/index.md) for upstream Docker images.
diff --git a/doc/user/group/insights/index.md b/doc/user/group/insights/index.md
index e6ba47939b3..f0e7f7239c1 100644
--- a/doc/user/group/insights/index.md
+++ b/doc/user/group/insights/index.md
@@ -2,7 +2,7 @@
type: reference, howto
---
-# Insights **[ULTIMATE]**
+# Insights **(ULTIMATE)**
> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/725) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 12.0.
diff --git a/doc/user/group/issues_analytics/index.md b/doc/user/group/issues_analytics/index.md
index 46d5c1e2e09..dc4b057789f 100644
--- a/doc/user/group/issues_analytics/index.md
+++ b/doc/user/group/issues_analytics/index.md
@@ -2,7 +2,7 @@
type: reference
---
-# Issues Analytics **[PREMIUM]**
+# Issues Analytics **(PREMIUM)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/7478) in [GitLab Premium](https://about.gitlab.com/pricing/) 11.5.
diff --git a/doc/user/group/roadmap/index.md b/doc/user/group/roadmap/index.md
index 683c715c8d5..a72cd990706 100644
--- a/doc/user/group/roadmap/index.md
+++ b/doc/user/group/roadmap/index.md
@@ -2,9 +2,9 @@
type: reference
---
-# Roadmap **[ULTIMATE]**
+# Roadmap **(ULTIMATE)**
-> Introduced in [GitLab Ultimate](https://about.gitlab.com/pricing) 10.5.
+> Introduced in [GitLab Ultimate](https://about.gitlab.com/pricing/) 10.5.
An Epic within a group containing **Start date** and/or **Due date**
can be visualized in a form of a timeline (e.g. a Gantt chart). The Epics Roadmap page
@@ -30,7 +30,7 @@ Roadmaps can also be [visualized inside an epic](../epics/index.md#roadmap-in-ep
## Timeline duration
-> Introduced in [GitLab Ultimate](https://about.gitlab.com/pricing) 11.0.
+> Introduced in [GitLab Ultimate](https://about.gitlab.com/pricing/) 11.0.
Roadmap supports the following date ranges:
diff --git a/doc/user/group/saml_sso/index.md b/doc/user/group/saml_sso/index.md
index 26893f7e31e..54923ab69ff 100644
--- a/doc/user/group/saml_sso/index.md
+++ b/doc/user/group/saml_sso/index.md
@@ -2,7 +2,7 @@
type: reference, howto
---
-# SAML SSO for GitLab.com Groups **[SILVER ONLY]**
+# SAML SSO for GitLab.com Groups **(SILVER ONLY)**
> Introduced in [GitLab.com Silver](https://about.gitlab.com/pricing/) 11.0.
diff --git a/doc/user/group/saml_sso/scim_setup.md b/doc/user/group/saml_sso/scim_setup.md
index 5aef463d782..2d408766db8 100644
--- a/doc/user/group/saml_sso/scim_setup.md
+++ b/doc/user/group/saml_sso/scim_setup.md
@@ -2,7 +2,7 @@
type: howto, reference
---
-# SCIM provisioning using SAML SSO for Groups **[SILVER ONLY]**
+# SCIM provisioning using SAML SSO for Groups **(SILVER ONLY)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/9388) in [GitLab.com Silver](https://about.gitlab.com/pricing/) 11.10.
diff --git a/doc/user/index.md b/doc/user/index.md
index 899026a801f..501d74c76d1 100644
--- a/doc/user/index.md
+++ b/doc/user/index.md
@@ -173,7 +173,7 @@ Learn what is [Git](../topics/git/index.md) and its best practices.
See [various statistics](instance_statistics/index.md) of your GitLab instance.
-## Operations Dashboard **[PREMIUM]**
+## Operations Dashboard **(PREMIUM)**
See [Operations Dashboard](operations_dashboard/index.md) for a summary of each
project's operational health.
diff --git a/doc/user/markdown.md b/doc/user/markdown.md
index f8eea618c84..83629fc2e4b 100644
--- a/doc/user/markdown.md
+++ b/doc/user/markdown.md
@@ -25,7 +25,7 @@ You can use GFM in the following areas:
- Snippets (the snippet must be named with a `.md` extension)
- Wiki pages
- Markdown documents inside repositories
-- Epics **[ULTIMATE]**
+- Epics **(ULTIMATE)**
You can also use other rich text files in GitLab. You might have to install a dependency
to do so. Please see the [`gitlab-markup` gem project](https://gitlab.com/gitlab-org/gitlab-markup)
@@ -119,7 +119,7 @@ changing how standard markdown is used:
| [links](#links) | [automatically linking URLs](#url-auto-linking) |
## New GFM markdown extensions
-
+
### Colors
> If this is not rendered correctly, [view it in GitLab itself](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/user/markdown.md#colors).
@@ -136,26 +136,26 @@ Supported formats (named colors are not supported):
Color written inside backticks will be followed by a color "chip":
```markdown
-`#F00`
-`#F00A`
-`#FF0000`
-`#FF0000AA`
-`RGB(0,255,0)`
-`RGB(0%,100%,0%)`
-`RGBA(0,255,0,0.3)`
-`HSL(540,70%,50%)`
-`HSLA(540,70%,50%,0.3)`
-```
-
-`#F00`
-`#F00A`
-`#FF0000`
-`#FF0000AA`
-`RGB(0,255,0)`
-`RGB(0%,100%,0%)`
-`RGBA(0,255,0,0.3)`
-`HSL(540,70%,50%)`
-`HSLA(540,70%,50%,0.3)`
+`#F00`
+`#F00A`
+`#FF0000`
+`#FF0000AA`
+`RGB(0,255,0)`
+`RGB(0%,100%,0%)`
+`RGBA(0,255,0,0.3)`
+`HSL(540,70%,50%)`
+`HSLA(540,70%,50%,0.3)`
+```
+
+`#F00`
+`#F00A`
+`#FF0000`
+`#FF0000AA`
+`RGB(0,255,0)`
+`RGB(0%,100%,0%)`
+`RGBA(0,255,0,0.3)`
+`HSL(540,70%,50%)`
+`HSLA(540,70%,50%,0.3)`
### Diagrams and flowcharts using Mermaid
@@ -288,7 +288,7 @@ $example = array(
> If this is not rendered correctly, [view it in GitLab itself](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/user/markdown.md#inline-diff).
-With inline diff tags you can display {+ additions +} or [- deletions -].
+With inline diff tags you can display `{+ additions +}` or `[- deletions -]`.
The wrapping tags can be either curly braces or square brackets:
@@ -359,7 +359,7 @@ version to reference other projects from the same namespace.
GFM will recognize the following:
-| references | input | cross-project reference | shortcut within same namespace |
+| references | input | cross-project reference | shortcut within same namespace |
| :------------------------------ | :------------------------- | :-------------------------------------- | :----------------------------- |
| specific user | `@user_name` | | |
| specific group | `@group_name` | | |
@@ -368,7 +368,7 @@ GFM will recognize the following:
| issue | ``#123`` | `namespace/project#123` | `project#123` |
| merge request | `!123` | `namespace/project!123` | `project!123` |
| snippet | `$123` | `namespace/project$123` | `project$123` |
-| epic **[ULTIMATE]** | `&123` | `group1/subgroup&123` | |
+| epic **(ULTIMATE)** | `&123` | `group1/subgroup&123` | |
| label by ID | `~123` | `namespace/project~123` | `project~123` |
| one-word label by name | `~bug` | `namespace/project~bug` | `project~bug` |
| multi-word label by name | `~"feature request"` | `namespace/project~"feature request"` | `project~"feature request"` |
@@ -704,7 +704,7 @@ but_emphasis is_desired _here_
```
perform_complicated_task
-
+
do_this_and_do_that_and_another_thing
but_emphasis is_desired _here_
@@ -715,12 +715,12 @@ If you wish to emphasize only a part of a word, it can still be done with asteri
```md
perform*complicated*task
-
+
do*this*and*do*that*and*another thing
```
perform*complicated*task
-
+
do*this*and*do*that*and*another thing
### Footnotes
@@ -910,9 +910,9 @@ are separated into their own lines:
<dt>Markdown in HTML</dt>
<dd>
-
+
Does *not* work **very** well. HTML tags will always work.
-
+
</dd>
</dl>
```
@@ -925,9 +925,9 @@ are separated into their own lines:
<dt>Markdown in HTML</dt>
<dd>
-
+
Does <em>not</em> work <b>very</b> well. HTML tags will always work.
-
+
</dd>
</dl>
@@ -1045,14 +1045,14 @@ A new line due to the previous backslash.
First paragraph.
Another line in the same paragraph.
-A third line in the same paragraph, but this time ending with two spaces.
+A third line in the same paragraph, but this time ending with two spaces.
A new line directly under the first paragraph.
<!-- (Do *NOT* remove the two ending whitespaces in the second line) -->
<!-- (They are needed for the Markdown text to render correctly on docs.gitlab.com, the backslash works fine inside GitLab itself) -->
Second paragraph.
-Another line, this time ending with a backslash.
+Another line, this time ending with a backslash.
A new line due to the previous backslash.
### Links
@@ -1123,12 +1123,12 @@ GFM will autolink almost any URL you put into your text:
- http://localhost:3000
```
-- https://www.google.com
-- https://google.com/
-- ftp://ftp.us.debian.org/debian/
-- smb://foo/bar/baz
-- irc://irc.freenode.net/gitlab
-- http://localhost:3000
+- <https://www.google.com>
+- <https://google.com/>
+- <ftp://ftp.us.debian.org/debian/>
+- <smb://foo/bar/baz>
+- <irc://irc.freenode.net/gitlab>
+- <http://localhost:3000>
### Lists
@@ -1229,7 +1229,7 @@ while the equation for the theory of relativity is E = mc<sup>2</sup>.
Tables aren't part of the core Markdown spec, but they are part of GFM.
-1. The first line contains the headers, separated by "pipes" (`|`).
+1. The first line contains the headers, separated by "pipes" (`|`).
1. The second line separates the headers from the cells, and must contain three or more dashes.
1. The third, and any following lines, contain the cell values.
- You **can't** have cells separated over many lines in the markdown, they must be kept to single lines,
diff --git a/doc/user/operations_dashboard/index.md b/doc/user/operations_dashboard/index.md
index 54bf3ff8a40..8c4d387190a 100644
--- a/doc/user/operations_dashboard/index.md
+++ b/doc/user/operations_dashboard/index.md
@@ -1,4 +1,4 @@
-# Operations Dashboard **[PREMIUM]**
+# Operations Dashboard **(PREMIUM)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/5781) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 11.5. [Moved](https://gitlab.com/gitlab-org/gitlab-ee/issues/9218) to [GitLab Premium](https://about.gitlab.com/pricing/) in 11.10.
diff --git a/doc/user/permissions.md b/doc/user/permissions.md
index 03abef9fc62..1b279173d1c 100644
--- a/doc/user/permissions.md
+++ b/doc/user/permissions.md
@@ -43,10 +43,10 @@ The following table depicts the various user permission levels in a project.
|---------------------------------------------------|---------|------------|-------------|----------|--------|
| Download project | ✓ (*1*) | ✓ | ✓ | ✓ | ✓ |
| Leave comments | ✓ (*1*) | ✓ | ✓ | ✓ | ✓ |
-| View Insights charts **[ULTIMATE]** | ✓ | ✓ | ✓ | ✓ | ✓ |
-| View approved/blacklisted licenses **[ULTIMATE]** | ✓ | ✓ | ✓ | ✓ | ✓ |
-| View license management reports **[ULTIMATE]** | ✓ (*1*) | ✓ | ✓ | ✓ | ✓ |
-| View Security reports **[ULTIMATE]** | ✓ (*1*) | ✓ | ✓ | ✓ | ✓ |
+| View Insights charts **(ULTIMATE)** | ✓ | ✓ | ✓ | ✓ | ✓ |
+| View approved/blacklisted licenses **(ULTIMATE)** | ✓ | ✓ | ✓ | ✓ | ✓ |
+| View license management reports **(ULTIMATE)** | ✓ (*1*) | ✓ | ✓ | ✓ | ✓ |
+| View Security reports **(ULTIMATE)** | ✓ (*1*) | ✓ | ✓ | ✓ | ✓ |
| View project code | ✓ (*1*) | ✓ | ✓ | ✓ | ✓ |
| Pull project code | ✓ (*1*) | ✓ | ✓ | ✓ | ✓ |
| View GitLab Pages protected by [access control](project/pages/introduction.md#gitlab-pages-access-control-core-only) | ✓ | ✓ | ✓ | ✓ | ✓ |
@@ -62,8 +62,8 @@ The following table depicts the various user permission levels in a project.
| Label issues | | ✓ | ✓ | ✓ | ✓ |
| Lock issue discussions | | ✓ | ✓ | ✓ | ✓ |
| Manage issue tracker | | ✓ | ✓ | ✓ | ✓ |
-| Manage related issues **[STARTER]** | | ✓ | ✓ | ✓ | ✓ |
-| Create issue from vulnerability **[ULTIMATE]** | | ✓ | ✓ | ✓ | ✓ |
+| Manage related issues **(STARTER)** | | ✓ | ✓ | ✓ | ✓ |
+| Create issue from vulnerability **(ULTIMATE)** | | ✓ | ✓ | ✓ | ✓ |
| Manage labels | | ✓ | ✓ | ✓ | ✓ |
| Create code snippets | | ✓ | ✓ | ✓ | ✓ |
| See a commit status | | ✓ | ✓ | ✓ | ✓ |
@@ -72,8 +72,8 @@ The following table depicts the various user permission levels in a project.
| See a list of merge requests | | ✓ | ✓ | ✓ | ✓ |
| View project statistics | | ✓ | ✓ | ✓ | ✓ |
| View Error Tracking list | | ✓ | ✓ | ✓ | ✓ |
-| Pull from [Maven repository](project/packages/maven_repository.md) or [NPM registry](project/packages/npm_registry.md) **[PREMIUM]** | | ✓ | ✓ | ✓ | ✓ |
-| Publish to [Maven repository](project/packages/maven_repository.md) or [NPM registry](project/packages/npm_registry.md) **[PREMIUM]** | | | ✓ | ✓ | ✓ ||
+| Pull from [Maven repository](project/packages/maven_repository.md) or [NPM registry](project/packages/npm_registry.md) **(PREMIUM)** | | ✓ | ✓ | ✓ | ✓ |
+| Publish to [Maven repository](project/packages/maven_repository.md) or [NPM registry](project/packages/npm_registry.md) **(PREMIUM)** | | | ✓ | ✓ | ✓ ||
| Create new branches | | | ✓ | ✓ | ✓ |
| Push to non-protected branches | | | ✓ | ✓ | ✓ |
| Force push to non-protected branches | | | ✓ | ✓ | ✓ |
@@ -91,13 +91,13 @@ The following table depicts the various user permission levels in a project.
| Update a container registry | | | ✓ | ✓ | ✓ |
| Remove a container registry image | | | ✓ | ✓ | ✓ |
| Create/edit/delete project milestones | | | ✓ | ✓ | ✓ |
-| Use security dashboard **[ULTIMATE]** | | | ✓ | ✓ | ✓ |
-| Dismiss vulnerability **[ULTIMATE]** | | | ✓ | ✓ | ✓ |
+| Use security dashboard **(ULTIMATE)** | | | ✓ | ✓ | ✓ |
+| Dismiss vulnerability **(ULTIMATE)** | | | ✓ | ✓ | ✓ |
| Apply code change suggestions | | | ✓ | ✓ | ✓ |
| Create and edit wiki pages | | | ✓ | ✓ | ✓ |
| Rewrite/remove Git tags | | | ✓ | ✓ | ✓ |
| Use environment terminals | | | | ✓ | ✓ |
-| Run Web IDE's Interactive Web Terminals **[ULTIMATE ONLY]** | | | | ✓ | ✓ |
+| Run Web IDE's Interactive Web Terminals **(ULTIMATE ONLY)** | | | | ✓ | ✓ |
| Add new team members | | | | ✓ | ✓ |
| Enable/disable branch protection | | | | ✓ | ✓ |
| Push to protected branches | | | | ✓ | ✓ |
@@ -113,7 +113,7 @@ The following table depicts the various user permission levels in a project.
| Manage GitLab Pages domains and certificates | | | | ✓ | ✓ |
| Remove GitLab Pages | | | | ✓ | ✓ |
| Manage clusters | | | | ✓ | ✓ |
-| Manage license policy **[ULTIMATE]** | | | | ✓ | ✓ |
+| Manage license policy **(ULTIMATE)** | | | | ✓ | ✓ |
| Edit comments (posted by any user) | | | | ✓ | ✓ |
| Manage Error Tracking | | | | ✓ | ✓ |
| Delete wiki pages | | | | ✓ | ✓ |
@@ -122,8 +122,8 @@ The following table depicts the various user permission levels in a project.
| Transfer project to another namespace | | | | | ✓ |
| Remove project | | | | | ✓ |
| Delete issues | | | | | ✓ |
-| Force push to protected branches [^4] | | | | | |
-| Remove protected branches [^4] | | | | | |
+| Force push to protected branches (*4*) | | | | | |
+| Remove protected branches (*4*) | | | | | |
- (*1*): All users are able to perform this action on public and internal projects, but not private projects.
- (*2*): Guest users can only view the confidential issues they created themselves
@@ -167,7 +167,7 @@ and drag issues around. Read though the
[documentation on Issue Boards permissions](project/issue_board.md#permissions)
to learn more.
-### File Locking permissions **[PREMIUM]**
+### File Locking permissions **(PREMIUM)**
The user that locks a file or directory is the only one that can edit and push their changes back to the repository where the locked objects are located.
@@ -202,18 +202,18 @@ group.
| Action | Guest | Reporter | Developer | Maintainer | Owner |
|-------------------------------------------------|-------|----------|-----------|------------|-------|
| Browse group | ✓ | ✓ | ✓ | ✓ | ✓ |
-| View Insights charts **[ULTIMATE]** | ✓ | ✓ | ✓ | ✓ | ✓ |
-| View group epic **[ULTIMATE]** | ✓ | ✓ | ✓ | ✓ | ✓ |
-| Create/edit group epic **[ULTIMATE]** | | ✓ | ✓ | ✓ | ✓ |
+| View Insights charts **(ULTIMATE)** | ✓ | ✓ | ✓ | ✓ | ✓ |
+| View group epic **(ULTIMATE)** | ✓ | ✓ | ✓ | ✓ | ✓ |
+| Create/edit group epic **(ULTIMATE)** | | ✓ | ✓ | ✓ | ✓ |
| Manage group labels | | ✓ | ✓ | ✓ | ✓ |
| Create project in group | | | ✓ | ✓ | ✓ |
| Create/edit/delete group milestones | | | ✓ | ✓ | ✓ |
-| Enable/disable a dependency proxy **[PREMIUM]** | | | ✓ | ✓ | ✓ |
+| Enable/disable a dependency proxy **(PREMIUM)** | | | ✓ | ✓ | ✓ |
| Edit group | | | | | ✓ |
| Create subgroup | | | | | ✓ |
| Manage group members | | | | | ✓ |
| Remove group | | | | | ✓ |
-| Delete group epic **[ULTIMATE]** | | | | | ✓ |
+| Delete group epic **(ULTIMATE)** | | | | | ✓ |
| View group Audit Events | | | | | ✓ |
### Subgroup permissions
@@ -264,7 +264,7 @@ Here are some examples:
Please be aware that this regex could lead to a DOS attack, [see](https://en.wikipedia.org/wiki/ReDoS?) ReDos on Wikipedia.
-## Auditor users **[PREMIUM ONLY]**
+## Auditor users **(PREMIUM ONLY)**
>[Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/998) in [GitLab Premium](https://about.gitlab.com/pricing/) 8.17.
diff --git a/doc/user/profile/preferences.md b/doc/user/profile/preferences.md
index b61216b7b67..b1fde3b577b 100644
--- a/doc/user/profile/preferences.md
+++ b/doc/user/profile/preferences.md
@@ -79,7 +79,7 @@ You have 8 options here that you can use for your default dashboard view:
- Your [Todos](../../workflow/todos.md)
- Assigned Issues
- Assigned Merge Requests
-- Operations Dashboard **[PREMIUM]**
+- Operations Dashboard **(PREMIUM)**
### Project overview content
diff --git a/doc/user/project/canary_deployments.md b/doc/user/project/canary_deployments.md
index cce862b0911..5068d2757be 100644
--- a/doc/user/project/canary_deployments.md
+++ b/doc/user/project/canary_deployments.md
@@ -1,4 +1,4 @@
-# Canary Deployments **[PREMIUM]**
+# Canary Deployments **(PREMIUM)**
> [Introduced][ee-1659] in [GitLab Premium][eep] 9.1.
@@ -44,7 +44,7 @@ Canary deployments require that you properly configure Deploy Boards:
1. Follow the steps to [enable Deploy Boards](deploy_boards.md#enabling-deploy-boards).
1. To track canary deployments you need to label your Kubernetes deployments and
- pods with `track: canary`. To get started quickly, you can use the [Auto Deploy]
+ pods with `track: canary`. To get started quickly, you can use the [Auto Deploy](../../ci/autodeploy/index.md)
template for canary deployments that GitLab provides.
Depending on the deploy, the label should be either `stable` or `canary`.
@@ -62,7 +62,6 @@ can easily notice them.
![Canary deployments on Deploy Board](img/deploy_boards_canary_deployments.png)
-[autodeploy]: ../../ci/autodeploy/index.md "GitLab Autodeploy"
[eep]: https://about.gitlab.com/pricing/
[ee-1659]: https://gitlab.com/gitlab-org/gitlab-ee/issues/1659
[kube-canary]: https://kubernetes.io/docs/concepts/cluster-administration/manage-deployment/#canary-deployments
diff --git a/doc/user/project/clusters/index.md b/doc/user/project/clusters/index.md
index c6ee168bad0..56f8257fbe7 100644
--- a/doc/user/project/clusters/index.md
+++ b/doc/user/project/clusters/index.md
@@ -5,6 +5,9 @@
Connect your project to Google Kubernetes Engine (GKE) or an existing Kubernetes
cluster in a few steps.
+NOTE: **Scalable app deployment with GitLab and Google Cloud Platform**
+[Watch the webcast](https://about.gitlab.com/webcast/scalable-app-deploy/) and learn how to spin up a Kubernetes cluster managed by Google Cloud Platform (GCP) in a few clicks.
+
## Overview
With one or more Kubernetes clusters associated to your project, you can use
@@ -222,7 +225,7 @@ functionalities needed to successfully build and deploy a containerized
application. Bear in mind that the same credentials are used for all the
applications running on the cluster.
-## Gitlab-managed clusters
+## GitLab-managed clusters
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/22011) in GitLab 11.5.
> Became [optional](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/26565) in GitLab 11.11.
@@ -432,7 +435,7 @@ record](https://en.wikipedia.org/wiki/Wildcard_DNS_record) such as `*.example.co
in order to be able to reach your apps. If your external endpoint is an IP address,
use an A record. If your external endpoint is a hostname, use a CNAME record.
-## Multiple Kubernetes clusters **[PREMIUM]**
+## Multiple Kubernetes clusters **(PREMIUM)**
> Introduced in [GitLab Premium][ee] 10.3.
@@ -444,7 +447,7 @@ Simply add another cluster, like you did the first time, and make sure to
[set an environment scope](#setting-the-environment-scope-premium) that will
differentiate the new cluster with the rest.
-## Setting the environment scope **[PREMIUM]**
+## Setting the environment scope **(PREMIUM)**
When adding more than one Kubernetes cluster to your project, you need to differentiate
them with an environment scope. The environment scope associates clusters with [environments](../../../ci/environments.md) similar to how the
@@ -547,7 +550,7 @@ in a way that causes this error. Ensure you deselect the
[GitLab-managed cluster](#gitlab-managed-clusters) option if you want to manage
namespaces and service accounts yourself.
-## Monitoring your Kubernetes cluster **[ULTIMATE]**
+## Monitoring your Kubernetes cluster **(ULTIMATE)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/4701) in [GitLab Ultimate][ee] 10.6.
@@ -585,7 +588,7 @@ and add a Kubernetes cluster again.
Here's what you can do with GitLab if you enable the Kubernetes integration.
-### Deploy Boards **[PREMIUM]**
+### Deploy Boards **(PREMIUM)**
GitLab's Deploy Boards offer a consolidated view of the current health and
status of each CI [environment](../../../ci/environments.md) running on Kubernetes,
@@ -595,7 +598,7 @@ workflow they already use without any need to access Kubernetes.
[Read more about Deploy Boards](../deploy_boards.md)
-### Canary Deployments **[PREMIUM]**
+### Canary Deployments **(PREMIUM)**
Leverage [Kubernetes' Canary deployments](https://kubernetes.io/docs/concepts/cluster-administration/manage-deployment/#canary-deployments)
and visualize your canary deployments right inside the Deploy Board, without
@@ -603,7 +606,7 @@ the need to leave GitLab.
[Read more about Canary Deployments](../canary_deployments.md)
-### Pod logs **[ULTIMATE]**
+### Pod logs **(ULTIMATE)**
GitLab makes it easy to view the logs of running pods in connected Kubernetes clusters. By displaying the logs directly in GitLab, developers can avoid having to manage console tools or jump to a different interface.
diff --git a/doc/user/project/clusters/kubernetes_pod_logs.md b/doc/user/project/clusters/kubernetes_pod_logs.md
index 25d8abebf07..864cd75823c 100644
--- a/doc/user/project/clusters/kubernetes_pod_logs.md
+++ b/doc/user/project/clusters/kubernetes_pod_logs.md
@@ -1,4 +1,4 @@
-# Kubernetes Pod Logs **[ULTIMATE]**
+# Kubernetes Pod Logs **(ULTIMATE)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/4752) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 11.0.
diff --git a/doc/user/project/clusters/serverless/index.md b/doc/user/project/clusters/serverless/index.md
index 91f0e24b44e..a06c3d3c662 100644
--- a/doc/user/project/clusters/serverless/index.md
+++ b/doc/user/project/clusters/serverless/index.md
@@ -94,10 +94,55 @@ adding an existing installation of Knative.
It is also possible to use GitLab Serverless with an existing Kubernetes
cluster which already has Knative installed.
-Simply:
+You must do the following:
1. Follow the steps to
[add an existing Kubernetes cluster](../index.md#adding-an-existing-kubernetes-cluster).
+
+1. Ensure GitLab can manage Knative:
+ - For a non-GitLab managed cluster, ensure that the service account for the token
+ provided can manage resources in the `serving.knative.dev` API group.
+ - For a GitLab managed cluster,
+ GitLab uses a service account with the `edit` cluster role. This account needs
+ the ability to manage resources in the `serving.knative.dev` API group.
+ We suggest you do this with an [aggregated ClusterRole](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#aggregated-clusterroles)
+ adding rules to the default `edit` cluster role:
+ First, save the following YAML as `knative-serving-only-role.yaml`:
+
+ ```yaml
+ apiVersion: rbac.authorization.k8s.io/v1
+ kind: ClusterRole
+ metadata:
+ name: knative-serving-only-role
+ labels:
+ rbac.authorization.k8s.io/aggregate-to-edit: "true"
+ rules:
+ - apiGroups:
+ - serving.knative.dev
+ resources:
+ - configurations
+ - configurationgenerations
+ - routes
+ - revisions
+ - revisionuids
+ - autoscalers
+ - services
+ verbs:
+ - get
+ - list
+ - create
+ - update
+ - delete
+ - patch
+ - watch
+ ```
+
+ Then run the following command:
+
+ ```bash
+ kubectl apply -f knative-serving-only-role.yaml
+ ```
+
1. Follow the steps to deploy [functions](#deploying-functions)
or [serverless applications](#deploying-serverless-applications) onto your
cluster.
diff --git a/doc/user/project/code_owners.md b/doc/user/project/code_owners.md
index ae04616943f..78ffa11d59b 100644
--- a/doc/user/project/code_owners.md
+++ b/doc/user/project/code_owners.md
@@ -1,10 +1,12 @@
-# Code Owners **[STARTER]**
+# Code Owners **(STARTER)**
-> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/6916)
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/6916)
in [GitLab Starter](https://about.gitlab.com/pricing/) 11.3.
+> - [Support for group namespaces](https://gitlab.com/gitlab-org/gitlab-ce/issues/53182) added in GitLab Starter 12.1.
-You can use a `CODEOWNERS` file to specify users that are responsible
-for certain files in a repository.
+You can use a `CODEOWNERS` file to specify users or
+[shared groups](members/share_project_with_groups.md)
+that are responsible for certain files in a repository.
You can choose and add the `CODEOWNERS` file in three places:
@@ -25,7 +27,8 @@ the given file.
Files can be specified using the same kind of patterns you would use
in the `.gitignore` file followed by the `@username` or email of one
-or more users that should be owners of the file.
+or more users or by the `@name` of one or more groups that should
+be owners of the file.
The order in which the paths are defined is significant: the last
pattern that matches a given path will be used to find the code
@@ -63,6 +66,10 @@ CODEOWNERS @multiple @owners @tab-separated
# owner for the LICENSE file
LICENSE @legal this_does_not_match janedoe@gitlab.com
+# Group names can be used to match groups and nested groups to specify
+# them as owners for a file
+README @group @group/with-nested/subgroup
+
# Ending a path in a `/` will specify the code owners for every file
# nested in that directory, on any level
/docs/ @all-docs
diff --git a/doc/user/project/container_registry.md b/doc/user/project/container_registry.md
index fdf9ce3e225..eac7fc6b195 100644
--- a/doc/user/project/container_registry.md
+++ b/doc/user/project/container_registry.md
@@ -29,7 +29,7 @@ to enable it.
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
- registry on GitLab.com, as part of the [repository size limit](repository/index.html#repository-size).
+ registry on GitLab.com, as part of the [repository size limit](repository/index.md).
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
projects this might be enabled by default. For existing projects
@@ -168,6 +168,19 @@ curl localhost:5001/debug/health
curl localhost:5001/debug/vars
```
+#### Docker connection error
+
+A Docker connection error can occur when there are special characters in either the group,
+project or branch name. Special characters can include:
+
+* Leading underscore
+* Trailing hyphen/dash
+* Double hyphen/dash
+
+To get around this, you can [change the group path](../group/index.md#changing-a-groups-path),
+[change the project path](../project/settings/index.md#renaming-a-repository) or chanage the branch
+name.
+
### Advanced Troubleshooting
>**NOTE:** The following section is only recommended for experts.
diff --git a/doc/user/project/cycle_analytics.md b/doc/user/project/cycle_analytics.md
index dc97a44fd68..5d36e1d4be3 100644
--- a/doc/user/project/cycle_analytics.md
+++ b/doc/user/project/cycle_analytics.md
@@ -156,6 +156,6 @@ Learn more about Cycle Analytics in the following resources:
[environment]: ../../ci/yaml/README.md#environment
[GitLab flow]: ../../workflow/gitlab_flow.md
[idea to production]: https://about.gitlab.com/2016/08/05/continuous-integration-delivery-and-deployment-with-gitlab/#from-idea-to-production-with-gitlab
-[issue closing pattern]: issues/automatic_issue_closing.md
+[issue closing pattern]: issues/managing_issues.md#closing-issues-automatically
[permissions]: ../permissions.md
[yml]: ../../ci/yaml/README.md
diff --git a/doc/user/project/deploy_boards.md b/doc/user/project/deploy_boards.md
index 175384bc985..cb1faa771bc 100644
--- a/doc/user/project/deploy_boards.md
+++ b/doc/user/project/deploy_boards.md
@@ -1,4 +1,4 @@
-# Deploy Boards **[PREMIUM]**
+# Deploy Boards **(PREMIUM)**
> [Introduced][ee-1589] in [GitLab Premium][ee] 9.0.
@@ -125,6 +125,6 @@ version of your application.
[kube-service]: integrations/kubernetes.md "Kubernetes project service"
[review apps]: ../../ci/review_apps/index.md "Review Apps documentation"
[variables]: ../../ci/variables/README.md "GitLab CI variables"
-[autodeploy]: ../../ci/autodeploy/index.md "GitLab Autodeploy"
+[autodeploy]: ../../topics/autodevops/index.md#auto-deploy "GitLab Autodeploy"
[kube-image]: https://gitlab.com/gitlab-examples/kubernetes-deploy/container_registry "Kubernetes deploy Container Registry"
[runners]: ../../ci/runners/README.md
diff --git a/doc/user/project/deploy_tokens/img/deploy_tokens.png b/doc/user/project/deploy_tokens/img/deploy_tokens.png
index 55c537fd1d3..421aa1ab3e5 100644
--- a/doc/user/project/deploy_tokens/img/deploy_tokens.png
+++ b/doc/user/project/deploy_tokens/img/deploy_tokens.png
Binary files differ
diff --git a/doc/user/project/deploy_tokens/index.md b/doc/user/project/deploy_tokens/index.md
index 92a29b68a22..72594733cd3 100644
--- a/doc/user/project/deploy_tokens/index.md
+++ b/doc/user/project/deploy_tokens/index.md
@@ -15,7 +15,7 @@ You can create as many deploy tokens as you like from the settings of your proje
1. Go to the project you want to create Deploy Tokens for.
1. Go to **Settings** > **Repository**.
1. Click on "Expand" on **Deploy Tokens** section.
-1. Choose a name and optionally an expiry date for the token.
+1. Choose a name, expiry date (optional), and username (optional) for the token.
1. Choose the [desired scopes](#limiting-scopes-of-a-deploy-token).
1. Click on **Create deploy token**.
1. Save the deploy token somewhere safe. Once you leave or refresh
@@ -39,6 +39,13 @@ the following table.
| `read_repository` | Allows read-access to the repository through `git clone` |
| `read_registry` | Allows read-access to [container registry] images if a project is private and authorization is required. |
+## Deploy token custom username
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/29639) in GitLab 12.1.
+
+The default username format is `gitlab+deploy-token-#{n}`. Some tools or platforms may not support this format,
+in such case you can specify custom username to be used when creating the deploy token.
+
## Usage
### Git clone a repository
diff --git a/doc/user/project/description_templates.md b/doc/user/project/description_templates.md
index 7520237251a..196874fdc86 100644
--- a/doc/user/project/description_templates.md
+++ b/doc/user/project/description_templates.md
@@ -55,7 +55,7 @@ changes you made after picking the template and return it to its initial status.
![Description templates](img/description_templates.png)
-## Setting a default template for issues and merge requests **[STARTER]**
+## Setting a default template for issues and merge requests **(STARTER)**
> **Notes:**
>
diff --git a/doc/user/project/file_lock.md b/doc/user/project/file_lock.md
index 40603790c12..dec679fc975 100644
--- a/doc/user/project/file_lock.md
+++ b/doc/user/project/file_lock.md
@@ -1,4 +1,4 @@
-# File Locking **[PREMIUM]**
+# File Locking **(PREMIUM)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/440) in [GitLab Premium](https://about.gitlab.com/pricing/) 8.9.
diff --git a/doc/user/project/import/gemnasium.md b/doc/user/project/import/gemnasium.md
index 7f79ebf6353..0afa32e4133 100644
--- a/doc/user/project/import/gemnasium.md
+++ b/doc/user/project/import/gemnasium.md
@@ -1,4 +1,4 @@
-# Gemnasium **[ULTIMATE]**
+# Gemnasium **(ULTIMATE)**
This guide describes how to migrate from Gemnasium.com to your own GitLab
instance or GitLab.com.
@@ -40,14 +40,14 @@ some steps to migrate your projects. There is no automatic import since GitLab
doesn't know anything about any projects which existed on Gemnasium.com.
Security features are free for public (open-source) projects hosted on GitLab.com.
-### If your project is hosted on GitLab (https://gitlab.com / self-hosted)
+### If your project is hosted on GitLab (`https://gitlab.com` / self-hosted)
You're almost set! If you're already using
[Auto DevOps](../../../topics/autodevops/), you are already covered.
Otherwise, you must configure your `.gitlab-ci.yml` according to the
[dependency scanning page](../../application_security/dependency_scanning/index.md).
-### If your project is hosted on GitHub (https://github.com / GitHub Enterprise)
+### If your project is hosted on GitHub (`https://github.com` / GitHub Enterprise)
Since [GitLab 10.6 comes with GitHub integration](https://about.gitlab.com/features/github/),
GitLab users can now create a CI/CD project in GitLab connected to an external
diff --git a/doc/user/project/import/github.md b/doc/user/project/import/github.md
index e194d57e2e0..cdb7f837158 100644
--- a/doc/user/project/import/github.md
+++ b/doc/user/project/import/github.md
@@ -121,10 +121,10 @@ Depending your GitLab tier, [project mirroring](../../../workflow/repository_mir
your imported project in sync with its GitHub copy.
Additionally, you can configure GitLab to send pipeline status updates back GitHub with the
-[GitHub Project Integration](../integrations/github.md). **[PREMIUM]**
+[GitHub Project Integration](../integrations/github.md). **(PREMIUM)**
If you import your project using [CI/CD for external repo](../../../ci/ci_cd_for_external_repos/index.md), then both
-of the above are automatically configured. **[PREMIUM]**
+of the above are automatically configured. **(PREMIUM)**
## Improving the speed of imports on self-hosted instances
diff --git a/doc/user/project/import/index.md b/doc/user/project/import/index.md
index 2b6927bd780..334be713aa5 100644
--- a/doc/user/project/import/index.md
+++ b/doc/user/project/import/index.md
@@ -20,7 +20,7 @@ In addition to the specific migration documentation above, you can import any
Git repository via HTTP from the New Project page. Be aware that if the
repository is too large the import can timeout.
-There is also the option of [connecting your external repository to get CI/CD benefits](../../../ci/ci_cd_for_external_repos/index.md). **[PREMIUM]**
+There is also the option of [connecting your external repository to get CI/CD benefits](../../../ci/ci_cd_for_external_repos/index.md). **(PREMIUM)**
## Migrating from self-hosted GitLab to GitLab.com
diff --git a/doc/user/project/import/svn.md b/doc/user/project/import/svn.md
index 4825b005a85..7359487e1bf 100644
--- a/doc/user/project/import/svn.md
+++ b/doc/user/project/import/svn.md
@@ -29,7 +29,7 @@ directly in a filesystem level.
1. Install Oracle JRE 1.8 or newer. On Debian-based Linux distributions you can
follow [this article](http://www.webupd8.org/2012/09/install-oracle-java-8-in-ubuntu-via-ppa.html).
-1. Download SubGit from <https://subgit.com/download/>.
+1. Download SubGit from <https://subgit.com/download>.
1. Unpack the downloaded SubGit zip archive to the `/opt` directory. The `subgit`
command will be available at `/opt/subgit-VERSION/bin/subgit`.
diff --git a/doc/user/project/import/tfs.md b/doc/user/project/import/tfs.md
index 8727c2ff6c3..b4597a4da60 100644
--- a/doc/user/project/import/tfs.md
+++ b/doc/user/project/import/tfs.md
@@ -1,6 +1,6 @@
# Migrating from TFS
-[TFS](https://www.visualstudio.com/tfs/) is a set of tools developed by Microsoft
+[TFS](https://visualstudio.microsoft.com/tfs/) is a set of tools developed by Microsoft
which also includes a centralized version control system (TFVC) similar to Git.
In this document, we emphasize on the TFVC to Git migration.
@@ -18,10 +18,10 @@ The following list illustrates the main differences between TFVC and Git:
a committed file(s) is stored in its entirety (snapshot). That means that's
very easy in Git to revert or undo a whole change.
-_Check also Microsoft's documentation on the
-[comparison of Git and TFVC](https://www.visualstudio.com/en-us/docs/tfvc/comparison-git-tfvc)
-and the Wikipedia article on
-[comparing the different version control software](https://en.wikipedia.org/wiki/Comparison_of_version_control_software)._
+Check also Microsoft's documentation on the
+[comparison of Git and TFVC](https://docs.microsoft.com/en-us/azure/devops/repos/tfvc/comparison-git-tfvc?view=azure-devops)
+and the Wikipedia
+[comparison of version control software](https://en.wikipedia.org/wiki/Comparison_of_version_control_software).
## Why migrate
diff --git a/doc/user/project/index.md b/doc/user/project/index.md
index 06286951e20..f332281fa82 100644
--- a/doc/user/project/index.md
+++ b/doc/user/project/index.md
@@ -17,7 +17,7 @@ When you create a project in GitLab, you'll have access to a large number of
- [Issue tracker](issues/index.md): Discuss implementations with your team within issues
- [Issue Boards](issue_board.md): Organize and prioritize your workflow
- - [Multiple Issue Boards](issue_board.md#multiple-issue-boards-starter): Allow your teams to create their own workflows (Issue Boards) for the same project **[STARTER]**
+ - [Multiple Issue Boards](issue_board.md#multiple-issue-boards-starter): Allow your teams to create their own workflows (Issue Boards) for the same project **(STARTER)**
- [Repositories](repository/index.md): Host your code in a fully
integrated platform
- [Branches](repository/branches/index.md): use Git branching strategies to
@@ -34,11 +34,11 @@ When you create a project in GitLab, you'll have access to a large number of
- [Issue tracker](issues/index.md): Discuss implementations with your team within issues
- [Issue Boards](issue_board.md): Organize and prioritize your workflow
- - [Multiple Issue Boards](issue_board.md#multiple-issue-boards-starter): Allow your teams to create their own workflows (Issue Boards) for the same project **[STARTER]**
+ - [Multiple Issue Boards](issue_board.md#multiple-issue-boards-starter): Allow your teams to create their own workflows (Issue Boards) for the same project **(STARTER)**
- [Merge Requests](merge_requests/index.md): Apply your branching
strategy and get reviewed by your team
- [Merge Request Approvals](merge_requests/merge_request_approvals.md): Ask for approval before
- implementing a change **[STARTER]**
+ implementing a change **(STARTER)**
- [Fix merge conflicts from the UI](merge_requests/resolve_conflicts.md):
Your Git diff tool right from GitLab's UI
- [Review Apps](../../ci/review_apps/index.md): Live preview the results
@@ -75,7 +75,7 @@ When you create a project in GitLab, you'll have access to a large number of
- [Kubernetes cluster integration](clusters/index.md): Connecting your GitLab project
with a Kubernetes cluster
- [Feature Flags](operations/feature_flags.md): Feature flags allow you to ship a project in
- different flavors by dynamically toggling certain functionality **[PREMIUM]**
+ different flavors by dynamically toggling certain functionality **(PREMIUM)**
- [GitLab Pages](pages/index.md): Build, test, and deploy your static
website with GitLab Pages
@@ -84,18 +84,18 @@ When you create a project in GitLab, you'll have access to a large number of
- [Wiki](wiki/index.md): document your GitLab project in an integrated Wiki.
- [Snippets](../snippets.md): store, share and collaborate on code snippets.
- [Cycle Analytics](cycle_analytics.md): review your development lifecycle.
-- [Insights](insights/index.md): configure the Insights that matter for your projects. **[ULTIMATE]**
-- [Security Dashboard](security_dashboard.md): Security Dashboard. **[ULTIMATE]**
+- [Insights](insights/index.md): configure the Insights that matter for your projects. **(ULTIMATE)**
+- [Security Dashboard](security_dashboard.md): Security Dashboard. **(ULTIMATE)**
- [Syntax highlighting](highlighting.md): an alternative to customize
your code blocks, overriding GitLab's default choice of language.
- [Badges](badges.md): badges for the project overview.
- [Releases](releases/index.md): a way to track deliverables in your project as snapshot in time of
the source, build output, and other metadata or artifacts
associated with a released version of your code.
-- [Maven packages](packages/maven_repository.md): your private Maven repository in GitLab. **[PREMIUM]**
-- [NPM packages](packages/npm_registry.md): your private NPM package registry in GitLab. **[PREMIUM]**
-- [Code owners](code_owners.md): specify code owners for certain files **[STARTER]**
-- [License Management](../application_security/license_management/index.md): approve and blacklist licenses for projects. **[ULTIMATE]**
+- [Maven packages](packages/maven_repository.md): your private Maven repository in GitLab. **(PREMIUM)**
+- [NPM packages](packages/npm_registry.md): your private NPM package registry in GitLab. **(PREMIUM)**
+- [Code owners](code_owners.md): specify code owners for certain files **(STARTER)**
+- [License Management](../application_security/license_management/index.md): approve and blacklist licenses for projects. **(ULTIMATE)**
### Project integrations
@@ -131,7 +131,7 @@ Read through the documentation on [project settings](settings/index.md).
- [Export a project from GitLab](settings/import_export.md#exporting-a-project-and-its-data)
- [Importing and exporting projects between GitLab instances](settings/import_export.md)
-## CI/CD for external repositories **[PREMIUM]**
+## CI/CD for external repositories **(PREMIUM)**
Instead of importing a repository directly to GitLab, you can connect your repository
as a CI/CD project.
@@ -193,7 +193,7 @@ password <personal_access_token>
To quickly access a project from the GitLab UI using the project ID,
visit the `/projects/:id` URL in your browser or other tool accessing the project.
-## Project aliases **[PREMIUM ONLY]**
+## Project aliases **(PREMIUM ONLY)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/3264) in [GitLab Premium](https://about.gitlab.com/pricing/) 12.1.
diff --git a/doc/user/project/insights/index.md b/doc/user/project/insights/index.md
index 1c6ad0b8b2b..76a6a96eec5 100644
--- a/doc/user/project/insights/index.md
+++ b/doc/user/project/insights/index.md
@@ -1,4 +1,4 @@
-# Insights **[ULTIMATE]**
+# Insights **(ULTIMATE)**
> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/725) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 12.0.
diff --git a/doc/user/project/integrations/github.md b/doc/user/project/integrations/github.md
index cdb0e34fdf6..d0399f9193b 100644
--- a/doc/user/project/integrations/github.md
+++ b/doc/user/project/integrations/github.md
@@ -1,4 +1,4 @@
-# GitHub project integration **[PREMIUM]**
+# GitHub project integration **(PREMIUM)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/3836) in GitLab Premium 10.6.
@@ -14,10 +14,10 @@ and is automatically configured on [GitHub import](../../../integration/github.m
### Complete these steps on GitHub
-This integration requires a [GitHub API token](https://help.github.com/articles/creating-a-personal-access-token-for-the-command-line/)
+This integration requires a [GitHub API token](https://help.github.com/en/articles/creating-a-personal-access-token-for-the-command-line)
with `repo:status` access granted:
-1. Go to your "Personal access tokens" page at https://github.com/settings/tokens
+1. Go to your "Personal access tokens" page at <https://github.com/settings/tokens>
1. Click "Generate New Token"
1. Ensure that `repo:status` is checked and click "Generate token"
1. Copy the generated token to use on GitLab
diff --git a/doc/user/project/integrations/img/jira_api_token.png b/doc/user/project/integrations/img/jira_api_token.png
index 4fa7a46854e..29689271bf7 100644
--- a/doc/user/project/integrations/img/jira_api_token.png
+++ b/doc/user/project/integrations/img/jira_api_token.png
Binary files differ
diff --git a/doc/user/project/integrations/img/jira_api_token_menu.png b/doc/user/project/integrations/img/jira_api_token_menu.png
index 14037bd0b47..1aca1d78f36 100644
--- a/doc/user/project/integrations/img/jira_api_token_menu.png
+++ b/doc/user/project/integrations/img/jira_api_token_menu.png
Binary files differ
diff --git a/doc/user/project/integrations/img/jira_issue_reference.png b/doc/user/project/integrations/img/jira_issue_reference.png
index 72c81460df7..a3e80c1b054 100644
--- a/doc/user/project/integrations/img/jira_issue_reference.png
+++ b/doc/user/project/integrations/img/jira_issue_reference.png
Binary files differ
diff --git a/doc/user/project/integrations/img/jira_merge_request_close.png b/doc/user/project/integrations/img/jira_merge_request_close.png
index 0f82ceba557..1c089c94207 100644
--- a/doc/user/project/integrations/img/jira_merge_request_close.png
+++ b/doc/user/project/integrations/img/jira_merge_request_close.png
Binary files differ
diff --git a/doc/user/project/integrations/img/jira_service_close_comment.png b/doc/user/project/integrations/img/jira_service_close_comment.png
deleted file mode 100644
index 9af0d38f098..00000000000
--- a/doc/user/project/integrations/img/jira_service_close_comment.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/project/integrations/img/jira_service_close_issue.png b/doc/user/project/integrations/img/jira_service_close_issue.png
index c85b1d1dd97..73d6498192c 100644
--- a/doc/user/project/integrations/img/jira_service_close_issue.png
+++ b/doc/user/project/integrations/img/jira_service_close_issue.png
Binary files differ
diff --git a/doc/user/project/integrations/img/jira_service_page.png b/doc/user/project/integrations/img/jira_service_page.png
index 377b69d9d06..80dd65ea24e 100644
--- a/doc/user/project/integrations/img/jira_service_page.png
+++ b/doc/user/project/integrations/img/jira_service_page.png
Binary files differ
diff --git a/doc/user/project/integrations/jira.md b/doc/user/project/integrations/jira.md
index 8f2e5a55b5f..ca990ee6c32 100644
--- a/doc/user/project/integrations/jira.md
+++ b/doc/user/project/integrations/jira.md
@@ -39,21 +39,17 @@ a GitLab project with any single Jira project.
If you have one Jira instance, you can pre-fill the settings page with a default
template. See the [Services Templates][services-templates] docs.
-Configuration happens via user name and password. Connecting to a Jira Server
-via CAS is not possible.
-
-In order to enable the Jira service in GitLab, you need to first configure the
-project in Jira and then enter the correct values in GitLab.
+In order to enable the Jira service in GitLab, you need to first configure the project in Jira and then enter the correct values in GitLab.
### Configuring Jira
-When connecting to **Jira Server**, which supports basic authentication, a **username and password** are required. Check the link below and proceed to the next step:
+#### Jira Server
-- [Setting up a user in Jira Server](jira_server_configuration.md)
+When connecting to **Jira Server**, which supports basic authentication, a **username and password** are required. Note that connecting to a Jira server via CAS is not possible. [Set up a user in Jira Server](jira_server_configuration.md) first and then proceed to [Configuring GitLab](#configuring-gitlab).
-When connecting to **Jira Cloud**, which supports authentication via API token, an **email and API token**, are required. Check the link below and proceed to the next step:
+#### Jira Cloud
-- [Setting up a user in Jira Cloud](jira_cloud_configuration.md)
+When connecting to **Jira Cloud**, which supports authentication via API token, an **email and API token**, are required. [Set up a user in Jira Cloud](jira_cloud_configuration.md) first and then proceed to [Configuring GitLab](#configuring-gitlab).
### Configuring GitLab
@@ -68,7 +64,7 @@ When connecting to **Jira Cloud**, which supports authentication via API token,
> to enable Basic Auth. The cookie being added to each request is `OBBasicAuth` with
> a value of `fromDialog`.
-To enable Jira integration in a project, navigate to the
+To enable the Jira integration in a project, navigate to the
[Integrations page](project_services.md#accessing-the-project-services), click
the **Jira** service, and fill in the required details on the page as described
in the table below.
@@ -127,6 +123,12 @@ ENTITY_TITLE
![example of mentioning or closing the Jira issue](img/jira_issue_reference.png)
+For example, the following commit will reference the Jira issue with `PROJECT-1` as its ID:
+
+```bash
+git commit -m "PROJECT-1 Fix spelling and grammar"
+```
+
### Closing Jira Issues
Jira issues can be closed directly from GitLab by using trigger words in
@@ -142,7 +144,7 @@ the same goal:
- `Closes PROJECT-1`
- `Fixes PROJECT-1`
-where `PROJECT-1` is the issue ID of the Jira project.
+where `PROJECT-1` is the ID of the Jira issue.
> **Notes:**
>
@@ -174,8 +176,6 @@ with a link to the commit that resolved the issue.
![The GitLab integration closes Jira issue](img/jira_service_close_issue.png)
-![The GitLab integration creates a comment and a link on Jira issue.](img/jira_service_close_comment.png)
-
## Troubleshooting
If these features do not work as expected, it is likely due to a problem with the way the integration settings were configured.
diff --git a/doc/user/project/integrations/jira_cloud_configuration.md b/doc/user/project/integrations/jira_cloud_configuration.md
index 614f05d5b7e..5a5ba2dd168 100644
--- a/doc/user/project/integrations/jira_cloud_configuration.md
+++ b/doc/user/project/integrations/jira_cloud_configuration.md
@@ -3,16 +3,18 @@
An API token is needed when integrating with Jira Cloud, follow the steps
below to create one:
-1. Log in to <https://id.atlassian.com> with your email.
-1. **Click API tokens**, then **Create API token**.
+1. Log in to <https://id.atlassian.com/manage/api-tokens> with your email address.
+
+ NOTE: **Note**
+ It is important that the user associated with this email address has *write* access
+ to projects in Jira.
+
+2. Click **Create API token**.
![Jira API token](img/jira_api_token_menu.png)
![Jira API token](img/jira_api_token.png)
-1. Make sure to write down your new API token as you will need it in the next [steps](jira.md#configuring-gitlab).
-
-NOTE: **Note**
-It is important that the user associated with this email has 'write' access to projects in Jira.
+1. Click **Copy to clipboard**, or click **View** and write down the new API token. It is required when [configuring GitLab](jira.md#configuring-gitlab).
-The Jira configuration is complete. You are going to need this newly created token and the email you used to log in, when [configuring GitLab in the next section](jira.md#configuring-gitlab).
+The Jira configuration is complete. You need the newly created token, and the associated email address, when [configuring GitLab](jira.md#configuring-gitlab) in the next section.
diff --git a/doc/user/project/integrations/project_services.md b/doc/user/project/integrations/project_services.md
index 0e4c71a9d3e..62e08a183f7 100644
--- a/doc/user/project/integrations/project_services.md
+++ b/doc/user/project/integrations/project_services.md
@@ -34,12 +34,12 @@ Click on the service links to see further configuration instructions and details
| [Emails on push](emails_on_push.md) | Email the commits and diff of each push to a list of recipients |
| External Wiki | Replaces the link to the internal wiki with a link to an external wiki |
| Flowdock | Flowdock is a collaboration web app for technical teams |
-| [GitHub](github.md) **[PREMIUM]** | Sends pipeline notifications to GitHub |
+| [GitHub](github.md) **(PREMIUM)** | Sends pipeline notifications to GitHub |
| [Hangouts Chat](hangouts_chat.md) | Receive events notifications in Google Hangouts Chat |
| [HipChat](hipchat.md) | Private group chat and IM |
| [Irker (IRC gateway)](irker.md) | Send IRC messages, on update, to a list of recipients through an Irker gateway |
| [Jira](jira.md) | Jira issue tracker |
-| [Jenkins](../../../integration/jenkins.md) **[STARTER]** | An extendable open source continuous integration server |
+| [Jenkins](../../../integration/jenkins.md) **(STARTER)** | An extendable open source continuous integration server |
| JetBrains TeamCity CI | A continuous integration and build server |
| [Mattermost slash commands](mattermost_slash_commands.md) | Mattermost chat and ChatOps slash commands |
| [Mattermost Notifications](mattermost.md) | Receive event notifications in Mattermost |
@@ -47,7 +47,7 @@ Click on the service links to see further configuration instructions and details
| Packagist | Update your project on Packagist, the main Composer repository |
| Pipelines emails | Email the pipeline status to a list of recipients |
| [Slack Notifications](slack.md) | Send GitLab events (e.g. issue created) to Slack as notifications |
-| [Slack slash commands](slack_slash_commands.md) **[CORE ONLY]** | Use slash commands in Slack to control GitLab |
+| [Slack slash commands](slack_slash_commands.md) **(CORE ONLY)** | Use slash commands in Slack to control GitLab |
| [GitLab Slack application](gitlab_slack_application.md) **[FREE ONLY]** | Use Slack's official application |
| PivotalTracker | Project Management Software (Source Commits Endpoint) |
| [Prometheus](prometheus.md) | Monitor the performance of your deployed apps |
diff --git a/doc/user/project/integrations/prometheus.md b/doc/user/project/integrations/prometheus.md
index aab7131e353..01b6650bfab 100644
--- a/doc/user/project/integrations/prometheus.md
+++ b/doc/user/project/integrations/prometheus.md
@@ -18,6 +18,7 @@ Once enabled, GitLab will automatically detect metrics from known services in th
## Enabling Prometheus Integration
### Managed Prometheus on Kubernetes
+
> **Note**: [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/28916) in GitLab 10.5
GitLab can seamlessly deploy and manage Prometheus on a [connected Kubernetes cluster](../clusters/index.md), making monitoring of your apps easy.
@@ -39,9 +40,9 @@ Once you have a connected Kubernetes cluster with Helm installed, deploying a ma
#### About managed Prometheus deployments
-Prometheus is deployed into the `gitlab-managed-apps` namespace, using the [official Helm chart](https://github.com/kubernetes/charts/tree/master/stable/prometheus). Prometheus is only accessible within the cluster, with GitLab communicating through the [Kubernetes API](https://kubernetes.io/docs/concepts/overview/kubernetes-api/).
+Prometheus is deployed into the `gitlab-managed-apps` namespace, using the [official Helm chart](https://github.com/helm/charts/tree/master/stable/prometheus). Prometheus is only accessible within the cluster, with GitLab communicating through the [Kubernetes API](https://kubernetes.io/docs/concepts/overview/kubernetes-api/).
-The Prometheus server will [automatically detect and monitor](https://prometheus.io/docs/prometheus/latest/configuration/configuration/#%3Ckubernetes_sd_config%3E) nodes, pods, and endpoints. To configure a resource to be monitored by Prometheus, simply set the following [Kubernetes annotations](https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/):
+The Prometheus server will [automatically detect and monitor](https://prometheus.io/docs/prometheus/latest/configuration/configuration/#kubernetes_sd_config) nodes, pods, and endpoints. To configure a resource to be monitored by Prometheus, simply set the following [Kubernetes annotations](https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/):
- `prometheus.io/scrape` to `true` to enable monitoring of the resource.
- `prometheus.io/port` to define the port of the metrics endpoint.
@@ -66,9 +67,9 @@ Integration with Prometheus requires the following:
Installing and configuring Prometheus to monitor applications is fairly straight forward.
-1. [Install Prometheus](https://prometheus.io/docs/introduction/install/)
+1. [Install Prometheus](https://prometheus.io/docs/prometheus/latest/installation/)
1. Set up one of the [supported monitoring targets](prometheus_library/index.md)
-1. Configure the Prometheus server to [collect their metrics](https://prometheus.io/docs/operating/configuration/#scrape_config)
+1. Configure the Prometheus server to [collect their metrics](https://prometheus.io/docs/prometheus/latest/configuration/configuration/#scrape_config)
#### Configuration in GitLab
@@ -93,7 +94,7 @@ GitLab will automatically scan the Prometheus server for metrics from known serv
You can view the performance dashboard for an environment by [clicking on the monitoring button](../../../ci/environments.md#monitoring-environments).
-### Adding additional metrics **[PREMIUM]**
+### Adding additional metrics **(PREMIUM)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/3799) in [GitLab Premium](https://about.gitlab.com/pricing/) 10.6.
@@ -120,7 +121,7 @@ GitLab supports a limited set of [CI variables](../../../ci/variables/README.htm
To specify a variable in a query, enclose it in curly braces with a leading percent. For example: `%{ci_environment_slug}`.
-### Setting up alerts for Prometheus metrics **[ULTIMATE]**
+### Setting up alerts for Prometheus metrics **(ULTIMATE)**
#### Managed Prometheus instances
@@ -156,7 +157,7 @@ receivers:
...
```
-### Taking action on incidents **[ULTIMATE]**
+### Taking action on incidents **(ULTIMATE)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/4925) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 11.11.
diff --git a/doc/user/project/integrations/prometheus_library/cloudwatch.md b/doc/user/project/integrations/prometheus_library/cloudwatch.md
index 66f1b587070..5049733abdd 100644
--- a/doc/user/project/integrations/prometheus_library/cloudwatch.md
+++ b/doc/user/project/integrations/prometheus_library/cloudwatch.md
@@ -18,9 +18,9 @@ The [Prometheus service](../prometheus.md) must be enabled.
## Configuring Prometheus to monitor for Cloudwatch metrics
-To get started with Cloudwatch monitoring, you should install and configure the [Cloudwatch exporter](https://github.com/hnlq715/nginx-vts-exporter) which retrieves and parses the specified Cloudwatch metrics and translates them into a Prometheus monitoring endpoint.
+To get started with Cloudwatch monitoring, you should install and configure the [Cloudwatch exporter](https://github.com/prometheus/cloudwatch_exporter) which retrieves and parses the specified Cloudwatch metrics and translates them into a Prometheus monitoring endpoint.
-Right now, the only AWS resource supported is the Elastic Load Balancer, whose Cloudwatch metrics can be found [here](http://docs.aws.amazon.com/elasticloadbalancing/latest/classic/elb-cloudwatch-metrics.html).
+Right now, the only AWS resource supported is the Elastic Load Balancer, whose Cloudwatch metrics are [documented here](https://docs.aws.amazon.com/elasticloadbalancing/latest/classic/elb-cloudwatch-metrics.html).
A sample Cloudwatch Exporter configuration file, configured for basic AWS ELB monitoring, is [available for download](../samples/cloudwatch.yml).
diff --git a/doc/user/project/integrations/prometheus_library/haproxy.md b/doc/user/project/integrations/prometheus_library/haproxy.md
index abb0c01ad18..6be8fc82431 100644
--- a/doc/user/project/integrations/prometheus_library/haproxy.md
+++ b/doc/user/project/integrations/prometheus_library/haproxy.md
@@ -11,8 +11,8 @@ The [Prometheus service](../prometheus.md) must be enabled.
| Name | Query |
| ---- | ----- |
-| Throughput (req/sec) | sum(rate(haproxy_frontend_http_requests_total{%{environment_filter}}[2m])) by (code) |
-| HTTP Error Rate (%) | sum(rate(haproxy_frontend_http_requests_total{code="5xx",%{environment_filter}}[2m])) / sum(rate(haproxy_frontend_http_requests_total{%{environment_filter}}[2m])) |
+| Throughput (req/sec) | `sum(rate(haproxy_frontend_http_requests_total{%{environment_filter}}[2m])) by (code)` |
+| HTTP Error Rate (%) | `sum(rate(haproxy_frontend_http_requests_total{code="5xx",%{environment_filter}}[2m])) / sum(rate(haproxy_frontend_http_requests_total{%{environment_filter}}[2m]))` |
## Configuring Prometheus to monitor for HAProxy metrics
diff --git a/doc/user/project/integrations/prometheus_library/kubernetes.md b/doc/user/project/integrations/prometheus_library/kubernetes.md
index 8b1cf1a251a..0d300d3c418 100644
--- a/doc/user/project/integrations/prometheus_library/kubernetes.md
+++ b/doc/user/project/integrations/prometheus_library/kubernetes.md
@@ -36,7 +36,7 @@ In order to isolate and only display relevant CPU and Memory metrics for a given
Instead, the [Deployment](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/) or [DaemonSet](https://kubernetes.io/docs/concepts/workloads/controllers/daemonset/) name should begin with [CI_ENVIRONMENT_SLUG](../../../../ci/variables/README.md#predefined-environment-variables). It can be followed by a `-` and additional content if desired. For example, a deployment name of `review-homepage-5620p5` would match the `review/homepage` environment.
-## Displaying Canary metrics **[PREMIUM]**
+## Displaying Canary metrics **(PREMIUM)**
> Introduced in [GitLab 10.2](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/15201).
diff --git a/doc/user/project/integrations/prometheus_library/nginx.md b/doc/user/project/integrations/prometheus_library/nginx.md
index c4fea178ab5..7db9629c002 100644
--- a/doc/user/project/integrations/prometheus_library/nginx.md
+++ b/doc/user/project/integrations/prometheus_library/nginx.md
@@ -14,9 +14,9 @@ NGINX server metrics are detected, which tracks the pages and content directly s
| Name | Query |
| ---- | ----- |
-| Throughput (req/sec) | sum(rate(nginx_server_requests{server_zone!="*", server_zone!="_", %{environment_filter}}[2m])) by (code) |
-| Latency (ms) | avg(nginx_server_requestMsec{%{environment_filter}}) |
-| HTTP Error Rate (HTTP Errors / sec) | sum(rate(nginx_server_requests{code="5xx", %{environment_filter}}[2m])) |
+| Throughput (req/sec) | `sum(rate(nginx_server_requests{server_zone!="*", server_zone!="_", %{environment_filter}}[2m])) by (code)` |
+| Latency (ms) | `avg(nginx_server_requestMsec{%{environment_filter}})` |
+| HTTP Error Rate (HTTP Errors / sec) | `sum(rate(nginx_server_requests{code="5xx", %{environment_filter}}[2m]))` |
## Configuring Prometheus to monitor for NGINX metrics
diff --git a/doc/user/project/integrations/prometheus_library/nginx_ingress.md b/doc/user/project/integrations/prometheus_library/nginx_ingress.md
index de7fc93f0a4..fd743855a8c 100644
--- a/doc/user/project/integrations/prometheus_library/nginx_ingress.md
+++ b/doc/user/project/integrations/prometheus_library/nginx_ingress.md
@@ -14,9 +14,9 @@ GitLab has support for automatically detecting and monitoring the Kubernetes NGI
| Name | Query |
| ---- | ----- |
-| Throughput (req/sec) | sum(label_replace(rate(nginx_ingress_controller_requests{namespace="%{kube_namespace}",ingress=~".*%{ci_environment_slug}.*"}[2m]), "status_code", "${1}xx", "status", "(.)..")) by (status_code) |
-| Latency (ms) | sum(rate(nginx_ingress_controller_ingress_upstream_latency_seconds_sum{namespace="%{kube_namespace}",ingress=~".*%{ci_environment_slug}.*"}[2m])) / sum(rate(nginx_ingress_controller_ingress_upstream_latency_seconds_count{namespace="%{kube_namespace}",ingress=~".*%{ci_environment_slug}.*"}[2m])) * 1000 |
-| HTTP Error Rate (%) | sum(rate(nginx_ingress_controller_requests{status=~"5.*",namespace="%{kube_namespace}",ingress=~".*%{ci_environment_slug}.*"}[2m])) / sum(rate(nginx_ingress_controller_requests{namespace="%{kube_namespace}",ingress=~".*%{ci_environment_slug}.*"}[2m])) * 100 |
+| Throughput (req/sec) | `sum(label_replace(rate(nginx_ingress_controller_requests{namespace="%{kube_namespace}",ingress=~".*%{ci_environment_slug}.*"}[2m]), "status_code", "${1}xx", "status", "(.)..")) by (status_code)` |
+| Latency (ms) | `sum(rate(nginx_ingress_controller_ingress_upstream_latency_seconds_sum{namespace="%{kube_namespace}",ingress=~".*%{ci_environment_slug}.*"}[2m])) / sum(rate(nginx_ingress_controller_ingress_upstream_latency_seconds_count{namespace="%{kube_namespace}",ingress=~".*%{ci_environment_slug}.*"}[2m])) * 1000` |
+| HTTP Error Rate (%) | `sum(rate(nginx_ingress_controller_requests{status=~"5.*",namespace="%{kube_namespace}",ingress=~".*%{ci_environment_slug}.*"}[2m])) / sum(rate(nginx_ingress_controller_requests{namespace="%{kube_namespace}",ingress=~".*%{ci_environment_slug}.*"}[2m])) * 100` |
## Configuring NGINX ingress monitoring
diff --git a/doc/user/project/integrations/prometheus_library/nginx_ingress_vts.md b/doc/user/project/integrations/prometheus_library/nginx_ingress_vts.md
index 31ac53c0d14..b03787b3e0d 100644
--- a/doc/user/project/integrations/prometheus_library/nginx_ingress_vts.md
+++ b/doc/user/project/integrations/prometheus_library/nginx_ingress_vts.md
@@ -14,9 +14,9 @@ GitLab has support for automatically detecting and monitoring the Kubernetes NGI
| Name | Query |
| ---- | ----- |
-| Throughput (req/sec) | sum(rate(nginx_upstream_responses_total{upstream=~"%{kube_namespace}-%{ci_environment_slug}-.*"}[2m])) by (status_code) |
-| Latency (ms) | avg(nginx_upstream_response_msecs_avg{upstream=~"%{kube_namespace}-%{ci_environment_slug}-.*"}) |
-| HTTP Error Rate (%) | sum(rate(nginx_upstream_responses_total{status_code="5xx", upstream=~"%{kube_namespace}-%{ci_environment_slug}-.*"}[2m])) / sum(rate(nginx_upstream_responses_total{upstream=~"%{kube_namespace}-%{ci_environment_slug}-.*"}[2m])) * 100 |
+| Throughput (req/sec) | `sum(rate(nginx_upstream_responses_total{upstream=~"%{kube_namespace}-%{ci_environment_slug}-.*"}[2m])) by (status_code)` |
+| Latency (ms) | `avg(nginx_upstream_response_msecs_avg{upstream=~"%{kube_namespace}-%{ci_environment_slug}-.*"})` |
+| HTTP Error Rate (%) | `sum(rate(nginx_upstream_responses_total{status_code="5xx", upstream=~"%{kube_namespace}-%{ci_environment_slug}-.*"}[2m])) / sum(rate(nginx_upstream_responses_total{upstream=~"%{kube_namespace}-%{ci_environment_slug}-.*"}[2m])) * 100` |
## Configuring NGINX ingress monitoring
diff --git a/doc/user/project/integrations/slack.md b/doc/user/project/integrations/slack.md
index bb8d276c2fc..508e72b5753 100644
--- a/doc/user/project/integrations/slack.md
+++ b/doc/user/project/integrations/slack.md
@@ -6,7 +6,7 @@ The Slack Notifications Service allows your GitLab project to send events (e.g.
## Slack Configuration
-1. Sign in to your Slack team and [start a new Incoming WebHooks configuration](https://my.slack.com/services/new/incoming-webhook/).
+1. Sign in to your Slack team and [start a new Incoming WebHooks configuration](https://my.slack.com/services/new/incoming-webhook).
1. Select the Slack channel where notifications will be sent to by default. Click the **Add Incoming WebHooks integration** button to add the configuration.
1. Copy the **Webhook URL**, which we'll use later in the GitLab configuration.
diff --git a/doc/user/project/integrations/slack_slash_commands.md b/doc/user/project/integrations/slack_slash_commands.md
index 371e78ca3a4..813066c51ac 100644
--- a/doc/user/project/integrations/slack_slash_commands.md
+++ b/doc/user/project/integrations/slack_slash_commands.md
@@ -1,4 +1,4 @@
-# Slack slash commands **[CORE ONLY]**
+# Slack slash commands **(CORE ONLY)**
> Introduced in GitLab 8.15.
diff --git a/doc/user/project/integrations/webhooks.md b/doc/user/project/integrations/webhooks.md
index 04a9d9568ca..30940b65454 100644
--- a/doc/user/project/integrations/webhooks.md
+++ b/doc/user/project/integrations/webhooks.md
@@ -24,7 +24,7 @@ to the webhook URL.
In most cases, you'll need to set up your own [webhook receiver](#example-webhook-receiver)
to receive information from GitLab, and send it to another app, according to your needs.
-We already have a [built-in receiver](https://docs.gitlab.com/ce/project_services/slack.html)
+We already have a [built-in receiver](slack.md)
for sending [Slack](https://api.slack.com/incoming-webhooks) notifications _per project_.
## Overview
diff --git a/doc/user/project/issue_board.md b/doc/user/project/issue_board.md
index 31020de5208..3eb5581912a 100644
--- a/doc/user/project/issue_board.md
+++ b/doc/user/project/issue_board.md
@@ -28,11 +28,11 @@ Issue Boards** (version introduced in GitLab 8.11 - August 2016).
### Advanced features of Issue Boards
With [GitLab Starter](https://about.gitlab.com/pricing/), you can create
-[multiple issue boards](#multiple-issue-boards-starter) for a given project. **[STARTER]**
+[multiple issue boards](#multiple-issue-boards-starter) for a given project. **(STARTER)**
With [GitLab Premium](https://about.gitlab.com/pricing/), you can also create multiple
issue boards for your groups, and add lists for [assignees](#assignee-lists-premium) and
-[milestones](#milestone-lists-premium). **[PREMIUM]**
+[milestones](#milestone-lists-premium). **(PREMIUM)**
Check all the [advanced features of Issue Boards](#gitlab-enterprise-features-for-issue-boards)
below.
@@ -163,7 +163,7 @@ on the following sections.
For a collection of [features per tier](#summary-of-features-per-tier), check the summary below.
-### Multiple Issue Boards **[STARTER]**
+### Multiple Issue Boards **(STARTER)**
> Introduced in [GitLab Enterprise Edition 8.13](https://about.gitlab.com/2016/10/22/gitlab-8-13-released/#multiple-issue-boards-ee).
@@ -188,7 +188,7 @@ NOTE: **Note:**
The Multiple Issue Boards feature is available for
**projects in GitLab Starter Edition** and for **groups in GitLab Premium Edition**.
-### Configurable Issue Boards **[STARTER]**
+### 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).
@@ -208,7 +208,7 @@ If you don't have editing permission in a board, you're still able to see the co
![Viewing board configuration](img/issue_board_view_scope.png)
-### Focus mode **[STARTER]**
+### 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).
@@ -216,7 +216,7 @@ Click the button at the top right to toggle focus mode on and off. In focus mode
![Board focus mode](img/issue_board_focus_mode.gif)
-### Sum of Issue Weights **[STARTER]**
+### 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,
@@ -224,7 +224,7 @@ especially in combination with [assignee lists](#assignee-lists-premium).
![Issue Board summed weights](img/issue_board_summed_weights.png)
-### Group Issue Boards **[PREMIUM]**
+### Group Issue Boards **(PREMIUM)**
> Introduced in [GitLab Premium 10.0](https://about.gitlab.com/2017/09/22/gitlab-10-0-released/#group-issue-boards).
@@ -240,7 +240,7 @@ 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]**
+### Assignee lists **(PREMIUM)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/5784) in GitLab 11.0 Premium.
@@ -259,7 +259,7 @@ 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]**
+### Milestone lists **(PREMIUM)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/6469) in GitLab 11.2 Premium.
diff --git a/doc/user/project/issues/automatic_issue_closing.md b/doc/user/project/issues/automatic_issue_closing.md
index c3e06b219ff..dab79327d6a 100644
--- a/doc/user/project/issues/automatic_issue_closing.md
+++ b/doc/user/project/issues/automatic_issue_closing.md
@@ -1,63 +1,5 @@
-# Automatic issue closing
-
->**Notes:**
->
-> - This is the user docs. In order to change the default issue closing pattern,
-> follow the steps in the [administration docs].
-> - For performance reasons, automatic issue closing is disabled for the very
-> first push from an existing repository.
-
-When a commit or merge request resolves one or more issues, it is possible to
-automatically have these issues closed when the commit or merge request lands
-in the project's default branch.
-
-If a commit message or merge request description contains a sentence matching
-a certain regular expression, all issues referenced from the matched text will
-be closed. This happens when the commit is pushed to a project's
-[**default** branch](../repository/branches/index.md#default-branch), or when a
-commit or merge request is merged into it.
-
-## Default closing pattern value
-
-When not specified, the default issue closing pattern as shown below will be
-used:
-
-```bash
-((?:[Cc]los(?:e[sd]?|ing)|[Ff]ix(?:e[sd]|ing)?|[Rr]esolv(?:e[sd]?|ing)|[Ii]mplement(?:s|ed|ing)?)(:?) +(?:(?:issues? +)?%{issue_ref}(?:(?:, *| +and +)?)|([A-Z][A-Z0-9_]+-\d+))+)
-```
-
-Note that `%{issue_ref}` is a complex regular expression defined inside GitLab's
-source code that can match references to:
-
-- A local issue (`#123`).
-- A cross-project issue (`group/project#123`).
-- A link to an issue
- (`https://gitlab.example.com/group/project/issues/123`).
-
---
-
-This translates to the following keywords:
-
-- Close, Closes, Closed, Closing, close, closes, closed, closing
-- Fix, Fixes, Fixed, Fixing, fix, fixes, fixed, fixing
-- Resolve, Resolves, Resolved, Resolving, resolve, resolves, resolved, resolving
-- Implement, Implements, Implemented, Implementing, implement, implements, implemented, implementing
-
+redirect_to: 'managing_issues.md#closing-issues-automatically'
---
-For example the following commit message:
-
-```
-Awesome commit message
-
-Fix #20, Fixes #21 and Closes group/otherproject#22.
-This commit is also related to #17 and fixes #18, #19
-and https://gitlab.example.com/group/otherproject/issues/23.
-```
-
-will close `#18`, `#19`, `#20`, and `#21` in the project this commit is pushed
-to, as well as `#22` and `#23` in group/otherproject. `#17` won't be closed as
-it does not match the pattern. It works with multi-line commit messages as well
-as one-liners when used with `git commit -m`.
-
-[administration docs]: ../../../administration/issue_closing_pattern.md
+This document was moved to [another location](managing_issues.md#closing-issues-automatically).
diff --git a/doc/user/project/issues/closing_issues.md b/doc/user/project/issues/closing_issues.md
index 1d88745af9f..04f1c8e1a4a 100644
--- a/doc/user/project/issues/closing_issues.md
+++ b/doc/user/project/issues/closing_issues.md
@@ -1,59 +1,5 @@
-# Closing Issues
+---
+redirect_to: 'managing_issues.md#closing-issues'
+---
-Please read through the [GitLab Issue Documentation](index.md) for an overview on GitLab Issues.
-
-## Directly
-
-Whenever you decide that's no longer need for that issue,
-close the issue using the close button:
-
-![close issue - button](img/button_close_issue.png)
-
-## Via Merge Request
-
-When a merge request resolves the discussion over an issue, you can
-make it close that issue(s) when merged.
-
-All you need is to use a [keyword](automatic_issue_closing.md)
-accompanying the issue number, add to the description of that MR.
-
-In this example, the keyword "closes" prefixing the issue number will create a relationship
-in such a way that the merge request will close the issue when merged.
-
-Mentioning various issues in the same line also works for this purpose:
-
-```md
-Closes #333, #444, #555 and #666
-```
-
-If the issue is in a different repository rather then the MR's,
-add the full URL for that issue(s):
-
-```md
-Closes #333, #444, and https://gitlab.com/<username>/<projectname>/issues/<xxx>
-```
-
-All the following keywords will produce the same behaviour:
-
-- Close, Closes, Closed, Closing, close, closes, closed, closing
-- Fix, Fixes, Fixed, Fixing, fix, fixes, fixed, fixing
-- Resolve, Resolves, Resolved, Resolving, resolve, resolves, resolved, resolving
-
-![merge request closing issue when merged](img/merge_request_closes_issue.png)
-
-If you use any other word before the issue number, the issue and the MR will
-link to each other, but the MR will NOT close the issue(s) when merged.
-
-![mention issues in MRs - closing and related](img/closing_and_related_issues.png)
-
-## From the Issue Board
-
-You can close an issue from [Issue Boards](../issue_board.md) by dragging an issue card
-from its list and dropping into **Closed**.
-
-![close issue from the Issue Board](img/close_issue_from_board.gif)
-
-## Customizing the issue closing pattern
-
-Alternatively, a GitLab **administrator** can
-[customize the issue closing pattern](../../../administration/issue_closing_pattern.md).
+This document was moved to [another location](managing_issues.md#closing-issues).
diff --git a/doc/user/project/issues/create_new_issue.md b/doc/user/project/issues/create_new_issue.md
index c2916c79876..8eec29716c1 100644
--- a/doc/user/project/issues/create_new_issue.md
+++ b/doc/user/project/issues/create_new_issue.md
@@ -1,104 +1,5 @@
-# Create a new Issue
+---
+redirect_to: 'managing_issues.md#create-a-new-issue'
+---
-Please read through the [GitLab Issue Documentation](index.md) for an overview on GitLab Issues.
-
-When you create a new issue, you'll be prompted to fill in
-the information illustrated on the image below.
-
-![New issue from the issues list](img/new_issue.png)
-
-Read through the [issue data and actions documentation](issue_data_and_actions.md#parts-of-an-issue)
-to understand these fields one by one.
-
-## New issue from the Issue Tracker
-
-Navigate to your **Project's Dashboard** > **Issues** > **New Issue** to create a new issue:
-
-![New issue from the issue list view](img/new_issue_from_tracker_list.png)
-
-## New issue from an opened issue
-
-From an **opened issue** in your project, click **New Issue** to create a new
-issue in the same project:
-
-![New issue from an open issue](img/new_issue_from_open_issue.png)
-
-## New issue from the project's dashboard
-
-From your **Project's Dashboard**, click the plus sign (**+**) to open a dropdown
-menu with a few options. Select **New Issue** to create an issue in that project:
-
-![New issue from a project's dashboard](img/new_issue_from_projects_dashboard.png)
-
-## New issue from the Issue Board
-
-From an Issue Board, create a new issue by clicking on the plus sign (**+**) on the top of a list.
-It opens a new issue for that project labeled after its respective list.
-
-![From the issue board](img/new_issue_from_issue_board.png)
-
-## New issue via email
-
-At the bottom of a project's Issues List page, a link to **Email a new issue to this project**
-is displayed if your GitLab instance has [incoming email](../../../administration/incoming_email.md) configured.
-
-![Bottom of a project issues page](img/new_issue_from_email.png)
-
-When you click this link, an email address is displayed which belongs to you for creating issues in this project.
-You can save this address as a contact in your email client for easy acceess.
-
-CAUTION: **Caution:**
-This is a private email address, generated just for you. **Keep it to yourself**,
-as anyone who gets ahold of it can create issues or merge requests as if they
-were you. If the address is compromised, or you'd like it to be regenerated for
-any reason, click **Email a new issue to this project** again and click the reset link.
-
-Sending an email to this address will create a new issue on your behalf for
-this project, where:
-
-- The email subject becomes the issue title.
-- The email body becomes the issue description.
-- [Markdown](../../markdown.md) and [quick actions](../quick_actions.md) are supported.
-
-NOTE: **Note:**
-In GitLab 11.7, we updated the format of the generated email address.
-However the older format is still supported, allowing existing aliases
-or contacts to continue working._
-
-## New issue via Service Desk **[PREMIUM]**
-
-Enable [Service Desk](../service_desk.md) to your project and offer email support.
-By doing so, when your customer sends a new email, a new issue can be created in
-the appropriate project and followed up from there.
-
-## New issue from the group-level Issue Tracker
-
-Head to the Group dashboard and click "Issues" in the sidebar to visit the Issue Tracker
-for all projects in your Group. Select the project you'd like to add an issue for
-using the dropdown button at the top-right of the page.
-
-![Select project to create issue](img/select_project_from_group_level_issue_tracker.png)
-
-We'll keep track of the project you selected most recently, and use it as the default
-for your next visit. This should save you a lot of time and clicks, if you mostly
-create issues for the same project.
-
-![Create issue from group-level issue tracker](img/create_issue_from_group_level_issue_tracker.png)
-
-## New issue via URL with prefilled fields
-
-You can link directly to the new issue page for a given project, with prefilled
-field values using query string parameters in a URL. This is useful for embedding
-a URL in an external HTML page, and also certain scenarios where you want the user to
-create an issue with certain fields prefilled.
-
-The title, description, and description template fields can be prefilled using
-this method. The description and description template fields cannot be pre-entered
-in the same URL (since a description template just populates the description field).
-
-Follow these examples to form your new issue URL with prefilled fields.
-
-- For a new issue in the GitLab Community Edition project with a pre-entered title
- and a pre-entered description, the URL would be `https://gitlab.com/gitlab-org/gitlab-ce/issues/new?issue[title]=Validate%20new%20concept&issue[description]=Research%20idea`
-- For a new issue in the GitLab Community Edition project with a pre-entered title
- and a pre-entered description template, the URL would be `https://gitlab.com/gitlab-org/gitlab-ce/issues/new?issue[title]=Validate%20new%20concept&issuable_template=Research%20proposal`
+This document was moved to [another location](managing_issues.md#create-a-new-issue).
diff --git a/doc/user/project/issues/crosslinking_issues.md b/doc/user/project/issues/crosslinking_issues.md
index ff5b1f2ce50..93dc2a2e4ca 100644
--- a/doc/user/project/issues/crosslinking_issues.md
+++ b/doc/user/project/issues/crosslinking_issues.md
@@ -25,9 +25,8 @@ git commit -m "this is my commit message. Related to https://gitlab.com/<usernam
Of course, you can replace `gitlab.com` with the URL of your own GitLab instance.
-**Note:** Linking your first commit to your issue is going to be relevant
-for tracking your process far ahead with
-[GitLab Cycle Analytics](https://about.gitlab.com/features/cycle-analytics/)).
+NOTE: **Note:** Linking your first commit to your issue is going to be relevant
+for tracking your process with [GitLab Cycle Analytics](https://about.gitlab.com/features/cycle-analytics/).
It will measure the time taken for planning the implementation of that issue,
which is the time between creating an issue and making the first commit.
@@ -35,14 +34,13 @@ which is the time between creating an issue and making the first commit.
Mentioning related issues in merge requests and other issues is useful
for your team members and collaborators to know that there are opened
-issues around that same idea.
+issues regarding the same topic.
-You do that as explained above, when
-[mentioning an issue from a commit message](#from-commit-messages).
+You do that as explained above, when [mentioning an issue from a commit message](#from-commit-messages).
-When mentioning the issue "A" in issue "B", the issue "A" will also
-display a notification in its tracker. The same is valid for mentioning
-issues in merge requests.
+When mentioning issue `#111` in issue `#222`, issue `#111` will also display a notification
+in its tracker. That is, you only need to mention the relationship once for it to
+display in both issues. The same is valid when mentioning issues in [merge requests](#from-merge-requests).
![issue mentioned in issue](img/mention_in_issue.png)
@@ -53,10 +51,7 @@ they do for [related issues](#from-related-issues).
When you mention an issue in a merge request description, it will simply
[link the issue and merge request together](#from-related-issues). Additionally,
-you can also [set an issue to close as soon as the merge request is merged](closing_issues.md#via-merge-request).
+you can also [set an issue to close automatically](managing_issues.md#closing-issues-automatically)
+as soon as the merge request is merged.
![issue mentioned in MR](img/mention_in_merge_request.png)
-
-### Close an issue by merging a merge request
-
-To [close an issue when a merge request is merged](closing_issues.md#via-merge-request), use the [automatic issue closing pattern](automatic_issue_closing.md).
diff --git a/doc/user/project/issues/csv_export.md b/doc/user/project/issues/csv_export.md
index 56b94585672..0b7a7af5927 100644
--- a/doc/user/project/issues/csv_export.md
+++ b/doc/user/project/issues/csv_export.md
@@ -1,4 +1,4 @@
-# Export Issues to CSV **[STARTER]**
+# Export Issues to CSV **(STARTER)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/1126) in [GitLab Starter 9.0](https://about.gitlab.com/2017/03/22/gitlab-9-0-released/#export-issues-ees-eep).
diff --git a/doc/user/project/issues/csv_import.md b/doc/user/project/issues/csv_import.md
index b0b1cfcfdf7..cc0d5ac9028 100644
--- a/doc/user/project/issues/csv_import.md
+++ b/doc/user/project/issues/csv_import.md
@@ -7,7 +7,8 @@ Issues can be imported to a project by uploading a CSV file with the columns
The user uploading the CSV file will be set as the author of the imported issues.
-> **Note:** A permission level of `Developer` or higher is required to import issues.
+NOTE: **Note:** A permission level of [Developer](../../permissions.md), or higher, is required
+to import issues.
## Prepare for the import
@@ -24,42 +25,26 @@ To import issues:
1. Select the file and click the **Import issues** button.
The file is processed in the background and a notification email is sent
-to you once the import is completed.
+to you once the import is complete.
## CSV file format
-### Header row
+When importing issues from a CSV file, it must be formatted in a certain way:
-CSV files must contain a header row where the first column header is `title` and the second is `description`.
-If additional columns are present, they will be ignored.
+- **header row:** CSV files must contain a header row where the first column header
+ is `title` and the second is `description`. If additional columns are present, they
+ will be ignored.
+- **separators:** The column separator is automatically detected from the header row.
+ Supported separator characters are: commas (`,`), semicolons (`;`), and tabs (`\t`).
+ The row separator can be either `CRLF` or `LF`.
+- **double-quote character:** The double-quote (`"`) character is used to quote fields,
+ enabling the use of the column separator within a field (see the third line in the
+ sample CSV data below). To insert a double-quote (`"`) within a quoted
+ field, use two double-quote characters in succession, i.e. `""`.
+- **data rows:** After the header row, succeeding rows must follow the same column
+ order. The issue title is required while the description is optional.
-### Column separator
-
-The column separator is automatically detected from the header row.
-
-Supported separator characters are: commas (`,`), semicolons (`;`), and tabs (`\t`).
-
-### Row separator
-
-Lines ending in either `CRLF` or `LF` are supported.
-
-### Quote character
-
-The double-quote (`"`) character is used to quote fields so you can use the column separator within a field. To insert
-a double-quote (`"`) within a quoted field, use two double-quote characters in succession, i.e. `""`.
-
-### Data rows
-
-After the header row, succeeding rows must follow the same column order. The issue title is required while the
-description is optional.
-
-### File size
-
-The limit depends on the configuration value of Max Attachment Size for the GitLab instance.
-
-For GitLab.com, it is set to 10 MB.
-
-## Sample data
+Sample CSV data:
```csv
title,description
@@ -67,3 +52,9 @@ My Issue Title,My Issue Description
Another Title,"A description, with a comma"
"One More Title","One More Description"
```
+
+### File size
+
+The limit depends on the configuration value of Max Attachment Size for the GitLab instance.
+
+For GitLab.com, it is set to 10 MB.
diff --git a/doc/user/project/issues/deleting_issues.md b/doc/user/project/issues/deleting_issues.md
index 536a0de8974..e50259e0dcf 100644
--- a/doc/user/project/issues/deleting_issues.md
+++ b/doc/user/project/issues/deleting_issues.md
@@ -1,13 +1,5 @@
-# Deleting Issues
+---
+redirect_to: 'managing_issues.md#deleting-issues'
+---
-> [Introduced][ce-2982] in GitLab 8.6
-
-Please read through the [GitLab Issue Documentation](index.md) for an overview on GitLab Issues.
-
-You can delete an issue by editing it and clicking on the delete button.
-
-![delete issue - button](img/delete_issue.png)
-
->**Note:** Only [project owners](../../permissions.md) can delete issues.
-
-[ce-2982]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/2982 \ No newline at end of file
+This document was moved to [another location](managing_issues.md#deleting-issues).
diff --git a/doc/user/project/issues/due_dates.md b/doc/user/project/issues/due_dates.md
index 987c16dfab6..bd3298497d2 100644
--- a/doc/user/project/issues/due_dates.md
+++ b/doc/user/project/issues/due_dates.md
@@ -4,30 +4,32 @@
Please read through the [GitLab Issue Documentation](index.md) for an overview on GitLab Issues.
-Due dates can be used in issues to keep track of deadlines and make sure
-features are shipped on time. Due dates require at least [Reporter permissions](../../permissions.md#project-members-permissions)
-to be able to edit them. On the contrary, they can be seen by everybody.
+Due dates can be used in issues to keep track of deadlines and make sure features are
+shipped on time. Users must have at least [Reporter permissions](../../permissions.md)
+to be able to edit them, but they can be seen by everybody with permission to view
+the issue.
## Setting a due date
-When creating or editing an issue, you can see the due date field from where
-a calendar will appear to help you choose the date you want. To remove it,
-select the date text and delete it.
+When creating or editing an issue, you can click in the **due date** field and a calendar
+will appear to help you choose the date you want. To remove the date, select the date
+text and delete it. The date is related to the server's timezone, not the timezone of
+the user setting the due date.
![Create a due date](img/due_dates_create.png)
-A quicker way to set a due date is via the issue sidebar. Simply expand the
-sidebar and select **Edit** to pick a due date or remove the existing one.
+You can also set a due date via the issue sidebar. Expand the
+sidebar and click **Edit** to pick a due date or remove the existing one.
Changes are saved immediately.
![Edit a due date via the sidebar](img/due_dates_edit_sidebar.png)
## Making use of due dates
-Issues that have a due date can be distinctively seen in the issue tracker
+Issues that have a due date can be easily seen in the issue tracker,
displaying a date next to them. Issues where the date is overdue will have
the icon and the date colored red. You can sort issues by those that are
-_Due soon_ or _Due later_ from the dropdown menu in the right.
+`Due soon` or `Due later` from the dropdown menu on the right.
![Issues with due dates in the issues index page](img/due_dates_issues_index_page.png)
@@ -36,14 +38,13 @@ Due dates also appear in your [todos list](../../../workflow/todos.md).
![Issues with due dates in the todos](img/due_dates_todos.png)
The day before an open issue is due, an email will be sent to all participants
-of the issue. Both the due date and the day before are calculated using the
+of the issue. Like the due date, the "day before the due date" is determined by the
server's timezone.
Issues with due dates can also be exported as an iCalendar feed. The URL of the
feed can be added to calendar applications. The feed is accessible by clicking
-on the _Subscribe to calendar_ button on the following pages:
+on the **Subscribe to calendar** button on the following pages:
-- on the **Assigned Issues** page that is linked on the right-hand side of the
- GitLab header
+- on the **Assigned Issues** page that is linked on the right-hand side of the GitLab header
- on the **Project Issues** page
- on the **Group Issues** page
diff --git a/doc/user/project/issues/index.md b/doc/user/project/issues/index.md
index 4acbb4cc3f6..e917697e973 100644
--- a/doc/user/project/issues/index.md
+++ b/doc/user/project/issues/index.md
@@ -6,8 +6,9 @@ Issues are the fundamental medium for collaborating on ideas and planning work i
The GitLab issue tracker is an advanced tool for collaboratively developing ideas, solving problems, and planning work.
-Issues can allow you, your team, and your collaborators to share and discuss proposals before and during their implementation.
-However, they can be used for a variety of other purposes, customized to your needs and workflow.
+Issues can allow you, your team, and your collaborators to share and discuss proposals
+before, and during, their implementation. However, they can be used for a variety of
+other purposes, customized to your needs and workflow.
Issues are always associated with a specific project, but if you have multiple projects in a group,
you can also view all the issues collectively at the group level.
@@ -17,13 +18,15 @@ you can also view all the issues collectively at the group level.
- Discussing the implementation of a new idea
- Tracking tasks and work status
- Accepting feature proposals, questions, support requests, or bug reports
-- Elaborating new code implementations
+- Elaborating on new code implementations
-See also the blog post "[Always start a discussion with an issue](https://about.gitlab.com/2016/03/03/start-with-an-issue/)".
+See also [Always start a discussion with an issue](https://about.gitlab.com/2016/03/03/start-with-an-issue/).
## Parts of an issue
-Issues contain a variety of content and metadata, enabling a large range of flexibility in how they are used. Each issue can contain the following attributes, though some items may remain unset.
+Issues contain a variety of content and metadata, enabling a large range of flexibility
+in how they are used. Each issue can contain the following attributes, though not all items
+must be set.
<table class="borderless-table fixed-table">
<tr>
@@ -70,23 +73,36 @@ Issues contain a variety of content and metadata, enabling a large range of flex
## Viewing and managing issues
-While you can view and manage the full detail of an issue at its URL, you can also work with multiple issues at a time using the Issues List, Issue Boards, Epics **[ULTIMATE]**, and issue references.
+While you can view and manage the full details of an issue on the [issue page](#issue-page),
+you can also work with multiple issues at a time using the [Issues List](#issues-list),
+[Issue Boards](#issue-boards), Issue references, and [Epics](#epics-ultimate)**(ULTIMATE)**.
+
+Key actions for Issues include:
+
+- [Creating issues](managing_issues.md#create-a-new-issue)
+- [Moving issues](managing_issues.md#moving-issues)
+- [Closing issues](managing_issues.md#closing-issues)
+- [Deleting issues](managing_issues.md#deleting-issues)
### Issue page
![Issue view](img/issues_main_view.png)
-On an issue’s page, you can view all aspects of the issue, and you can also modify them if you you have the necessary [permissions](../../permissions.md).
-
-For more information, see the [Issue Data and Actions](issue_data_and_actions.md) page.
+On an issue's page, you can view [all aspects of the issue](issue_data_and_actions.md),
+and modify them if you you have the necessary [permissions](../../permissions.md).
### Issues list
![Project issues list view](img/project_issues_list_view.png)
-On the Issues List, you can view all issues in the current project, or from multiple projects when opening the Issues List from the higher-level group context. Filter the issue list by [any search query](../../search/index.md#issues-and-merge-requests-per-project) and/or specific metadata, such as label(s), assignees(s), status, and more. From this view, you can also make certain changes [in bulk](../bulk_editing.md) to the displayed issues.
+On the Issues List, you can view all issues in the current project, or from multiple
+projects when opening the Issues List from the higher-level group context. Filter the
+issue list with a [search query](../../search/index.md#issues-and-merge-requests-per-project),
+including specific metadata, such as label(s), assignees(s), status, and more. From this
+view, you can also make certain changes [in bulk](../bulk_editing.md) to the displayed issues.
-For more information on interacting with Issues, see the [Issue Data and Actions](issue_data_and_actions.md) page.
+For more information, see the [Issue Data and Actions](issue_data_and_actions.md) page
+for a rundown of all the fields and information in an issue.
For sorting by issue priority, see [Label Priority](../labels.md#label-priority).
@@ -94,44 +110,55 @@ For sorting by issue priority, see [Label Priority](../labels.md#label-priority)
![Issue board](img/issue_board.png)
-Issue boards are Kanban boards with columns that display issues based on their labels or their assignees**[PREMIUM]**. They offer the flexibility to manage issues using highly customizable workflows.
-
-You can reorder issues within a column, or drag an issue card to another column; its associated label or assignee will change to match that of the new column. The entire board can also be filtered to only include issues from a certain milestone or an overarching label.
+[Issue boards](../issue_board.md) are Kanban boards with columns that display issues based on their labels
+or their assignees**(PREMIUM)**. They offer the flexibility to manage issues using
+highly customizable workflows.
-For more information, see the [Issue Boards](../issue_board.md) page.
+You can reorder issues within a column. If you drag an issue card to another column, its
+associated label or assignee will change to match that of the new column. The entire
+board can also be filtered to only include issues from a certain milestone or an overarching
+label.
-### Epics **[ULTIMATE]**
+### Epics **(ULTIMATE)**
-Epics let you manage your portfolio of projects more efficiently and with less effort by tracking groups of issues that share a theme, across projects and milestones.
+[Epics](../../group/epics/index.md) let you manage your portfolio of projects more
+efficiently and with less effort by tracking groups of issues that share a theme, across
+projects and milestones.
-For more information, see the [Epics](../../group/epics/index.md) page.
+### Related issues **(STARTER)**
-### Related issues **[STARTER]**
+You can mark two issues as related, so that when viewing one, the other is always
+listed in its [Related Issues](related_issues.md) section. This can help display important
+context, such as past work, dependencies, or duplicates.
-You can mark two issues as related, so that when viewing each one, the other is always listed in its Related Issues section. This can help display important context, such as past work, dependencies, or duplicates.
+### Crosslinking issues
-For more information, see [Related Issues](related_issues.md).
+You can [crosslink issues](crosslinking_issues.md) by referencing an issue from another
+issue or merge request by including its URL or ID. The referenced issue displays a
+message in the Activity stream about the reference, with a link to the other issue or MR.
-### Crosslinking issues
+### Similar issues
-When you reference an issue from another issue or merge request by including its URL or ID, the referenced issue displays a message in the Activity stream about the reference, with a link to the other issue or MR.
+> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/22866) in GitLab 11.6.
-For more information, see [Crosslinking issues](crosslinking_issues.md).
+To prevent duplication of issues for the same topic, GitLab searches for similar issues
+when new issues are being created.
-## Issue actions
+When typing in the title in the **New Issue** page, GitLab searches titles and descriptions
+across all issues the user has access to in the current project. Up 5 similar issues,
+sorted by most recently updated, are displayed below the title box. Note that this feature
+requires [GraphQL](../../../api/graphql/index.md) to be enabled.
-- [Create an issue](create_new_issue.md)
-- [Create an issue from a template](../../project/description_templates.md#using-the-templates)
-- [Close an issue](closing_issues.md)
-- [Move an issue](moving_issues.md)
-- [Delete an issue](deleting_issues.md)
-- [Create a merge request from an issue](issue_data_and_actions.md#22-create-merge-request)
+![Similar issues](img/similar_issues.png)
-## Advanced issue management
+## Other Issue actions
-- [Bulk edit issues](../bulk_editing.md) - From the Issues List, select multiple issues in order to change their status, assignee, milestone, or labels in bulk.
+- [Create an issue from a template](../../project/description_templates.md#using-the-templates)
+- [Set a due date](due_dates.md)
+- [Bulk edit issues](../bulk_editing.md) - From the Issues List, select multiple issues
+ in order to change their status, assignee, milestone, or labels in bulk.
- [Import issues](csv_import.md)
-- [Export issues](csv_export.md) **[STARTER]**
+- [Export issues](csv_export.md) **(STARTER)**
- [Issues API](../../../api/issues.md)
-- Configure an [external issue tracker](../../../integration/external-issue-tracker.md) such as Jira, Redmine,
- or Bugzilla.
+- Configure an [external issue tracker](../../../integration/external-issue-tracker.md)
+ such as Jira, Redmine, or Bugzilla.
diff --git a/doc/user/project/issues/issue_data_and_actions.md b/doc/user/project/issues/issue_data_and_actions.md
index 2103f331aa2..9c4d0de46d3 100644
--- a/doc/user/project/issues/issue_data_and_actions.md
+++ b/doc/user/project/issues/issue_data_and_actions.md
@@ -39,16 +39,19 @@ after it is closed.
![Report Abuse](img/report-abuse.png)
-#### 2. Todos
+#### 2. To Do
-You can click **add todo** to add the issue to your [GitLab Todo](../../../workflow/todos.md)
-list. If it is already on your todo list, the buttom will show **mark todo as done**,
-which you can click to mark that issue as done (which will be reflected in the Todo list).
+You can add issues to and remove issues from your [GitLab To-Do List](../../../workflow/todos.md).
+
+The button to do this has a different label depending on whether the issue is already on your To-Do List or not. If the issue is:
+
+- Already on your To-Do List: The button is labeled **Mark as done**. Click the button to remove the issue from your To-Do List.
+- Not on your To-Do List: The button is labelled **Add a To Do**. Click the button to add the issue to your To-Do List.
#### 3. Assignee
An issue can be assigned to yourself, another person, or [many people](#31-multiple-assignees-STARTER).
-The assignee(s) can be changed as much as needed. The idea is that the assignees are
+The assignee(s) can be changed as often as needed. The idea is that the assignees are
responsible for that issue until it's reassigned to someone else to take it from there.
When assigned to someone, it will appear in their assigned issues list.
@@ -56,7 +59,7 @@ TIP: **Tip:**
If a user is not member of that project, it can only be
assigned to them if they created the issue themselves.
-##### 3.1. Multiple Assignees **[STARTER]**
+##### 3.1. Multiple Assignees **(STARTER)**
Often multiple people work on the same issue together, which can be especially difficult
to track in large teams where there is shared ownership of an issue.
@@ -64,7 +67,7 @@ to track in large teams where there is shared ownership of an issue.
In [GitLab Starter](https://about.gitlab.com/pricing/), you can
[assign multiple people](multiple_assignees_for_issues.md) to an issue.
-#### 4. Epic **[ULTIMATE]**
+#### 4. Epic **(ULTIMATE)**
You can assign issues to an [Epic](../../group/epics/index.md), which allows better
management of groups of related issues.
@@ -99,7 +102,7 @@ TIP: **Tip:**
If a label doesn't exist yet, you can click **Edit**, and it opens a dropdown menu
from which you can select **Create new label**.
-#### 9. Weight **[STARTER]**
+#### 9. Weight **(STARTER)**
[Assign a weight](../../../workflow/issue_weight.md) to an issue.
Larger values are used to indicate more effort is required to complete the issue. Only
@@ -177,7 +180,7 @@ TIP: **Tip:**
Avoid mentioning `@all` in issues and merge requests, as it sends an email notification
to all the members of that project's group, which can be interpreted as spam.
-#### 18. Related Issues **[STARTER]**
+#### 18. Related Issues **(STARTER)**
Issues that were mentioned as [related issues](related_issues.md) are listed here.
You can also click the `+` to add more related issues.
@@ -206,6 +209,14 @@ You can filter what is displayed in the issue history by clicking on **Show all
and selecting either **Show comments only**, which only shows discussions and hides
updates to the issue, or **Show history only**, which hides discussions and only shows updates.
+- You can mention a user or a group present in your GitLab instance with
+ `@username` or `@groupname` and they will be notified via To-Do items
+ and email, unless they have [disabled all notifications](#13-notifications)
+ in their profile settings.
+- Mentions for yourself (the current logged in user), will be highlighted
+ in a different color, allowing you to easily see which comments involve you,
+ helping you focus on them quickly.
+
![Show all activity](img/show-all-activity.png)
#### 22. Create Merge Request
diff --git a/doc/user/project/issues/managing_issues.md b/doc/user/project/issues/managing_issues.md
new file mode 100644
index 00000000000..709588959c1
--- /dev/null
+++ b/doc/user/project/issues/managing_issues.md
@@ -0,0 +1,225 @@
+# Managing Issues
+
+[GitLab Issues](index.md) are the fundamental medium for collaborating on ideas and
+planning work in GitLab. [Creating](#create-a-new-issue), [moving](#moving-issues),
+[closing](#closing-issues), and [deleting](#deleting-issues) are key actions that
+you can do with issues.
+
+## Create a new Issue
+
+When you create a new issue, you'll be prompted to fill in the [data and fields of the issue](issue_data_and_actions.md#parts-of-an-issue), as illustrated below.
+
+![New issue from the issues list](img/new_issue.png)
+
+### Accessing the new Issue form
+
+There are many ways to get to the new Issue form from within a project:
+
+- Navigate to your **Project's Dashboard** > **Issues** > **New Issue**:
+
+ ![New issue from the issue list view](img/new_issue_from_tracker_list.png)
+
+- From an **opened issue** in your project, click **New Issue** to create a new
+ issue in the same project:
+
+ ![New issue from an open issue](img/new_issue_from_open_issue.png)
+
+- From your **Project's Dashboard**, click the plus sign (**+**) to open a dropdown
+ menu with a few options. Select **New Issue** to create an issue in that project:
+
+ ![New issue from a project's dashboard](img/new_issue_from_projects_dashboard.png)
+
+- From an **Issue Board**, create a new issue by clicking on the plus sign (**+**) at the top of a list.
+ It opens a new issue for that project, pre-labeled with its respective list.
+
+ ![From the issue board](img/new_issue_from_issue_board.png)
+
+### New issue from the group-level Issue Tracker
+
+Go to the Group dashboard and click "Issues" in the sidebar to visit the Issue Tracker
+for all projects in your Group. Select the project you'd like to add an issue for
+using the dropdown button at the top-right of the page.
+
+![Select project to create issue](img/select_project_from_group_level_issue_tracker.png)
+
+We'll keep track of the project you selected most recently, and use it as the default
+for your next visit. This should save you a lot of time and clicks, if you mostly
+create issues for the same project.
+
+![Create issue from group-level issue tracker](img/create_issue_from_group_level_issue_tracker.png)
+
+### New issue via Service Desk **(PREMIUM)**
+
+Enable [Service Desk](../service_desk.md) for your project and offer email support.
+By doing so, when your customer sends a new email, a new issue can be created in
+the appropriate project and followed up from there.
+
+### New issue via email
+
+A link to **Email a new issue to this project** is displayed at the bottom of a project's
+**Issues List** page, if your GitLab instance has [incoming email](../../../administration/incoming_email.md)
+configured.
+
+![Bottom of a project issues page](img/new_issue_from_email.png)
+
+When you click this link, an email address is generated and displayed, which should be used
+by **you only**, to create issues in this project. You can save this address as a
+contact in your email client for easy acceess.
+
+CAUTION: **Caution:**
+This is a private email address, generated just for you. **Keep it to yourself**,
+as anyone who knows it can create issues or merge requests as if they
+were you. If the address is compromised, or you'd like it to be regenerated for
+any reason, click **Email a new issue to this project** again and click the reset link.
+
+Sending an email to this address will create a new issue in your name for
+this project, where:
+
+- The email subject becomes the issue title.
+- The email body becomes the issue description.
+- [Markdown](../../markdown.md) and [quick actions](../quick_actions.md) are supported.
+
+NOTE: **Note:**
+In GitLab 11.7, we updated the format of the generated email address. However the
+older format is still supported, allowing existing aliases or contacts to continue working.
+
+### New issue via URL with prefilled fields
+
+You can link directly to the new issue page for a given project, with prefilled
+field values using query string parameters in a URL. This is useful for embedding
+a URL in an external HTML page, and also certain scenarios where you want the user to
+create an issue with certain fields prefilled.
+
+The title, description, and description template fields can be prefilled using
+this method. You cannot pre-fill both the description and description template fields
+in the same URL (since a description template also populates the description field).
+
+Follow these examples to form your new issue URL with prefilled fields.
+
+- For a new issue in the GitLab Community Edition project with a pre-filled title
+ and a pre-filled description, the URL would be `https://gitlab.com/gitlab-org/gitlab-ce/issues/new?issue[title]=Validate%20new%20concept&issue[description]=Research%20idea`
+- For a new issue in the GitLab Community Edition project with a pre-filled title
+ and a pre-filled description template, the URL would be `https://gitlab.com/gitlab-org/gitlab-ce/issues/new?issue[title]=Validate%20new%20concept&issuable_template=Research%20proposal`
+
+## Moving Issues
+
+Moving an issue will copy it to a new location (project), and close it in the old project,
+but it will not be deleted. There will also be a system note added to both issues
+indicating where it came from and went to.
+
+The "Move issue" button is at the bottom of the right-sidebar when viewing the issue.
+
+![move issue - button](img/sidebar_move_issue.png)
+
+### Moving Issues in Bulk
+
+If you have advanced technical skills you can also bulk move all the issues from one project to another in the rails console. The below script will move all the issues from one project to another that are not in status **closed**.
+
+To access rails console run `sudo gitlab-rails console` on the GitLab server and run the below script. Please be sure to change **project**, **admin_user** and **target_project** to your values. We do also recommend [creating a backup](../../../raketasks/backup_restore.md#creating-a-backup-of-the-gitlab-system) before attempting any changes in the console.
+
+```ruby
+project = Project.find_by_full_path('full path of the project where issues are moved from')
+issues = project.issues
+admin_user = User.find_by_username('username of admin user') # make sure user has permissions to move the issues
+target_project = Project.find_by_full_path('full path of target project where issues moved to')
+
+issues.each do |issue|
+ if issue.state != "closed" && issue.moved_to.nil?
+ Issues::MoveService.new(project, admin_user).execute(issue, target_project)
+ else
+ puts "issue with id: #{issue.id} and title: #{issue.title} was not moved"
+ end
+end; nil
+```
+
+## Closing Issues
+
+When you decide that an issue is resolved, or no longer needed, you can close the issue
+using the close button:
+
+![close issue - button](img/button_close_issue.png)
+
+You can also close an issue from the [Issue Boards](../issue_board.md) by dragging an issue card
+from its list and dropping it into the **Closed** list.
+
+![close issue from the Issue Board](img/close_issue_from_board.gif)
+
+### Closing issues automatically
+
+NOTE: **Note:**
+For performance reasons, automatic issue closing is disabled for the very first
+push from an existing repository.
+
+When a commit or merge request resolves one or more issues, it is possible to have
+these issues closed automatically when the commit or merge request reaches the project's
+default branch.
+
+If a commit message or merge request description contains text matching a [defined pattern](#default-closing-pattern),
+all issues referenced in the matched text will be closed. This happens when the commit
+is pushed to a project's [**default** branch](../repository/branches/index.md#default-branch),
+or when a commit or merge request is merged into it.
+
+For example, if `Closes #4, #6, Related to #5` is included in a Merge Request
+description, issues `#4` and `#6` will close automatically when the MR is merged, but not `#5`.
+Using `Related to` flags `#5` as a [related issue](related_issues.md),
+but it will not close automatically.
+
+![merge request closing issue when merged](img/merge_request_closes_issue.png)
+
+If the issue is in a different repository than the MR, add the full URL for the issue(s):
+
+```md
+Closes #4, #6, and https://gitlab.com/<username>/<projectname>/issues/<xxx>
+```
+
+#### Default closing pattern
+
+When not specified, the default issue closing pattern as shown below will be used:
+
+```bash
+((?:[Cc]los(?:e[sd]?|ing)|[Ff]ix(?:e[sd]|ing)?|[Rr]esolv(?:e[sd]?|ing)|[Ii]mplement(?:s|ed|ing)?)(:?) +(?:(?:issues? +)?%{issue_ref}(?:(?:, *| +and +)?)|([A-Z][A-Z0-9_]+-\d+))+)
+```
+
+This translates to the following keywords:
+
+- Close, Closes, Closed, Closing, close, closes, closed, closing
+- Fix, Fixes, Fixed, Fixing, fix, fixes, fixed, fixing
+- Resolve, Resolves, Resolved, Resolving, resolve, resolves, resolved, resolving
+- Implement, Implements, Implemented, Implementing, implement, implements, implemented, implementing
+
+Note that `%{issue_ref}` is a complex regular expression defined inside GitLab's
+source code that can match references to:
+
+- A local issue (`#123`).
+- A cross-project issue (`group/project#123`).
+- A link to an issue (`https://gitlab.example.com/group/project/issues/123`).
+
+For example the following commit message:
+
+```
+Awesome commit message
+
+Fix #20, Fixes #21 and Closes group/otherproject#22.
+This commit is also related to #17 and fixes #18, #19
+and https://gitlab.example.com/group/otherproject/issues/23.
+```
+
+will close `#18`, `#19`, `#20`, and `#21` in the project this commit is pushed to,
+as well as `#22` and `#23` in group/otherproject. `#17` won't be closed as it does
+not match the pattern. It works with multi-line commit messages as well as one-liners
+when used from the command line with `git commit -m`.
+
+#### Customizing the issue closing pattern **(CORE ONLY)**
+
+In order to change the default issue closing pattern, GitLab administrators must edit the
+[`gitlab.rb` or `gitlab.yml` file](../../../administration/issue_closing_pattern.md)
+of your installation.
+
+## Deleting Issues
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/2982) in GitLab 8.6
+
+Users with [project owner permission](../../permissions.md) can delete an issue by
+editing it and clicking on the delete button.
+
+![delete issue - button](img/delete_issue.png)
diff --git a/doc/user/project/issues/moving_issues.md b/doc/user/project/issues/moving_issues.md
index 8aac2c01444..8331f865b83 100644
--- a/doc/user/project/issues/moving_issues.md
+++ b/doc/user/project/issues/moving_issues.md
@@ -1,35 +1,5 @@
-# Moving Issues
-
-Please read through the [GitLab Issue Documentation](index.md) for an overview on GitLab Issues.
-
-Moving an issue will close it and duplicate it on the specified project.
-There will also be a system note added to both issues indicating where it came from or went to.
-
-You can move an issue with the "Move issue" button at the bottom of the right-sidebar when viewing the issue.
-
-![move issue - button](img/sidebar_move_issue.png)
-
-## Troubleshooting
-
-### Moving Issues in Bulk
-
-If you have advanced technical skills you can also bulk move all the issues from one project to another in the rails console. The below script will move all the issues from one project to another that are not in status **closed**.
-
-To access rails console run `sudo gitlab-rails console` on the GitLab server and run the below script. Please be sure to change **project**, **admin_user** and **target_project** to your values. We do also recommend [creating a backup](https://docs.gitlab.com/ee/raketasks/backup_restore.html#creating-a-backup-of-the-gitlab-system) before attempting any changes in the console.
-
-```ruby
-project = Project.find_by_full_path('full path of the project where issues are moved from')
-issues = project.issues
-admin_user = User.find_by_username('username of admin user') # make sure user has permissions to move the issues
-target_project = Project.find_by_full_path('full path of target project where issues moved to')
-
-issues.each do |issue|
- if issue.state != "closed" && issue.moved_to.nil?
- Issues::MoveService.new(project, admin_user).execute(issue, target_project)
- else
- puts "issue with id: #{issue.id} and title: #{issue.title} was not moved"
- end
-end; nil
-
-```
+---
+redirect_to: 'managing_issues.md#moving-issues'
+---
+This document was moved to [another location](managing_issues.md#moving-issues).
diff --git a/doc/user/project/issues/multiple_assignees_for_issues.md b/doc/user/project/issues/multiple_assignees_for_issues.md
index d1db0790d69..c9efe9f5031 100644
--- a/doc/user/project/issues/multiple_assignees_for_issues.md
+++ b/doc/user/project/issues/multiple_assignees_for_issues.md
@@ -1,4 +1,4 @@
-# Multiple Assignees for Issues **[STARTER]**
+# Multiple Assignees for Issues **(STARTER)**
> **Note:**
[Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/1904)
diff --git a/doc/user/project/issues/related_issues.md b/doc/user/project/issues/related_issues.md
index e679ebf86e6..9c72fe33d0d 100644
--- a/doc/user/project/issues/related_issues.md
+++ b/doc/user/project/issues/related_issues.md
@@ -1,4 +1,4 @@
-# Related issues **[STARTER]**
+# Related issues **(STARTER)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/1797) in [GitLab Starter](https://about.gitlab.com/pricing/) 9.4.
diff --git a/doc/user/project/issues/similar_issues.md b/doc/user/project/issues/similar_issues.md
index e90ecd88ec6..9cbac53ee41 100644
--- a/doc/user/project/issues/similar_issues.md
+++ b/doc/user/project/issues/similar_issues.md
@@ -1,16 +1,5 @@
-# Similar issues
+---
+redirect_to: 'index.md#similar-issues'
+---
-> [Introduced][ce-22866] in GitLab 11.6.
-
-Similar issues suggests issues that are similar when new issues are being created.
-This features requires [GraphQL] to be enabled.
-
-![Similar issues](img/similar_issues.png)
-
-You can see the similar issues when typing in the title in the new issue form.
-This searches both titles and descriptions across all issues the user has access
-to in the current project. It then displays the first 5 issues sorted by most
-recently updated.
-
-[GraphQL]: ../../../api/graphql/index.md
-[ce-22866]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/22866
+This document was moved to [another location](index.md#similar-issues).
diff --git a/doc/user/project/labels.md b/doc/user/project/labels.md
index 3eca1313a18..fdfeb4aa4cd 100644
--- a/doc/user/project/labels.md
+++ b/doc/user/project/labels.md
@@ -11,7 +11,7 @@ In GitLab, you can create project and group labels:
- **Project labels** can be assigned to issues or merge requests in that project only.
- **Group labels** can be assigned to any issue or merge request of any project in that group or any subgroups of the group.
-## Scoped labels **[PREMIUM]**
+## Scoped labels **(PREMIUM)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/9175) in [GitLab Premium](https://about.gitlab.com/pricing/) 11.10.
@@ -38,7 +38,7 @@ For example, `nested::key1::value1` and `nested::key1::value2` cannot both exist
`nested::key1::value1` and `nested::key2::value1` can both exist on the same issue, as these are considered to use two different label scopes, `nested::key1` and `nested::key2`.
-### Workflows with scoped labels **[PREMIUM]**
+### Workflows with scoped labels **(PREMIUM)**
Suppose you wanted a custom field in issues to track the platform operating system
that your features target, where each issue should only target one platform. You
@@ -144,9 +144,9 @@ From the group epic list page, you can [filter](../search/index.md#issues-and-me
### Filtering in issue boards
- From [project boards](issue_board.md), you can filter by both group labels and project labels in the [search and filter bar](../search/index.md#issue-boards).
-- From [group issue boards](issue_board.md#group-issue-boards-premium), you can filter by only group labels in the [search and filter bar](../search/index.md#issue-boards). **[PREMIUM]**
-- From [project boards](issue_board.md), you can filter by both group labels and project labels in the [issue board configuration](issue_board.md#configurable-issue-boards-starter). **[STARTER]**
-- From [group issue boards](issue_board.md#group-issue-boards-premium), you can filter by only group labels in the [issue board configuration](issue_board.md#configurable-issue-boards-starter). **[STARTER]**
+- From [group issue boards](issue_board.md#group-issue-boards-premium), you can filter by only group labels in the [search and filter bar](../search/index.md#issue-boards). **(PREMIUM)**
+- From [project boards](issue_board.md), you can filter by both group labels and project labels in the [issue board configuration](issue_board.md#configurable-issue-boards-starter). **(STARTER)**
+- From [group issue boards](issue_board.md#group-issue-boards-premium), you can filter by only group labels in the [issue board configuration](issue_board.md#configurable-issue-boards-starter). **(STARTER)**
## Subscribing to labels
diff --git a/doc/user/project/merge_requests/browser_performance_testing.md b/doc/user/project/merge_requests/browser_performance_testing.md
index f6c4f767e3c..49b9826a52a 100644
--- a/doc/user/project/merge_requests/browser_performance_testing.md
+++ b/doc/user/project/merge_requests/browser_performance_testing.md
@@ -2,7 +2,7 @@
type: reference, howto
---
-# Browser Performance Testing **[PREMIUM]**
+# Browser Performance Testing **(PREMIUM)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/3507)
in [GitLab Premium](https://about.gitlab.com/pricing/) 10.3.
@@ -19,7 +19,7 @@ tool for measuring the performance of web sites, and has built a simple
which outputs the results in a file called `performance.json`. This plugin
outputs the performance score for each page that is analyzed.
-The [Sitespeed.io performance score](http://examples.sitespeed.io/6.0/2017-11-23-23-43-35/help.html)
+The [Sitespeed.io performance score](https://examples.sitespeed.io/6.0/2017-11-23-23-43-35/help.html)
is a composite value based on best practices, and we will be expanding support
for [additional metrics](https://gitlab.com/gitlab-org/gitlab-ee/issues/4370)
in a future release.
diff --git a/doc/user/project/merge_requests/code_quality.md b/doc/user/project/merge_requests/code_quality.md
index c3c2bdd94b3..ad1d79ae5b1 100644
--- a/doc/user/project/merge_requests/code_quality.md
+++ b/doc/user/project/merge_requests/code_quality.md
@@ -2,7 +2,7 @@
type: reference, howto
---
-# Code Quality **[STARTER]**
+# Code Quality **(STARTER)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/1984)
in [GitLab Starter](https://about.gitlab.com/pricing/) 9.3.
diff --git a/doc/user/project/merge_requests/index.md b/doc/user/project/merge_requests/index.md
index 447b338928c..37a0630d0f3 100644
--- a/doc/user/project/merge_requests/index.md
+++ b/doc/user/project/merge_requests/index.md
@@ -23,7 +23,7 @@ With GitLab merge requests, you can:
- Build, test, and deploy your code in a per-branch basis with built-in [GitLab CI/CD](../../../ci/README.md)
- Prevent the merge request from being merged before it's ready with [WIP MRs](#work-in-progress-merge-requests)
- View the deployment process through [Pipeline Graphs](../../../ci/pipelines.md#visualizing-pipelines)
-- [Automatically close the issue(s)](../../project/issues/closing_issues.md#via-merge-request) that originated the implementation proposed in the merge request
+- [Automatically close the issue(s)](../../project/issues/managing_issues.md#closing-issues-automatically) that originated the implementation proposed in the merge request
- Assign it to any registered user, and change the assignee how many times you need
- Assign a [milestone](../../project/milestones/index.md) and track the development of a broader implementation
- Organize your issues and merge requests consistently throughout the project with [labels](../../project/labels.md)
@@ -37,16 +37,16 @@ With GitLab merge requests, you can:
With **[GitLab Enterprise Edition][ee]**, you can also:
-- Prepare a full review and submit it once it's ready with [Merge Request Reviews](../../discussions/index.md#merge-request-reviews-premium) **[PREMIUM]**
-- View the deployment process across projects with [Multi-Project Pipelines](../../../ci/multi_project_pipelines.md) **[PREMIUM]**
-- Request [approvals](merge_request_approvals.md) from your managers **[STARTER]**
-- Analyze the impact of your changes with [Code Quality reports](code_quality.md) **[STARTER]**
-- Manage the licenses of your dependencies with [License Management](../../application_security/license_management/index.md) **[ULTIMATE]**
-- Analyze your source code for vulnerabilities with [Static Application Security Testing](../../application_security/sast/index.md) **[ULTIMATE]**
-- Analyze your running web applications for vulnerabilities with [Dynamic Application Security Testing](../../application_security/dast/index.md) **[ULTIMATE]**
-- Analyze your dependencies for vulnerabilities with [Dependency Scanning](../../application_security/dependency_scanning/index.md) **[ULTIMATE]**
-- Analyze your Docker images for vulnerabilities with [Container Scanning](../../application_security/container_scanning/index.md) **[ULTIMATE]**
-- Determine the performance impact of changes with [Browser Performance Testing](#browser-performance-testing-premium) **[PREMIUM]**
+- Prepare a full review and submit it once it's ready with [Merge Request Reviews](../../discussions/index.md#merge-request-reviews-premium) **(PREMIUM)**
+- View the deployment process across projects with [Multi-Project Pipelines](../../../ci/multi_project_pipelines.md) **(PREMIUM)**
+- Request [approvals](merge_request_approvals.md) from your managers **(STARTER)**
+- Analyze the impact of your changes with [Code Quality reports](code_quality.md) **(STARTER)**
+- Manage the licenses of your dependencies with [License Management](../../application_security/license_management/index.md) **(ULTIMATE)**
+- Analyze your source code for vulnerabilities with [Static Application Security Testing](../../application_security/sast/index.md) **(ULTIMATE)**
+- Analyze your running web applications for vulnerabilities with [Dynamic Application Security Testing](../../application_security/dast/index.md) **(ULTIMATE)**
+- Analyze your dependencies for vulnerabilities with [Dependency Scanning](../../application_security/dependency_scanning/index.md) **(ULTIMATE)**
+- Analyze your Docker images for vulnerabilities with [Container Scanning](../../application_security/container_scanning/index.md) **(ULTIMATE)**
+- Determine the performance impact of changes with [Browser Performance Testing](#browser-performance-testing-premium) **(PREMIUM)**
## Use cases
@@ -54,9 +54,9 @@ A. Consider you are a software developer working in a team:
1. You checkout a new branch, and submit your changes through a merge request
1. You gather feedback from your team
-1. You work on the implementation optimizing code with [Code Quality reports](code_quality.md) **[STARTER]**
+1. You work on the implementation optimizing code with [Code Quality reports](code_quality.md) **(STARTER)**
1. You verify your changes with [JUnit test reports](../../../ci/junit_test_reports.md) in GitLab CI/CD
-1. You avoid using dependencies whose license is not compatible with your project with [License Management reports](license_management.md) **[ULTIMATE]**
+1. You avoid using dependencies whose license is not compatible with your project with [License Management reports](license_management.md) **(ULTIMATE)**
1. You request the [approval](#merge-request-approvals-starter) from your manager
1. Your manager pushes a commit with their final review, [approves the merge request](merge_request_approvals.md), and set it to [merge when pipeline succeeds](#merge-when-pipeline-succeeds) (Merge Request Approvals are available in GitLab Starter)
1. Your changes get deployed to production with [manual actions](../../../ci/yaml/README.md#whenmanual) for GitLab CI/CD
@@ -68,7 +68,7 @@ B. Consider you're a web developer writing a webpage for your company's website:
1. You gather feedback from your reviewers
1. Your changes are previewed with [Review Apps](../../../ci/review_apps/index.md)
1. You request your web designers for their implementation
-1. You request the [approval](merge_request_approvals.md) from your manager **[STARTER]**
+1. You request the [approval](merge_request_approvals.md) from your manager **(STARTER)**
1. Once approved, your merge request is [squashed and merged](squash_and_merge.md), and [deployed to staging with GitLab Pages](https://about.gitlab.com/2016/08/26/ci-deployment-and-environments/)
1. Your production team [cherry picks](#cherry-pick-changes) the merge commit into production
@@ -172,7 +172,7 @@ in a Merge Request. To do so, click the **...** button in the gutter of the Merg
![Comment on any diff file line](img/comment-on-any-diff-line.png)
-## Perform a Review **[PREMIUM]**
+## Perform a Review **(PREMIUM)**
Start a review in order to create multiple comments on a diff and publish them once you're ready.
Starting a review allows you to get all your thoughts in order and ensure you haven't missed anything
@@ -197,7 +197,7 @@ can easily apply them to the codebase directly from the UI. Read
through the documentation on [Suggest changes](../../discussions/index.md#suggest-changes)
to learn more.
-## Multiple assignees **[STARTER]**
+## Multiple assignees **(STARTER)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/2004)
in [GitLab Starter 11.11](https://about.gitlab.com/pricing).
@@ -364,7 +364,7 @@ have been marked as a **Work In Progress**.
[Learn more about setting a merge request as "Work In Progress".](work_in_progress_merge_requests.md)
-## Merge request approvals **[STARTER]**
+## Merge request approvals **(STARTER)**
> Included in [GitLab Starter][products].
@@ -375,7 +375,7 @@ list of approvers that will need to approve every merge request in a project.
[Read more about merge request approvals.](merge_request_approvals.md)
-## Code Quality **[STARTER]**
+## Code Quality **(STARTER)**
> Introduced in [GitLab Starter][products] 9.3.
@@ -385,7 +385,7 @@ can show the Code Climate report right in the merge request widget area.
[Read more about Code Quality reports.](code_quality.md)
-## Browser Performance Testing **[PREMIUM]**
+## Browser Performance Testing **(PREMIUM)**
> Introduced in [GitLab Premium][products] 10.3.
@@ -395,7 +395,7 @@ GitLab runs the [Sitespeed.io container][sitespeed-container] and displays the d
[Read more about Browser Performance Testing.](browser_performance_testing.md)
-## Security reports **[ULTIMATE]**
+## Security reports **(ULTIMATE)**
GitLab can scan and report any vulnerabilities found in your project.
diff --git a/doc/user/project/merge_requests/merge_request_approvals.md b/doc/user/project/merge_requests/merge_request_approvals.md
index 8e8ec26daf2..0f392676316 100644
--- a/doc/user/project/merge_requests/merge_request_approvals.md
+++ b/doc/user/project/merge_requests/merge_request_approvals.md
@@ -2,7 +2,7 @@
type: reference, concepts
---
-# Merge request approvals **[STARTER]**
+# Merge request approvals **(STARTER)**
> Introduced in [GitLab Enterprise Edition 7.12](https://about.gitlab.com/2015/06/22/gitlab-7-12-released/#merge-request-approvers-ee-only).
@@ -64,7 +64,7 @@ suitable to your workflow:
[overridden per merge request](#overriding-the-merge-request-approvals-default-settings)
- Choose whether [approvals will be reset with new pushed commits](#resetting-approvals-on-push)
-## Editing approvals **[PREMIUM]**
+## Editing approvals **(PREMIUM)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/1979) in [GitLab Premium](https://about.gitlab.com/pricing/) 11.8.
@@ -85,7 +85,7 @@ request approval rules:
![Approvals premium project edit](img/approvals_premium_project_edit.png)
-## Multiple approval rules **[PREMIUM]**
+## Multiple approval rules **(PREMIUM)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/1979) in [GitLab Premium](https://about.gitlab.com/pricing/) 11.8.
@@ -165,7 +165,7 @@ are other conditions that may block it, such as merge conflicts,
[pending discussions](../../discussions/index.md#only-allow-merge-requests-to-be-merged-if-all-discussions-are-resolved)
or a [failed CI/CD pipeline](merge_when_pipeline_succeeds.md).
-## Code Owners approvals **[PREMIUM]**
+## Code Owners approvals **(PREMIUM)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/4418) in [GitLab Premium](https://about.gitlab.com/pricing/) 11.9.
@@ -237,7 +237,7 @@ If you are contributing to a forked project, things are a little different.
Read what happens when the
[source and target branches are not the same](#merge-requests-with-different-source-branch-and-target-branch-projects).
-## Overriding merge request approvals default settings **[PREMIUM]**
+## Overriding merge request approvals default settings **(PREMIUM)**
In GitLab Premium, when the approval rules are [set at the project level](#editing-approvals-premium), and
**Can override approvers and approvals required per merge request** is checked, there are a few more
@@ -295,7 +295,7 @@ enabling [**Prevent approval of merge requests by their committers**](#prevent-a
1. Tick the checkbox **Prevent approval of merge requests by their committers**.
1. Click **Save changes**.
-## Require authentication when approving a merge request **[STARTER]**
+## Require authentication when approving a merge request **(STARTER)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/5981) in [GitLab Starter](https://about.gitlab.com/pricing/) 12.0.
diff --git a/doc/user/project/merge_requests/squash_and_merge.md b/doc/user/project/merge_requests/squash_and_merge.md
index 39fd2588811..38459584eed 100644
--- a/doc/user/project/merge_requests/squash_and_merge.md
+++ b/doc/user/project/merge_requests/squash_and_merge.md
@@ -50,7 +50,10 @@ all you have to do is enable squashing before you press merge to join
the commits in the merge request into a single commit.
This way, the history of your base branch remains clean with
-meaningful commit messages and is simpler to [revert](revert_changes.md) if necessary.
+meaningful commit messages and:
+
+- It's simpler to [revert](revert_changes.md) if necessary.
+- The merged branch will retain the full commit history.
## Enabling squash for a merge request
diff --git a/doc/user/project/merge_requests/work_in_progress_merge_requests.md b/doc/user/project/merge_requests/work_in_progress_merge_requests.md
index 9cd868067bc..142178ba241 100644
--- a/doc/user/project/merge_requests/work_in_progress_merge_requests.md
+++ b/doc/user/project/merge_requests/work_in_progress_merge_requests.md
@@ -15,7 +15,7 @@ being merged, and it will stay disabled until the "WIP" flag has been removed.
There are several ways to flag a merge request as a Work In Progress:
-- Add "[WIP]" or "WIP:" to the start of the merge request's title. Clicking on
+- Add `[WIP]` or `WIP:` to the start of the merge request's title. Clicking on
**Start the title with WIP:**, under the title box, when editing the merge request's
description will have the same effect.
- Add the `/wip` [quick action](../quick_actions.md#quick-actions-for-issues-and-merge-requests)
@@ -30,7 +30,7 @@ There are several ways to flag a merge request as a Work In Progress:
Similar to above, when a Merge Request is ready to be merged, you can remove the
"Work in Progress" flag in several ways:
-- Remove "[WIP]" or "WIP:" from the start of the merge request's title. Clicking on
+- Remove `[WIP]` or `WIP:` from the start of the merge request's title. Clicking on
**Remove the WIP: prefix from the title**, under the title box, when editing the merge
request's description, will have the same effect.
- Add the `/wip` [quick action](../quick_actions.md#quick-actions-for-issues-and-merge-requests)
diff --git a/doc/user/project/milestones/burndown_charts.md b/doc/user/project/milestones/burndown_charts.md
index 7ffeb032d7f..84e08b4eeb8 100644
--- a/doc/user/project/milestones/burndown_charts.md
+++ b/doc/user/project/milestones/burndown_charts.md
@@ -1,4 +1,4 @@
-# Burndown Charts **[STARTER]**
+# Burndown Charts **(STARTER)**
> **Notes:**
> - [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/1540) in [GitLab Starter](https://about.gitlab.com/pricing/) 9.1 for project milestones.
diff --git a/doc/user/project/milestones/index.md b/doc/user/project/milestones/index.md
index 6cd866b5c0d..b0745b1e2c5 100644
--- a/doc/user/project/milestones/index.md
+++ b/doc/user/project/milestones/index.md
@@ -84,9 +84,9 @@ From the project issue/merge request list pages and the group issue/merge reques
### Filtering in issue boards
- From [project issue boards](../issue_board.md), you can filter by both group milestones and project milestones in the [search and filter bar](../../search/index.md#issue-boards).
-- From [group issue boards](../issue_board.md#group-issue-boards-premium), you can filter by only group milestones in the [search and filter bar](../../search/index.md#issue-boards). **[PREMIUM]**
-- From [project issue boards](../issue_board.md), you can filter by both group milestones and project milestones in the [issue board configuration](../issue_board.md#configurable-issue-boards-starter). **[STARTER]**
-- From [group issue boards](../issue_board.md#group-issue-boards-premium) you can filter by only group milestones in the [issue board configuration](../issue_board.md#configurable-issue-boards-starter). **[STARTER]**
+- From [group issue boards](../issue_board.md#group-issue-boards-premium), you can filter by only group milestones in the [search and filter bar](../../search/index.md#issue-boards). **(PREMIUM)**
+- From [project issue boards](../issue_board.md), you can filter by both group milestones and project milestones in the [issue board configuration](../issue_board.md#configurable-issue-boards-starter). **(STARTER)**
+- From [group issue boards](../issue_board.md#group-issue-boards-premium) you can filter by only group milestones in the [issue board configuration](../issue_board.md#configurable-issue-boards-starter). **(STARTER)**
### Special milestone filters
@@ -124,13 +124,13 @@ These features are only available for project milestones and not group milestone
- Participants and labels that are used in issues and merge requests that have the milestone assigned are displayed.
- [Burndown chart](#project-burndown-charts-starter).
-### Project Burndown Charts **[STARTER]**
+### Project Burndown Charts **(STARTER)**
For project milestones in [GitLab Starter](https://about.gitlab.com/pricing), a [burndown chart](burndown_charts.md) is in the milestone view, showing the progress of completing a milestone.
![burndown chart](img/burndown_chart.png)
-### Group Burndown Charts **[PREMIUM]**
+### Group Burndown Charts **(PREMIUM)**
For group milestones in [GitLab Premium](https://about.gitlab.com/pricing), a [burndown chart](burndown_charts.md) is in the milestone view, showing the progress of completing a milestone.
diff --git a/doc/user/project/new_ci_build_permissions_model.md b/doc/user/project/new_ci_build_permissions_model.md
index c07c4099f22..d35a8568394 100644
--- a/doc/user/project/new_ci_build_permissions_model.md
+++ b/doc/user/project/new_ci_build_permissions_model.md
@@ -185,7 +185,7 @@ The [Job environment variable][jobenv] `CI_JOB_TOKEN` can be used to
authenticate any clones of dependent repositories. For example:
```
-git clone https://gitlab-ci-token:${CI_JOB_TOKEN}@gitlab.com/myuser/mydependentrepo
+git clone https://gitlab-ci-token:${CI_JOB_TOKEN}@gitlab.com/<user>/<mydependentrepo>.git
```
It can also be used for system-wide authentication
diff --git a/doc/user/project/operations/feature_flags.md b/doc/user/project/operations/feature_flags.md
index a5db3d70bb9..fdc1e978291 100644
--- a/doc/user/project/operations/feature_flags.md
+++ b/doc/user/project/operations/feature_flags.md
@@ -1,4 +1,4 @@
-# Feature Flags **[PREMIUM]**
+# Feature Flags **(PREMIUM)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/11845) in GitLab 11.4.
diff --git a/doc/user/project/operations/index.md b/doc/user/project/operations/index.md
index 84711d1146f..2da9c3e70cf 100644
--- a/doc/user/project/operations/index.md
+++ b/doc/user/project/operations/index.md
@@ -7,6 +7,6 @@ your applications:
- Deploy to different [environments](../../../ci/environments.md).
- Connect your project to a [Kubernetes cluster](../clusters/index.md).
- Discover and view errors generated by your applications with [Error Tracking](error_tracking.md).
-- Create, toggle, and remove [Feature Flags](feature_flags.md). **[PREMIUM]**
-- [Trace](tracing.md) the performance and health of a deployed application. **[ULTIMATE]**
+- Create, toggle, and remove [Feature Flags](feature_flags.md). **(PREMIUM)**
+- [Trace](tracing.md) the performance and health of a deployed application. **(ULTIMATE)**
- Add a [button to the Monitoring dashboard](linking_to_an_external_dashboard.md) linking directly to your existing external dashboards.
diff --git a/doc/user/project/operations/tracing.md b/doc/user/project/operations/tracing.md
index 0416e096cf2..b92d2e49839 100644
--- a/doc/user/project/operations/tracing.md
+++ b/doc/user/project/operations/tracing.md
@@ -1,4 +1,4 @@
-# Tracing **[ULTIMATE]**
+# Tracing **(ULTIMATE)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/7903) in GitLab Ultimate 11.5.
@@ -17,8 +17,8 @@ systems.
### Deploying Jaeger
To learn more about deploying Jaeger, read the official
-[Getting Started documentation](https://www.jaegertracing.io/docs/latest/getting-started/).
-There is an easy to use [all-in-one Docker image](https://www.jaegertracing.io/docs/latest/getting-started/#AllinoneDockerimage),
+[Getting Started documentation](https://www.jaegertracing.io/docs/1.13/getting-started/).
+There is an easy to use [all-in-one Docker image](https://www.jaegertracing.io/docs/1.13/getting-started/#AllinoneDockerimage),
as well as deployment options for [Kubernetes](https://github.com/jaegertracing/jaeger-kubernetes)
and [OpenShift](https://github.com/jaegertracing/jaeger-openshift).
@@ -27,8 +27,8 @@ and [OpenShift](https://github.com/jaegertracing/jaeger-openshift).
GitLab provides an easy way to open the Jaeger UI from within your project:
1. [Set up Jaeger](#deploying-jaeger) and configure your application using one of the
- [client libraries](https://www.jaegertracing.io/docs/latest/client-libraries/).
+ [client libraries](https://www.jaegertracing.io/docs/1.13/client-libraries/).
1. Navigate to your project's **Settings > Operations** and provide the Jaeger URL.
1. Click **Save changes** for the changes to take effect.
1. You can now visit **Operations > Tracing** in your project's sidebar and
- GitLab will redirect you to the configured Jaeger URL. \ No newline at end of file
+ GitLab will redirect you to the configured Jaeger URL.
diff --git a/doc/user/project/packages/maven_repository.md b/doc/user/project/packages/maven_repository.md
index 9b7af738696..27c052fb2bc 100644
--- a/doc/user/project/packages/maven_repository.md
+++ b/doc/user/project/packages/maven_repository.md
@@ -1,4 +1,4 @@
-# GitLab Maven Repository **[PREMIUM]**
+# GitLab Maven Repository **(PREMIUM)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/5811) in
[GitLab Premium](https://about.gitlab.com/pricing/) 11.3.
@@ -12,7 +12,7 @@ project can have its own space to store its Maven artifacts.
NOTE: **Note:**
This option is available only if your GitLab administrator has
-[enabled support for the Maven repository](../../../administration/packages.md).**[PREMIUM ONLY]**
+[enabled support for the Maven repository](../../../administration/packages.md).**(PREMIUM ONLY)**
After the Packages feature is enabled, the Maven Repository will be available for
all new projects by default. To enable it for existing projects, or if you want
diff --git a/doc/user/project/packages/npm_registry.md b/doc/user/project/packages/npm_registry.md
index 2e274573434..481b1ce0337 100644
--- a/doc/user/project/packages/npm_registry.md
+++ b/doc/user/project/packages/npm_registry.md
@@ -1,4 +1,4 @@
-# GitLab NPM Registry **[PREMIUM]**
+# GitLab NPM Registry **(PREMIUM)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/5934)
in [GitLab Premium](https://about.gitlab.com/pricing/) 11.7.
@@ -11,16 +11,11 @@ project can have its own space to store NPM packages.
NOTE: **Note:**
Only [scoped](https://docs.npmjs.com/misc/scope) packages are supported.
-
-NOTE: **Note:**
-As `@group/subgroup/project` is not a valid NPM package name, publishing a package
-within a subgroup is not supported yet.
-
## Enabling the NPM Registry
NOTE: **Note:**
This option is available only if your GitLab administrator has
-[enabled support for the NPM registry](../../../administration/packages.md).**[PREMIUM ONLY]**
+[enabled support for the NPM registry](../../../administration/packages.md).**(PREMIUM ONLY)**
After the NPM registry is enabled, it will be available for all new projects
by default. To enable it for existing projects, or if you want to disable it:
@@ -36,12 +31,15 @@ get familiar with the package naming convention.
## Package naming convention
-**Only packages that have the same path as the project** are supported. For
- example:
+**Packages must be scoped in the root namespace of the project**. The package
+name may be anything but it is preferred that the project name be used unless
+it is not possible due to a naming collision. For example:
| Project | Package | Supported |
| ---------------------- | ----------------------- | --------- |
| `foo/bar` | `@foo/bar` | Yes |
+| `foo/bar/baz` | `@foo/baz` | Yes |
+| `foo/bar/buz` | `@foo/anything` | Yes |
| `gitlab-org/gitlab-ce` | `@gitlab-org/gitlab-ce` | Yes |
| `gitlab-org/gitlab-ce` | `@foo/bar` | No |
@@ -113,6 +111,9 @@ npm publish
You can then navigate to your project's **Packages** page and see the uploaded
packages or even delete them.
+If you attempt to publish a package with a name that already exists within
+a given scope, you will receive a `403 Forbidden!` error.
+
## Uploading a package with the same version twice
If you upload a package with a same name and version twice, GitLab will show
diff --git a/doc/user/project/pages/getting_started_part_four.md b/doc/user/project/pages/getting_started_part_four.md
index 8baf41dba78..d844d4222b1 100644
--- a/doc/user/project/pages/getting_started_part_four.md
+++ b/doc/user/project/pages/getting_started_part_four.md
@@ -380,7 +380,7 @@ What you can do with GitLab CI is pretty much up to your
creativity. Once you get used to it, you start creating
awesome scripts that automate most of tasks you'd do
manually in the past. Read through the
-[documentation of GitLab CI](https://docs.gitlab.com/ce/ci/yaml/README.html)
+[documentation of GitLab CI](../../../ci/yaml/README.md)
to understand how to go even further on your scripts.
- On this blog post, understand the concept of
diff --git a/doc/user/project/pages/index.md b/doc/user/project/pages/index.md
index fa79c393b72..64b1e259292 100644
--- a/doc/user/project/pages/index.md
+++ b/doc/user/project/pages/index.md
@@ -140,7 +140,7 @@ To learn more about configuration options for GitLab Pages, read the following:
| [Static websites and Pages domains](getting_started_part_one.md) | Understand what is a static website, and how GitLab Pages default domains work. |
| [Projects and URL structure](getting_started_part_two.md) | Forking projects and creating new ones from scratch, understanding URLs structure and baseurls. |
| [GitLab CI/CD for GitLab Pages](getting_started_part_four.md) | Understand how to create your own `.gitlab-ci.yml` for your site. |
-| [Exploring GitLab Pages](introduction.md) | Requirements, technical aspects, specific GitLab CI's configuration options, custom 404 pages, limitations, FAQ. |
+| [Exploring GitLab Pages](introduction.md) | Requirements, technical aspects, specific GitLab CI's configuration options, Access Control, custom 404 pages, limitations, FAQ. |
|---+---|
| [Custom domains and SSL/TLS Certificates](getting_started_part_three.md) | How to add custom domains and subdomains to your website, configure DNS records and SSL/TLS certificates. |
| [CloudFlare certificates](https://about.gitlab.com/2017/02/07/setting-up-gitlab-pages-with-cloudflare-certificates/) | Secure your Pages site with CloudFlare certificates. |
diff --git a/doc/user/project/pages/introduction.md b/doc/user/project/pages/introduction.md
index 4ea3bd9be9b..9451b5349c0 100644
--- a/doc/user/project/pages/introduction.md
+++ b/doc/user/project/pages/introduction.md
@@ -67,7 +67,7 @@ Some static site generators provide plugins for that functionality so that you
don't have to create and edit HTML files manually. For example, Jekyll has the
[redirect-from plugin](https://github.com/jekyll/jekyll-redirect-from).
-## GitLab Pages Access Control **[CORE ONLY]**
+## GitLab Pages Access Control **(CORE ONLY)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/33422) in GitLab 11.5.
diff --git a/doc/user/project/pipelines/job_artifacts.md b/doc/user/project/pipelines/job_artifacts.md
index 002addfc043..1966b136e9d 100644
--- a/doc/user/project/pipelines/job_artifacts.md
+++ b/doc/user/project/pipelines/job_artifacts.md
@@ -187,9 +187,13 @@ information in the UI.
DANGER: **Warning:**
This is a destructive action that leads to data loss. Use with caution.
-If you have at least Developer [permissions](../../permissions.md#gitlab-cicd-permissions)
-on the project, you can erase a single job via the UI which will also remove the
-artifacts and the job's trace.
+You can erase a single job via the UI, which will also remove the job's
+artifacts and trace, if you are:
+
+- The owner of the job.
+- A [Maintainer](../../permissions.md#gitlab-cicd-permissions) of the project.
+
+To erase a job:
1. Navigate to a job's page.
1. Click the trash icon at the top right of the job's trace.
diff --git a/doc/user/project/protected_branches.md b/doc/user/project/protected_branches.md
index 99cede557a0..20a03dff2da 100644
--- a/doc/user/project/protected_branches.md
+++ b/doc/user/project/protected_branches.md
@@ -66,7 +66,7 @@ dropdown list in the "Already protected" area.
If you don't choose any of those options while creating a protected branch,
they are set to "Maintainers" by default.
-## Restricting push and merge access to certain users **[STARTER]**
+## Restricting push and merge access to certain users **(STARTER)**
> This feature was [introduced][ce-5081] in [GitLab Starter][ee] 8.11.
diff --git a/doc/user/project/quick_actions.md b/doc/user/project/quick_actions.md
index 1281ba561b8..8b8aa51b6dd 100644
--- a/doc/user/project/quick_actions.md
+++ b/doc/user/project/quick_actions.md
@@ -16,8 +16,8 @@ discussions, and descriptions:
|:---------------------------|:------------------------------ |:------|:--------------|
| `/tableflip <Comment>` | Append the comment with `(╯°□°)╯︵ ┻━┻` | ✓ | ✓ |
| `/shrug <Comment>` | Append the comment with `¯\_(ツ)_/¯` | ✓ | ✓ |
-| `/todo` | Add a todo | ✓ | ✓ |
-| `/done` | Mark todo as done | ✓ | ✓ |
+| `/todo` | Add a To Do | ✓ | ✓ |
+| `/done` | Mark To Do as done | ✓ | ✓ |
| `/subscribe` | Subscribe | ✓ | ✓ |
| `/unsubscribe` | Unsubscribe | ✓ | ✓ |
| `/close` | Close | ✓ | ✓ |
@@ -26,9 +26,9 @@ discussions, and descriptions:
| `/award :emoji:` | Toggle emoji award | ✓ | ✓ |
| `/assign me` | Assign yourself | ✓ | ✓ |
| `/assign @user` | Assign one user | ✓ | ✓ |
-| `/assign @user1 @user2` | Assign multiple users **[STARTER]** | ✓ | ✓ |
-| `/unassign @user1 @user2` | Remove assignee(s) **[STARTER]** | ✓ | ✓ |
-| `/reassign @user1 @user2` | Change assignee **[STARTER]** | ✓ | ✓ |
+| `/assign @user1 @user2` | Assign multiple users **(STARTER)** | ✓ | ✓ |
+| `/unassign @user1 @user2` | Remove assignee(s) **(STARTER)** | ✓ | ✓ |
+| `/reassign @user1 @user2` | Change assignee **(STARTER)** | ✓ | ✓ |
| `/unassign` | Remove current assignee | ✓ | ✓ |
| `/milestone %milestone` | Set milestone | ✓ | ✓ |
| `/remove_milestone` | Remove milestone | ✓ | ✓ |
@@ -44,11 +44,11 @@ discussions, and descriptions:
| `/unlock` | Unlock the discussion | ✓ | ✓ |
| <code>/due &lt;in 2 days &#124; this Friday &#124; December 31st&gt;</code>| Set due date | ✓ | |
| `/remove_due_date` | Remove due date | ✓ | |
-| <code>/weight &lt;0 &#124; 1 &#124; 2 &#124; ...&gt;</code> | Set weight **[STARTER]** | ✓ | |
-| `/clear_weight` | Clears weight **[STARTER]** | ✓ | |
-| <code>/epic &lt;&epic &#124; group&epic &#124; Epic URL&gt;</code> | Add to epic **[ULTIMATE]** | ✓ | |
-| `/remove_epic` | Removes from epic **[ULTIMATE]** | ✓ | |
-| `/promote` | Promote issue to epic **[ULTIMATE]** | ✓ | |
+| <code>/weight &lt;0 &#124; 1 &#124; 2 &#124; ...&gt;</code> | Set weight **(STARTER)** | ✓ | |
+| `/clear_weight` | Clears weight **(STARTER)** | ✓ | |
+| <code>/epic &lt;&epic &#124; group&epic &#124; Epic URL&gt;</code> | Add to epic **(ULTIMATE)** | ✓ | |
+| `/remove_epic` | Removes from epic **(ULTIMATE)** | ✓ | |
+| `/promote` | Promote issue to epic **(ULTIMATE)** | ✓ | |
| `/confidential` | Make confidential | ✓ | |
| `/duplicate <#issue>` | Mark this issue as a duplicate of another issue | ✓ |
| `/move <path/to/project>` | Move this issue to another project | ✓ | |
@@ -57,7 +57,7 @@ discussions, and descriptions:
| `/approve` | Approve the merge request | | ✓ |
| `/merge` | Merge (when pipeline succeeds) | | ✓ |
| `/create_merge_request <branch name>` | Create a new merge request starting from the current issue | ✓ | |
-| `/relate #issue1 #issue2` | Mark issues as related **[STARTER]** | ✓ | |
+| `/relate #issue1 #issue2` | Mark issues as related **(STARTER)** | ✓ | |
## Quick actions for commit messages
@@ -67,7 +67,7 @@ The following quick actions are applicable for commit messages:
|:------------------------|:------------------------------------------|
| `/tag v1.2.3 <message>` | Tags this commit with an optional message |
-## Quick actions for Epics **[ULTIMATE]**
+## Quick actions for Epics **(ULTIMATE)**
The following quick actions are applicable for epics threads and description:
@@ -75,8 +75,8 @@ The following quick actions are applicable for epics threads and description:
|:---------------------------|:----------------------------------------|
| `/tableflip <Comment>` | Append the comment with `(╯°□°)╯︵ ┻━┻` |
| `/shrug <Comment>` | Append the comment with `¯\_(ツ)_/¯` |
-| `/todo` | Add a todo |
-| `/done` | Mark todo as done |
+| `/todo` | Add a To Do |
+| `/done` | Mark To Do as done |
| `/subscribe` | Subscribe |
| `/unsubscribe` | Unsubscribe |
| `/close` | Close |
@@ -88,3 +88,5 @@ The following quick actions are applicable for epics threads and description:
| `/relabel ~label1 ~label2` | Replace label |
| <code>/child_epic &lt;&epic &#124; group&epic &#124; Epic URL&gt;</code> | Adds child epic to epic ([introduced in GitLab 12.0](https://gitlab.com/gitlab-org/gitlab-ee/issues/7330)) |
| <code>/remove_child_epic &lt;&epic &#124; group&epic &#124; Epic URL&gt;</code> | Removes child epic from epic ([introduced in GitLab 12.0](https://gitlab.com/gitlab-org/gitlab-ee/issues/7330)) |
+| <code>/parent_epic &lt;&epic &#124; group&epic &#124; Epic URL&gt;</code> | Sets parent epic to epic ([introduced in GitLab 12.1](https://gitlab.com/gitlab-org/gitlab-ee/issues/10556)) |
+| <code>/remove_parent_epic | Removes parent epic from epic ([introduced in GitLab 12.1](https://gitlab.com/gitlab-org/gitlab-ee/issues/10556)) |
diff --git a/doc/user/project/repository/branches/index.md b/doc/user/project/repository/branches/index.md
index 13e4f2ce163..a81c9197ec1 100644
--- a/doc/user/project/repository/branches/index.md
+++ b/doc/user/project/repository/branches/index.md
@@ -21,7 +21,7 @@ branch for your project. You can choose another branch to be your project's
default under your project's **Settings > Repository**.
The default branch is the branch affected by the
-[issue closing pattern](../../issues/automatic_issue_closing.md),
+[issue closing pattern](../../issues/managing_issues.md#closing-issues-automatically),
which means that _an issue will be closed when a merge request is merged to
the **default branch**_.
diff --git a/doc/user/project/repository/gpg_signed_commits/index.md b/doc/user/project/repository/gpg_signed_commits/index.md
index 3260a355fdc..cf0a986887e 100644
--- a/doc/user/project/repository/gpg_signed_commits/index.md
+++ b/doc/user/project/repository/gpg_signed_commits/index.md
@@ -261,7 +261,7 @@ To remove a GPG key from your account:
1. Navigate to the **GPG keys** tab.
1. Click on the trash icon besides the GPG key you want to delete.
-## Rejecting commits that are not signed **[PREMIUM]**
+## Rejecting commits that are not signed **(PREMIUM)**
You can configure your project to reject commits that aren't GPG-signed
via [push rules](../../../../push_rules/push_rules.md).
diff --git a/doc/user/project/repository/index.md b/doc/user/project/repository/index.md
index 165f4c15165..5b5685b3418 100644
--- a/doc/user/project/repository/index.md
+++ b/doc/user/project/repository/index.md
@@ -171,17 +171,14 @@ Via command line, you can commit multiple times before pushing.
- **Sign a commit:**
Use GPG to [sign your commits](gpg_signed_commits/index.md).
-## Repository size
+## Project and repository size
-A project's repository size is reported on the project's **Details** page. The reported size is
-updated every 15 minutes at most, so may not reflect recent activity.
+A project's size is reported on the project's **Details** page. The reported size is
+updated every 15 minutes at most, so may not reflect recent activity. The displayed files size includes repository files, artifacts, and LFS.
-The repository size for:
+The project size may differ slightly from one instance to another due to compression, housekeeping, and other factors.
-- GitLab.com [is set by GitLab](../../gitlab_com/index.md#repository-size-limit).
-- Self-managed instances is set by your GitLab administrators.
-
-You can [reduce a repository's size using Git](reducing_the_repo_size_using_git.md).
+[Repository size limit](../../admin_area/settings/account_and_limit_settings.md) may be set by admins. GitLab.com's repository size limit [is set by GitLab](../../gitlab_com/index.md#repository-size-limit).
## Contributors
@@ -224,7 +221,7 @@ Select branches to compare using the [branch filter search box](branches/index.m
Find it under your project's **Repository > Compare**.
-## Locked files **[PREMIUM]**
+## Locked files **(PREMIUM)**
Use [File Locking](../file_lock.md) to
lock your files to prevent any conflicting changes.
diff --git a/doc/user/project/repository/web_editor.md b/doc/user/project/repository/web_editor.md
index ce9d23bf911..253e5374f52 100644
--- a/doc/user/project/repository/web_editor.md
+++ b/doc/user/project/repository/web_editor.md
@@ -114,7 +114,7 @@ If your [project is already configured with a deployment service][project-servic
After the branch is created, you can edit files in the repository to fix
the issue. When a merge request is created based on the newly created branch,
-the description field will automatically display the [issue closing pattern]
+the description field will automatically display the [issue closing pattern](../issues/managing_issues.md#closing-issues-automatically)
`Closes #ID`, where `ID` the ID of the issue. This will close the issue once the
merge request is merged.
@@ -181,4 +181,3 @@ through the web editor, you can choose to use another of your linked email
addresses from the **User Settings > Edit Profile** page.
[ce-2808]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/2808
-[issue closing pattern]: ../issues/automatic_issue_closing.md
diff --git a/doc/user/project/service_desk.md b/doc/user/project/service_desk.md
index 1a582164d03..f899120f0c2 100644
--- a/doc/user/project/service_desk.md
+++ b/doc/user/project/service_desk.md
@@ -1,4 +1,4 @@
-# Service Desk **[PREMIUM]**
+# Service Desk **(PREMIUM)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/149) in [GitLab Premium 9.1](https://about.gitlab.com/2017/04/22/gitlab-9-1-released/#service-desk-eep).
diff --git a/doc/user/project/settings/import_export.md b/doc/user/project/settings/import_export.md
index 819515d7a4c..98bcc7cc09f 100644
--- a/doc/user/project/settings/import_export.md
+++ b/doc/user/project/settings/import_export.md
@@ -74,6 +74,13 @@ The following items will NOT be exported:
- CI variables
- Webhooks
- Any encrypted tokens
+- Merge Request Approvers
+- Push Rules
+- Awards
+
+NOTE: **Note:**
+For more details on the specific data persisted in a project export, see the
+[`import_export.yml`](https://gitlab.com/gitlab-org/gitlab-ee/blob/master/lib/gitlab/import_export/import_export.yml) file.
## Exporting a project and its data
diff --git a/doc/user/project/settings/index.md b/doc/user/project/settings/index.md
index 2bf8d4dfe7b..06b431decad 100644
--- a/doc/user/project/settings/index.md
+++ b/doc/user/project/settings/index.md
@@ -9,7 +9,7 @@ to your project's homepage and clicking **Settings**.
## General settings
-Under a project's general settings you can find everything concerning the
+Under a project's general settings, you can find everything concerning the
functionality of a project.
### General project settings
@@ -26,7 +26,7 @@ Set up your project's access, [visibility](../../../public_access/public_access.
![projects sharing permissions](img/sharing_and_permissions_settings.png)
-If Issues are disabled, or you can't access Issues because you're not a project member, then Lables and Milestones
+If Issues are disabled, or you can't access Issues because you're not a project member, then Labels and Milestones
links will be missing from the sidebar UI.
You can still access them with direct links if you can access Merge Requests. This is deliberate, if you can see
@@ -42,13 +42,13 @@ Set up your project's merge request settings:
- Set up the merge request method (merge commit, [fast-forward merge](../merge_requests/fast_forward_merge.html)).
- Merge request [description templates](../description_templates.md#description-templates).
-- Enable [merge request approvals](../merge_requests/merge_request_approvals.md). **[STARTER]**
+- Enable [merge request approvals](../merge_requests/merge_request_approvals.md). **(STARTER)**
- Enable [merge only of pipeline succeeds](../merge_requests/merge_when_pipeline_succeeds.md).
- Enable [merge only when all discussions are resolved](../../discussions/index.md#only-allow-merge-requests-to-be-merged-if-all-discussions-are-resolved).
![project's merge request settings](img/merge_requests_settings.png)
-### Service Desk **[PREMIUM]**
+### Service Desk **(PREMIUM)**
Enable [Service Desk](../service_desk.md) for your project to offer customer support.
@@ -96,7 +96,7 @@ To rename a repository:
1. Hit **Rename project**.
Remember that this can have unintended side effects since everyone with the
-old URL will not be able to push or pull. Read more about what happens with the
+old URL will not be able to push or pull. Read more about what happens with the
[redirects when renaming repositories](../index.md#redirects-when-changing-repository-paths).
#### Transferring an existing project into another namespace
@@ -135,6 +135,6 @@ namespace if needed.
Configure Error Tracking to discover and view [Sentry errors within GitLab](../operations/error_tracking.md).
-### Jaeger tracing **[ULTIMATE]**
+### Jaeger tracing **(ULTIMATE)**
Add the URL of a Jaeger server to allow your users to [easily access the Jaeger UI from within GitLab](../operations/tracing.md).
diff --git a/doc/user/project/web_ide/index.md b/doc/user/project/web_ide/index.md
index 7d85f4adfed..3d92508ad04 100644
--- a/doc/user/project/web_ide/index.md
+++ b/doc/user/project/web_ide/index.md
@@ -129,7 +129,7 @@ below.
}
```
-## Interactive Web Terminals for the Web IDE **[ULTIMATE ONLY]**
+## Interactive Web Terminals for the Web IDE **(ULTIMATE ONLY)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/5426) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 11.6.
@@ -151,7 +151,7 @@ to work:
- The Runner needs to have
[`[session_server]` configured properly](https://docs.gitlab.com/runner/configuration/advanced-configuration.html#the-session_server-section).
- If you are using a reverse proxy with your GitLab instance, web terminals need to be
- [enabled](../../../administration/integration/terminal.md#enabling-and-disabling-terminal-support). **[ULTIMATE ONLY]**
+ [enabled](../../../administration/integration/terminal.md#enabling-and-disabling-terminal-support). **(ULTIMATE ONLY)**
If you have the terminal open and the job has finished with its tasks, the
terminal will block the job from finishing for the duration configured in
diff --git a/doc/user/search/advanced_global_search.md b/doc/user/search/advanced_global_search.md
index f80f4183802..52da6d65000 100644
--- a/doc/user/search/advanced_global_search.md
+++ b/doc/user/search/advanced_global_search.md
@@ -1,4 +1,4 @@
-# Advanced Global Search **[STARTER ONLY]**
+# Advanced Global Search **(STARTER ONLY)**
> - [Introduced][ee-109] in GitLab [Starter][ee] 8.4.
> - This is the user documentation. To install and configure Elasticsearch,
diff --git a/doc/user/search/advanced_search_syntax.md b/doc/user/search/advanced_search_syntax.md
index d302cb7a809..ad9f065b19b 100644
--- a/doc/user/search/advanced_search_syntax.md
+++ b/doc/user/search/advanced_search_syntax.md
@@ -1,4 +1,4 @@
-# Advanced Syntax Search **[STARTER ONLY]**
+# Advanced Syntax Search **(STARTER ONLY)**
> **Notes:**
> - Introduced in [GitLab Enterprise Starter][ee] 9.2
diff --git a/doc/user/search/index.md b/doc/user/search/index.md
index bb6c48471c7..c34b9ae3d7e 100644
--- a/doc/user/search/index.md
+++ b/doc/user/search/index.md
@@ -97,10 +97,10 @@ quickly access issues and merge requests created or assigned to you within that
![search per project - shortcut](img/project_search.png)
-## Todos
+## To-Do List
-Your [todos](../../workflow/todos.md#gitlab-todos) can be searched by "to do" and "done".
-You can [filter](../../workflow/todos.md#filtering-your-todos) them per project,
+Your [To-Do List](../../workflow/todos.md#gitlab-to-do-list) can be searched by "to do" and "done".
+You can [filter](../../workflow/todos.md#filtering-your-to-do-list) them per project,
author, type, and action. Also, you can sort them by
[**Label priority**](../../user/project/labels.md#label-priority),
**Last created** and **Oldest created**.
@@ -143,14 +143,14 @@ and **Labels**, select multiple issues to add to a list of your choice:
![search and select issues to add to board](img/search_issues_board.png)
-## Advanced Global Search **[STARTER]**
+## Advanced Global Search **(STARTER)**
Leverage Elasticsearch for faster, more advanced code search across your entire
GitLab instance.
[Learn how to use the Advanced Global Search.](advanced_global_search.md)
-## Advanced Syntax Search **[STARTER]**
+## Advanced Syntax Search **(STARTER)**
Use advanced queries for more targeted search results.
diff --git a/doc/workflow/README.md b/doc/workflow/README.md
index 40e2486ace5..6ad61932868 100644
--- a/doc/workflow/README.md
+++ b/doc/workflow/README.md
@@ -4,7 +4,7 @@ comments: false
# Workflow
-- [Automatic issue closing](../user/project/issues/automatic_issue_closing.md)
+- [Automatic issue closing](../user/project/issues/managing_issues.md#closing-issues-automatically)
- [Change your time zone](timezone.md)
- [Cycle Analytics](../user/project/cycle_analytics.md)
- [Description templates](../user/project/description_templates.md)
@@ -13,15 +13,15 @@ comments: false
- [Groups](../user/group/index.md)
- Issues - The GitLab Issue Tracker is an advanced and complete tool for
tracking the evolution of a new idea or the process of solving a problem.
- - [Exporting Issues](../user/project/issues/csv_export.md) **[STARTER]** Export issues as a CSV, emailed as an attachment.
+ - [Exporting Issues](../user/project/issues/csv_export.md) **(STARTER)** Export issues as a CSV, emailed as an attachment.
- [Confidential issues](../user/project/issues/confidential_issues.md)
- [Due date for issues](../user/project/issues/due_dates.md)
- [Issue Board](../user/project/issue_board.md)
- [Keyboard shortcuts](shortcuts.md)
- [File finder](file_finder.md)
-- [File lock](../user/project/file_lock.md) **[PREMIUM]**
+- [File lock](../user/project/file_lock.md) **(PREMIUM)**
- [Labels](../user/project/labels.md)
-- [Issue weight](issue_weight.md) **[STARTER]**
+- [Issue weight](issue_weight.md) **(STARTER)**
- [Notification emails](notifications.md)
- [Projects](../user/project/index.md)
- [Project forking workflow](forking_workflow.md)
@@ -44,9 +44,9 @@ comments: false
- [Merge requests versions](../user/project/merge_requests/versions.md)
- ["Work In Progress" merge requests](../user/project/merge_requests/work_in_progress_merge_requests.md)
- [Fast-forward merge requests](../user/project/merge_requests/fast_forward_merge.md)
- - [Merge request approvals](../user/project/merge_requests/merge_request_approvals.md) **[STARTER]**
-- [Repository mirroring](repository_mirroring.md) **[STARTER]**
-- [Service Desk](../user/project/service_desk.md) **[PREMIUM]**
+ - [Merge request approvals](../user/project/merge_requests/merge_request_approvals.md) **(STARTER)**
+- [Repository mirroring](repository_mirroring.md) **(STARTER)**
+- [Service Desk](../user/project/service_desk.md) **(PREMIUM)**
- [Manage large binaries with Git LFS](lfs/manage_large_binaries_with_git_lfs.md)
- [Importing from SVN, GitHub, Bitbucket, etc](importing/README.md)
- [Todos](todos.md)
diff --git a/doc/workflow/gitlab_flow.md b/doc/workflow/gitlab_flow.md
index 3e24557591c..2f365e42cc9 100644
--- a/doc/workflow/gitlab_flow.md
+++ b/doc/workflow/gitlab_flow.md
@@ -1,7 +1,8 @@
-![GitLab Flow](gitlab_flow.png)
# Introduction to GitLab Flow
+![GitLab Flow](img/gitlab_flow.png)
+
Git allows a wide variety of branching strategies and workflows.
Because of this, many organizations end up with workflows that are too complicated, not clearly defined, or not integrated with issue tracking systems.
Therefore, we propose GitLab flow as a clearly defined set of best practices.
@@ -11,7 +12,7 @@ Organizations coming to Git from other version control systems frequently find i
This article describes GitLab flow, which integrates the Git workflow with an issue tracking system.
It offers a simple, transparent, and effective way to work with Git.
-![Four stages (working copy, index, local repo, remote repo) and three steps between them](four_stages.png)
+![Four stages (working copy, index, local repo, remote repo) and three steps between them](img/four_stages.png)
When converting to Git, you have to get used to the fact that it takes three steps to share a commit with colleagues.
Most version control systems have only one step: committing from the working copy to a shared server.
@@ -19,7 +20,7 @@ In Git, you add files from the working copy to the staging area. After that, you
The third step is pushing to a shared remote repository.
After getting used to these three steps, the next challenge is the branching model.
-![Multiple long-running branches and merging in all directions](messy_flow.png)
+![Multiple long-running branches and merging in all directions](img/messy_flow.png)
Since many organizations new to Git have no conventions for how to work with it, their repositories can quickly become messy.
The biggest problem is that many long-running branches emerge that all contain part of the changes.
@@ -31,7 +32,7 @@ For a video introduction of how this works in GitLab, see [GitLab Flow](https://
## Git flow and its problems
-![Git Flow timeline by Vincent Driessen, used with permission](gitdashflow.png)
+![Git Flow timeline by Vincent Driessen, used with permission](img/gitdashflow.png)
Git flow was one of the first proposals to use Git branches, and it has received a lot of attention.
It suggests a `master` branch and a separate `develop` branch, as well as supporting branches for features, releases, and hotfixes.
@@ -54,7 +55,7 @@ For example, many projects do releases but don't need to do hotfixes.
## GitHub flow as a simpler alternative
-![Master branch with feature branches merged in](github_flow.png)
+![Master branch with feature branches merged in](img/github_flow.png)
In reaction to Git flow, GitHub created a simpler alternative.
[GitHub flow](https://guides.github.com/introduction/flow/index.html) has only feature branches and a `master` branch.
@@ -66,7 +67,7 @@ With GitLab flow, we offer additional guidance for these questions.
## Production branch with GitLab flow
-![Master branch and production branch with an arrow that indicates a deployment](production_branch.png)
+![Master branch and production branch with an arrow that indicates a deployment](img/production_branch.png)
GitHub flow assumes you can deploy to production every time you merge a feature branch.
While this is possible in some cases, such as SaaS applications, there are many cases where this is not possible.
@@ -82,7 +83,7 @@ This flow prevents the overhead of releasing, tagging, and merging that happens
## Environment branches with GitLab flow
-![Multiple branches with the code cascading from one to another](environment_branches.png)
+![Multiple branches with the code cascading from one to another](img/environment_branches.png)
It might be a good idea to have an environment that is automatically updated to the `master` branch.
Only, in this case, the name of this environment might differ from the branch name.
@@ -98,7 +99,7 @@ If this is not possible because more manual testing is required, you can send me
## Release branches with GitLab flow
-![Master and multiple release branches that vary in length with cherry-picks from master](release_branches.png)
+![Master and multiple release branches that vary in length with cherry-picks from master](img/release_branches.png)
You only need to work with release branches if you need to release software to the outside world.
In this case, each branch contains a minor version, for example, 2-3-stable, 2-4-stable, etc.
@@ -114,7 +115,7 @@ In this flow, it is not common to have a production branch (or Git flow `master`
## Merge/pull requests with GitLab flow
-![Merge request with inline comments](mr_inline_comments.png)
+![Merge request with inline comments](img/mr_inline_comments.png)
Merge or pull requests are created in a Git management application. They ask an assigned person to merge two branches.
Tools such as GitHub and Bitbucket choose the name "pull request" since the first manual action is to pull the feature branch.
@@ -147,11 +148,11 @@ It also ensures that if someone reopens the issue, they can use the same branch
NOTE: **Note:**
When you reopen an issue you need to create a new merge request.
-![Remove checkbox for branch in merge requests](remove_checkbox.png)
+![Remove checkbox for branch in merge requests](img/remove_checkbox.png)
## Issue tracking with GitLab flow
-![Merge request with the branch name "15-require-a-password-to-change-it" and assignee field shown](merge_request.png)
+![Merge request with the branch name "15-require-a-password-to-change-it" and assignee field shown](img/merge_request.png)
GitLab flow is a way to make the relation between the code and the issue tracker more transparent.
@@ -175,7 +176,7 @@ A merge request is an online place to discuss the change and review the code.
If you open the merge request but do not assign it to anyone, it is a "Work In Progress" merge request.
These are used to discuss the proposed implementation but are not ready for inclusion in the `master` branch yet.
-Start the title of the merge request with "[WIP]" or "WIP:" to prevent it from being merged before it's ready.
+Start the title of the merge request with `[WIP]` or `WIP:` to prevent it from being merged before it's ready.
When you think the code is ready, assign the merge request to a reviewer.
The reviewer can merge the changes when they think the code is ready for inclusion in the `master` branch.
@@ -192,7 +193,7 @@ It is possible that one feature branch solves more than one issue.
## Linking and closing issues from merge requests
-![Merge request showing the linked issues that will be closed](close_issue_mr.png)
+![Merge request showing the linked issues that will be closed](img/close_issue_mr.png)
Link to issues by mentioning them in commit messages or the description of a merge request, for example, "Fixes #16" or "Duck typing is preferred. See #12."
GitLab then creates links to the mentioned issues and creates comments in the issues linking back to the merge request.
@@ -203,7 +204,7 @@ If you have an issue that spans across multiple repositories, create an issue fo
## Squashing commits with rebase
-![Vim screen showing the rebase view](rebase.png)
+![Vim screen showing the rebase view](img/rebase.png)
With Git, you can use an interactive rebase (`rebase -i`) to squash multiple commits into one or reorder them.
This functionality is useful if you want to replace a couple of small commits with a single commit, or if you want to make the order more logical.
@@ -229,7 +230,7 @@ Git does not allow you to merge the code again otherwise.
## Reducing merge commits in feature branches
-![List of sequential merge commits](merge_commits.png)
+![List of sequential merge commits](img/merge_commits.png)
Having lots of merge commits can make your repository history messy.
Therefore, you should try to avoid merge commits in feature branches.
@@ -289,7 +290,7 @@ Sharing your work before it's complete also allows for discussion and feedback a
## How to write a good commit message
-![Good and bad commit message](good_commit.png)
+![Good and bad commit message](img/good_commit.png)
A commit message should reflect your intention, not just the contents of the commit.
It is easy to see the changes in a commit, so the commit message should explain why you made those changes.
@@ -300,7 +301,7 @@ For more information about formatting commit messages, please see this excellent
## Testing before merging
-![Merge requests showing the test states: red, yellow, and green](ci_mr.png)
+![Merge requests showing the test states: red, yellow, and green](img/ci_mr.png)
In old workflows, the continuous integration (CI) server commonly ran tests on the `master` branch only.
Developers had to ensure their code did not break the `master` branch.
@@ -317,7 +318,7 @@ As said before, if you often have feature branches that last for more than a few
## Working with feature branches
-![Shell output showing git pull output](git_pull.png)
+![Shell output showing git pull output](img/git_pull.png)
When creating a feature branch, always branch from an up-to-date `master`.
If you know before you start that your work depends on another branch, you can also branch from there.
diff --git a/doc/workflow/ci_mr.png b/doc/workflow/img/ci_mr.png
index 85a609cb814..85a609cb814 100644
--- a/doc/workflow/ci_mr.png
+++ b/doc/workflow/img/ci_mr.png
Binary files differ
diff --git a/doc/workflow/close_issue_mr.png b/doc/workflow/img/close_issue_mr.png
index 70de2fb6cee..70de2fb6cee 100644
--- a/doc/workflow/close_issue_mr.png
+++ b/doc/workflow/img/close_issue_mr.png
Binary files differ
diff --git a/doc/workflow/environment_branches.png b/doc/workflow/img/environment_branches.png
index 0aff33c6bb8..0aff33c6bb8 100644
--- a/doc/workflow/environment_branches.png
+++ b/doc/workflow/img/environment_branches.png
Binary files differ
diff --git a/doc/workflow/four_stages.png b/doc/workflow/img/four_stages.png
index 3ef6a33d2d4..3ef6a33d2d4 100644
--- a/doc/workflow/four_stages.png
+++ b/doc/workflow/img/four_stages.png
Binary files differ
diff --git a/doc/workflow/git_pull.png b/doc/workflow/img/git_pull.png
index 0e56e59471c..0e56e59471c 100644
--- a/doc/workflow/git_pull.png
+++ b/doc/workflow/img/git_pull.png
Binary files differ
diff --git a/doc/workflow/gitdashflow.png b/doc/workflow/img/gitdashflow.png
index 65900853d84..65900853d84 100644
--- a/doc/workflow/gitdashflow.png
+++ b/doc/workflow/img/gitdashflow.png
Binary files differ
diff --git a/doc/workflow/github_flow.png b/doc/workflow/img/github_flow.png
index 21a22becdb6..21a22becdb6 100644
--- a/doc/workflow/github_flow.png
+++ b/doc/workflow/img/github_flow.png
Binary files differ
diff --git a/doc/workflow/gitlab_flow.png b/doc/workflow/img/gitlab_flow.png
index a6f3c947843..a6f3c947843 100644
--- a/doc/workflow/gitlab_flow.png
+++ b/doc/workflow/img/gitlab_flow.png
Binary files differ
diff --git a/doc/workflow/good_commit.png b/doc/workflow/img/good_commit.png
index ceb0d4b1691..ceb0d4b1691 100644
--- a/doc/workflow/good_commit.png
+++ b/doc/workflow/img/good_commit.png
Binary files differ
diff --git a/doc/workflow/merge_commits.png b/doc/workflow/img/merge_commits.png
index 4a80811c6e3..4a80811c6e3 100644
--- a/doc/workflow/merge_commits.png
+++ b/doc/workflow/img/merge_commits.png
Binary files differ
diff --git a/doc/workflow/merge_request.png b/doc/workflow/img/merge_request.png
index 010e95983fc..010e95983fc 100644
--- a/doc/workflow/merge_request.png
+++ b/doc/workflow/img/merge_request.png
Binary files differ
diff --git a/doc/workflow/messy_flow.png b/doc/workflow/img/messy_flow.png
index 4fa22d2bb5d..4fa22d2bb5d 100644
--- a/doc/workflow/messy_flow.png
+++ b/doc/workflow/img/messy_flow.png
Binary files differ
diff --git a/doc/workflow/mr_inline_comments.png b/doc/workflow/img/mr_inline_comments.png
index a18801f56e4..a18801f56e4 100644
--- a/doc/workflow/mr_inline_comments.png
+++ b/doc/workflow/img/mr_inline_comments.png
Binary files differ
diff --git a/doc/workflow/production_branch.png b/doc/workflow/img/production_branch.png
index c132d51bfb6..c132d51bfb6 100644
--- a/doc/workflow/production_branch.png
+++ b/doc/workflow/img/production_branch.png
Binary files differ
diff --git a/doc/workflow/rebase.png b/doc/workflow/img/rebase.png
index fe865177ba8..fe865177ba8 100644
--- a/doc/workflow/rebase.png
+++ b/doc/workflow/img/rebase.png
Binary files differ
diff --git a/doc/workflow/release_branches.png b/doc/workflow/img/release_branches.png
index 0a7f61d0248..0a7f61d0248 100644
--- a/doc/workflow/release_branches.png
+++ b/doc/workflow/img/release_branches.png
Binary files differ
diff --git a/doc/workflow/remove_checkbox.png b/doc/workflow/img/remove_checkbox.png
index fb0e792b37b..fb0e792b37b 100644
--- a/doc/workflow/remove_checkbox.png
+++ b/doc/workflow/img/remove_checkbox.png
Binary files differ
diff --git a/doc/workflow/issue_weight.md b/doc/workflow/issue_weight.md
index 267160dae2a..afb623e1967 100644
--- a/doc/workflow/issue_weight.md
+++ b/doc/workflow/issue_weight.md
@@ -1,4 +1,4 @@
-# Issue Weight **[STARTER]**
+# Issue Weight **(STARTER)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/76)
> in [GitLab Starter](https://about.gitlab.com/pricing/) 8.3.
diff --git a/doc/workflow/lfs/lfs_administration.md b/doc/workflow/lfs/lfs_administration.md
index 6d941135bf2..03af8fad759 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 set up, and works well with GitLab instances.
+[Minio](https://min.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".
diff --git a/doc/workflow/notifications.md b/doc/workflow/notifications.md
index 5d560f2e000..1e8674f863d 100644
--- a/doc/workflow/notifications.md
+++ b/doc/workflow/notifications.md
@@ -64,18 +64,18 @@ These settings can be configured on project page under the name of the project.
Below is the table of events users can be notified of:
-| Event | Sent to | Settings level |
-|------------------------------|-------------------------------------------------------------------|------------------------------|
-| New SSH key added | User | Security email, always sent. |
-| New email added | User | Security email, always sent. |
-| Email changed | User | Security email, always sent. |
-| Password changed | User | Security email, always sent. |
-| New user created | User | Sent on user creation, except for omniauth (LDAP)|
-| User added to project | User | Sent when user is added to project |
-| Project access level changed | User | Sent when user project access level is changed |
-| User added to group | User | Sent when user is added to group |
-| Group access level changed | User | Sent when user group access level is changed |
-| Project moved | Project members [1] | [1] not disabled |
+| Event | Sent to | Settings level |
+|------------------------------|---------------------|------------------------------|
+| New SSH key added | User | Security email, always sent. |
+| New email added | User | Security email, always sent. |
+| Email changed | User | Security email, always sent. |
+| Password changed | User | Security email, always sent. |
+| New user created | User | Sent on user creation, except for omniauth (LDAP)|
+| User added to project | User | Sent when user is added to project |
+| Project access level changed | User | Sent when user project access level is changed |
+| User added to group | User | Sent when user is added to group |
+| Group access level changed | User | Sent when user group access level is changed |
+| Project moved | Project members (1) | (1) not disabled |
### Issue / Epics / Merge request events
@@ -84,11 +84,11 @@ In most of the below cases, the notification will be sent to:
- Participants:
- the author and assignee of the issue/merge request
- authors of comments on the issue/merge request
- - anyone mentioned by `@username` in the title or description of the issue, merge request or epic **[ULTIMATE]**
+ - anyone mentioned by `@username` in the title or description of the issue, merge request or epic **(ULTIMATE)**
- anyone with notification level "Participating" or higher that is mentioned by `@username`
- in any of the comments on the issue, merge request, or epic **[ULTIMATE]**
+ in any of the comments on the issue, merge request, or epic **(ULTIMATE)**
- Watchers: users with notification level "Watch"
-- Subscribers: anyone who manually subscribed to the issue, merge request, or epic **[ULTIMATE]**
+- Subscribers: anyone who manually subscribed to the issue, merge request, or epic **(ULTIMATE)**
- Custom: Users with notification level "custom" who turned on notifications for any of the events present in the table below
| Event | Sent to |
@@ -111,9 +111,9 @@ In most of the below cases, the notification will be sent to:
| New comment | The above, plus anyone mentioned by `@username` in the comment, with notification level "Mention" or higher |
| Failed pipeline | The author of the pipeline |
| Successful pipeline | The author of the pipeline, if they have the custom notification setting for successful pipelines set |
-| New epic **[ULTIMATE]** | |
-| Close epic **[ULTIMATE]** | |
-| Reopen epic **[ULTIMATE]** | |
+| New epic **(ULTIMATE)** | |
+| Close epic **(ULTIMATE)** | |
+| Reopen epic **(ULTIMATE)** | |
In addition, if the title or description of an Issue or Merge Request is
changed, notifications will be sent to any **new** mentions by `@username` as
diff --git a/doc/workflow/repository_mirroring.md b/doc/workflow/repository_mirroring.md
index 5a24c254ed1..87ca46e94be 100644
--- a/doc/workflow/repository_mirroring.md
+++ b/doc/workflow/repository_mirroring.md
@@ -13,7 +13,7 @@ Repository mirroring is useful when you want to use a repository outside of GitL
There are two kinds of repository mirroring supported by GitLab:
- Push: for mirroring a GitLab repository to another location.
-- Pull: for mirroring a repository from another location to GitLab. **[STARTER]**
+- Pull: for mirroring a repository from another location to GitLab. **(STARTER)**
When the mirror repository is updated, all new branches, tags, and commits will be visible in the
project's activity feed.
@@ -30,12 +30,12 @@ The following are some possible use cases for repository mirroring:
- You migrated to GitLab but still need to keep your project in another source. In that case, you
can simply set it up to mirror to GitLab (pull) and all the essential history of commits, tags,
- and branches will be available in your GitLab instance. **[STARTER]**
+ and branches will be available in your GitLab instance. **(STARTER)**
- You have old projects in another source that you don't use actively anymore, but don't want to
remove for archiving purposes. In that case, you can create a push mirror so that your active
GitLab repository can push its changes to the old location.
-## Pushing to a remote repository **[CORE]**
+## Pushing to a remote repository **(CORE)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/249) in GitLab Enterprise
> Edition 8.7. [Moved to GitLab Core](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/18715) in 10.8.
@@ -65,7 +65,7 @@ Changes pushed to files in the repository are automatically pushed to the remote
In the case of a diverged branch, you will see an error indicated at the **Mirroring repositories**
section.
-### Push only protected branches **[CORE]**
+### Push only protected branches **(CORE)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/3350) in
> [GitLab Starter](https://about.gitlab.com/pricing/) 10.3. [Moved to GitLab Core](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/18715) in 10.8.
@@ -75,7 +75,7 @@ You can choose to only push your protected branches from GitLab to your remote r
To use this option, check the **Only mirror protected branches** box when creating a repository
mirror.
-## Setting up a push mirror from GitLab to GitHub **[CORE]**
+## Setting up a push mirror from GitLab to GitHub **(CORE)**
To set up a mirror from GitLab to GitHub, you need to follow these steps:
@@ -96,7 +96,7 @@ The repository will push soon. To force a push, click the appropriate button.
1. Fill in **Password** field with the GitLab personal access token created on the destination GitLab instance.
1. Click the **Mirror repository** button.
-## Pulling from a remote repository **[STARTER]**
+## Pulling from a remote repository **(STARTER)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/51) in GitLab Enterprise Edition 8.2.
> [Added Git LFS support](https://gitlab.com/gitlab-org/gitlab-ee/issues/10871) in [GitLab Starter](https://about.gitlab.com/pricing/) 11.11.
@@ -243,7 +243,7 @@ If you need to change the key at any time, you can remove and re-add the mirror
to generate a new key. You'll have to update the other repository with the new
key to keep the mirror running.
-### Overwrite diverged branches **[STARTER]**
+### Overwrite diverged branches **(STARTER)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/4559) in
> [GitLab Starter](https://about.gitlab.com/pricing/) 10.6.
@@ -256,7 +256,7 @@ For mirrored branches, enabling this option results in the loss of local changes
To use this option, check the **Overwrite diverged branches** box when creating a repository mirror.
-### Only mirror protected branches **[STARTER]**
+### Only mirror protected branches **(STARTER)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/3326) in
> [GitLab Starter](https://about.gitlab.com/pricing/) 10.3.
@@ -266,7 +266,7 @@ Non-protected branches are not mirrored and can diverge.
To use this option, check the **Only mirror protected branches** box when creating a repository mirror.
-### Hard failure **[STARTER]**
+### Hard failure **(STARTER)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/3117) in
> [GitLab Starter](https://about.gitlab.com/pricing/) 10.2.
@@ -280,25 +280,25 @@ failed. This will become visible in either the:
When a project is hard failed, it will no longer get picked up for mirroring. A user can resume the
project mirroring again by [Forcing an update](#forcing-an-update-core).
-### Trigger update using API **[STARTER]**
+### Trigger update using API **(STARTER)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/3453) in
[GitLab Starter](https://about.gitlab.com/pricing/) 10.3.
Pull mirroring uses polling to detect new branches and commits added upstream, often minutes
-afterwards. If you notify GitLab by [API](https://docs.gitlab.com/ee/api/projects.html#start-the-pull-mirroring-process-for-a-project-starter),
+afterwards. If you notify GitLab by [API](../api/projects.md#start-the-pull-mirroring-process-for-a-project-starter),
updates will be pulled immediately.
-For more information, see [Start the pull mirroring process for a Project](https://docs.gitlab.com/ee/api/projects.html#start-the-pull-mirroring-process-for-a-project-starter).
+For more information, see [Start the pull mirroring process for a Project](../api/projects.md#start-the-pull-mirroring-process-for-a-project-starter).
-## Forcing an update **[CORE]**
+## Forcing an update **(CORE)**
While mirrors are scheduled to update automatically, you can always force an update by using the
update button which is available on the **Mirroring repositories** section of the **Repository Settings** page.
![Repository mirroring force update user interface](img/repository_mirroring_force_update.png)
-## Bidirectional mirroring **[STARTER]**
+## Bidirectional mirroring **(STARTER)**
CAUTION: **Caution:**
Bidirectional mirroring may cause conflicts.
@@ -395,7 +395,7 @@ else
fi
```
-### Mirroring with Perforce Helix via Git Fusion **[STARTER]**
+### Mirroring with Perforce Helix via Git Fusion **(STARTER)**
CAUTION: **Warning:**
Bidirectional mirroring should not be used as a permanent configuration. Refer to
diff --git a/doc/workflow/shortcuts.md b/doc/workflow/shortcuts.md
index 5068b5d4d20..fd67ea8ce87 100644
--- a/doc/workflow/shortcuts.md
+++ b/doc/workflow/shortcuts.md
@@ -85,7 +85,7 @@ You can see GitLab's keyboard shortcuts by using <kbd>shift</kbd> + <kbd>?</kbd>
| <kbd>]</kbd> or <kbd>j</kbd> | Move to next file |
| <kbd>[</kbd> or <kbd>k</kbd> | Move to previous file |
-## Epics **[ULTIMATE]**
+## Epics **(ULTIMATE)**
| Keyboard Shortcut | Description |
| ----------------- | ----------- |
diff --git a/doc/workflow/timezone.md b/doc/workflow/timezone.md
index da51c0f2c93..60a4d0f19de 100644
--- a/doc/workflow/timezone.md
+++ b/doc/workflow/timezone.md
@@ -2,13 +2,12 @@
The global time zone configuration parameter can be changed in `config/gitlab.yml`:
-```
+```text
# time_zone: 'UTC'
```
Uncomment and customize if you want to change the default time zone of the GitLab application.
-
## Viewing available timezones
To see all available time zones, run `bundle exec rake time:zones:all`.
@@ -26,14 +25,13 @@ To obtain a list of timezones, log in to your GitLab application server and run
To update, add the timezone that best applies to your location. For example:
-```
+```ruby
gitlab_rails['time_zone'] = 'America/New_York'
```
After adding the configuration parameter, reconfigure and restart your GitLab instance:
-```
+```sh
gitlab-ctl reconfigure
gitlab-ctl restart
```
-
diff --git a/doc/workflow/todos.md b/doc/workflow/todos.md
index 3eac79427cf..1f8900c734b 100644
--- a/doc/workflow/todos.md
+++ b/doc/workflow/todos.md
@@ -1,50 +1,57 @@
-# GitLab Todos
+# GitLab To-Do List
> [Introduced][ce-2817] in GitLab 8.5.
When you log into GitLab, you normally want to see where you should spend your
-time and take some action, or what you need to keep an eye on. All without the
-mess of a huge pile of e-mail notifications. GitLab is where you do your work,
-so being able to get started quickly is very important.
+time, take some action, or know what you need to keep an eye on without
+a huge pile of e-mail notifications. GitLab is where you do your work,
+so being able to get started quickly is important.
-Todos is a chronological list of to-dos that are waiting for your input, all
+Your To-Do List offers a chronological list of items that are waiting for your input, all
in a simple dashboard.
-![Todos screenshot showing a list of items to check on](img/todos_index.png)
+![To Do screenshot showing a list of items to check on](img/todos_index.png)
---
-You can quickly access the Todos dashboard using the checkmark icon next to the
-search bar in the upper right corner. The number in blue is the number of Todos
-you still have open if the count is < 100, else it's 99+. The exact number
-will still be shown in the body of the _To do_ tab.
+You can quickly access your To-Do List by clicking the checkmark icon next to the
+search bar in the top navigation. If the count is:
-![Todos icon](img/todos_icon.png)
+- Less than 100, the number in blue is the number of To-Do items.
+- 100 or more, the number displays as 99+. The exact number displays
+ on the To-Do List.
+you still have open. Otherwise, the number displays as 99+. The exact number
+displays on the To-Do List.
-## What triggers a Todo
+![To Do icon](img/todos_icon.png)
-A Todo appears in your Todos dashboard when:
+## What triggers a To Do
-- an issue or merge request is assigned to you
-- you are `@mentioned` in the description or in a comment of an issue, merge request, or epic **[ULTIMATE]**
-- you are `@mentioned` in a comment on a commit,
-- a job in the CI pipeline running for your merge request failed, but this
- job is not allowed to fail.
-- an open merge request becomes unmergeable due to conflict, and you are either:
- - the author, or
- - have set it to automatically merge once pipeline succeeds.
+A To Do displays on your To-Do List when:
-Todo triggers are not affected by [GitLab Notification Email settings](notifications.md).
+- An issue or merge request is assigned to you
+- You are `@mentioned` in the description or comment of an:
+ - Issue
+ - Merge Request
+ - Epic **(ULTIMATE)**
+- You are `@mentioned` in a comment on a commit
+- A job in the CI pipeline running for your merge request failed, but this
+ job is not allowed to fail
+- An open merge request becomes unmergeable due to conflict, and you are either:
+ - The author
+ - Have set it to automatically merge once the pipeline succeeds
+
+To-do triggers are not affected by [GitLab Notification Email settings](notifications.md).
NOTE: **Note:**
-When an user no longer has access to a resource related to a Todo like an issue, merge request, project or group the related Todos, for security reasons, gets deleted within the next hour. The delete is delayed to prevent data loss in case user got their access revoked by mistake.
+When a user no longer has access to a resource related to a To Do (like an issue, merge request, project, or group) the related To-Do items are deleted within the next hour for security reasons. The delete is delayed to prevent data loss, in case the user's access was revoked by mistake.
-### Directly addressed Todos
+### Directly addressing a To Do
> [Introduced][ce-7926] in GitLab 9.0.
-If you are mentioned at the start of a line, the todo you receive will be listed
-as 'directly addressed'. For instance, in this comment:
+If you are mentioned at the start of a line, the To Do you receive will be listed
+as 'directly addressed'. For example, in this comment:
```markdown
@alice What do you think? cc: @bob
@@ -58,67 +65,80 @@ as 'directly addressed'. For instance, in this comment:
@erin @frank thank you!
```
-The people receiving directly addressed todos are `@alice`, `@erin`, and
-`@frank`. Directly addressed todos only differ from mention todos in their type,
-for filtering; otherwise, they appear as normal.
+The people receiving directly addressed To-Do items are `@alice`, `@erin`, and
+`@frank`. Directly addressed To-Do items only differ from mentions in their type
+for filtering purposes; otherwise, they appear as normal.
+
+### Manually creating a To Do
+
+You can also add the following to your To-Do List by clicking the **Add a To Do** button on an:
-### Manually creating a Todo
+- Issue
+- Merge Request
+- Epic **(ULTIMATE)**
-You can also add an issue, merge request or epic to your Todos dashboard by clicking
-the "Add todo" button in the sidebar of the issue, merge request, or epic **[ULTIMATE]**.
+![Adding a To Do from the issuable sidebar](img/todos_add_todo_sidebar.png)
-![Adding a Todo from the issuable sidebar](img/todos_add_todo_sidebar.png)
+## Marking a To Do as done
-## Marking a Todo as done
+Any action to the following will mark the corresponding To Do as done:
-Any action to the corresponding issue, merge request or epic **[ULTIMATE]** will mark your Todo as
-**Done**. Actions that dismiss Todos include:
+- Issue
+- Merge Request
+- Epic **(ULTIMATE)**
-- changing the assignee
-- changing the milestone
-- adding/removing a label
-- commenting on the issue
+Actions that dismiss To-Do items include:
+
+- Changing the assignee
+- Changing the milestone
+- Adding/removing a label
+- Commenting on the issue
---
-Todos are personal, and they're only marked as done if the action is coming from
-you. If you close the issue or merge request, your Todo will automatically
-be marked as done.
+Your To-Do List is personal, and items are only marked as done if the action comes from
+you. If you close the issue or merge request, your To Do is automatically
+marked as done.
+
+To prevent other users from closing issues without you being notified, if someone else closes, merges, or takes action on the any of the following, your To Do will remain pending:
-If someone else closes, merges, or takes action on the issue, epic or merge
-request, your Todo will remain pending. This prevents other users from closing issues without you being notified.
+- Issue
+- Merge request
+- Epic **(ULTIMATE)**
-There is just one Todo per issue, epic or merge request, so mentioning a user a
-hundred times in an issue will only trigger one Todo.
+There is just one To Do for each of these, so mentioning a user a hundred times in an issue will only trigger one To Do.
---
-If no action is needed, you can manually mark the Todo as done by clicking the
-corresponding **Done** button, and it will disappear from your Todo list.
+If no action is needed, you can manually mark the To Do as done by clicking the
+corresponding **Done** button, and it will disappear from your To-Do List.
+
+![A To Do in the To-Do List](img/todo_list_item.png)
-![A Todo in the Todos dashboard](img/todo_list_item.png)
+You can also mark a To Do as done by clicking the **Mark as done** button in the sidebar of the following:
-A Todo can also be marked as done from the issue, merge request or epic sidebar using
-the "Mark todo as done" button.
+- Issue
+- Merge Request
+- Epic **(ULTIMATE)**
-![Mark todo as done from the issuable sidebar](img/todos_mark_done_sidebar.png)
+![Mark as done from the issuable sidebar](img/todos_mark_done_sidebar.png)
-You can mark all your Todos as done at once by clicking on the **Mark all as
+You can mark all your To-Do items as done at once by clicking the **Mark all as
done** button.
-## Filtering your Todos
+## Filtering your To-Do List
-There are four kinds of filters you can use on your Todos dashboard.
+There are four kinds of filters you can use on your To-Do List.
| Filter | Description |
| ------- | ----------- |
| Project | Filter by project |
| Group | Filter by group |
-| Author | Filter by the author that triggered the Todo |
-| Type | Filter by issue, merge request, or epic **[ULTIMATE]** |
-| Action | Filter by the action that triggered the Todo |
+| Author | Filter by the author that triggered the To Do |
+| Type | Filter by issue, merge request, or epic **(ULTIMATE)** |
+| Action | Filter by the action that triggered the To Do |
-You can also filter by more than one of these at the same time. The possible Actions are `Any Action`, `Assigned`, `Mentioned`, `Added`, `Pipelines`, and `Directly Addressed`, [as described above](#what-triggers-a-todo).
+You can also filter by more than one of these at the same time. The possible Actions are `Any Action`, `Assigned`, `Mentioned`, `Added`, `Pipelines`, and `Directly Addressed`, [as described above](#what-triggers-a-to-do).
[ce-2817]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/2817
[ce-7926]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/7926
diff --git a/lib/api/api.rb b/lib/api/api.rb
index 20f8c637274..7016a66593d 100644
--- a/lib/api/api.rb
+++ b/lib/api/api.rb
@@ -52,7 +52,10 @@ module API
rack_response({ 'message' => '404 Not found' }.to_json, 404)
end
- rescue_from ::Gitlab::ExclusiveLeaseHelpers::FailedToObtainLockError do
+ rescue_from(
+ ::ActiveRecord::StaleObjectError,
+ ::Gitlab::ExclusiveLeaseHelpers::FailedToObtainLockError
+ ) do
rack_response({ 'message' => '409 Conflict: Resource lock' }.to_json, 409)
end
@@ -163,6 +166,7 @@ module API
mount ::API::Templates
mount ::API::Todos
mount ::API::Triggers
+ mount ::API::UserCounts
mount ::API::Users
mount ::API::Variables
mount ::API::Version
diff --git a/lib/api/entities.rb b/lib/api/entities.rb
index d783591c238..b9aa387ba61 100644
--- a/lib/api/entities.rb
+++ b/lib/api/entities.rb
@@ -498,9 +498,9 @@ module API
expose :state, :created_at, :updated_at
# Avoids an N+1 query when metadata is included
- def issuable_metadata(subject, options, method)
+ def issuable_metadata(subject, options, method, args = nil)
cached_subject = options.dig(:issuable_metadata, subject.id)
- (cached_subject || subject).public_send(method) # rubocop: disable GitlabSecurity/PublicSend
+ (cached_subject || subject).public_send(method, *args) # rubocop: disable GitlabSecurity/PublicSend
end
end
@@ -564,7 +564,7 @@ module API
end
expose(:user_notes_count) { |issue, options| issuable_metadata(issue, options, :user_notes_count) }
- expose(:merge_requests_count) { |issue, options| issuable_metadata(issue, options, :merge_requests_count) }
+ expose(:merge_requests_count) { |issue, options| issuable_metadata(issue, options, :merge_requests_count, options[:current_user]) }
expose(:upvotes) { |issue, options| issuable_metadata(issue, options, :upvotes) }
expose(:downvotes) { |issue, options| issuable_metadata(issue, options, :downvotes) }
expose :due_date
@@ -757,7 +757,9 @@ module API
merge_request.metrics&.pipeline
end
- expose :head_pipeline, using: 'API::Entities::Pipeline'
+ expose :head_pipeline, using: 'API::Entities::Pipeline', if: -> (_, options) do
+ Ability.allowed?(options[:current_user], :read_pipeline, options[:project])
+ end
expose :diff_refs, using: Entities::DiffRefs
@@ -1186,8 +1188,10 @@ module API
MarkupHelper.markdown_field(entity, :description)
end
expose :created_at
+ expose :released_at
expose :author, using: Entities::UserBasic, if: -> (release, _) { release.author.present? }
expose :commit, using: Entities::Commit, if: lambda { |_, _| can_download_code? }
+ expose :upcoming_release?, as: :upcoming_release
expose :assets do
expose :assets_count, as: :count do |release, _|
diff --git a/lib/api/helpers/graphql_helpers.rb b/lib/api/helpers/graphql_helpers.rb
index 94010ab1bc2..bd60470fbd6 100644
--- a/lib/api/helpers/graphql_helpers.rb
+++ b/lib/api/helpers/graphql_helpers.rb
@@ -7,8 +7,6 @@ module API
# should be in app/graphql/ or lib/gitlab/graphql/
module GraphqlHelpers
def conditionally_graphql!(fallback:, query:, context: {}, transform: nil)
- return fallback.call unless Feature.enabled?(:graphql)
-
result = GitlabSchema.execute(query, context: context)
if transform
diff --git a/lib/api/issues.rb b/lib/api/issues.rb
index 039ebf92187..d687acf3423 100644
--- a/lib/api/issues.rb
+++ b/lib/api/issues.rb
@@ -96,7 +96,7 @@ module API
with: Entities::Issue,
with_labels_details: declared_params[:with_labels_details],
current_user: current_user,
- issuable_metadata: issuable_meta_data(issues, 'Issue')
+ issuable_metadata: issuable_meta_data(issues, 'Issue', current_user)
}
present issues, options
@@ -122,7 +122,7 @@ module API
with: Entities::Issue,
with_labels_details: declared_params[:with_labels_details],
current_user: current_user,
- issuable_metadata: issuable_meta_data(issues, 'Issue')
+ issuable_metadata: issuable_meta_data(issues, 'Issue', current_user)
}
present issues, options
@@ -161,7 +161,7 @@ module API
with_labels_details: declared_params[:with_labels_details],
current_user: current_user,
project: user_project,
- issuable_metadata: issuable_meta_data(issues, 'Issue')
+ issuable_metadata: issuable_meta_data(issues, 'Issue', current_user)
}
present issues, options
diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb
index bf87e9ec2ff..64ee82cd775 100644
--- a/lib/api/merge_requests.rb
+++ b/lib/api/merge_requests.rb
@@ -72,7 +72,7 @@ module API
if params[:view] == 'simple'
options[:with] = Entities::MergeRequestSimple
else
- options[:issuable_metadata] = issuable_meta_data(merge_requests, 'MergeRequest')
+ options[:issuable_metadata] = issuable_meta_data(merge_requests, 'MergeRequest', current_user)
end
options
@@ -429,9 +429,10 @@ module API
authorize_push_to_merge_request!(merge_request)
- RebaseWorker.perform_async(merge_request.id, current_user.id)
+ merge_request.rebase_async(current_user.id)
status :accepted
+ present rebase_in_progress: merge_request.rebase_in_progress?
end
desc 'List issues that will be closed on merge' do
diff --git a/lib/api/projects.rb b/lib/api/projects.rb
index 1e14c77b5be..a7d62014509 100644
--- a/lib/api/projects.rb
+++ b/lib/api/projects.rb
@@ -474,7 +474,7 @@ module API
authorize_admin_project
begin
- ::Projects::HousekeepingService.new(user_project).execute
+ ::Projects::HousekeepingService.new(user_project, :gc).execute
rescue ::Projects::HousekeepingService::LeaseTaken => error
conflict!(error.message)
end
diff --git a/lib/api/releases.rb b/lib/api/releases.rb
index 6b17f4317db..fdd8406388e 100644
--- a/lib/api/releases.rb
+++ b/lib/api/releases.rb
@@ -54,6 +54,7 @@ module API
requires :url, type: String
end
end
+ optional :released_at, type: DateTime, desc: 'The date when the release will be/was ready. Defaults to the current time.'
end
post ':id/releases' do
authorize_create_release!
@@ -77,6 +78,7 @@ module API
requires :tag_name, type: String, desc: 'The name of the tag', as: :tag
optional :name, type: String, desc: 'The name of the release'
optional :description, type: String, desc: 'Release notes with markdown support'
+ optional :released_at, type: DateTime, desc: 'The date when the release will be/was ready. Defaults to the current time.'
end
put ':id/releases/:tag_name', requirements: RELEASE_ENDPOINT_REQUIREMETS do
authorize_update_release!
diff --git a/lib/api/runners.rb b/lib/api/runners.rb
index f3fea463e7f..c2d371b6867 100644
--- a/lib/api/runners.rb
+++ b/lib/api/runners.rb
@@ -115,6 +115,8 @@ module API
params do
requires :id, type: Integer, desc: 'The ID of the runner'
optional :status, type: String, desc: 'Status of the job', values: Ci::Build::AVAILABLE_STATUSES
+ optional :order_by, type: String, desc: 'Order by `id` or not', values: RunnerJobsFinder::ALLOWED_INDEXED_COLUMNS
+ optional :sort, type: String, values: %w[asc desc], default: 'desc', desc: 'Sort by asc (ascending) or desc (descending)'
use :pagination
end
get ':id/jobs' do
diff --git a/lib/api/settings.rb b/lib/api/settings.rb
index 3c5c1a9fd5f..4275d911708 100644
--- a/lib/api/settings.rb
+++ b/lib/api/settings.rb
@@ -55,6 +55,8 @@ module API
optional :gitaly_timeout_default, type: Integer, desc: 'Default Gitaly timeout, in seconds. Set to 0 to disable timeouts.'
optional :gitaly_timeout_fast, type: Integer, desc: 'Gitaly fast operation timeout, in seconds. Set to 0 to disable timeouts.'
optional :gitaly_timeout_medium, type: Integer, desc: 'Medium Gitaly timeout, in seconds. Set to 0 to disable timeouts.'
+ optional :grafana_enabled, type: Boolean, desc: 'Enable Grafana'
+ optional :grafana_url, type: String, desc: 'Grafana URL'
optional :gravatar_enabled, type: Boolean, desc: 'Flag indicating if the Gravatar service is enabled'
optional :help_page_hide_commercial_content, type: Boolean, desc: 'Hide marketing-related entries from help'
optional :help_page_support_url, type: String, desc: 'Alternate support URL for help page'
diff --git a/lib/api/todos.rb b/lib/api/todos.rb
index 871eaabc887..7260ecfb5ee 100644
--- a/lib/api/todos.rb
+++ b/lib/api/todos.rb
@@ -65,7 +65,7 @@ module API
next unless collection
targets = collection.map(&:target)
- options[type] = { issuable_metadata: issuable_meta_data(targets, type) }
+ options[type] = { issuable_metadata: issuable_meta_data(targets, type, current_user) }
end
end
end
diff --git a/lib/api/user_counts.rb b/lib/api/user_counts.rb
new file mode 100644
index 00000000000..8df4b381bbf
--- /dev/null
+++ b/lib/api/user_counts.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+module API
+ class UserCounts < Grape::API
+ resource :user_counts do
+ desc 'Return the user specific counts' do
+ detail 'Open MR Count'
+ end
+ get do
+ unauthorized! unless current_user
+
+ {
+ merge_requests: current_user.assigned_open_merge_requests_count
+ }
+ end
+ end
+ end
+end
diff --git a/lib/banzai/filter/relative_link_filter.rb b/lib/banzai/filter/relative_link_filter.rb
index 80c84c0f622..86f18679496 100644
--- a/lib/banzai/filter/relative_link_filter.rb
+++ b/lib/banzai/filter/relative_link_filter.rb
@@ -56,10 +56,10 @@ module Banzai
def process_link_to_upload_attr(html_attr)
path_parts = [Addressable::URI.unescape(html_attr.value)]
- if group
- path_parts.unshift(relative_url_root, 'groups', group.full_path, '-')
- elsif project
+ if project
path_parts.unshift(relative_url_root, project.full_path)
+ elsif group
+ path_parts.unshift(relative_url_root, 'groups', group.full_path, '-')
else
path_parts.unshift(relative_url_root)
end
@@ -102,7 +102,7 @@ module Banzai
end
def relative_file_path(uri)
- path = Addressable::URI.unescape(uri.path)
+ path = Addressable::URI.unescape(uri.path).delete("\0")
request_path = Addressable::URI.unescape(context[:requested_path])
nested_path = build_relative_path(path, request_path)
file_exists?(nested_path) ? nested_path : path
diff --git a/lib/banzai/filter/syntax_highlight_filter.rb b/lib/banzai/filter/syntax_highlight_filter.rb
index fe56f9a1e33..9b66759a5fb 100644
--- a/lib/banzai/filter/syntax_highlight_filter.rb
+++ b/lib/banzai/filter/syntax_highlight_filter.rb
@@ -14,7 +14,7 @@ module Banzai
LANG_PARAMS_ATTR = 'data-lang-params'.freeze
def call
- doc.search('pre > code').each do |node|
+ doc.search('pre:not([data-math-style]) > code').each do |node|
highlight_node(node)
end
diff --git a/lib/banzai/pipeline/ascii_doc_pipeline.rb b/lib/banzai/pipeline/ascii_doc_pipeline.rb
index cc4af280872..6be489c6572 100644
--- a/lib/banzai/pipeline/ascii_doc_pipeline.rb
+++ b/lib/banzai/pipeline/ascii_doc_pipeline.rb
@@ -6,6 +6,7 @@ module Banzai
def self.filters
FilterArray[
Filter::SanitizationFilter,
+ Filter::SyntaxHighlightFilter,
Filter::ExternalLinkFilter,
Filter::PlantumlFilter,
Filter::AsciiDocPostProcessingFilter
diff --git a/lib/feature.rb b/lib/feature.rb
index cc9c9d44005..e28333aa58e 100644
--- a/lib/feature.rb
+++ b/lib/feature.rb
@@ -34,7 +34,9 @@ class Feature
begin
# We saw on GitLab.com, this database request was called 2300
# times/s. Let's cache it for a minute to avoid that load.
- Rails.cache.fetch('flipper:persisted_names', expires_in: 1.minute) { FlipperFeature.feature_names }
+ Gitlab::ThreadMemoryCache.cache_backend.fetch('flipper:persisted_names', expires_in: 1.minute) do
+ FlipperFeature.feature_names
+ end
end
end
@@ -101,10 +103,27 @@ class Feature
feature_class: FlipperFeature,
gate_class: FlipperGate)
+ # Redis L2 cache
+ redis_cache_adapter =
+ Flipper::Adapters::ActiveSupportCacheStore.new(
+ active_record_adapter,
+ l2_cache_backend,
+ expires_in: 1.hour)
+
+ # Thread-local L1 cache: use a short timeout since we don't have a
+ # way to expire this cache all at once
Flipper::Adapters::ActiveSupportCacheStore.new(
- active_record_adapter,
- Rails.cache,
- expires_in: 1.hour)
+ redis_cache_adapter,
+ l1_cache_backend,
+ expires_in: 1.minute)
+ end
+
+ def l1_cache_backend
+ Gitlab::ThreadMemoryCache.cache_backend
+ end
+
+ def l2_cache_backend
+ Rails.cache
end
end
diff --git a/lib/feature/gitaly.rb b/lib/feature/gitaly.rb
index d7a8f8a0b9e..67c0b902c0c 100644
--- a/lib/feature/gitaly.rb
+++ b/lib/feature/gitaly.rb
@@ -8,7 +8,12 @@ class Feature
# CATFILE_CACHE sets an incorrect example
CATFILE_CACHE = 'catfile-cache'.freeze
- SERVER_FEATURE_FLAGS = [CATFILE_CACHE].freeze
+ SERVER_FEATURE_FLAGS =
+ [
+ CATFILE_CACHE,
+ 'get_commit_signatures'.freeze
+ ].freeze
+
DEFAULT_ON_FLAGS = Set.new([CATFILE_CACHE]).freeze
class << self
diff --git a/lib/gitlab/asciidoc.rb b/lib/gitlab/asciidoc.rb
index 7f8300a0c2f..00c87cce7b6 100644
--- a/lib/gitlab/asciidoc.rb
+++ b/lib/gitlab/asciidoc.rb
@@ -4,6 +4,7 @@ require 'asciidoctor'
require 'asciidoctor-plantuml'
require 'asciidoctor/extensions'
require 'gitlab/asciidoc/html5_converter'
+require 'gitlab/asciidoc/syntax_highlighter/html_pipeline_adapter'
module Gitlab
# Parser/renderer for the AsciiDoc format that uses Asciidoctor and filters
@@ -16,7 +17,7 @@ module Gitlab
'idseparator' => '-',
'env' => 'gitlab',
'env-gitlab' => '',
- 'source-highlighter' => 'html-pipeline',
+ 'source-highlighter' => 'gitlab-html-pipeline',
'icons' => 'font',
'outfilesuffix' => '.adoc',
'max-include-depth' => MAX_INCLUDE_DEPTH
diff --git a/lib/gitlab/asciidoc/syntax_highlighter/html_pipeline_adapter.rb b/lib/gitlab/asciidoc/syntax_highlighter/html_pipeline_adapter.rb
new file mode 100644
index 00000000000..5fc3323f0fd
--- /dev/null
+++ b/lib/gitlab/asciidoc/syntax_highlighter/html_pipeline_adapter.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Asciidoc
+ module SyntaxHighlighter
+ class HtmlPipelineAdapter < Asciidoctor::SyntaxHighlighter::Base
+ register_for 'gitlab-html-pipeline'
+
+ def format(node, lang, opts)
+ %(<pre><code #{lang ? %[ lang="#{lang}"] : ''}>#{node.content}</code></pre>)
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/background_migration/create_fork_network_memberships_range.rb b/lib/gitlab/background_migration/create_fork_network_memberships_range.rb
deleted file mode 100644
index ccd1f9b4dba..00000000000
--- a/lib/gitlab/background_migration/create_fork_network_memberships_range.rb
+++ /dev/null
@@ -1,85 +0,0 @@
-# frozen_string_literal: true
-# rubocop:disable Style/Documentation
-
-module Gitlab
- module BackgroundMigration
- class CreateForkNetworkMembershipsRange
- RESCHEDULE_DELAY = 15
-
- class ForkedProjectLink < ActiveRecord::Base
- self.table_name = 'forked_project_links'
- end
-
- def perform(start_id, end_id)
- log("Creating memberships for forks: #{start_id} - #{end_id}")
-
- insert_members(start_id, end_id)
-
- if missing_members?(start_id, end_id)
- BackgroundMigrationWorker.perform_in(RESCHEDULE_DELAY, "CreateForkNetworkMembershipsRange", [start_id, end_id])
- end
- end
-
- def insert_members(start_id, end_id)
- ActiveRecord::Base.connection.execute <<~INSERT_MEMBERS
- INSERT INTO fork_network_members (fork_network_id, project_id, forked_from_project_id)
-
- SELECT fork_network_members.fork_network_id,
- forked_project_links.forked_to_project_id,
- forked_project_links.forked_from_project_id
-
- FROM forked_project_links
-
- INNER JOIN fork_network_members
- ON forked_project_links.forked_from_project_id = fork_network_members.project_id
-
- WHERE forked_project_links.id BETWEEN #{start_id} AND #{end_id}
- AND NOT EXISTS (
- SELECT true
- FROM fork_network_members existing_members
- WHERE existing_members.project_id = forked_project_links.forked_to_project_id
- )
- INSERT_MEMBERS
- rescue ActiveRecord::RecordNotUnique => e
- # `fork_network_member` was created concurrently in another migration
- log(e.message)
- end
-
- def missing_members?(start_id, end_id)
- count_sql = <<~MISSING_MEMBERS
- SELECT COUNT(*)
-
- FROM forked_project_links
-
- WHERE NOT EXISTS (
- SELECT true
- FROM fork_network_members
- WHERE fork_network_members.project_id = forked_project_links.forked_to_project_id
- )
- AND EXISTS (
- SELECT true
- FROM projects
- WHERE forked_project_links.forked_from_project_id = projects.id
- )
- AND NOT EXISTS (
- SELECT true
- FROM forked_project_links AS parent_links
- WHERE parent_links.forked_to_project_id = forked_project_links.forked_from_project_id
- AND NOT EXISTS (
- SELECT true
- FROM projects
- WHERE parent_links.forked_from_project_id = projects.id
- )
- )
- AND forked_project_links.id BETWEEN #{start_id} AND #{end_id}
- MISSING_MEMBERS
-
- ForkedProjectLink.count_by_sql(count_sql) > 0
- end
-
- def log(message)
- Rails.logger.info("#{self.class.name} - #{message}")
- end
- end
- end
-end
diff --git a/lib/gitlab/background_migration/delete_conflicting_redirect_routes_range.rb b/lib/gitlab/background_migration/delete_conflicting_redirect_routes_range.rb
deleted file mode 100644
index 21b626dde56..00000000000
--- a/lib/gitlab/background_migration/delete_conflicting_redirect_routes_range.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-# frozen_string_literal: true
-# rubocop:disable Style/Documentation
-
-module Gitlab
- module BackgroundMigration
- class DeleteConflictingRedirectRoutesRange
- def perform(start_id, end_id)
- # No-op.
- # See https://gitlab.com/gitlab-com/infrastructure/issues/3460#note_53223252
- end
- end
- end
-end
diff --git a/lib/gitlab/background_migration/migrate_events_to_push_event_payloads.rb b/lib/gitlab/background_migration/migrate_events_to_push_event_payloads.rb
deleted file mode 100644
index 42fcaa87e66..00000000000
--- a/lib/gitlab/background_migration/migrate_events_to_push_event_payloads.rb
+++ /dev/null
@@ -1,179 +0,0 @@
-# frozen_string_literal: true
-# rubocop:disable Style/Documentation
-
-module Gitlab
- module BackgroundMigration
- # Class that migrates events for the new push event payloads setup. All
- # events are copied to a shadow table, and push events will also have a row
- # created in the push_event_payloads table.
- class MigrateEventsToPushEventPayloads
- class Event < ActiveRecord::Base
- self.table_name = 'events'
-
- serialize :data
-
- BLANK_REF = ('0' * 40).freeze
- TAG_REF_PREFIX = 'refs/tags/'.freeze
- MAX_INDEX = 69
- PUSHED = 5
-
- def push_event?
- action == PUSHED && data.present?
- end
-
- def commit_title
- commit = commits.last
-
- return unless commit && commit[:message]
-
- index = commit[:message].index("\n")
- message = index ? commit[:message][0..index] : commit[:message]
-
- message.strip.truncate(70)
- end
-
- def commit_from_sha
- if create?
- nil
- else
- data[:before]
- end
- end
-
- def commit_to_sha
- if remove?
- nil
- else
- data[:after]
- end
- end
-
- def data
- super || {}
- end
-
- def commits
- data[:commits] || []
- end
-
- def commit_count
- data[:total_commits_count] || 0
- end
-
- def ref
- data[:ref]
- end
-
- def trimmed_ref_name
- if ref_type == :tag
- ref[10..-1]
- else
- ref[11..-1]
- end
- end
-
- def create?
- data[:before] == BLANK_REF
- end
-
- def remove?
- data[:after] == BLANK_REF
- end
-
- def push_action
- if create?
- :created
- elsif remove?
- :removed
- else
- :pushed
- end
- end
-
- def ref_type
- if ref.start_with?(TAG_REF_PREFIX)
- :tag
- else
- :branch
- end
- end
- end
-
- class EventForMigration < ActiveRecord::Base
- self.table_name = 'events_for_migration'
- end
-
- class PushEventPayload < ActiveRecord::Base
- self.table_name = 'push_event_payloads'
-
- enum action: {
- created: 0,
- removed: 1,
- pushed: 2
- }
-
- enum ref_type: {
- branch: 0,
- tag: 1
- }
- end
-
- # start_id - The start ID of the range of events to process
- # end_id - The end ID of the range to process.
- def perform(start_id, end_id)
- return unless migrate?
-
- find_events(start_id, end_id).each { |event| process_event(event) }
- end
-
- def process_event(event)
- ActiveRecord::Base.transaction do
- replicate_event(event)
- create_push_event_payload(event) if event.push_event?
- end
- rescue ActiveRecord::InvalidForeignKey => e
- # A foreign key error means the associated event was removed. In this
- # case we'll just skip migrating the event.
- Rails.logger.error("Unable to migrate event #{event.id}: #{e}")
- end
-
- def replicate_event(event)
- new_attributes = event.attributes
- .with_indifferent_access.except(:title, :data)
-
- EventForMigration.create!(new_attributes)
- end
-
- def create_push_event_payload(event)
- commit_from = pack(event.commit_from_sha)
- commit_to = pack(event.commit_to_sha)
-
- PushEventPayload.create!(
- event_id: event.id,
- commit_count: event.commit_count,
- ref_type: event.ref_type,
- action: event.push_action,
- commit_from: commit_from,
- commit_to: commit_to,
- ref: event.trimmed_ref_name,
- commit_title: event.commit_title
- )
- end
-
- def find_events(start_id, end_id)
- Event
- .where('NOT EXISTS (SELECT true FROM events_for_migration WHERE events_for_migration.id = events.id)')
- .where(id: start_id..end_id)
- end
-
- def migrate?
- Event.table_exists? && PushEventPayload.table_exists? &&
- EventForMigration.table_exists?
- end
-
- def pack(value)
- value ? [value].pack('H*') : nil
- end
- end
- end
-end
diff --git a/lib/gitlab/background_migration/migrate_system_uploads_to_new_folder.rb b/lib/gitlab/background_migration/migrate_system_uploads_to_new_folder.rb
deleted file mode 100644
index ef50fe4adb1..00000000000
--- a/lib/gitlab/background_migration/migrate_system_uploads_to_new_folder.rb
+++ /dev/null
@@ -1,29 +0,0 @@
-# frozen_string_literal: true
-# rubocop:disable Style/Documentation
-
-module Gitlab
- module BackgroundMigration
- class MigrateSystemUploadsToNewFolder
- include Gitlab::Database::MigrationHelpers
- attr_reader :old_folder, :new_folder
-
- class Upload < ActiveRecord::Base
- self.table_name = 'uploads'
- include EachBatch
- end
-
- def perform(old_folder, new_folder)
- replace_sql = replace_sql(uploads[:path], old_folder, new_folder)
- affected_uploads = Upload.where(uploads[:path].matches("#{old_folder}%"))
-
- affected_uploads.each_batch do |batch|
- batch.update_all("path = #{replace_sql}")
- end
- end
-
- def uploads
- Arel::Table.new('uploads')
- end
- end
- end
-end
diff --git a/lib/gitlab/background_migration/move_personal_snippet_files.rb b/lib/gitlab/background_migration/move_personal_snippet_files.rb
deleted file mode 100644
index 5b2b2af718a..00000000000
--- a/lib/gitlab/background_migration/move_personal_snippet_files.rb
+++ /dev/null
@@ -1,82 +0,0 @@
-# frozen_string_literal: true
-# rubocop:disable Style/Documentation
-
-module Gitlab
- module BackgroundMigration
- class MovePersonalSnippetFiles
- delegate :select_all, :execute, :quote_string, to: :connection
-
- def perform(relative_source, relative_destination)
- @source_relative_location = relative_source
- @destination_relative_location = relative_destination
-
- move_personal_snippet_files
- end
-
- def move_personal_snippet_files
- query = "SELECT uploads.path, uploads.model_id FROM uploads "\
- "INNER JOIN snippets ON snippets.id = uploads.model_id WHERE uploader = 'PersonalFileUploader'"
- select_all(query).each do |upload|
- secret = upload['path'].split('/')[0]
- file_name = upload['path'].split('/')[1]
-
- move_file(upload['model_id'], secret, file_name)
- update_markdown(upload['model_id'], secret, file_name)
- end
- end
-
- def move_file(snippet_id, secret, file_name)
- source_dir = File.join(base_directory, @source_relative_location, snippet_id.to_s, secret)
- destination_dir = File.join(base_directory, @destination_relative_location, snippet_id.to_s, secret)
-
- source_file_path = File.join(source_dir, file_name)
- destination_file_path = File.join(destination_dir, file_name)
-
- unless File.exist?(source_file_path)
- say "Source file `#{source_file_path}` doesn't exist. Skipping."
- return
- end
-
- say "Moving file #{source_file_path} -> #{destination_file_path}"
-
- FileUtils.mkdir_p(destination_dir)
- FileUtils.move(source_file_path, destination_file_path)
- end
-
- def update_markdown(snippet_id, secret, file_name)
- source_markdown_path = File.join(@source_relative_location, snippet_id.to_s, secret, file_name)
- destination_markdown_path = File.join(@destination_relative_location, snippet_id.to_s, secret, file_name)
-
- source_markdown = "](#{source_markdown_path})"
- destination_markdown = "](#{destination_markdown_path})"
- quoted_source = quote_string(source_markdown)
- quoted_destination = quote_string(destination_markdown)
-
- execute("UPDATE snippets "\
- "SET description = replace(snippets.description, '#{quoted_source}', '#{quoted_destination}'), description_html = NULL "\
- "WHERE id = #{snippet_id}")
-
- query = "SELECT id, note FROM notes WHERE noteable_id = #{snippet_id} "\
- "AND noteable_type = 'Snippet' AND note IS NOT NULL"
- select_all(query).each do |note|
- text = note['note'].gsub(source_markdown, destination_markdown)
- quoted_text = quote_string(text)
-
- execute("UPDATE notes SET note = '#{quoted_text}', note_html = NULL WHERE id = #{note['id']}")
- end
- end
-
- def base_directory
- File.join(Rails.root, 'public')
- end
-
- def connection
- ActiveRecord::Base.connection
- end
-
- def say(message)
- Rails.logger.debug(message)
- end
- end
- end
-end
diff --git a/lib/gitlab/background_migration/normalize_ldap_extern_uids_range.rb b/lib/gitlab/background_migration/normalize_ldap_extern_uids_range.rb
deleted file mode 100644
index 48aa369705f..00000000000
--- a/lib/gitlab/background_migration/normalize_ldap_extern_uids_range.rb
+++ /dev/null
@@ -1,319 +0,0 @@
-# frozen_string_literal: true
-# rubocop:disable Metrics/MethodLength
-# rubocop:disable Metrics/ClassLength
-# rubocop:disable Metrics/BlockLength
-# rubocop:disable Style/Documentation
-
-module Gitlab
- module BackgroundMigration
- class NormalizeLdapExternUidsRange
- class Identity < ActiveRecord::Base
- self.table_name = 'identities'
- end
-
- # Copied this class to make this migration resilient to future code changes.
- # And if the normalize behavior is changed in the future, it must be
- # accompanied by another migration.
- module Gitlab
- module Auth
- module LDAP
- class DN
- FormatError = Class.new(StandardError)
- MalformedError = Class.new(FormatError)
- UnsupportedError = Class.new(FormatError)
-
- def self.normalize_value(given_value)
- dummy_dn = "placeholder=#{given_value}"
- normalized_dn = new(*dummy_dn).to_normalized_s
- normalized_dn.sub(/\Aplaceholder=/, '')
- end
-
- ##
- # Initialize a DN, escaping as required. Pass in attributes in name/value
- # pairs. If there is a left over argument, it will be appended to the dn
- # without escaping (useful for a base string).
- #
- # Most uses of this class will be to escape a DN, rather than to parse it,
- # so storing the dn as an escaped String and parsing parts as required
- # with a state machine seems sensible.
- def initialize(*args)
- if args.length > 1
- initialize_array(args)
- else
- initialize_string(args[0])
- end
- end
-
- ##
- # Parse a DN into key value pairs using ASN from
- # http://tools.ietf.org/html/rfc2253 section 3.
- # rubocop:disable Metrics/AbcSize
- # rubocop:disable Metrics/CyclomaticComplexity
- # rubocop:disable Metrics/PerceivedComplexity
- def each_pair
- state = :key
- key = StringIO.new
- value = StringIO.new
- hex_buffer = ""
-
- @dn.each_char.with_index do |char, dn_index|
- case state
- when :key then
- case char
- when 'a'..'z', 'A'..'Z' then
- state = :key_normal
- key << char
- when '0'..'9' then
- state = :key_oid
- key << char
- when ' ' then state = :key
- else raise(MalformedError, "Unrecognized first character of an RDN attribute type name \"#{char}\"")
- end
- when :key_normal then
- case char
- when '=' then state = :value
- when 'a'..'z', 'A'..'Z', '0'..'9', '-', ' ' then key << char
- else raise(MalformedError, "Unrecognized RDN attribute type name character \"#{char}\"")
- end
- when :key_oid then
- case char
- when '=' then state = :value
- when '0'..'9', '.', ' ' then key << char
- else raise(MalformedError, "Unrecognized RDN OID attribute type name character \"#{char}\"")
- end
- when :value then
- case char
- when '\\' then state = :value_normal_escape
- when '"' then state = :value_quoted
- when ' ' then state = :value
- when '#' then
- state = :value_hexstring
- value << char
- when ',' then
- state = :key
- yield key.string.strip, rstrip_except_escaped(value.string, dn_index)
- key = StringIO.new
- value = StringIO.new
- else
- state = :value_normal
- value << char
- end
- when :value_normal then
- case char
- when '\\' then state = :value_normal_escape
- when ',' then
- state = :key
- yield key.string.strip, rstrip_except_escaped(value.string, dn_index)
- key = StringIO.new
- value = StringIO.new
- when '+' then raise(UnsupportedError, "Multivalued RDNs are not supported")
- else value << char
- end
- when :value_normal_escape then
- case char
- when '0'..'9', 'a'..'f', 'A'..'F' then
- state = :value_normal_escape_hex
- hex_buffer = char
- else
- state = :value_normal
- value << char
- end
- when :value_normal_escape_hex then
- case char
- when '0'..'9', 'a'..'f', 'A'..'F' then
- state = :value_normal
- value << "#{hex_buffer}#{char}".to_i(16).chr
- else raise(MalformedError, "Invalid escaped hex code \"\\#{hex_buffer}#{char}\"")
- end
- when :value_quoted then
- case char
- when '\\' then state = :value_quoted_escape
- when '"' then state = :value_end
- else value << char
- end
- when :value_quoted_escape then
- case char
- when '0'..'9', 'a'..'f', 'A'..'F' then
- state = :value_quoted_escape_hex
- hex_buffer = char
- else
- state = :value_quoted
- value << char
- end
- when :value_quoted_escape_hex then
- case char
- when '0'..'9', 'a'..'f', 'A'..'F' then
- state = :value_quoted
- value << "#{hex_buffer}#{char}".to_i(16).chr
- else raise(MalformedError, "Expected the second character of a hex pair inside a double quoted value, but got \"#{char}\"")
- end
- when :value_hexstring then
- case char
- when '0'..'9', 'a'..'f', 'A'..'F' then
- state = :value_hexstring_hex
- value << char
- when ' ' then state = :value_end
- when ',' then
- state = :key
- yield key.string.strip, rstrip_except_escaped(value.string, dn_index)
- key = StringIO.new
- value = StringIO.new
- else raise(MalformedError, "Expected the first character of a hex pair, but got \"#{char}\"")
- end
- when :value_hexstring_hex then
- case char
- when '0'..'9', 'a'..'f', 'A'..'F' then
- state = :value_hexstring
- value << char
- else raise(MalformedError, "Expected the second character of a hex pair, but got \"#{char}\"")
- end
- when :value_end then
- case char
- when ' ' then state = :value_end
- when ',' then
- state = :key
- yield key.string.strip, rstrip_except_escaped(value.string, dn_index)
- key = StringIO.new
- value = StringIO.new
- else raise(MalformedError, "Expected the end of an attribute value, but got \"#{char}\"")
- end
- else raise "Fell out of state machine"
- end
- end
-
- # Last pair
- raise(MalformedError, 'DN string ended unexpectedly') unless
- [:value, :value_normal, :value_hexstring, :value_end].include? state
-
- yield key.string.strip, rstrip_except_escaped(value.string, @dn.length)
- end
-
- def rstrip_except_escaped(str, dn_index)
- str_ends_with_whitespace = str.match(/\s\z/)
-
- if str_ends_with_whitespace
- dn_part_ends_with_escaped_whitespace = @dn[0, dn_index].match(/\\(\s+)\z/)
-
- if dn_part_ends_with_escaped_whitespace
- dn_part_rwhitespace = dn_part_ends_with_escaped_whitespace[1]
- num_chars_to_remove = dn_part_rwhitespace.length - 1
- str = str[0, str.length - num_chars_to_remove]
- else
- str.rstrip!
- end
- end
-
- str
- end
-
- ##
- # Returns the DN as an array in the form expected by the constructor.
- def to_a
- a = []
- self.each_pair { |key, value| a << key << value } unless @dn.empty?
- a
- end
-
- ##
- # Return the DN as an escaped string.
- def to_s
- @dn
- end
-
- ##
- # Return the DN as an escaped and normalized string.
- def to_normalized_s
- self.class.new(*to_a).to_s.downcase
- end
-
- # https://tools.ietf.org/html/rfc4514 section 2.4 lists these exceptions
- # for DN values. All of the following must be escaped in any normal string
- # using a single backslash ('\') as escape. The space character is left
- # out here because in a "normalized" string, spaces should only be escaped
- # if necessary (i.e. leading or trailing space).
- NORMAL_ESCAPES = [',', '+', '"', '\\', '<', '>', ';', '='].freeze
-
- # The following must be represented as escaped hex
- HEX_ESCAPES = {
- "\n" => '\0a',
- "\r" => '\0d'
- }.freeze
-
- # Compiled character class regexp using the keys from the above hash, and
- # checking for a space or # at the start, or space at the end, of the
- # string.
- ESCAPE_RE = Regexp.new("(^ |^#| $|[" +
- NORMAL_ESCAPES.map { |e| Regexp.escape(e) }.join +
- "])")
-
- HEX_ESCAPE_RE = Regexp.new("([" +
- HEX_ESCAPES.keys.map { |e| Regexp.escape(e) }.join +
- "])")
-
- ##
- # Escape a string for use in a DN value
- def self.escape(string)
- escaped = string.gsub(ESCAPE_RE) { |char| "\\" + char }
- escaped.gsub(HEX_ESCAPE_RE) { |char| HEX_ESCAPES[char] }
- end
-
- private
-
- def initialize_array(args)
- buffer = StringIO.new
-
- args.each_with_index do |arg, index|
- if index.even? # key
- buffer << "," if index > 0
- buffer << arg
- else # value
- buffer << "="
- buffer << self.class.escape(arg)
- end
- end
-
- @dn = buffer.string
- end
-
- def initialize_string(arg)
- @dn = arg.to_s
- end
-
- ##
- # Proxy all other requests to the string object, because a DN is mainly
- # used within the library as a string
- # rubocop:disable GitlabSecurity/PublicSend
- def method_missing(method, *args, &block)
- @dn.send(method, *args, &block)
- end
-
- ##
- # Redefined to be consistent with redefined `method_missing` behavior
- def respond_to?(sym, include_private = false)
- @dn.respond_to?(sym, include_private)
- end
- end
- end
- end
- end
-
- def perform(start_id, end_id)
- return unless migrate?
-
- ldap_identities = Identity.where("provider like 'ldap%'").where(id: start_id..end_id)
- ldap_identities.each do |identity|
- identity.extern_uid = Gitlab::Auth::LDAP::DN.new(identity.extern_uid).to_normalized_s
- unless identity.save
- Rails.logger.info "Unable to normalize \"#{identity.extern_uid}\". Skipping."
- end
- rescue Gitlab::Auth::LDAP::DN::FormatError => e
- Rails.logger.info "Unable to normalize \"#{identity.extern_uid}\" due to \"#{e.message}\". Skipping."
- end
- end
-
- def migrate?
- Identity.table_exists?
- end
- end
- end
-end
diff --git a/lib/gitlab/background_migration/populate_fork_networks_range.rb b/lib/gitlab/background_migration/populate_fork_networks_range.rb
deleted file mode 100644
index aa4f130538c..00000000000
--- a/lib/gitlab/background_migration/populate_fork_networks_range.rb
+++ /dev/null
@@ -1,128 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module BackgroundMigration
- # This background migration is going to create all `fork_networks` and
- # the `fork_network_members` for the roots of fork networks based on the
- # existing `forked_project_links`.
- #
- # When the source of a fork is deleted, we will create the fork with the
- # target project as the root. This way, when there are forks of the target
- # project, they will be joined into the same fork network.
- #
- # When the `fork_networks` and memberships for the root projects are created
- # the `CreateForkNetworkMembershipsRange` migration is scheduled. This
- # migration will create the memberships for all remaining forks-of-forks
- class PopulateForkNetworksRange
- def perform(start_id, end_id)
- create_fork_networks_for_existing_projects(start_id, end_id)
- create_fork_networks_for_missing_projects(start_id, end_id)
- create_fork_networks_memberships_for_root_projects(start_id, end_id)
-
- delay = BackgroundMigration::CreateForkNetworkMembershipsRange::RESCHEDULE_DELAY
- BackgroundMigrationWorker.perform_in(
- delay, "CreateForkNetworkMembershipsRange", [start_id, end_id]
- )
- end
-
- def create_fork_networks_for_existing_projects(start_id, end_id)
- log("Creating fork networks: #{start_id} - #{end_id}")
- ActiveRecord::Base.connection.execute <<~INSERT_NETWORKS
- INSERT INTO fork_networks (root_project_id)
- SELECT DISTINCT forked_project_links.forked_from_project_id
-
- FROM forked_project_links
-
- -- Exclude the forks that are not the first level fork of a project
- WHERE NOT EXISTS (
- SELECT true
- FROM forked_project_links inner_links
- WHERE inner_links.forked_to_project_id = forked_project_links.forked_from_project_id
- )
-
- /* Exclude the ones that are already created, in case the fork network
- was already created for another fork of the project.
- */
- AND NOT EXISTS (
- SELECT true
- FROM fork_networks
- WHERE forked_project_links.forked_from_project_id = fork_networks.root_project_id
- )
-
- -- Only create a fork network for a root project that still exists
- AND EXISTS (
- SELECT true
- FROM projects
- WHERE projects.id = forked_project_links.forked_from_project_id
- )
- AND forked_project_links.id BETWEEN #{start_id} AND #{end_id}
- INSERT_NETWORKS
- end
-
- def create_fork_networks_for_missing_projects(start_id, end_id)
- log("Creating fork networks with missing root: #{start_id} - #{end_id}")
- ActiveRecord::Base.connection.execute <<~INSERT_NETWORKS
- INSERT INTO fork_networks (root_project_id)
- SELECT DISTINCT forked_project_links.forked_to_project_id
-
- FROM forked_project_links
-
- -- Exclude forks that are not the root forks
- WHERE NOT EXISTS (
- SELECT true
- FROM forked_project_links inner_links
- WHERE inner_links.forked_to_project_id = forked_project_links.forked_from_project_id
- )
-
- /* Exclude the ones that are already created, in case this migration is
- re-run
- */
- AND NOT EXISTS (
- SELECT true
- FROM fork_networks
- WHERE forked_project_links.forked_to_project_id = fork_networks.root_project_id
- )
-
- /* Exclude projects for which the project still exists, those are
- Processed in the previous step of this migration
- */
- AND NOT EXISTS (
- SELECT true
- FROM projects
- WHERE projects.id = forked_project_links.forked_from_project_id
- )
- AND forked_project_links.id BETWEEN #{start_id} AND #{end_id}
- INSERT_NETWORKS
- end
-
- def create_fork_networks_memberships_for_root_projects(start_id, end_id)
- log("Creating memberships for root projects: #{start_id} - #{end_id}")
-
- ActiveRecord::Base.connection.execute <<~INSERT_ROOT
- INSERT INTO fork_network_members (fork_network_id, project_id)
- SELECT DISTINCT fork_networks.id, fork_networks.root_project_id
-
- FROM fork_networks
-
- /* Joining both on forked_from- and forked_to- so we could create the
- memberships for forks for which the source was deleted
- */
- INNER JOIN forked_project_links
- ON forked_project_links.forked_from_project_id = fork_networks.root_project_id
- OR forked_project_links.forked_to_project_id = fork_networks.root_project_id
-
- WHERE NOT EXISTS (
- SELECT true
- FROM fork_network_members
- WHERE fork_network_members.project_id = fork_networks.root_project_id
- )
- AND forked_project_links.id BETWEEN #{start_id} AND #{end_id}
- INSERT_ROOT
- end
-
- def log(message)
- Rails.logger.info("#{self.class.name} - #{message}")
- end
- end
- end
-end
diff --git a/lib/gitlab/background_migration/populate_merge_requests_latest_merge_request_diff_id.rb b/lib/gitlab/background_migration/populate_merge_requests_latest_merge_request_diff_id.rb
deleted file mode 100644
index dcac355e1b0..00000000000
--- a/lib/gitlab/background_migration/populate_merge_requests_latest_merge_request_diff_id.rb
+++ /dev/null
@@ -1,33 +0,0 @@
-# frozen_string_literal: true
-# rubocop:disable Style/Documentation
-
-module Gitlab
- module BackgroundMigration
- class PopulateMergeRequestsLatestMergeRequestDiffId
- BATCH_SIZE = 1_000
-
- class MergeRequest < ActiveRecord::Base
- self.table_name = 'merge_requests'
-
- include ::EachBatch
- end
-
- def perform(start_id, stop_id)
- update = '
- latest_merge_request_diff_id = (
- SELECT MAX(id)
- FROM merge_request_diffs
- WHERE merge_requests.id = merge_request_diffs.merge_request_id
- )'.squish
-
- MergeRequest
- .where(id: start_id..stop_id)
- .where(latest_merge_request_diff_id: nil)
- .each_batch(of: BATCH_SIZE) do |relation|
-
- relation.update_all(update)
- end
- end
- end
- end
-end
diff --git a/lib/gitlab/ci/config.rb b/lib/gitlab/ci/config.rb
index 7aeac11df55..cde042c5e0a 100644
--- a/lib/gitlab/ci/config.rb
+++ b/lib/gitlab/ci/config.rb
@@ -23,6 +23,11 @@ module Gitlab
@root = Entry::Root.new(@config)
@root.compose!
+
+ rescue Gitlab::Config::Loader::Yaml::DataTooLargeError => e
+ Gitlab::Sentry.track_exception(e, extra: { user: user.inspect, project: project.inspect })
+ raise Config::ConfigError, e.message
+
rescue *rescue_errors => e
raise Config::ConfigError, e.message
end
diff --git a/lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml b/lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml
index 65a6630365d..cf3d261c1cb 100644
--- a/lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml
@@ -74,16 +74,16 @@ stages:
- cleanup
include:
- - template: Jobs/Build.gitlab-ci.yml
- - template: Jobs/Test.gitlab-ci.yml
- - template: Jobs/Code-Quality.gitlab-ci.yml
- - template: Jobs/Deploy.gitlab-ci.yml
- - template: Jobs/Browser-Performance-Testing.gitlab-ci.yml
- - template: Security/DAST.gitlab-ci.yml
- - template: Security/Container-Scanning.gitlab-ci.yml
- - template: Security/Dependency-Scanning.gitlab-ci.yml
- - template: Security/License-Management.gitlab-ci.yml
- - template: Security/SAST.gitlab-ci.yml
+ - template: Jobs/Build.gitlab-ci.yml # https://gitlab.com/gitlab-org/gitlab-ce/blob/master/lib/gitlab/ci/templates/Jobs/Build.gitlab-ci.yml
+ - template: Jobs/Test.gitlab-ci.yml # https://gitlab.com/gitlab-org/gitlab-ce/blob/master/lib/gitlab/ci/templates/Jobs/Test.gitlab-ci.yml
+ - template: Jobs/Code-Quality.gitlab-ci.yml # https://gitlab.com/gitlab-org/gitlab-ce/blob/master/lib/gitlab/ci/templates/Jobs/Code-Quality.gitlab-ci.yml
+ - template: Jobs/Deploy.gitlab-ci.yml # https://gitlab.com/gitlab-org/gitlab-ce/blob/master/lib/gitlab/ci/templates/Jobs/Deploy.gitlab-ci.yml
+ - template: Jobs/Browser-Performance-Testing.gitlab-ci.yml # https://gitlab.com/gitlab-org/gitlab-ce/blob/master/lib/gitlab/ci/templates/Jobs/Browser-Performance-Testing.gitlab-ci.yml
+ - template: Security/DAST.gitlab-ci.yml # https://gitlab.com/gitlab-org/gitlab-ce/blob/master/lib/gitlab/ci/templates/Security/DAST.gitlab-ci.yml
+ - template: Security/Container-Scanning.gitlab-ci.yml # https://gitlab.com/gitlab-org/gitlab-ce/blob/master/lib/gitlab/ci/templates/Security/Container-Scanning.gitlab-ci.yml
+ - template: Security/Dependency-Scanning.gitlab-ci.yml # https://gitlab.com/gitlab-org/gitlab-ce/blob/master/lib/gitlab/ci/templates/Security/Dependency-Scanning.gitlab-ci.yml
+ - template: Security/License-Management.gitlab-ci.yml # https://gitlab.com/gitlab-org/gitlab-ce/blob/master/lib/gitlab/ci/templates/Security/License-Management.gitlab-ci.yml
+ - template: Security/SAST.gitlab-ci.yml # https://gitlab.com/gitlab-org/gitlab-ce/blob/master/lib/gitlab/ci/templates/Security/SAST.gitlab-ci.yml
# Override DAST job to exclude master branch
dast:
diff --git a/lib/gitlab/ci/templates/Jobs/Deploy.gitlab-ci.yml b/lib/gitlab/ci/templates/Jobs/Deploy.gitlab-ci.yml
index dcf8254ef94..108f0119ae1 100644
--- a/lib/gitlab/ci/templates/Jobs/Deploy.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Jobs/Deploy.gitlab-ci.yml
@@ -246,7 +246,6 @@ rollout 100%:
auto_database_url=postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@${CI_ENVIRONMENT_SLUG}-postgres:5432/${POSTGRES_DB}
export DATABASE_URL=${DATABASE_URL-$auto_database_url}
export TILLER_NAMESPACE=$KUBE_NAMESPACE
- # Extract "MAJOR.MINOR" from CI_SERVER_VERSION and generate "MAJOR-MINOR-stable" for Security Products
function get_replicas() {
track="${1:-stable}"
diff --git a/lib/gitlab/ci/templates/PHP.gitlab-ci.yml b/lib/gitlab/ci/templates/PHP.gitlab-ci.yml
index b9fee2d5731..25ea20e454f 100644
--- a/lib/gitlab/ci/templates/PHP.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/PHP.gitlab-ci.yml
@@ -1,5 +1,5 @@
# Select image from https://hub.docker.com/_/php/
-image: php:7.1.1
+image: php:latest
# Select what we should cache between builds
cache:
diff --git a/lib/gitlab/ci/templates/Pages/Jekyll.gitlab-ci.yml b/lib/gitlab/ci/templates/Pages/Jekyll.gitlab-ci.yml
index 0d742aa282d..e7dacd3a1fc 100644
--- a/lib/gitlab/ci/templates/Pages/Jekyll.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Pages/Jekyll.gitlab-ci.yml
@@ -4,6 +4,7 @@ image: ruby:2.3
variables:
JEKYLL_ENV: production
+ LC_ALL: C.UTF-8
before_script:
- bundle install
diff --git a/lib/gitlab/ci/templates/Security/SAST.gitlab-ci.yml b/lib/gitlab/ci/templates/Security/SAST.gitlab-ci.yml
index 8713b833011..0a97a16b83c 100644
--- a/lib/gitlab/ci/templates/Security/SAST.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Security/SAST.gitlab-ci.yml
@@ -54,6 +54,7 @@ sast:
MAVEN_PATH \
MAVEN_REPO_PATH \
SBT_PATH \
+ FAIL_NEVER \
) \
--volume "$PWD:/code" \
--volume /var/run/docker.sock:/var/run/docker.sock \
diff --git a/lib/gitlab/cluster/lifecycle_events.rb b/lib/gitlab/cluster/lifecycle_events.rb
index e0f9eb59924..8f796748199 100644
--- a/lib/gitlab/cluster/lifecycle_events.rb
+++ b/lib/gitlab/cluster/lifecycle_events.rb
@@ -11,6 +11,9 @@ module Gitlab
# We have three lifecycle events.
#
# - before_fork (only in forking processes)
+ # In forking processes (Unicorn and Puma in multiprocess mode) this
+ # will be called exactly once, on startup, before the workers are
+ # forked. This will be called in the parent process.
# - worker_start
# - before_master_restart (only in forking processes)
#
diff --git a/lib/gitlab/config/loader/yaml.rb b/lib/gitlab/config/loader/yaml.rb
index 8159f8b8026..4cedab1545c 100644
--- a/lib/gitlab/config/loader/yaml.rb
+++ b/lib/gitlab/config/loader/yaml.rb
@@ -4,6 +4,13 @@ module Gitlab
module Config
module Loader
class Yaml
+ DataTooLargeError = Class.new(Loader::FormatError)
+
+ include Gitlab::Utils::StrongMemoize
+
+ MAX_YAML_SIZE = 1.megabyte
+ MAX_YAML_DEPTH = 100
+
def initialize(config)
@config = YAML.safe_load(config, [Symbol], [], true)
rescue Psych::Exception => e
@@ -11,16 +18,35 @@ module Gitlab
end
def valid?
- @config.is_a?(Hash)
+ hash? && !too_big?
end
def load!
- unless valid?
- raise Loader::FormatError, 'Invalid configuration format'
- end
+ raise DataTooLargeError, 'The parsed YAML is too big' if too_big?
+ raise Loader::FormatError, 'Invalid configuration format' unless hash?
@config.deep_symbolize_keys
end
+
+ private
+
+ def hash?
+ @config.is_a?(Hash)
+ end
+
+ def too_big?
+ return false unless Feature.enabled?(:ci_yaml_limit_size, default_enabled: true)
+
+ !deep_size.valid?
+ end
+
+ def deep_size
+ strong_memoize(:deep_size) do
+ Gitlab::Utils::DeepSize.new(@config,
+ max_size: MAX_YAML_SIZE,
+ max_depth: MAX_YAML_DEPTH)
+ end
+ end
end
end
end
diff --git a/lib/gitlab/danger/helper.rb b/lib/gitlab/danger/helper.rb
index 1ecf4a12db7..0fc145534bf 100644
--- a/lib/gitlab/danger/helper.rb
+++ b/lib/gitlab/danger/helper.rb
@@ -103,6 +103,11 @@ module Gitlab
yarn\.lock
)\z}x => :frontend,
+ %r{\A(ee/)?db/} => :database,
+ %r{\A(ee/)?lib/gitlab/(database|background_migration|sql|github_import)(/|\.rb)} => :database,
+ %r{\A(app/models/project_authorization|app/services/users/refresh_authorized_projects_service)(/|\.rb)} => :database,
+ %r{\Arubocop/cop/migration(/|\.rb)} => :database,
+
%r{\A(ee/)?app/(?!assets|views)[^/]+} => :backend,
%r{\A(ee/)?(bin|config|danger|generator_templates|lib|rubocop|scripts)/} => :backend,
%r{\A(ee/)?spec/features/} => :test,
@@ -112,7 +117,6 @@ module Gitlab
%r{\A(Dangerfile|Gemfile|Gemfile.lock|Procfile|Rakefile|\.gitlab-ci\.yml)\z} => :backend,
%r{\A[A-Z_]+_VERSION\z} => :backend,
- %r{\A(ee/)?db/} => :database,
%r{\A(ee/)?qa/} => :qa,
# Files that don't fit into any category are marked with :none
diff --git a/lib/gitlab/database/median.rb b/lib/gitlab/database/median.rb
index 1455e410d4b..b8d895dee7d 100644
--- a/lib/gitlab/database/median.rb
+++ b/lib/gitlab/database/median.rb
@@ -158,7 +158,7 @@ module Gitlab
Arel::Nodes::Window.new.order(arel_table[column_sym])
).as('row_id')
- count = arel_table.project("COUNT(1)").as('ct')
+ count = arel_table.where(arel_table[column_sym].gteq(zero_interval)).project("COUNT(1)").as('ct')
[column_row, row_id, count]
end
diff --git a/lib/gitlab/diff/lines_unfolder.rb b/lib/gitlab/diff/lines_unfolder.rb
index 6cf904b2b2a..0bd18fe9622 100644
--- a/lib/gitlab/diff/lines_unfolder.rb
+++ b/lib/gitlab/diff/lines_unfolder.rb
@@ -54,7 +54,7 @@ module Gitlab
def unfold_required?
strong_memoize(:unfold_required) do
next false unless @diff_file.text?
- next false unless @position.unchanged?
+ next false unless @position.on_text? && @position.unchanged?
next false if @diff_file.new_file? || @diff_file.deleted_file?
next false unless @position.old_line
# Invalid position (MR import scenario)
diff --git a/lib/gitlab/diff/position.rb b/lib/gitlab/diff/position.rb
index d349c378e53..dfa80eb4a64 100644
--- a/lib/gitlab/diff/position.rb
+++ b/lib/gitlab/diff/position.rb
@@ -134,6 +134,10 @@ module Gitlab
@line_code ||= diff_file(repository)&.line_code_for_position(self)
end
+ def file_hash
+ @file_hash ||= Digest::SHA1.hexdigest(file_path)
+ end
+
def on_image?
position_type == 'image'
end
diff --git a/lib/gitlab/diff/position_tracer.rb b/lib/gitlab/diff/position_tracer.rb
index af3df820422..a1c82ce9afc 100644
--- a/lib/gitlab/diff/position_tracer.rb
+++ b/lib/gitlab/diff/position_tracer.rb
@@ -17,187 +17,13 @@ module Gitlab
@paths = paths
end
- def trace(ab_position)
+ def trace(old_position)
return unless old_diff_refs&.complete? && new_diff_refs&.complete?
- return unless ab_position.diff_refs == old_diff_refs
+ return unless old_position.diff_refs == old_diff_refs
- # Suppose we have an MR with source branch `feature` and target branch `master`.
- # When the MR was created, the head of `master` was commit A, and the
- # head of `feature` was commit B, resulting in the original diff A->B.
- # Since creation, `master` was updated to C.
- # Now `feature` is being updated to D, and the newly generated MR diff is C->D.
- # It is possible that C and D are direct descendants of A and B respectively,
- # but this isn't necessarily the case as rebases and merges come into play.
- #
- # Suppose we have a diff note on the original diff A->B. Now that the MR
- # is updated, we need to find out what line in C->D corresponds to the
- # line the note was originally created on, so that we can update the diff note's
- # records and continue to display it in the right place in the diffs.
- # If we cannot find this line in the new diff, this means the diff note is now
- # outdated, and we will display that fact to the user.
- #
- # In the new diff, the file the diff note was originally created on may
- # have been renamed, deleted or even created, if the file existed in A and B,
- # but was removed in C, and restored in D.
- #
- # Every diff note stores a Position object that defines a specific location,
- # identified by paths and line numbers, within a specific diff, identified
- # by start, head and base commit ids.
- #
- # For diff notes for diff A->B, the position looks like this:
- # Position
- # start_sha - ID of commit A
- # head_sha - ID of commit B
- # base_sha - ID of base commit of A and B
- # old_path - path as of A (nil if file was newly created)
- # new_path - path as of B (nil if file was deleted)
- # old_line - line number as of A (nil if file was newly created)
- # new_line - line number as of B (nil if file was deleted)
- #
- # We can easily update `start_sha` and `head_sha` to hold the IDs of
- # commits C and D, and can trivially determine `base_sha` based on those,
- # but need to find the paths and line numbers as of C and D.
- #
- # If the file was unchanged or newly created in A->B, the path as of D can be found
- # by generating diff B->D ("head to head"), finding the diff file with
- # `diff_file.old_path == position.new_path`, and taking `diff_file.new_path`.
- # The path as of C can be found by taking diff C->D, finding the diff file
- # with that same `new_path` and taking `diff_file.old_path`.
- # The line number as of D can be found by using the LineMapper on diff B->D
- # and providing the line number as of B.
- # The line number as of C can be found by using the LineMapper on diff C->D
- # and providing the line number as of D.
- #
- # If the file was deleted in A->B, the path as of C can be found
- # by generating diff A->C ("base to base"), finding the diff file with
- # `diff_file.old_path == position.old_path`, and taking `diff_file.new_path`.
- # The path as of D can be found by taking diff C->D, finding the diff file
- # with `old_path` set to that `diff_file.new_path` and taking `diff_file.new_path`.
- # The line number as of C can be found by using the LineMapper on diff A->C
- # and providing the line number as of A.
- # The line number as of D can be found by using the LineMapper on diff C->D
- # and providing the line number as of C.
+ strategy = old_position.on_text? ? LineStrategy : ImageStrategy
- if ab_position.added?
- trace_added_line(ab_position)
- elsif ab_position.removed?
- trace_removed_line(ab_position)
- else # unchanged
- trace_unchanged_line(ab_position)
- end
- end
-
- private
-
- def trace_added_line(ab_position)
- b_path = ab_position.new_path
- b_line = ab_position.new_line
-
- bd_diff = bd_diffs.diff_file_with_old_path(b_path)
-
- d_path = bd_diff&.new_path || b_path
- d_line = LineMapper.new(bd_diff).old_to_new(b_line)
-
- if d_line
- cd_diff = cd_diffs.diff_file_with_new_path(d_path)
-
- c_path = cd_diff&.old_path || d_path
- c_line = LineMapper.new(cd_diff).new_to_old(d_line)
-
- if c_line
- # If the line is still in D but also in C, it has turned from an
- # added line into an unchanged one.
- new_position = position(cd_diff, c_line, d_line)
- if valid_position?(new_position)
- # If the line is still in the MR, we don't treat this as outdated.
- { position: new_position, outdated: false }
- else
- # If the line is no longer in the MR, we unfortunately cannot show
- # the current state on the CD diff, so we treat it as outdated.
- ac_diff = ac_diffs.diff_file_with_new_path(c_path)
-
- { position: position(ac_diff, nil, c_line), outdated: true }
- end
- else
- # If the line is still in D and not in C, it is still added.
- { position: position(cd_diff, nil, d_line), outdated: false }
- end
- else
- # If the line is no longer in D, it has been removed from the MR.
- { position: position(bd_diff, b_line, nil), outdated: true }
- end
- end
-
- def trace_removed_line(ab_position)
- a_path = ab_position.old_path
- a_line = ab_position.old_line
-
- ac_diff = ac_diffs.diff_file_with_old_path(a_path)
-
- c_path = ac_diff&.new_path || a_path
- c_line = LineMapper.new(ac_diff).old_to_new(a_line)
-
- if c_line
- cd_diff = cd_diffs.diff_file_with_old_path(c_path)
-
- d_path = cd_diff&.new_path || c_path
- d_line = LineMapper.new(cd_diff).old_to_new(c_line)
-
- if d_line
- # If the line is still in C but also in D, it has turned from a
- # removed line into an unchanged one.
- bd_diff = bd_diffs.diff_file_with_new_path(d_path)
-
- { position: position(bd_diff, nil, d_line), outdated: true }
- else
- # If the line is still in C and not in D, it is still removed.
- { position: position(cd_diff, c_line, nil), outdated: false }
- end
- else
- # If the line is no longer in C, it has been removed outside of the MR.
- { position: position(ac_diff, a_line, nil), outdated: true }
- end
- end
-
- def trace_unchanged_line(ab_position)
- a_path = ab_position.old_path
- a_line = ab_position.old_line
- b_path = ab_position.new_path
- b_line = ab_position.new_line
-
- ac_diff = ac_diffs.diff_file_with_old_path(a_path)
-
- c_path = ac_diff&.new_path || a_path
- c_line = LineMapper.new(ac_diff).old_to_new(a_line)
-
- bd_diff = bd_diffs.diff_file_with_old_path(b_path)
-
- d_line = LineMapper.new(bd_diff).old_to_new(b_line)
-
- cd_diff = cd_diffs.diff_file_with_old_path(c_path)
-
- if c_line && d_line
- # If the line is still in C and D, it is still unchanged.
- new_position = position(cd_diff, c_line, d_line)
- if valid_position?(new_position)
- # If the line is still in the MR, we don't treat this as outdated.
- { position: new_position, outdated: false }
- else
- # If the line is no longer in the MR, we unfortunately cannot show
- # the current state on the CD diff or any change on the BD diff,
- # so we treat it as outdated.
- { position: nil, outdated: true }
- end
- elsif d_line # && !c_line
- # If the line is still in D but no longer in C, it has turned from
- # an unchanged line into an added one.
- # We don't treat this as outdated since the line is still in the MR.
- { position: position(cd_diff, nil, d_line), outdated: false }
- else # !d_line && (c_line || !c_line)
- # If the line is no longer in D, it has turned from an unchanged line
- # into a removed one.
- { position: position(bd_diff, b_line, nil), outdated: true }
- end
+ strategy.new(self).trace(old_position)
end
def ac_diffs
@@ -216,18 +42,12 @@ module Gitlab
@cd_diffs ||= compare(new_diff_refs.start_sha, new_diff_refs.head_sha)
end
+ private
+
def compare(start_sha, head_sha, straight: false)
compare = CompareService.new(project, head_sha).execute(project, start_sha, straight: straight)
compare.diffs(paths: paths, expanded: true)
end
-
- def position(diff_file, old_line, new_line)
- Position.new(diff_file: diff_file, old_line: old_line, new_line: new_line)
- end
-
- def valid_position?(position)
- !!position.diff_line(project.repository)
- end
end
end
end
diff --git a/lib/gitlab/diff/position_tracer/base_strategy.rb b/lib/gitlab/diff/position_tracer/base_strategy.rb
new file mode 100644
index 00000000000..65049daabf4
--- /dev/null
+++ b/lib/gitlab/diff/position_tracer/base_strategy.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Diff
+ class PositionTracer
+ class BaseStrategy
+ attr_reader :tracer
+
+ delegate \
+ :project,
+ :ac_diffs,
+ :bd_diffs,
+ :cd_diffs,
+ to: :tracer
+
+ def initialize(tracer)
+ @tracer = tracer
+ end
+
+ def trace(position)
+ raise NotImplementedError
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/diff/position_tracer/image_strategy.rb b/lib/gitlab/diff/position_tracer/image_strategy.rb
new file mode 100644
index 00000000000..79244a17951
--- /dev/null
+++ b/lib/gitlab/diff/position_tracer/image_strategy.rb
@@ -0,0 +1,50 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Diff
+ class PositionTracer
+ class ImageStrategy < BaseStrategy
+ def trace(position)
+ b_path = position.new_path
+
+ # If file exists in B->D (e.g. updated, renamed, removed), let the
+ # note become outdated.
+ bd_diff = bd_diffs.diff_file_with_old_path(b_path)
+
+ return { position: new_position(position, bd_diff), outdated: true } if bd_diff
+
+ # If file still exists in the new diff, update the position.
+ cd_diff = cd_diffs.diff_file_with_new_path(bd_diff&.new_path || b_path)
+
+ return { position: new_position(position, cd_diff), outdated: false } if cd_diff
+
+ # If file exists in A->C (e.g. rebased and same changes were present
+ # in target branch), let the note become outdated.
+ ac_diff = ac_diffs.diff_file_with_old_path(position.old_path)
+
+ return { position: new_position(position, ac_diff), outdated: true } if ac_diff
+
+ # If ever there's a case that the file no longer exists in any diff,
+ # don't set a change position and let the note become outdated.
+ #
+ # This should never happen given the file should exist in one of the
+ # diffs above.
+ { outdated: true }
+ end
+
+ private
+
+ def new_position(position, diff_file)
+ Position.new(
+ diff_file: diff_file,
+ x: position.x,
+ y: position.y,
+ width: position.width,
+ height: position.height,
+ position_type: position.position_type
+ )
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/diff/position_tracer/line_strategy.rb b/lib/gitlab/diff/position_tracer/line_strategy.rb
new file mode 100644
index 00000000000..8db0fc6f963
--- /dev/null
+++ b/lib/gitlab/diff/position_tracer/line_strategy.rb
@@ -0,0 +1,201 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Diff
+ class PositionTracer
+ class LineStrategy < BaseStrategy
+ def trace(position)
+ # Suppose we have an MR with source branch `feature` and target branch `master`.
+ # When the MR was created, the head of `master` was commit A, and the
+ # head of `feature` was commit B, resulting in the original diff A->B.
+ # Since creation, `master` was updated to C.
+ # Now `feature` is being updated to D, and the newly generated MR diff is C->D.
+ # It is possible that C and D are direct descendants of A and B respectively,
+ # but this isn't necessarily the case as rebases and merges come into play.
+ #
+ # Suppose we have a diff note on the original diff A->B. Now that the MR
+ # is updated, we need to find out what line in C->D corresponds to the
+ # line the note was originally created on, so that we can update the diff note's
+ # records and continue to display it in the right place in the diffs.
+ # If we cannot find this line in the new diff, this means the diff note is now
+ # outdated, and we will display that fact to the user.
+ #
+ # In the new diff, the file the diff note was originally created on may
+ # have been renamed, deleted or even created, if the file existed in A and B,
+ # but was removed in C, and restored in D.
+ #
+ # Every diff note stores a Position object that defines a specific location,
+ # identified by paths and line numbers, within a specific diff, identified
+ # by start, head and base commit ids.
+ #
+ # For diff notes for diff A->B, the position looks like this:
+ # Position
+ # start_sha - ID of commit A
+ # head_sha - ID of commit B
+ # base_sha - ID of base commit of A and B
+ # old_path - path as of A (nil if file was newly created)
+ # new_path - path as of B (nil if file was deleted)
+ # old_line - line number as of A (nil if file was newly created)
+ # new_line - line number as of B (nil if file was deleted)
+ #
+ # We can easily update `start_sha` and `head_sha` to hold the IDs of
+ # commits C and D, and can trivially determine `base_sha` based on those,
+ # but need to find the paths and line numbers as of C and D.
+ #
+ # If the file was unchanged or newly created in A->B, the path as of D can be found
+ # by generating diff B->D ("head to head"), finding the diff file with
+ # `diff_file.old_path == position.new_path`, and taking `diff_file.new_path`.
+ # The path as of C can be found by taking diff C->D, finding the diff file
+ # with that same `new_path` and taking `diff_file.old_path`.
+ # The line number as of D can be found by using the LineMapper on diff B->D
+ # and providing the line number as of B.
+ # The line number as of C can be found by using the LineMapper on diff C->D
+ # and providing the line number as of D.
+ #
+ # If the file was deleted in A->B, the path as of C can be found
+ # by generating diff A->C ("base to base"), finding the diff file with
+ # `diff_file.old_path == position.old_path`, and taking `diff_file.new_path`.
+ # The path as of D can be found by taking diff C->D, finding the diff file
+ # with `old_path` set to that `diff_file.new_path` and taking `diff_file.new_path`.
+ # The line number as of C can be found by using the LineMapper on diff A->C
+ # and providing the line number as of A.
+ # The line number as of D can be found by using the LineMapper on diff C->D
+ # and providing the line number as of C.
+
+ if position.added?
+ trace_added_line(position)
+ elsif position.removed?
+ trace_removed_line(position)
+ else # unchanged
+ trace_unchanged_line(position)
+ end
+ end
+
+ private
+
+ def trace_added_line(position)
+ b_path = position.new_path
+ b_line = position.new_line
+
+ bd_diff = bd_diffs.diff_file_with_old_path(b_path)
+
+ d_path = bd_diff&.new_path || b_path
+ d_line = LineMapper.new(bd_diff).old_to_new(b_line)
+
+ if d_line
+ cd_diff = cd_diffs.diff_file_with_new_path(d_path)
+
+ c_path = cd_diff&.old_path || d_path
+ c_line = LineMapper.new(cd_diff).new_to_old(d_line)
+
+ if c_line
+ # If the line is still in D but also in C, it has turned from an
+ # added line into an unchanged one.
+ new_position = new_position(cd_diff, c_line, d_line)
+ if valid_position?(new_position)
+ # If the line is still in the MR, we don't treat this as outdated.
+ { position: new_position, outdated: false }
+ else
+ # If the line is no longer in the MR, we unfortunately cannot show
+ # the current state on the CD diff, so we treat it as outdated.
+ ac_diff = ac_diffs.diff_file_with_new_path(c_path)
+
+ { position: new_position(ac_diff, nil, c_line), outdated: true }
+ end
+ else
+ # If the line is still in D and not in C, it is still added.
+ { position: new_position(cd_diff, nil, d_line), outdated: false }
+ end
+ else
+ # If the line is no longer in D, it has been removed from the MR.
+ { position: new_position(bd_diff, b_line, nil), outdated: true }
+ end
+ end
+
+ def trace_removed_line(position)
+ a_path = position.old_path
+ a_line = position.old_line
+
+ ac_diff = ac_diffs.diff_file_with_old_path(a_path)
+
+ c_path = ac_diff&.new_path || a_path
+ c_line = LineMapper.new(ac_diff).old_to_new(a_line)
+
+ if c_line
+ cd_diff = cd_diffs.diff_file_with_old_path(c_path)
+
+ d_path = cd_diff&.new_path || c_path
+ d_line = LineMapper.new(cd_diff).old_to_new(c_line)
+
+ if d_line
+ # If the line is still in C but also in D, it has turned from a
+ # removed line into an unchanged one.
+ bd_diff = bd_diffs.diff_file_with_new_path(d_path)
+
+ { position: new_position(bd_diff, nil, d_line), outdated: true }
+ else
+ # If the line is still in C and not in D, it is still removed.
+ { position: new_position(cd_diff, c_line, nil), outdated: false }
+ end
+ else
+ # If the line is no longer in C, it has been removed outside of the MR.
+ { position: new_position(ac_diff, a_line, nil), outdated: true }
+ end
+ end
+
+ def trace_unchanged_line(position)
+ a_path = position.old_path
+ a_line = position.old_line
+ b_path = position.new_path
+ b_line = position.new_line
+
+ ac_diff = ac_diffs.diff_file_with_old_path(a_path)
+
+ c_path = ac_diff&.new_path || a_path
+ c_line = LineMapper.new(ac_diff).old_to_new(a_line)
+
+ bd_diff = bd_diffs.diff_file_with_old_path(b_path)
+
+ d_line = LineMapper.new(bd_diff).old_to_new(b_line)
+
+ cd_diff = cd_diffs.diff_file_with_old_path(c_path)
+
+ if c_line && d_line
+ # If the line is still in C and D, it is still unchanged.
+ new_position = new_position(cd_diff, c_line, d_line)
+ if valid_position?(new_position)
+ # If the line is still in the MR, we don't treat this as outdated.
+ { position: new_position, outdated: false }
+ else
+ # If the line is no longer in the MR, we unfortunately cannot show
+ # the current state on the CD diff or any change on the BD diff,
+ # so we treat it as outdated.
+ { position: nil, outdated: true }
+ end
+ elsif d_line # && !c_line
+ # If the line is still in D but no longer in C, it has turned from
+ # an unchanged line into an added one.
+ # We don't treat this as outdated since the line is still in the MR.
+ { position: new_position(cd_diff, nil, d_line), outdated: false }
+ else # !d_line && (c_line || !c_line)
+ # If the line is no longer in D, it has turned from an unchanged line
+ # into a removed one.
+ { position: new_position(bd_diff, b_line, nil), outdated: true }
+ end
+ end
+
+ def new_position(diff_file, old_line, new_line)
+ Position.new(
+ diff_file: diff_file,
+ old_line: old_line,
+ new_line: new_line
+ )
+ end
+
+ def valid_position?(position)
+ !!position.diff_line(project.repository)
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb
index 19b6aab1c4f..060a29be782 100644
--- a/lib/gitlab/git/repository.rb
+++ b/lib/gitlab/git/repository.rb
@@ -536,9 +536,9 @@ module Gitlab
tags.find { |tag| tag.name == name }
end
- def merge_to_ref(user, source_sha, branch, target_ref, message)
+ def merge_to_ref(user, source_sha, branch, target_ref, message, first_parent_ref)
wrapped_gitaly_errors do
- gitaly_operation_client.user_merge_to_ref(user, source_sha, branch, target_ref, message)
+ gitaly_operation_client.user_merge_to_ref(user, source_sha, branch, target_ref, message, first_parent_ref)
end
end
diff --git a/lib/gitlab/git/rugged_impl/blob.rb b/lib/gitlab/git/rugged_impl/blob.rb
index 11ee4ebda4b..86c9f33d82a 100644
--- a/lib/gitlab/git/rugged_impl/blob.rb
+++ b/lib/gitlab/git/rugged_impl/blob.rb
@@ -11,10 +11,11 @@ module Gitlab
module Blob
module ClassMethods
extend ::Gitlab::Utils::Override
+ include Gitlab::Git::RuggedImpl::UseRugged
override :tree_entry
def tree_entry(repository, sha, path, limit)
- if Feature.enabled?(:rugged_tree_entry)
+ if use_rugged?(repository, :rugged_tree_entry)
rugged_tree_entry(repository, sha, path, limit)
else
super
diff --git a/lib/gitlab/git/rugged_impl/commit.rb b/lib/gitlab/git/rugged_impl/commit.rb
index bce4fa14fb4..971a33b2e99 100644
--- a/lib/gitlab/git/rugged_impl/commit.rb
+++ b/lib/gitlab/git/rugged_impl/commit.rb
@@ -12,6 +12,7 @@ module Gitlab
module Commit
module ClassMethods
extend ::Gitlab::Utils::Override
+ include Gitlab::Git::RuggedImpl::UseRugged
def rugged_find(repo, commit_id)
obj = repo.rev_parse_target(commit_id)
@@ -34,7 +35,7 @@ module Gitlab
override :find_commit
def find_commit(repo, commit_id)
- if Feature.enabled?(:rugged_find_commit)
+ if use_rugged?(repo, :rugged_find_commit)
rugged_find(repo, commit_id)
else
super
@@ -43,7 +44,7 @@ module Gitlab
override :batch_by_oid
def batch_by_oid(repo, oids)
- if Feature.enabled?(:rugged_list_commits_by_oid)
+ if use_rugged?(repo, :rugged_list_commits_by_oid)
rugged_batch_by_oid(repo, oids)
else
super
@@ -52,6 +53,7 @@ module Gitlab
end
extend ::Gitlab::Utils::Override
+ include Gitlab::Git::RuggedImpl::UseRugged
override :init_commit
def init_commit(raw_commit)
@@ -65,7 +67,7 @@ module Gitlab
override :commit_tree_entry
def commit_tree_entry(path)
- if Feature.enabled?(:rugged_commit_tree_entry)
+ if use_rugged?(@repository, :rugged_commit_tree_entry)
rugged_tree_entry(path)
else
super
diff --git a/lib/gitlab/git/rugged_impl/repository.rb b/lib/gitlab/git/rugged_impl/repository.rb
index e91b0ddcd31..9268abdfed9 100644
--- a/lib/gitlab/git/rugged_impl/repository.rb
+++ b/lib/gitlab/git/rugged_impl/repository.rb
@@ -11,6 +11,7 @@ module Gitlab
module RuggedImpl
module Repository
extend ::Gitlab::Utils::Override
+ include Gitlab::Git::RuggedImpl::UseRugged
FEATURE_FLAGS = %i(rugged_find_commit rugged_tree_entries rugged_tree_entry rugged_commit_is_ancestor rugged_commit_tree_entry rugged_list_commits_by_oid).freeze
@@ -46,7 +47,7 @@ module Gitlab
override :ancestor?
def ancestor?(from, to)
- if Feature.enabled?(:rugged_commit_is_ancestor)
+ if use_rugged?(self, :rugged_commit_is_ancestor)
rugged_is_ancestor?(from, to)
else
super
diff --git a/lib/gitlab/git/rugged_impl/tree.rb b/lib/gitlab/git/rugged_impl/tree.rb
index 9c37bb01961..f3721a3f1b7 100644
--- a/lib/gitlab/git/rugged_impl/tree.rb
+++ b/lib/gitlab/git/rugged_impl/tree.rb
@@ -11,10 +11,11 @@ module Gitlab
module Tree
module ClassMethods
extend ::Gitlab::Utils::Override
+ include Gitlab::Git::RuggedImpl::UseRugged
override :tree_entries
def tree_entries(repository, sha, path, recursive)
- if Feature.enabled?(:rugged_tree_entries)
+ if use_rugged?(repository, :rugged_tree_entries)
tree_entries_with_flat_path_from_rugged(repository, sha, path, recursive)
else
super
diff --git a/lib/gitlab/git/rugged_impl/use_rugged.rb b/lib/gitlab/git/rugged_impl/use_rugged.rb
new file mode 100644
index 00000000000..99091b03cd1
--- /dev/null
+++ b/lib/gitlab/git/rugged_impl/use_rugged.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Git
+ module RuggedImpl
+ module UseRugged
+ def use_rugged?(repo, feature_key)
+ feature = Feature.get(feature_key)
+ return feature.enabled? if Feature.persisted?(feature)
+
+ Gitlab::GitalyClient.can_use_disk?(repo.storage)
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/gitaly_client.rb b/lib/gitlab/gitaly_client.rb
index 47976389af6..cf0157269a8 100644
--- a/lib/gitlab/gitaly_client.rb
+++ b/lib/gitlab/gitaly_client.rb
@@ -30,14 +30,10 @@ module Gitlab
SERVER_VERSION_FILE = 'GITALY_SERVER_VERSION'
MAXIMUM_GITALY_CALLS = 30
CLIENT_NAME = (Sidekiq.server? ? 'gitlab-sidekiq' : 'gitlab-web').freeze
+ GITALY_METADATA_FILENAME = '.gitaly-metadata'
MUTEX = Mutex.new
- define_histogram :gitaly_controller_action_duration_seconds do
- docstring "Gitaly endpoint histogram by controller and action combination"
- base_labels Gitlab::Metrics::Transaction::BASE_LABELS.merge(gitaly_service: nil, rpc: nil)
- end
-
def self.stub(name, storage)
MUTEX.synchronize do
@stubs ||= {}
@@ -161,10 +157,6 @@ module Gitlab
# Keep track, separately, for the performance bar
self.query_time += duration
- gitaly_controller_action_duration_seconds.observe(
- current_transaction_labels.merge(gitaly_service: service.to_s, rpc: rpc.to_s),
- duration)
-
if peek_enabled?
add_call_details(feature: "#{service}##{rpc}", duration: duration, request: request_hash, rpc: rpc,
backtrace: Gitlab::Profiler.clean_backtrace(caller))
@@ -387,6 +379,45 @@ module Gitlab
0
end
+ def self.storage_metadata_file_path(storage)
+ Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+ File.join(
+ Gitlab.config.repositories.storages[storage].legacy_disk_path, GITALY_METADATA_FILENAME
+ )
+ end
+ end
+
+ def self.can_use_disk?(storage)
+ cached_value = MUTEX.synchronize do
+ @can_use_disk ||= {}
+ @can_use_disk[storage]
+ end
+
+ return cached_value unless cached_value.nil?
+
+ gitaly_filesystem_id = filesystem_id(storage)
+ direct_filesystem_id = filesystem_id_from_disk(storage)
+
+ MUTEX.synchronize do
+ @can_use_disk[storage] = gitaly_filesystem_id.present? &&
+ gitaly_filesystem_id == direct_filesystem_id
+ end
+ end
+
+ def self.filesystem_id(storage)
+ response = Gitlab::GitalyClient::ServerService.new(storage).info
+ storage_status = response.storage_statuses.find { |status| status.storage_name == storage }
+ storage_status.filesystem_id
+ end
+
+ def self.filesystem_id_from_disk(storage)
+ metadata_file = File.read(storage_metadata_file_path(storage))
+ metadata_hash = JSON.parse(metadata_file)
+ metadata_hash['gitaly_filesystem_id']
+ rescue Errno::ENOENT, JSON::ParserError
+ nil
+ end
+
def self.timeout(timeout_name)
Gitlab::CurrentSettings.current_application_settings[timeout_name]
end
diff --git a/lib/gitlab/gitaly_client/operation_service.rb b/lib/gitlab/gitaly_client/operation_service.rb
index b42e6cbad8d..783c2ff0915 100644
--- a/lib/gitlab/gitaly_client/operation_service.rb
+++ b/lib/gitlab/gitaly_client/operation_service.rb
@@ -100,14 +100,15 @@ module Gitlab
end
end
- def user_merge_to_ref(user, source_sha, branch, target_ref, message)
+ def user_merge_to_ref(user, source_sha, branch, target_ref, message, first_parent_ref)
request = Gitaly::UserMergeToRefRequest.new(
repository: @gitaly_repo,
source_sha: source_sha,
branch: encode_binary(branch),
target_ref: encode_binary(target_ref),
user: Gitlab::Git::User.from_gitlab(user).to_gitaly,
- message: encode_binary(message)
+ message: encode_binary(message),
+ first_parent_ref: encode_binary(first_parent_ref)
)
response = GitalyClient.call(@repository.storage, :operation_service, :user_merge_to_ref, request)
diff --git a/lib/gitlab/gon_helper.rb b/lib/gitlab/gon_helper.rb
index 92917028851..41ec8741eb1 100644
--- a/lib/gitlab/gon_helper.rb
+++ b/lib/gitlab/gon_helper.rb
@@ -38,6 +38,11 @@ module Gitlab
gon.current_user_fullname = current_user.name
gon.current_user_avatar_url = current_user.avatar_url
end
+
+ # Flag controls a GFM feature used across many routes.
+ # Pushing the flag from one place simplifies control
+ # and facilitates easy removal.
+ push_frontend_feature_flag(:gfm_embedded_metrics)
end
# Exposes the state of a feature flag to the frontend code.
diff --git a/lib/gitlab/graphql.rb b/lib/gitlab/graphql.rb
index 8a59e83974f..74c04e5380e 100644
--- a/lib/gitlab/graphql.rb
+++ b/lib/gitlab/graphql.rb
@@ -3,9 +3,5 @@
module Gitlab
module Graphql
StandardGraphqlError = Class.new(StandardError)
-
- def self.enabled?
- Feature.enabled?(:graphql, default_enabled: true)
- end
end
end
diff --git a/lib/gitlab/graphql/authorize.rb b/lib/gitlab/graphql/authorize.rb
index f8d0208e275..e83b567308b 100644
--- a/lib/gitlab/graphql/authorize.rb
+++ b/lib/gitlab/graphql/authorize.rb
@@ -8,7 +8,7 @@ module Gitlab
extend ActiveSupport::Concern
def self.use(schema_definition)
- schema_definition.instrument(:field, Instrumentation.new, after_built_ins: true)
+ schema_definition.instrument(:field, Gitlab::Graphql::Authorize::Instrumentation.new, after_built_ins: true)
end
end
end
diff --git a/lib/gitlab/graphql/authorize/authorize_field_service.rb b/lib/gitlab/graphql/authorize/authorize_field_service.rb
index 619ce100421..3b5dde2fde5 100644
--- a/lib/gitlab/graphql/authorize/authorize_field_service.rb
+++ b/lib/gitlab/graphql/authorize/authorize_field_service.rb
@@ -39,6 +39,8 @@ module Gitlab
type = node_type_for_basic_connection(type)
end
+ type = type.unwrap if type.kind.non_null?
+
Array.wrap(type.metadata[:authorize])
end
diff --git a/lib/gitlab/graphql/calls_gitaly.rb b/lib/gitlab/graphql/calls_gitaly.rb
new file mode 100644
index 00000000000..40cd74a34f2
--- /dev/null
+++ b/lib/gitlab/graphql/calls_gitaly.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Graphql
+ # Wraps the field resolution to count Gitaly calls before and after.
+ # Raises an error if the field calls Gitaly but hadn't declared such.
+ module CallsGitaly
+ extend ActiveSupport::Concern
+
+ def self.use(schema_definition)
+ schema_definition.instrument(:field, Gitlab::Graphql::CallsGitaly::Instrumentation.new, after_built_ins: true)
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/graphql/calls_gitaly/instrumentation.rb b/lib/gitlab/graphql/calls_gitaly/instrumentation.rb
new file mode 100644
index 00000000000..fbd5e348c7d
--- /dev/null
+++ b/lib/gitlab/graphql/calls_gitaly/instrumentation.rb
@@ -0,0 +1,40 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Graphql
+ module CallsGitaly
+ class Instrumentation
+ # Check if any `calls_gitaly: true` declarations need to be added
+ # Do nothing if a constant complexity was provided
+ def instrument(_type, field)
+ type_object = field.metadata[:type_class]
+ return field unless type_object.respond_to?(:calls_gitaly?)
+ return field if type_object.constant_complexity? || type_object.calls_gitaly?
+
+ old_resolver_proc = field.resolve_proc
+
+ gitaly_wrapped_resolve = -> (typed_object, args, ctx) do
+ previous_gitaly_call_count = Gitlab::GitalyClient.get_request_count
+ result = old_resolver_proc.call(typed_object, args, ctx)
+ current_gitaly_call_count = Gitlab::GitalyClient.get_request_count
+ calls_gitaly_check(type_object, current_gitaly_call_count - previous_gitaly_call_count)
+ result
+ end
+
+ field.redefine do
+ resolve(gitaly_wrapped_resolve)
+ end
+ end
+
+ def calls_gitaly_check(type_object, calls)
+ return if calls < 1
+
+ # Will inform you if there needs to be `calls_gitaly: true` as a kwarg in the field declaration
+ # if there is at least 1 Gitaly call involved with the field resolution.
+ error = RuntimeError.new("Gitaly is called for field '#{type_object.name}' on #{type_object.owner.try(:name)} - please either specify a constant complexity or add `calls_gitaly: true` to the field declaration")
+ Gitlab::Sentry.track_exception(error)
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/graphql/find_argument_in_parent.rb b/lib/gitlab/graphql/find_argument_in_parent.rb
new file mode 100644
index 00000000000..1f83f8fce7a
--- /dev/null
+++ b/lib/gitlab/graphql/find_argument_in_parent.rb
@@ -0,0 +1,32 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Graphql
+ module FindArgumentInParent
+ # Searches up the GraphQL AST and returns the first matching argument
+ # passed to a node
+ def self.find(parent, argument, limit_depth: nil)
+ argument = argument.to_s.camelize(:lower).to_sym
+ depth = 0
+
+ while parent.respond_to?(:parent)
+ args = node_args(parent)
+ return args[argument] if args.key?(argument)
+
+ depth += 1
+ return if limit_depth && depth >= limit_depth
+
+ parent = parent.parent
+ end
+ end
+
+ class << self
+ private
+
+ def node_args(node)
+ node.irep_node.arguments
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/graphql/mount_mutation.rb b/lib/gitlab/graphql/mount_mutation.rb
index 9048967d4e1..b10e963170a 100644
--- a/lib/gitlab/graphql/mount_mutation.rb
+++ b/lib/gitlab/graphql/mount_mutation.rb
@@ -6,11 +6,12 @@ module Gitlab
extend ActiveSupport::Concern
class_methods do
- def mount_mutation(mutation_class)
+ def mount_mutation(mutation_class, **custom_kwargs)
# Using an underscored field name symbol will make `graphql-ruby`
# standardize the field name
field mutation_class.graphql_name.underscore.to_sym,
- mutation: mutation_class
+ mutation: mutation_class,
+ **custom_kwargs
end
end
end
diff --git a/lib/gitlab/http.rb b/lib/gitlab/http.rb
index db2b4dde244..58bce613a98 100644
--- a/lib/gitlab/http.rb
+++ b/lib/gitlab/http.rb
@@ -10,9 +10,9 @@ module Gitlab
RedirectionTooDeep = Class.new(StandardError)
HTTP_ERRORS = [
- SocketError, OpenSSL::SSL::SSLError, Errno::ECONNRESET,
- Errno::ECONNREFUSED, Errno::EHOSTUNREACH, Net::OpenTimeout,
- Net::ReadTimeout, Gitlab::HTTP::BlockedUrlError,
+ SocketError, OpenSSL::SSL::SSLError, OpenSSL::OpenSSLError,
+ Errno::ECONNRESET, Errno::ECONNREFUSED, Errno::EHOSTUNREACH,
+ Net::OpenTimeout, Net::ReadTimeout, Gitlab::HTTP::BlockedUrlError,
Gitlab::HTTP::RedirectionTooDeep
].freeze
diff --git a/lib/gitlab/import_export/import_export.yml b/lib/gitlab/import_export/import_export.yml
index a0fb051e806..01437c67fa9 100644
--- a/lib/gitlab/import_export/import_export.yml
+++ b/lib/gitlab/import_export/import_export.yml
@@ -160,6 +160,7 @@ excluded_attributes:
- :milestone_id
- :ref_fetched
- :merge_jid
+ - :rebase_jid
- :latest_merge_request_diff_id
award_emoji:
- :awardable_id
diff --git a/lib/gitlab/issuable_metadata.rb b/lib/gitlab/issuable_metadata.rb
index 351d15605e0..be73bcd5506 100644
--- a/lib/gitlab/issuable_metadata.rb
+++ b/lib/gitlab/issuable_metadata.rb
@@ -2,7 +2,7 @@
module Gitlab
module IssuableMetadata
- def issuable_meta_data(issuable_collection, collection_type)
+ def issuable_meta_data(issuable_collection, collection_type, user = nil)
# ActiveRecord uses Object#extend for null relations.
if !(issuable_collection.singleton_class < ActiveRecord::NullRelation) &&
issuable_collection.respond_to?(:limit_value) &&
@@ -23,7 +23,7 @@ module Gitlab
issuable_votes_count = ::AwardEmoji.votes_for_collection(issuable_ids, collection_type)
issuable_merge_requests_count =
if collection_type == 'Issue'
- ::MergeRequestsClosingIssues.count_for_collection(issuable_ids)
+ ::MergeRequestsClosingIssues.count_for_collection(issuable_ids, user)
else
[]
end
diff --git a/lib/gitlab/legacy_github_import/release_formatter.rb b/lib/gitlab/legacy_github_import/release_formatter.rb
index 746786b5a66..fdab6b512ea 100644
--- a/lib/gitlab/legacy_github_import/release_formatter.rb
+++ b/lib/gitlab/legacy_github_import/release_formatter.rb
@@ -10,6 +10,7 @@ module Gitlab
name: raw_data.name,
description: raw_data.body,
created_at: raw_data.created_at,
+ released_at: raw_data.published_at,
updated_at: raw_data.created_at
}
end
diff --git a/lib/gitlab/metrics/samplers/ruby_sampler.rb b/lib/gitlab/metrics/samplers/ruby_sampler.rb
index 17eacbd21d8..eef802caabb 100644
--- a/lib/gitlab/metrics/samplers/ruby_sampler.rb
+++ b/lib/gitlab/metrics/samplers/ruby_sampler.rb
@@ -6,6 +6,12 @@ module Gitlab
module Metrics
module Samplers
class RubySampler < BaseSampler
+ def initialize(interval)
+ metrics[:process_start_time_seconds].set(labels.merge(worker_label), Time.now.to_i)
+
+ super
+ end
+
def metrics
@metrics ||= init_metrics
end
@@ -47,7 +53,6 @@ module Gitlab
metrics[:file_descriptors].set(labels.merge(worker_label), System.file_descriptor_count)
metrics[:process_cpu_seconds_total].set(labels.merge(worker_label), ::Gitlab::Metrics::System.cpu_time)
metrics[:process_max_fds].set(labels.merge(worker_label), ::Gitlab::Metrics::System.max_open_file_descriptors)
- metrics[:process_start_time_seconds].set(labels.merge(worker_label), ::Gitlab::Metrics::System.process_start_time)
set_memory_usage_metrics
sample_gc
diff --git a/lib/gitlab/metrics/system.rb b/lib/gitlab/metrics/system.rb
index 34de40ca72f..5c2f07b95e2 100644
--- a/lib/gitlab/metrics/system.rb
+++ b/lib/gitlab/metrics/system.rb
@@ -31,14 +31,6 @@ module Gitlab
match[1].to_i
end
-
- def self.process_start_time
- fields = File.read('/proc/self/stat').split
-
- # fields[21] is linux proc stat field "(22) starttime".
- # The value is expressed in clock ticks, divide by clock ticks for seconds.
- ( fields[21].to_i || 0 ) / clk_tck
- end
else
def self.memory_usage
0.0
@@ -51,10 +43,6 @@ module Gitlab
def self.max_open_file_descriptors
0
end
-
- def self.process_start_time
- 0
- end
end
def self.cpu_time
diff --git a/lib/gitlab/namespaced_session_store.rb b/lib/gitlab/namespaced_session_store.rb
index 34520078bfb..f0f24c081c3 100644
--- a/lib/gitlab/namespaced_session_store.rb
+++ b/lib/gitlab/namespaced_session_store.rb
@@ -4,19 +4,24 @@ module Gitlab
class NamespacedSessionStore
delegate :[], :[]=, to: :store
- def initialize(key)
+ def initialize(key, session = Session.current)
@key = key
+ @session = session
end
def initiated?
- !Session.current.nil?
+ !session.nil?
end
def store
- return unless Session.current
+ return unless session
- Session.current[@key] ||= {}
- Session.current[@key]
+ session[@key] ||= {}
+ session[@key]
end
+
+ private
+
+ attr_reader :session
end
end
diff --git a/lib/gitlab/performance_bar.rb b/lib/gitlab/performance_bar.rb
index 4b0c7b5c7f8..07439d8e011 100644
--- a/lib/gitlab/performance_bar.rb
+++ b/lib/gitlab/performance_bar.rb
@@ -3,7 +3,8 @@
module Gitlab
module PerformanceBar
ALLOWED_USER_IDS_KEY = 'performance_bar_allowed_user_ids:v2'.freeze
- EXPIRY_TIME = 5.minutes
+ EXPIRY_TIME_L1_CACHE = 1.minute
+ EXPIRY_TIME_L2_CACHE = 5.minutes
def self.enabled?(user = nil)
return true if Rails.env.development?
@@ -19,20 +20,31 @@ module Gitlab
# rubocop: disable CodeReuse/ActiveRecord
def self.allowed_user_ids
- Rails.cache.fetch(ALLOWED_USER_IDS_KEY, expires_in: EXPIRY_TIME) do
- group = Group.find_by_id(allowed_group_id)
+ l1_cache_backend.fetch(ALLOWED_USER_IDS_KEY, expires_in: EXPIRY_TIME_L1_CACHE) do
+ l2_cache_backend.fetch(ALLOWED_USER_IDS_KEY, expires_in: EXPIRY_TIME_L2_CACHE) do
+ group = Group.find_by_id(allowed_group_id)
- if group
- GroupMembersFinder.new(group).execute.pluck(:user_id)
- else
- []
+ if group
+ GroupMembersFinder.new(group).execute.pluck(:user_id)
+ else
+ []
+ end
end
end
end
# rubocop: enable CodeReuse/ActiveRecord
def self.expire_allowed_user_ids_cache
- Rails.cache.delete(ALLOWED_USER_IDS_KEY)
+ l1_cache_backend.delete(ALLOWED_USER_IDS_KEY)
+ l2_cache_backend.delete(ALLOWED_USER_IDS_KEY)
+ end
+
+ def self.l1_cache_backend
+ Gitlab::ThreadMemoryCache.cache_backend
+ end
+
+ def self.l2_cache_backend
+ Rails.cache
end
end
end
diff --git a/lib/gitlab/performance_bar/redis_adapter_when_peek_enabled.rb b/lib/gitlab/performance_bar/redis_adapter_when_peek_enabled.rb
new file mode 100644
index 00000000000..2d997760c46
--- /dev/null
+++ b/lib/gitlab/performance_bar/redis_adapter_when_peek_enabled.rb
@@ -0,0 +1,12 @@
+# frozen_string_literal: true
+
+# Adapted from https://github.com/peek/peek/blob/master/lib/peek/adapters/redis.rb
+module Gitlab
+ module PerformanceBar
+ module RedisAdapterWhenPeekEnabled
+ def save
+ super unless ::Peek.request_id.blank?
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/quick_actions/issuable_actions.rb b/lib/gitlab/quick_actions/issuable_actions.rb
index 572c55efcc2..f7f89d4e897 100644
--- a/lib/gitlab/quick_actions/issuable_actions.rb
+++ b/lib/gitlab/quick_actions/issuable_actions.rb
@@ -146,8 +146,8 @@ module Gitlab
@updates[:todo_event] = 'add'
end
- desc _('Mark todo as done')
- explanation _('Marks todo as done.')
+ desc _('Mark to do as done')
+ explanation _('Marks to do as done.')
types Issuable
condition do
quick_action_target.persisted? &&
diff --git a/lib/gitlab/search/found_blob.rb b/lib/gitlab/search/found_blob.rb
index cfbe7f59a83..fa09ecbdf30 100644
--- a/lib/gitlab/search/found_blob.rb
+++ b/lib/gitlab/search/found_blob.rb
@@ -28,7 +28,7 @@ module Gitlab
@binary_data = opts.fetch(:data, nil)
@per_page = opts.fetch(:per_page, 20)
@project = opts.fetch(:project, nil)
- # Some caller (e.g. Elasticsearch) does not have project object,
+ # Some callers (e.g. Elasticsearch) do not have the Project object,
# yet they can trigger many calls in one go,
# causing duplicated queries.
# Allow those to just pass project_id instead.
diff --git a/lib/gitlab/sidekiq_status.rb b/lib/gitlab/sidekiq_status.rb
index 583a970bf4e..0f890a12134 100644
--- a/lib/gitlab/sidekiq_status.rb
+++ b/lib/gitlab/sidekiq_status.rb
@@ -53,14 +53,14 @@ module Gitlab
self.num_running(job_ids).zero?
end
- # Returns true if the given job is running
+ # Returns true if the given job is running or enqueued.
#
# job_id - The Sidekiq job ID to check.
def self.running?(job_id)
num_running([job_id]) > 0
end
- # Returns the number of jobs that are running.
+ # Returns the number of jobs that are running or enqueued.
#
# job_ids - The Sidekiq job IDs to check.
def self.num_running(job_ids)
@@ -81,7 +81,7 @@ module Gitlab
# job_ids - The Sidekiq job IDs to check.
#
# Returns an array of true or false indicating job completion.
- # true = job is still running
+ # true = job is still running or enqueued
# false = job completed
def self.job_status(job_ids)
keys = job_ids.map { |jid| key_for(jid) }
diff --git a/lib/gitlab/sql/pattern.rb b/lib/gitlab/sql/pattern.rb
index fd108b4c124..f6edbfced7f 100644
--- a/lib/gitlab/sql/pattern.rb
+++ b/lib/gitlab/sql/pattern.rb
@@ -9,14 +9,16 @@ module Gitlab
REGEX_QUOTED_WORD = /(?<=\A| )"[^"]+"(?= |\z)/.freeze
class_methods do
- def fuzzy_search(query, columns)
- matches = columns.map { |col| fuzzy_arel_match(col, query) }.compact.reduce(:or)
+ def fuzzy_search(query, columns, use_minimum_char_limit: true)
+ matches = columns.map do |col|
+ fuzzy_arel_match(col, query, use_minimum_char_limit: use_minimum_char_limit)
+ end.compact.reduce(:or)
where(matches)
end
- def to_pattern(query)
- if partial_matching?(query)
+ def to_pattern(query, use_minimum_char_limit: true)
+ if partial_matching?(query, use_minimum_char_limit: use_minimum_char_limit)
"%#{sanitize_sql_like(query)}%"
else
sanitize_sql_like(query)
@@ -27,7 +29,9 @@ module Gitlab
MIN_CHARS_FOR_PARTIAL_MATCHING
end
- def partial_matching?(query)
+ def partial_matching?(query, use_minimum_char_limit: true)
+ return true unless use_minimum_char_limit
+
query.length >= min_chars_for_partial_matching
end
@@ -35,14 +39,14 @@ module Gitlab
# query - The text to search for.
# lower_exact_match - When set to `true` we'll fall back to using
# `LOWER(column) = query` instead of using `ILIKE`.
- def fuzzy_arel_match(column, query, lower_exact_match: false)
+ def fuzzy_arel_match(column, query, lower_exact_match: false, use_minimum_char_limit: true)
query = query.squish
return unless query.present?
- words = select_fuzzy_words(query)
+ words = select_fuzzy_words(query, use_minimum_char_limit: use_minimum_char_limit)
if words.any?
- words.map { |word| arel_table[column].matches(to_pattern(word)) }.reduce(:and)
+ words.map { |word| arel_table[column].matches(to_pattern(word, use_minimum_char_limit: use_minimum_char_limit)) }.reduce(:and)
else
# No words of at least 3 chars, but we can search for an exact
# case insensitive match with the query as a whole
@@ -56,7 +60,7 @@ module Gitlab
end
end
- def select_fuzzy_words(query)
+ def select_fuzzy_words(query, use_minimum_char_limit: true)
quoted_words = query.scan(REGEX_QUOTED_WORD)
query = quoted_words.reduce(query) { |q, quoted_word| q.sub(quoted_word, '') }
@@ -67,7 +71,7 @@ module Gitlab
words.concat(quoted_words)
- words.select { |word| partial_matching?(word) }
+ words.select { |word| partial_matching?(word, use_minimum_char_limit: use_minimum_char_limit) }
end
end
end
diff --git a/lib/gitlab/thread_memory_cache.rb b/lib/gitlab/thread_memory_cache.rb
new file mode 100644
index 00000000000..7f363dc7feb
--- /dev/null
+++ b/lib/gitlab/thread_memory_cache.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+module Gitlab
+ class ThreadMemoryCache
+ THREAD_KEY = :thread_memory_cache
+
+ def self.cache_backend
+ # Note ActiveSupport::Cache::MemoryStore is thread-safe. Since
+ # each backend is local per thread we probably don't need to worry
+ # about synchronizing access, but this is a drop-in replacement
+ # for ActiveSupport::Cache::RedisStore.
+ Thread.current[THREAD_KEY] ||= ActiveSupport::Cache::MemoryStore.new
+ end
+ end
+end
diff --git a/lib/gitlab/user_extractor.rb b/lib/gitlab/user_extractor.rb
deleted file mode 100644
index ede60c9ab1d..00000000000
--- a/lib/gitlab/user_extractor.rb
+++ /dev/null
@@ -1,56 +0,0 @@
-# frozen_string_literal: true
-
-# This class extracts all users found in a piece of text by the username or the
-# email address
-
-module Gitlab
- class UserExtractor
- # Not using `Devise.email_regexp` to filter out any chars that an email
- # does not end with and not pinning the email to a start of end of a string.
- EMAIL_REGEXP = /(?<email>([^@\s]+@[^@\s]+(?<!\W)))/.freeze
- USERNAME_REGEXP = User.reference_pattern
-
- def initialize(text)
- # EE passes an Array to `text` in a few places, so we want to support both
- # here.
- @text = Array(text).join(' ')
- end
-
- def users
- return User.none unless @text.present?
- return User.none if references.empty?
-
- @users ||= User.from_union(union_relations)
- end
-
- def usernames
- matches[:usernames]
- end
-
- def emails
- matches[:emails]
- end
-
- def references
- @references ||= matches.values.flatten
- end
-
- def matches
- @matches ||= {
- emails: @text.scan(EMAIL_REGEXP).flatten.uniq,
- usernames: @text.scan(USERNAME_REGEXP).flatten.uniq
- }
- end
-
- private
-
- def union_relations
- relations = []
-
- relations << User.by_any_email(emails) if emails.any?
- relations << User.by_username(usernames) if usernames.any?
-
- relations
- end
- end
-end
diff --git a/lib/gitlab/utils/deep_size.rb b/lib/gitlab/utils/deep_size.rb
new file mode 100644
index 00000000000..562cf09e249
--- /dev/null
+++ b/lib/gitlab/utils/deep_size.rb
@@ -0,0 +1,79 @@
+# frozen_string_literal: true
+
+require 'objspace'
+
+module Gitlab
+ module Utils
+ class DeepSize
+ Error = Class.new(StandardError)
+ TooMuchDataError = Class.new(Error)
+
+ DEFAULT_MAX_SIZE = 1.megabyte
+ DEFAULT_MAX_DEPTH = 100
+
+ def initialize(root, max_size: DEFAULT_MAX_SIZE, max_depth: DEFAULT_MAX_DEPTH)
+ @root = root
+ @max_size = max_size
+ @max_depth = max_depth
+ @size = 0
+ @depth = 0
+
+ evaluate
+ end
+
+ def valid?
+ !too_big? && !too_deep?
+ end
+
+ private
+
+ def evaluate
+ add_object(@root)
+ rescue Error
+ # NOOP
+ end
+
+ def too_big?
+ @size > @max_size
+ end
+
+ def too_deep?
+ @depth > @max_depth
+ end
+
+ def add_object(object)
+ @size += ObjectSpace.memsize_of(object)
+ raise TooMuchDataError if @size > @max_size
+
+ add_array(object) if object.is_a?(Array)
+ add_hash(object) if object.is_a?(Hash)
+ end
+
+ def add_array(object)
+ with_nesting do
+ object.each do |n|
+ add_object(n)
+ end
+ end
+ end
+
+ def add_hash(object)
+ with_nesting do
+ object.each do |key, value|
+ add_object(key)
+ add_object(value)
+ end
+ end
+ end
+
+ def with_nesting
+ @depth += 1
+ raise TooMuchDataError if too_deep?
+
+ yield
+
+ @depth -= 1
+ end
+ end
+ end
+end
diff --git a/lib/peek/views/redis.rb b/lib/peek/views/redis.rb
new file mode 100644
index 00000000000..73de8672fa4
--- /dev/null
+++ b/lib/peek/views/redis.rb
@@ -0,0 +1,86 @@
+# frozen_string_literal: true
+
+require 'redis'
+require 'peek-redis'
+
+module Gitlab
+ module Peek
+ module RedisInstrumented
+ def call(*args, &block)
+ start = Time.now
+ super(*args, &block)
+ ensure
+ duration = (Time.now - start)
+ add_call_details(duration, args)
+ end
+
+ private
+
+ def add_call_details(duration, args)
+ # redis-rb passes an array (e.g. [:get, key])
+ return unless args.length == 1
+
+ detail_store << {
+ cmd: args.first,
+ duration: duration,
+ backtrace: Gitlab::Profiler.clean_backtrace(caller)
+ }
+ end
+
+ def detail_store
+ ::Gitlab::SafeRequestStore['redis_call_details'] ||= []
+ end
+ end
+ end
+end
+
+module Peek
+ module Views
+ module RedisDetailed
+ REDACTED_MARKER = "<redacted>"
+
+ def results
+ super.merge(details: details)
+ end
+
+ def details
+ detail_store
+ .sort { |a, b| b[:duration] <=> a[:duration] }
+ .map(&method(:format_call_details))
+ end
+
+ def detail_store
+ ::Gitlab::SafeRequestStore['redis_call_details'] ||= []
+ end
+
+ def format_call_details(call)
+ call.merge(cmd: format_command(call[:cmd]),
+ duration: (call[:duration] * 1000).round(3))
+ end
+
+ def format_command(cmd)
+ if cmd.length >= 2 && cmd.first =~ /^auth$/i
+ cmd[-1] = REDACTED_MARKER
+ # Scrub out the value of the SET calls to avoid binary
+ # data or large data from spilling into the view
+ elsif cmd.length >= 3 && cmd.first =~ /set/i
+ cmd[2..-1] = REDACTED_MARKER
+ end
+
+ cmd.join(' ')
+ end
+ end
+ end
+end
+
+class Redis::Client
+ prepend Gitlab::Peek::RedisInstrumented
+end
+
+module Peek
+ module Views
+ class Redis < View
+ prepend Peek::Views::RedisDetailed
+ end
+ end
+end
diff --git a/lib/tasks/migrate/setup_postgresql.rake b/lib/tasks/migrate/setup_postgresql.rake
index f69d204c579..cda88c130bb 100644
--- a/lib/tasks/migrate/setup_postgresql.rake
+++ b/lib/tasks/migrate/setup_postgresql.rake
@@ -1,23 +1,9 @@
desc 'GitLab | Sets up PostgreSQL'
task setup_postgresql: :environment do
- require Rails.root.join('db/migrate/20151007120511_namespaces_projects_path_lower_indexes')
- require Rails.root.join('db/migrate/20151008110232_add_users_lower_username_email_indexes')
- require Rails.root.join('db/migrate/20161212142807_add_lower_path_index_to_routes')
- require Rails.root.join('db/migrate/20170317203554_index_routes_path_for_like')
- require Rails.root.join('db/migrate/20170724214302_add_lower_path_index_to_redirect_routes')
- require Rails.root.join('db/migrate/20170503185032_index_redirect_routes_path_for_like')
- require Rails.root.join('db/migrate/20171220191323_add_index_on_namespaces_lower_name.rb')
require Rails.root.join('db/migrate/20180215181245_users_name_lower_index.rb')
require Rails.root.join('db/migrate/20180504195842_project_name_lower_index.rb')
require Rails.root.join('db/post_migrate/20180306164012_add_path_index_to_redirect_routes.rb')
- NamespacesProjectsPathLowerIndexes.new.up
- AddUsersLowerUsernameEmailIndexes.new.up
- AddLowerPathIndexToRoutes.new.up
- IndexRoutesPathForLike.new.up
- AddLowerPathIndexToRedirectRoutes.new.up
- IndexRedirectRoutesPathForLike.new.up
- AddIndexOnNamespacesLowerName.new.up
UsersNameLowerIndex.new.up
ProjectNameLowerIndex.new.up
AddPathIndexToRedirectRoutes.new.up
diff --git a/lib/tasks/yarn.rake b/lib/tasks/yarn.rake
index 2ac88a039e7..32061ad4a57 100644
--- a/lib/tasks/yarn.rake
+++ b/lib/tasks/yarn.rake
@@ -24,7 +24,7 @@ namespace :yarn do
desc 'Install Node dependencies with Yarn'
task install: ['yarn:available'] do
- unless system('yarn install --pure-lockfile --ignore-engines')
+ unless system('yarn install --pure-lockfile --ignore-engines --prefer-offline')
abort 'Error: Unable to install node modules.'.color(:red)
end
end
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index a04a0acd98e..9b6e8d8c8a4 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -28,6 +28,12 @@ msgstr ""
msgid " You need to do this before %{grace_period_deadline}."
msgstr ""
+msgid " and "
+msgstr ""
+
+msgid " and %{sliced}"
+msgstr ""
+
msgid " or "
msgstr ""
@@ -112,10 +118,10 @@ msgstr[1] ""
msgid "%{actionText} & %{openOrClose} %{noteable}"
msgstr ""
-msgid "%{commit_author_link} authored %{commit_timeago}"
+msgid "%{canMergeCount}/%{assigneesCount} can merge"
msgstr ""
-msgid "%{counter_repositories} repositories, %{counter_wikis} wikis, %{counter_build_artifacts} build artifacts, %{counter_lfs_objects} LFS"
+msgid "%{commit_author_link} authored %{commit_timeago}"
msgstr ""
msgid "%{count} more"
@@ -147,6 +153,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 "%{icon}You are about to add %{usersTag} people to the discussion. Proceed with caution."
+msgstr ""
+
msgid "%{issuableType} will be removed! Are you sure?"
msgstr ""
@@ -168,6 +177,9 @@ msgstr ""
msgid "%{link_start}Read more%{link_end} about role permissions"
msgstr ""
+msgid "%{listToShow}, and %{awardsListLength} more."
+msgstr ""
+
msgid "%{loadingIcon} Started"
msgstr ""
@@ -231,6 +243,9 @@ msgid_plural "%{strong_start}%{tag_count}%{strong_end} Tags"
msgstr[0] ""
msgstr[1] ""
+msgid "%{tabname} changed"
+msgstr ""
+
msgid "%{text} %{files}"
msgid_plural "%{text} %{files} files"
msgstr[0] ""
@@ -248,9 +263,15 @@ msgstr ""
msgid "%{usage_ping_link_start}Learn more%{usage_ping_link_end} about what information is shared with GitLab Inc."
msgstr ""
+msgid "%{userName}'s avatar"
+msgstr ""
+
msgid "%{user_name} profile page"
msgstr ""
+msgid "%{username}'s avatar"
+msgstr ""
+
msgid "%{verb} %{time_spent_value} spent time."
msgstr ""
@@ -269,6 +290,9 @@ msgstr ""
msgid "+ %{moreCount} more"
msgstr ""
+msgid "+ %{numberOfHiddenAssignees} more"
+msgstr ""
+
msgid ", or "
msgstr ""
@@ -345,9 +369,6 @@ msgstr ""
msgid "2FA"
msgstr ""
-msgid "2FA enabled"
-msgstr ""
-
msgid "2FADevice|Registered On"
msgstr ""
@@ -602,9 +623,18 @@ msgstr ""
msgid "Add a GPG key"
msgstr ""
+msgid "Add a Grafana button in the admin sidebar, monitoring section, to access a variety of statistics on the health and performance of GitLab."
+msgstr ""
+
+msgid "Add a To Do"
+msgstr ""
+
msgid "Add a bullet list"
msgstr ""
+msgid "Add a general comment to this %{noteableDisplayName}."
+msgstr ""
+
msgid "Add a general comment to this %{noteable_name}."
msgstr ""
@@ -677,9 +707,6 @@ msgstr ""
msgid "Add to review"
msgstr ""
-msgid "Add todo"
-msgstr ""
-
msgid "Add user(s) to the group:"
msgstr ""
@@ -866,9 +893,6 @@ msgstr ""
msgid "All projects"
msgstr ""
-msgid "All todos were marked as done."
-msgstr ""
-
msgid "All users"
msgstr ""
@@ -1196,6 +1220,9 @@ msgstr ""
msgid "Are you sure you want to cancel editing this comment?"
msgstr ""
+msgid "Are you sure you want to delete this %{typeOfComment}?"
+msgstr ""
+
msgid "Are you sure you want to delete this device? This action cannot be undone."
msgstr ""
@@ -1314,7 +1341,9 @@ msgid "Assigned to me"
msgstr ""
msgid "Assignee"
-msgstr ""
+msgid_plural "%d Assignees"
+msgstr[0] ""
+msgstr[1] ""
msgid "Assignee(s)"
msgstr ""
@@ -1870,9 +1899,15 @@ msgstr ""
msgid "Cancel"
msgstr ""
+msgid "Cancel running"
+msgstr ""
+
msgid "Cancel this job"
msgstr ""
+msgid "Cancelling Preview"
+msgstr ""
+
msgid "Cannot be merged automatically"
msgstr ""
@@ -1882,6 +1917,9 @@ msgstr ""
msgid "Cannot create the abuse report. This user has been blocked."
msgstr ""
+msgid "Cannot merge"
+msgstr ""
+
msgid "Cannot modify managed Kubernetes cluster"
msgstr ""
@@ -2149,6 +2187,9 @@ msgstr ""
msgid "Clear"
msgstr ""
+msgid "Clear recent searches"
+msgstr ""
+
msgid "Clear search"
msgstr ""
@@ -2206,6 +2247,9 @@ msgstr ""
msgid "Close"
msgstr ""
+msgid "Close %{tabname}"
+msgstr ""
+
msgid "Close milestone"
msgstr ""
@@ -2263,6 +2307,9 @@ msgstr ""
msgid "ClusterIntegration|Advanced options on this Kubernetes cluster's integration"
msgstr ""
+msgid "ClusterIntegration|All data not committed to GitLab will be deleted and cannot be restored."
+msgstr ""
+
msgid "ClusterIntegration|All data will be deleted and cannot be restored."
msgstr ""
@@ -2755,10 +2802,10 @@ msgstr ""
msgid "Comment & reopen %{noteable_name}"
msgstr ""
-msgid "Comment & resolve discussion"
+msgid "Comment & resolve thread"
msgstr ""
-msgid "Comment & unresolve discussion"
+msgid "Comment & unresolve thread"
msgstr ""
msgid "Comment form position"
@@ -2931,25 +2978,19 @@ msgstr ""
msgid "Container registry images"
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 ""
-
-msgid "ContainerRegistry|GitLab supports up to 3 levels of image names. The following examples of images are valid for your project:"
+msgid "ContainerRegistry|Container Registry"
msgstr ""
-msgid "ContainerRegistry|How to use the Container Registry"
+msgid "ContainerRegistry|Docker connection error"
msgstr ""
msgid "ContainerRegistry|Last Updated"
msgstr ""
-msgid "ContainerRegistry|Learn more about"
-msgstr ""
-
msgid "ContainerRegistry|No tags in Container Registry for this container image."
msgstr ""
-msgid "ContainerRegistry|Once you log in, you&rsquo;re free to create and upload a container image using the common %{build} and %{push} commands"
+msgid "ContainerRegistry|Quick Start"
msgstr ""
msgid "ContainerRegistry|Remove image"
@@ -2970,10 +3011,16 @@ msgstr ""
msgid "ContainerRegistry|Tag ID"
msgstr ""
-msgid "ContainerRegistry|Use different image names"
+msgid "ContainerRegistry|There are no container images stored for this project"
+msgstr ""
+
+msgid "ContainerRegistry|We are having trouble connecting to Docker, which could be due to an issue with your project name or path. For more information, please review the %{docLinkStart}Container Registry documentation%{docLinkEnd}."
+msgstr ""
+
+msgid "ContainerRegistry|With the Container Registry, every project can have its own space to store its Docker images. Learn more about the %{docLinkStart}Container Registry%{docLinkEnd}."
msgstr ""
-msgid "ContainerRegistry|With the Docker Container Registry integrated into GitLab, every project can have its own space to store its Docker images."
+msgid "ContainerRegistry|With the Docker Container Registry integrated into GitLab, every project can have its own space to store its Docker images. Learn more about the %{docLinkStart}Container Registry%{docLinkEnd}."
msgstr ""
msgid "ContainerRegistry|You are about to delete the image <b>%{title}</b>. This will delete the image and all tags pointing to this image."
@@ -2982,7 +3029,7 @@ msgstr ""
msgid "ContainerRegistry|You are about to remove repository <b>%{title}</b>. Once you confirm, this repository will be permanently deleted."
msgstr ""
-msgid "ContainerRegistry|You can also use a %{deploy_token} for read-only access to the registry images."
+msgid "ContainerRegistry|You can add an image to this registry with the following commands:"
msgstr ""
msgid "Contents of .gitlab-ci.yml"
@@ -3473,6 +3520,9 @@ msgstr ""
msgid "Deploy key was successfully updated."
msgstr ""
+msgid "Deploy to..."
+msgstr ""
+
msgid "DeployKeys|+%{count} others"
msgstr ""
@@ -3545,6 +3595,9 @@ msgstr ""
msgid "DeployTokens|Created"
msgstr ""
+msgid "DeployTokens|Default format is \"gitlab+deploy-token-{n}\". Enter custom username if you want to change it."
+msgstr ""
+
msgid "DeployTokens|Deploy Tokens"
msgstr ""
@@ -3596,6 +3649,9 @@ msgstr ""
msgid "Deployed"
msgstr ""
+msgid "Deployed %{deployedSince}"
+msgstr ""
+
msgid "Deployed to"
msgstr ""
@@ -3698,6 +3754,12 @@ msgstr ""
msgid "Discuss a specific suggestion or question that needs to be resolved"
msgstr ""
+msgid "Discuss a specific suggestion or question that needs to be resolved."
+msgstr ""
+
+msgid "Discuss a specific suggestion or question."
+msgstr ""
+
msgid "Discussion"
msgstr ""
@@ -3740,6 +3802,9 @@ msgstr ""
msgid "Download artifacts"
msgstr ""
+msgid "Download as"
+msgstr ""
+
msgid "Download asset"
msgstr ""
@@ -3902,9 +3967,15 @@ msgstr ""
msgid "Enable HTML emails"
msgstr ""
+msgid "Enable access to Grafana"
+msgstr ""
+
msgid "Enable access to the Performance Bar for a given group."
msgstr ""
+msgid "Enable and configure Grafana."
+msgstr ""
+
msgid "Enable and configure InfluxDB metrics."
msgstr ""
@@ -3917,6 +3988,9 @@ msgstr ""
msgid "Enable error tracking"
msgstr ""
+msgid "Enable feature to choose access level"
+msgstr ""
+
msgid "Enable for this project"
msgstr ""
@@ -3962,6 +4036,9 @@ msgstr ""
msgid "Enforce DNS rebinding attack protection"
msgstr ""
+msgid "Ensure connectivity is available from the GitLab server to the Prometheus server"
+msgstr ""
+
msgid "Enter at least three characters to search"
msgstr ""
@@ -3983,6 +4060,9 @@ msgstr ""
msgid "Enter the merge request title"
msgstr ""
+msgid "Enter zen mode"
+msgstr ""
+
msgid "Environment variables are applied to environments via the runner. They can be protected by only exposing them to protected branches or tags. Additionally, they can be masked so they are hidden in job logs, though they must match certain regexp requirements to do so. You can use environment variables for passwords, secret keys, or whatever you want."
msgstr ""
@@ -4133,6 +4213,12 @@ msgstr ""
msgid "Error fetching contributors data."
msgstr ""
+msgid "Error fetching diverging counts for branches. Please try again."
+msgstr ""
+
+msgid "Error fetching forked projects. Please try again."
+msgstr ""
+
msgid "Error fetching labels."
msgstr ""
@@ -4184,6 +4270,9 @@ msgstr ""
msgid "Error occurred when fetching sidebar data"
msgstr ""
+msgid "Error occurred when saving assignees"
+msgstr ""
+
msgid "Error occurred when toggling the notification subscription"
msgstr ""
@@ -4205,13 +4294,16 @@ msgstr ""
msgid "Error saving label update."
msgstr ""
+msgid "Error setting up editor. Please try again."
+msgstr ""
+
msgid "Error updating %{issuableType}"
msgstr ""
-msgid "Error updating status for all todos."
+msgid "Error updating status for all to-do items."
msgstr ""
-msgid "Error updating todo status."
+msgid "Error updating status of to-do item."
msgstr ""
msgid "Error uploading file"
@@ -4304,9 +4396,15 @@ msgstr ""
msgid "Everyone"
msgstr ""
+msgid "Everyone With Access"
+msgstr ""
+
msgid "Everyone can contribute"
msgstr ""
+msgid "Everything on your to-do list is marked as done."
+msgstr ""
+
msgid "Everything you need to create a GitLab Pages site using GitBook."
msgstr ""
@@ -4334,6 +4432,9 @@ msgstr ""
msgid "Expand all"
msgstr ""
+msgid "Expand dropdown"
+msgstr ""
+
msgid "Expand sidebar"
msgstr ""
@@ -4529,6 +4630,9 @@ msgstr ""
msgid "Failure"
msgstr ""
+msgid "Fast-forward merge is not possible. Rebase the source branch onto the target branch or merge target branch into source branch to allow this merge request to be merged."
+msgstr ""
+
msgid "Fast-forward merge without a merge commit"
msgstr ""
@@ -4711,6 +4815,9 @@ msgstr ""
msgid "Friday"
msgstr ""
+msgid "From"
+msgstr ""
+
msgid "From %{providerTitle}"
msgstr ""
@@ -4900,6 +5007,9 @@ msgstr ""
msgid "Got it!"
msgstr ""
+msgid "Grafana URL"
+msgstr ""
+
msgid "Grant access"
msgstr ""
@@ -5280,6 +5390,12 @@ msgstr ""
msgid "ImageDiffViewer|Swipe"
msgstr ""
+msgid "ImageViewerDimensions|H"
+msgstr ""
+
+msgid "ImageViewerDimensions|W"
+msgstr ""
+
msgid "Impersonation has been disabled"
msgstr ""
@@ -5553,6 +5669,9 @@ msgstr ""
msgid "Invite member"
msgstr ""
+msgid "Invocations"
+msgstr ""
+
msgid "Invoke Count"
msgstr ""
@@ -5583,6 +5702,21 @@ msgstr ""
msgid "IssueBoards|Boards"
msgstr ""
+msgid "IssueTracker|Bugzilla issue tracker"
+msgstr ""
+
+msgid "IssueTracker|Custom issue tracker"
+msgstr ""
+
+msgid "IssueTracker|GitLab issue tracker"
+msgstr ""
+
+msgid "IssueTracker|Redmine issue tracker"
+msgstr ""
+
+msgid "IssueTracker|YouTrack issue tracker"
+msgstr ""
+
msgid "Issues"
msgstr ""
@@ -6046,6 +6180,9 @@ msgstr ""
msgid "Locked"
msgstr ""
+msgid "Locked by %{fileLockUserName}"
+msgstr ""
+
msgid "Locked to current projects"
msgstr ""
@@ -6142,6 +6279,9 @@ msgstr ""
msgid "March"
msgstr ""
+msgid "Mark as done"
+msgstr ""
+
msgid "Mark as resolved"
msgstr ""
@@ -6151,7 +6291,7 @@ msgstr ""
msgid "Mark this issue as a duplicate of another issue"
msgstr ""
-msgid "Mark todo as done"
+msgid "Mark to do as done"
msgstr ""
msgid "Markdown"
@@ -6163,10 +6303,13 @@ msgstr ""
msgid "Markdown enabled"
msgstr ""
+msgid "Markdown is supported"
+msgstr ""
+
msgid "Marks this issue as a duplicate of %{duplicate_reference}."
msgstr ""
-msgid "Marks todo as done."
+msgid "Marks to do as done."
msgstr ""
msgid "Max access level"
@@ -6274,7 +6417,7 @@ msgstr ""
msgid "MergeRequests|Reply..."
msgstr ""
-msgid "MergeRequests|Resolve this discussion in a new issue"
+msgid "MergeRequests|Resolve this thread in a new issue"
msgstr ""
msgid "MergeRequests|Saving the comment failed"
@@ -6295,19 +6438,19 @@ msgstr ""
msgid "MergeRequests|commented on commit %{commitLink}"
msgstr ""
-msgid "MergeRequests|started a discussion"
+msgid "MergeRequests|started a thread"
msgstr ""
-msgid "MergeRequests|started a discussion on %{linkStart}an old version of the diff%{linkEnd}"
+msgid "MergeRequests|started a thread on %{linkStart}an old version of the diff%{linkEnd}"
msgstr ""
-msgid "MergeRequests|started a discussion on %{linkStart}the diff%{linkEnd}"
+msgid "MergeRequests|started a thread on %{linkStart}the diff%{linkEnd}"
msgstr ""
-msgid "MergeRequests|started a discussion on an outdated change in commit %{linkStart}%{commitId}%{linkEnd}"
+msgid "MergeRequests|started a thread on an outdated change in commit %{linkStart}%{commitId}%{linkEnd}"
msgstr ""
-msgid "MergeRequests|started a discussion on commit %{linkStart}%{commitId}%{linkEnd}"
+msgid "MergeRequests|started a thread on commit %{linkStart}%{commitId}%{linkEnd}"
msgstr ""
msgid "MergeRequest| %{paragraphStart}changed the description %{descriptionChangedTimes} times %{timeDifferenceMinutes}%{paragraphEnd}"
@@ -6337,12 +6480,18 @@ msgstr ""
msgid "Metrics"
msgstr ""
+msgid "Metrics - Grafana"
+msgstr ""
+
msgid "Metrics - Influx"
msgstr ""
msgid "Metrics - Prometheus"
msgstr ""
+msgid "Metrics Dashboard"
+msgstr ""
+
msgid "Metrics and profiling"
msgstr ""
@@ -6723,9 +6872,6 @@ msgstr ""
msgid "No connection could be made to a Gitaly Server, please check your logs!"
msgstr ""
-msgid "No container images stored for this project. Add one by following the instructions above."
-msgstr ""
-
msgid "No contributions"
msgstr ""
@@ -6756,6 +6902,9 @@ msgstr ""
msgid "No files found."
msgstr ""
+msgid "No forks available to you."
+msgstr ""
+
msgid "No job trace"
msgstr ""
@@ -6774,6 +6923,9 @@ msgstr ""
msgid "No milestones to show"
msgstr ""
+msgid "No one can merge"
+msgstr ""
+
msgid "No other labels with such name or description"
msgstr ""
@@ -6834,6 +6986,9 @@ msgstr ""
msgid "Not started"
msgstr ""
+msgid "Note"
+msgstr ""
+
msgid "Note that this invitation was sent to %{mail_to_invite_email}, but you are signed in as %{link_to_current_user} with email %{mail_to_current_user}."
msgstr ""
@@ -6977,6 +7132,9 @@ msgstr ""
msgid "One or more of your Google Code projects cannot be imported into GitLab directly because they use Subversion or Mercurial for version control, rather than Git."
msgstr ""
+msgid "Only Project Members"
+msgstr ""
+
msgid "Only admins"
msgstr ""
@@ -7010,6 +7168,9 @@ msgstr ""
msgid "Open in Xcode"
msgstr ""
+msgid "Open in file view"
+msgstr ""
+
msgid "Open issues"
msgstr ""
@@ -7229,6 +7390,12 @@ msgstr ""
msgid "Pipeline"
msgstr ""
+msgid "Pipeline %{label}"
+msgstr ""
+
+msgid "Pipeline %{label} for \"%{dataTitle}\""
+msgstr ""
+
msgid "Pipeline Schedule"
msgstr ""
@@ -7454,6 +7621,9 @@ msgstr ""
msgid "Please %{link_to_register} or %{link_to_sign_in} to comment"
msgstr ""
+msgid "Please %{startTagRegister}register%{endRegisterTag} or %{startTagSignIn}sign in%{endSignInTag} to reply"
+msgstr ""
+
msgid "Please accept the Terms of Service before continuing."
msgstr ""
@@ -7517,9 +7687,6 @@ msgstr ""
msgid "Please wait while we import the repository for you. Refresh at will."
msgstr ""
-msgid "Pre-release"
-msgstr ""
-
msgid "Preferences"
msgstr ""
@@ -8258,9 +8425,6 @@ msgstr ""
msgid "ProjectsDropdown|This feature requires browser localStorage support"
msgstr ""
-msgid "Prometheus server"
-msgstr ""
-
msgid "PrometheusService|%{exporters} with %{metrics} were found"
msgstr ""
@@ -8456,6 +8620,12 @@ msgstr ""
msgid "Real-time features"
msgstr ""
+msgid "Rebase"
+msgstr ""
+
+msgid "Rebase in progress"
+msgstr ""
+
msgid "Receive notifications about your own activity"
msgstr ""
@@ -8704,6 +8874,9 @@ msgstr ""
msgid "Repository storage"
msgstr ""
+msgid "Repository: %{counter_repositories} / Wikis: %{counter_wikis} / Build Artifacts: %{counter_build_artifacts} / LFS: %{counter_lfs_objects}"
+msgstr ""
+
msgid "Request Access"
msgstr ""
@@ -8737,7 +8910,7 @@ msgstr ""
msgid "Reset template"
msgstr ""
-msgid "Resolve all discussions in new issue"
+msgid "Resolve all threads in new issue"
msgstr ""
msgid "Resolve conflicts on source branch"
@@ -8746,6 +8919,9 @@ msgstr ""
msgid "Resolve discussion"
msgstr ""
+msgid "Resolve thread"
+msgstr ""
+
msgid "Resolved"
msgstr ""
@@ -8949,6 +9125,9 @@ msgstr ""
msgid "Save variables"
msgstr ""
+msgid "Saving"
+msgstr ""
+
msgid "Saving project."
msgstr ""
@@ -9114,6 +9293,12 @@ msgstr ""
msgid "Select members to invite"
msgstr ""
+msgid "Select merge moment"
+msgstr ""
+
+msgid "Select private project"
+msgstr ""
+
msgid "Select project"
msgstr ""
@@ -9192,6 +9377,9 @@ msgstr ""
msgid "ServerlessDetails|More information"
msgstr ""
+msgid "ServerlessDetails|No pods loaded at this time."
+msgstr ""
+
msgid "ServerlessDetails|Number of Kubernetes pods in use over time based on necessity."
msgstr ""
@@ -9222,9 +9410,21 @@ msgstr ""
msgid "Serverless|No functions available"
msgstr ""
+msgid "Serverless|The deploy job has not finished."
+msgstr ""
+
+msgid "Serverless|The functions listed in the %{startTag}serverless.yml%{endTag} file don't match the namespace of your cluster."
+msgstr ""
+
msgid "Serverless|There is currently no function data available from Knative. This could be for a variety of reasons including:"
msgstr ""
+msgid "Serverless|Your %{startTag}.gitlab-ci.yml%{endTag} file is not properly configured."
+msgstr ""
+
+msgid "Serverless|Your repository does not have a corresponding %{startTag}serverless.yml%{endTag} file."
+msgstr ""
+
msgid "Service"
msgstr ""
@@ -9500,6 +9700,9 @@ msgstr ""
msgid "Something went wrong while adding your award. Please try again."
msgstr ""
+msgid "Something went wrong while adding your comment. Please try again."
+msgstr ""
+
msgid "Something went wrong while applying the suggestion. Please try again."
msgstr ""
@@ -9509,6 +9712,12 @@ msgstr ""
msgid "Something went wrong while deleting the source branch. Please try again."
msgstr ""
+msgid "Something went wrong while deleting your note. Please try again."
+msgstr ""
+
+msgid "Something went wrong while editing your comment. Please try again."
+msgstr ""
+
msgid "Something went wrong while fetching comments. Please try again."
msgstr ""
@@ -9536,6 +9745,9 @@ msgstr ""
msgid "Something went wrong while resolving this discussion. Please try again."
msgstr ""
+msgid "Something went wrong while stopping this environment. Please try again."
+msgstr ""
+
msgid "Something went wrong, unable to search projects"
msgstr ""
@@ -9752,6 +9964,9 @@ msgstr ""
msgid "Start a %{new_merge_request} with these changes"
msgstr ""
+msgid "Start a new discussion..."
+msgstr ""
+
msgid "Start a new merge request"
msgstr ""
@@ -9767,16 +9982,16 @@ msgstr ""
msgid "Start date"
msgstr ""
-msgid "Start discussion"
+msgid "Start the Runner!"
msgstr ""
-msgid "Start discussion & close %{noteable_name}"
+msgid "Start thread"
msgstr ""
-msgid "Start discussion & reopen %{noteable_name}"
+msgid "Start thread & close %{noteable_name}"
msgstr ""
-msgid "Start the Runner!"
+msgid "Start thread & reopen %{noteable_name}"
msgstr ""
msgid "Started"
@@ -10121,6 +10336,9 @@ msgstr ""
msgid "Templates"
msgstr ""
+msgid "Terminal"
+msgstr ""
+
msgid "Terminal for environment"
msgstr ""
@@ -10519,6 +10737,9 @@ msgstr ""
msgid "This branch has changed since you started editing. Would you like to create a new branch?"
msgstr ""
+msgid "This comment has changed since you started editing, please review the %{startTag}updated comment%{endTag} to ensure information is not lost."
+msgstr ""
+
msgid "This commit is part of merge request %{link_to_merge_request}. Comments created here will be created in the context of that merge request."
msgstr ""
@@ -10555,6 +10776,9 @@ msgstr ""
msgid "This domain is not verified. You will need to verify ownership before access is enabled."
msgstr ""
+msgid "This feature requires local storage to be enabled"
+msgstr ""
+
msgid "This field is required."
msgstr ""
@@ -10567,6 +10791,9 @@ msgstr ""
msgid "This is a \"Ghost User\", created to hold all issues authored by users that have since been deleted. This user cannot be removed."
msgstr ""
+msgid "This is a Work in Progress"
+msgstr ""
+
msgid "This is a confidential issue."
msgstr ""
@@ -10585,6 +10812,9 @@ msgstr ""
msgid "This is your current session"
msgstr ""
+msgid "This issue is %{confidentialLinkStart}confidential%{linkEnd} and %{lockedLinkStart}locked%{linkEnd}."
+msgstr ""
+
msgid "This issue is confidential"
msgstr ""
@@ -10651,6 +10881,9 @@ msgstr ""
msgid "This job will automatically run after its timer finishes. Often they are used for incremental roll-out deploys to production environments. When unscheduled it converts into a manual action."
msgstr ""
+msgid "This may expose confidential information as the selected fork is in another namespace that can have other members."
+msgstr ""
+
msgid "This means you can not push code until you create an empty repository or import existing one."
msgstr ""
@@ -10765,12 +10998,21 @@ msgstr ""
msgid "TimeTrackingEstimated|Est"
msgstr ""
+msgid "TimeTracking|%{startTag}Spent: %{endTag}%{timeSpentHumanReadable}"
+msgstr ""
+
msgid "TimeTracking|Estimated:"
msgstr ""
+msgid "TimeTracking|Over by %{timeRemainingHumanReadable}"
+msgstr ""
+
msgid "TimeTracking|Spent"
msgstr ""
+msgid "TimeTracking|Time remaining: %{timeRemainingHumanReadable}"
+msgstr ""
+
msgid "Timeago|%s days ago"
msgstr ""
@@ -10982,6 +11224,12 @@ msgstr ""
msgid "To preserve performance only <strong>%{display_size} of %{real_size}</strong> files are displayed."
msgstr ""
+msgid "To protect this issue's confidentiality, %{link_start}fork the project%{link_end} and set the forks visiblity to private."
+msgstr ""
+
+msgid "To protect this issue's confidentiality, a private fork of this project was selected."
+msgstr ""
+
msgid "To see all the user's personal access tokens you must impersonate them first."
msgstr ""
@@ -11003,16 +11251,13 @@ msgstr ""
msgid "To widen your search, change or remove filters above"
msgstr ""
-msgid "Today"
-msgstr ""
-
-msgid "Todo"
+msgid "To-Do List"
msgstr ""
-msgid "Todo was successfully marked as done."
+msgid "To-do item successfully marked as done."
msgstr ""
-msgid "Todos"
+msgid "Today"
msgstr ""
msgid "Toggle Sidebar"
@@ -11030,15 +11275,18 @@ msgstr ""
msgid "Toggle commit list"
msgstr ""
-msgid "Toggle discussion"
-msgstr ""
-
msgid "Toggle emoji award"
msgstr ""
msgid "Toggle navigation"
msgstr ""
+msgid "Toggle sidebar"
+msgstr ""
+
+msgid "Toggle thread"
+msgstr ""
+
msgid "ToggleButton|Toggle Status: OFF"
msgstr ""
@@ -11153,6 +11401,12 @@ msgstr ""
msgid "Tuesday"
msgstr ""
+msgid "Turn Off"
+msgstr ""
+
+msgid "Turn On"
+msgstr ""
+
msgid "Twitter"
msgstr ""
@@ -11180,6 +11434,9 @@ msgstr ""
msgid "U2F only works with HTTPS-enabled websites. Contact your administrator for more details."
msgstr ""
+msgid "Unable to apply suggestions to a deleted line."
+msgstr ""
+
msgid "Unable to connect to Prometheus server"
msgstr ""
@@ -11216,6 +11473,12 @@ msgstr ""
msgid "Unfortunately, your email message to GitLab could not be processed."
msgstr ""
+msgid "Uninstall"
+msgstr ""
+
+msgid "Uninstalling"
+msgstr ""
+
msgid "Unknown encryption strategy: %{encrypted_strategy}!"
msgstr ""
@@ -11243,6 +11506,9 @@ msgstr ""
msgid "Unresolve discussion"
msgstr ""
+msgid "Unresolve thread"
+msgstr ""
+
msgid "Unschedule job"
msgstr ""
@@ -11279,6 +11545,9 @@ msgstr ""
msgid "Unsubscribe from %{type}"
msgstr ""
+msgid "Until"
+msgstr ""
+
msgid "Unverified"
msgstr ""
@@ -11288,6 +11557,9 @@ msgstr ""
msgid "Upcoming"
msgstr ""
+msgid "Upcoming Release"
+msgstr ""
+
msgid "Update"
msgstr ""
@@ -11321,6 +11593,9 @@ msgstr ""
msgid "Updated"
msgstr ""
+msgid "Updated to"
+msgstr ""
+
msgid "Updating"
msgstr ""
@@ -12070,6 +12345,9 @@ msgstr ""
msgid "You don't have any deployments right now."
msgstr ""
+msgid "You don't have any recent searches"
+msgstr ""
+
msgid "You have been granted %{access_level} access to the %{source_link} %{source_type}."
msgstr ""
@@ -12232,7 +12510,7 @@ msgstr ""
msgid "Your SSH keys (%{count})"
msgstr ""
-msgid "Your Todos"
+msgid "Your To-Do List"
msgstr ""
msgid "Your U2F device did not send a valid JSON response."
@@ -12334,6 +12612,9 @@ msgstr ""
msgid "among other things"
msgstr ""
+msgid "assign yourself"
+msgstr ""
+
msgid "attach a new file"
msgstr ""
@@ -12343,6 +12624,9 @@ msgstr ""
msgid "branch name"
msgstr ""
+msgid "by"
+msgstr ""
+
msgid "cannot be changed if a personal project has container registry tags."
msgstr ""
@@ -12352,6 +12636,9 @@ msgstr ""
msgid "cannot include leading slash or directory traversal."
msgstr ""
+msgid "comment"
+msgstr ""
+
msgid "commented on %{link_to_project}"
msgstr ""
@@ -12370,6 +12657,9 @@ msgstr ""
msgid "could not read private key, is the passphrase correct?"
msgstr ""
+msgid "created"
+msgstr ""
+
msgid "customize"
msgstr ""
@@ -12384,20 +12674,12 @@ msgstr[1] ""
msgid "deleted"
msgstr ""
-msgid "deploy token"
-msgstr ""
-
msgid "detached"
msgstr ""
msgid "disabled"
msgstr ""
-msgid "discussion resolved"
-msgid_plural "discussions resolved"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "done"
msgstr ""
@@ -12485,6 +12767,9 @@ msgstr ""
msgid "is not an email you own"
msgstr ""
+msgid "issue"
+msgstr ""
+
msgid "issue boards"
msgstr ""
@@ -12535,6 +12820,15 @@ msgstr ""
msgid "mrWidgetCommitsAdded|1 merge commit"
msgstr ""
+msgid "mrWidgetNothingToMerge|Currently there are no changes in this merge request's source branch. Please push new commits or use a different branch."
+msgstr ""
+
+msgid "mrWidgetNothingToMerge|Interested parties can even contribute by pushing commits if they want to."
+msgstr ""
+
+msgid "mrWidgetNothingToMerge|Merge requests are a place to propose changes you have made to a project and discuss those changes with others."
+msgstr ""
+
msgid "mrWidget| Please restore it or use a different %{missingBranchName} branch"
msgstr ""
@@ -12652,6 +12946,9 @@ msgstr ""
msgid "mrWidget|Request to merge"
msgstr ""
+msgid "mrWidget|Resolve WIP status"
+msgstr ""
+
msgid "mrWidget|Resolve conflicts"
msgstr ""
@@ -12700,7 +12997,7 @@ msgstr ""
msgid "mrWidget|There are merge conflicts"
msgstr ""
-msgid "mrWidget|There are unresolved discussions. Please resolve these discussions"
+msgid "mrWidget|There are unresolved threads. Please resolve these threads"
msgstr ""
msgid "mrWidget|This feature merges changes from the target branch to the source branch. You cannot use this feature since the source branch is protected."
@@ -12715,6 +13012,9 @@ msgstr ""
msgid "mrWidget|This project is archived, write access has been disabled"
msgstr ""
+msgid "mrWidget|When this merge request is ready, remove the WIP: prefix from the title to allow it to be merged"
+msgstr ""
+
msgid "mrWidget|You are not allowed to edit this project directly. Please fork to make changes."
msgstr ""
@@ -12754,6 +13054,9 @@ msgstr ""
msgid "none"
msgstr ""
+msgid "not found"
+msgstr ""
+
msgid "notification emails"
msgstr ""
@@ -12782,7 +13085,7 @@ msgstr[1] ""
msgid "password"
msgstr ""
-msgid "personal access token"
+msgid "pending comment"
msgstr ""
msgid "private"
@@ -12797,15 +13100,24 @@ msgstr ""
msgid "project"
msgstr ""
+msgid "project avatar"
+msgstr ""
+
msgid "quick actions"
msgstr ""
msgid "register"
msgstr ""
+msgid "released %{time}"
+msgstr ""
+
msgid "remaining"
msgstr ""
+msgid "remove"
+msgstr ""
+
msgid "remove due date"
msgstr ""
@@ -12868,15 +13180,29 @@ msgstr ""
msgid "this document"
msgstr ""
+msgid "thread resolved"
+msgid_plural "threads resolved"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "to list"
msgstr ""
+msgid "toggle collapse"
+msgstr ""
+
+msgid "toggle dropdown"
+msgstr ""
+
msgid "triggered"
msgstr ""
msgid "updated"
msgstr ""
+msgid "user avatar"
+msgstr ""
+
msgid "username"
msgstr ""
diff --git a/package.json b/package.json
index acbe87a5994..5955790488a 100644
--- a/package.json
+++ b/package.json
@@ -37,8 +37,8 @@
"@babel/plugin-syntax-import-meta": "^7.2.0",
"@babel/preset-env": "^7.4.4",
"@gitlab/csslab": "^1.9.0",
- "@gitlab/svgs": "^1.65.0",
- "@gitlab/ui": "^5.1.0",
+ "@gitlab/svgs": "^1.67.0",
+ "@gitlab/ui": "^5.5.0",
"apollo-cache-inmemory": "^1.5.1",
"apollo-client": "^2.5.1",
"apollo-link": "^1.2.11",
@@ -168,7 +168,6 @@
"gettext-extractor": "^3.4.3",
"gettext-extractor-vue": "^4.0.2",
"graphql-tag": "^2.10.0",
- "istanbul": "^0.4.5",
"jasmine-core": "^2.9.0",
"jasmine-diff": "^0.1.3",
"jasmine-jquery": "^2.1.1",
diff --git a/qa/.rspec_parallel b/qa/.rspec_parallel
new file mode 100644
index 00000000000..e5927927eaa
--- /dev/null
+++ b/qa/.rspec_parallel
@@ -0,0 +1,5 @@
+--color
+--format documentation
+--format ParallelTests::RSpec::SummaryLogger --out tmp/spec_summary.log
+--format ParallelTests::RSpec::RuntimeLogger --out tmp/parallel_runtime_rspec.log
+--require spec_helper
diff --git a/qa/Gemfile b/qa/Gemfile
index 12994b85322..c46be8a0362 100644
--- a/qa/Gemfile
+++ b/qa/Gemfile
@@ -1,5 +1,6 @@
source 'https://rubygems.org'
+gem 'gitlab-qa'
gem 'pry-byebug', '~> 3.5.1', platform: :mri
gem 'capybara', '~> 2.16.1'
gem 'capybara-screenshot', '~> 1.0.18'
@@ -11,3 +12,4 @@ gem 'nokogiri', '~> 1.10.3'
gem 'rspec-retry', '~> 0.6.1'
gem 'faker', '~> 1.6', '>= 1.6.6'
gem 'knapsack', '~> 1.17'
+gem 'parallel_tests', '~> 2.29'
diff --git a/qa/Gemfile.lock b/qa/Gemfile.lock
index 6b0635ed0e2..73aabf2c6ad 100644
--- a/qa/Gemfile.lock
+++ b/qa/Gemfile.lock
@@ -35,6 +35,7 @@ GEM
faker (1.9.3)
i18n (>= 0.7)
ffi (1.9.25)
+ gitlab-qa (4.0.0)
http-cookie (1.0.3)
domain_name (~> 0.5)
i18n (0.9.1)
@@ -53,6 +54,9 @@ GEM
netrc (0.11.0)
nokogiri (1.10.3)
mini_portile2 (~> 2.4.0)
+ parallel (1.17.0)
+ parallel_tests (2.29.0)
+ parallel
pry (0.11.3)
coderay (~> 1.1.0)
method_source (~> 0.9.0)
@@ -104,8 +108,10 @@ DEPENDENCIES
capybara (~> 2.16.1)
capybara-screenshot (~> 1.0.18)
faker (~> 1.6, >= 1.6.6)
+ gitlab-qa
knapsack (~> 1.17)
nokogiri (~> 1.10.3)
+ parallel_tests (~> 2.29)
pry-byebug (~> 3.5.1)
rake (~> 12.3.0)
rspec (~> 3.7)
diff --git a/qa/qa.rb b/qa/qa.rb
index 944dcc31917..be73776425b 100644
--- a/qa/qa.rb
+++ b/qa/qa.rb
@@ -162,9 +162,12 @@ module QA
module File
autoload :Form, 'qa/page/file/form'
autoload :Show, 'qa/page/file/show'
+ autoload :Edit, 'qa/page/file/edit'
module Shared
autoload :CommitMessage, 'qa/page/file/shared/commit_message'
+ autoload :CommitButton, 'qa/page/file/shared/commit_button'
+ autoload :Editor, 'qa/page/file/shared/editor'
end
end
@@ -218,6 +221,7 @@ module QA
autoload :Operations, 'qa/page/project/sub_menus/operations'
autoload :Repository, 'qa/page/project/sub_menus/repository'
autoload :Settings, 'qa/page/project/sub_menus/settings'
+ autoload :Project, 'qa/page/project/sub_menus/project'
end
module Issue
@@ -323,6 +327,7 @@ module QA
autoload :DropdownFilter, 'qa/page/component/dropdown_filter'
autoload :UsersSelect, 'qa/page/component/users_select'
autoload :Note, 'qa/page/component/note'
+ autoload :ConfirmModal, 'qa/page/component/confirm_modal'
module Issuable
autoload :Common, 'qa/page/component/issuable/common'
@@ -355,6 +360,7 @@ module QA
module Specs
autoload :Config, 'qa/specs/config'
autoload :Runner, 'qa/specs/runner'
+ autoload :ParallelRunner, 'qa/specs/parallel_runner'
module Helpers
autoload :Quarantine, 'qa/specs/helpers/quarantine'
diff --git a/qa/qa/page/component/confirm_modal.rb b/qa/qa/page/component/confirm_modal.rb
new file mode 100644
index 00000000000..355e2783fb7
--- /dev/null
+++ b/qa/qa/page/component/confirm_modal.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+module QA
+ module Page
+ module Component
+ module ConfirmModal
+ def self.included(base)
+ base.view 'app/views/shared/_confirm_modal.html.haml' do
+ element :confirm_modal
+ element :confirm_input
+ element :confirm_button
+ end
+ end
+
+ def fill_confirmation_text(text)
+ fill_element :confirm_input, text
+ end
+
+ def click_confirm_button
+ click_element :confirm_button
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/page/component/select2.rb b/qa/qa/page/component/select2.rb
index e40bc4b1d3e..85d4abcde9b 100644
--- a/qa/qa/page/component/select2.rb
+++ b/qa/qa/page/component/select2.rb
@@ -18,6 +18,10 @@ module QA
find('.select2-input').set(item_text)
select_item(item_text)
end
+
+ def expand_select_list
+ find('span.select2-arrow').click
+ end
end
end
end
diff --git a/qa/qa/page/file/edit.rb b/qa/qa/page/file/edit.rb
new file mode 100644
index 00000000000..3a4a1837b1c
--- /dev/null
+++ b/qa/qa/page/file/edit.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+module QA
+ module Page
+ module File
+ class Edit < Page::Base
+ include Shared::CommitMessage
+ include Shared::CommitButton
+ include Shared::Editor
+ end
+ end
+ end
+end
diff --git a/qa/qa/page/file/form.rb b/qa/qa/page/file/form.rb
index e42de7d65c5..a6251f185f9 100644
--- a/qa/qa/page/file/form.rb
+++ b/qa/qa/page/file/form.rb
@@ -6,14 +6,11 @@ module QA
class Form < Page::Base
include Shared::CommitMessage
include Page::Component::DropdownFilter
+ include Shared::CommitButton
+ include Shared::Editor
view 'app/views/projects/blob/_editor.html.haml' do
element :file_name, "text_field_tag 'file_name'" # rubocop:disable QA/ElementWithPattern
- element :editor, '#editor' # rubocop:disable QA/ElementWithPattern
- end
-
- view 'app/views/projects/_commit_button.html.haml' do
- element :commit_changes, "button_tag 'Commit changes'" # rubocop:disable QA/ElementWithPattern
end
view 'app/views/projects/blob/_template_selectors.html.haml' do
@@ -28,20 +25,6 @@ module QA
fill_in 'file_name', with: name
end
- def add_content(content)
- text_area.set content
- end
-
- def remove_content
- text_area.send_keys([:command, 'a'], :backspace)
- end
-
- def commit_changes
- click_on 'Commit changes'
-
- finished_loading?
- end
-
def select_template(template_type, template)
click_element :template_type_dropdown
click_link template_type
@@ -60,12 +43,6 @@ module QA
end
filter_and_select template
end
-
- private
-
- def text_area
- find('#editor>textarea', visible: false)
- end
end
end
end
diff --git a/qa/qa/page/file/shared/commit_button.rb b/qa/qa/page/file/shared/commit_button.rb
new file mode 100644
index 00000000000..d8e751dd7b6
--- /dev/null
+++ b/qa/qa/page/file/shared/commit_button.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+module QA
+ module Page
+ module File
+ module Shared
+ module CommitButton
+ def self.included(base)
+ base.view 'app/views/projects/_commit_button.html.haml' do
+ element :commit_button
+ end
+ end
+
+ def commit_changes
+ click_element(:commit_button)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/page/file/shared/editor.rb b/qa/qa/page/file/shared/editor.rb
new file mode 100644
index 00000000000..448c09cfbca
--- /dev/null
+++ b/qa/qa/page/file/shared/editor.rb
@@ -0,0 +1,33 @@
+# frozen_string_literal: true
+
+module QA
+ module Page
+ module File
+ module Shared
+ module Editor
+ def self.included(base)
+ base.view 'app/views/projects/blob/_editor.html.haml' do
+ element :editor
+ end
+ end
+
+ def add_content(content)
+ text_area.set content
+ end
+
+ def remove_content
+ text_area.send_keys([:command, 'a'], :backspace)
+ end
+
+ private
+
+ def text_area
+ within_element :editor do
+ find('textarea', visible: false)
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/page/file/show.rb b/qa/qa/page/file/show.rb
index eaf88c6e69e..92f9181f99d 100644
--- a/qa/qa/page/file/show.rb
+++ b/qa/qa/page/file/show.rb
@@ -5,6 +5,8 @@ module QA
module File
class Show < Page::Base
include Shared::CommitMessage
+ include Project::SubMenus::Settings
+ include Project::SubMenus::Common
view 'app/helpers/blob_helper.rb' do
element :edit_button, "_('Edit')" # rubocop:disable QA/ElementWithPattern
diff --git a/qa/qa/page/project/operations/kubernetes/show.rb b/qa/qa/page/project/operations/kubernetes/show.rb
index c81e13e9b91..4f625c5f0f0 100644
--- a/qa/qa/page/project/operations/kubernetes/show.rb
+++ b/qa/qa/page/project/operations/kubernetes/show.rb
@@ -28,12 +28,16 @@ module QA
end
end
- def await_installed(application_name)
+ def await_installed(application_name, button_text: 'Installed')
within(".js-cluster-application-row-#{application_name}") do
- page.has_text?('Installed', wait: 300)
+ page.has_text?(button_text, wait: 300)
end
end
+ def await_uninstallable(application_name)
+ await_installed(application_name, button_text: 'Uninstall')
+ end
+
def ingress_ip
# We need to wait longer since it can take some time before the
# ip address is assigned for the ingress controller
diff --git a/qa/qa/page/project/settings/advanced.rb b/qa/qa/page/project/settings/advanced.rb
index 75530832860..ab4e3d757b6 100644
--- a/qa/qa/page/project/settings/advanced.rb
+++ b/qa/qa/page/project/settings/advanced.rb
@@ -5,9 +5,13 @@ module QA
module Project
module Settings
class Advanced < Page::Base
+ include Component::Select2
+ include Component::ConfirmModal
+
view 'app/views/projects/edit.html.haml' do
element :project_path_field
element :change_path_button
+ element :transfer_button
end
def update_project_path_to(path)
@@ -22,6 +26,18 @@ module QA
def click_change_path_button
click_element :change_path_button
end
+
+ def select_transfer_option(namespace)
+ search_and_select(namespace)
+ end
+
+ def transfer_project!(project_name, namespace)
+ expand_select_list
+ select_transfer_option(namespace)
+ click_element(:transfer_button)
+ fill_confirmation_text(project_name)
+ click_confirm_button
+ end
end
end
end
diff --git a/qa/qa/page/project/settings/main.rb b/qa/qa/page/project/settings/main.rb
index d1f3b15f950..dbbe62e3b1d 100644
--- a/qa/qa/page/project/settings/main.rb
+++ b/qa/qa/page/project/settings/main.rb
@@ -6,6 +6,8 @@ module QA
module Settings
class Main < Page::Base
include Common
+ include Component::Select2
+ include SubMenus::Project
view 'app/views/projects/edit.html.haml' do
element :advanced_settings
diff --git a/qa/qa/page/project/show.rb b/qa/qa/page/project/show.rb
index 1a9a2fd413f..9fd668f812b 100644
--- a/qa/qa/page/project/show.rb
+++ b/qa/qa/page/project/show.rb
@@ -5,6 +5,7 @@ module QA
module Project
class Show < Page::Base
include Page::Component::ClonePanel
+ include Page::Project::SubMenus::Settings
view 'app/views/layouts/header/_new_dropdown.haml' do
element :new_menu_toggle
diff --git a/qa/qa/page/project/sub_menus/ci_cd.rb b/qa/qa/page/project/sub_menus/ci_cd.rb
index adae2ce08c4..2f0bc8b9ba6 100644
--- a/qa/qa/page/project/sub_menus/ci_cd.rb
+++ b/qa/qa/page/project/sub_menus/ci_cd.rb
@@ -5,6 +5,8 @@ module QA
module Project
module SubMenus
module CiCd
+ include Page::Project::SubMenus::Common
+
def self.included(base)
base.class_eval do
view 'app/views/layouts/nav/sidebar/_project.html.haml' do
diff --git a/qa/qa/page/project/sub_menus/issues.rb b/qa/qa/page/project/sub_menus/issues.rb
index f81e4f34909..8fb8fa06346 100644
--- a/qa/qa/page/project/sub_menus/issues.rb
+++ b/qa/qa/page/project/sub_menus/issues.rb
@@ -5,6 +5,8 @@ module QA
module Project
module SubMenus
module Issues
+ include Page::Project::SubMenus::Common
+
def self.included(base)
base.class_eval do
view 'app/views/layouts/nav/sidebar/_project.html.haml' do
diff --git a/qa/qa/page/project/sub_menus/operations.rb b/qa/qa/page/project/sub_menus/operations.rb
index 24a99a9464c..d266cb21417 100644
--- a/qa/qa/page/project/sub_menus/operations.rb
+++ b/qa/qa/page/project/sub_menus/operations.rb
@@ -5,6 +5,8 @@ module QA
module Project
module SubMenus
module Operations
+ include Page::Project::SubMenus::Common
+
def self.included(base)
base.class_eval do
view 'app/views/layouts/nav/sidebar/_project.html.haml' do
diff --git a/qa/qa/page/project/sub_menus/project.rb b/qa/qa/page/project/sub_menus/project.rb
new file mode 100644
index 00000000000..5e0ee3c274a
--- /dev/null
+++ b/qa/qa/page/project/sub_menus/project.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+module QA
+ module Page
+ module Project
+ module SubMenus
+ module Project
+ include Common
+
+ def self.included(base)
+ base.class_eval do
+ view 'app/views/layouts/nav/sidebar/_project.html.haml' do
+ element :link_project
+ end
+ end
+ end
+
+ def click_project
+ retry_on_exception do
+ within_sidebar do
+ click_element(:link_project)
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/page/project/sub_menus/repository.rb b/qa/qa/page/project/sub_menus/repository.rb
index 4cc73a6b25a..c53d805c61d 100644
--- a/qa/qa/page/project/sub_menus/repository.rb
+++ b/qa/qa/page/project/sub_menus/repository.rb
@@ -5,6 +5,8 @@ module QA
module Project
module SubMenus
module Repository
+ include Page::Project::SubMenus::Common
+
def self.included(base)
base.class_eval do
view 'app/views/layouts/nav/sidebar/_project.html.haml' do
diff --git a/qa/qa/page/project/sub_menus/settings.rb b/qa/qa/page/project/sub_menus/settings.rb
index 22743ebd0a1..1cd39fcff58 100644
--- a/qa/qa/page/project/sub_menus/settings.rb
+++ b/qa/qa/page/project/sub_menus/settings.rb
@@ -5,11 +5,14 @@ module QA
module Project
module SubMenus
module Settings
+ include Page::Project::SubMenus::Common
+
def self.included(base)
base.class_eval do
view 'app/views/layouts/nav/sidebar/_project.html.haml' do
element :settings_item
element :link_members_settings
+ element :general_settings_link
end
end
end
@@ -38,6 +41,14 @@ module QA
end
end
+ def go_to_general_settings
+ hover_settings do
+ within_submenu do
+ click_element :general_settings_link
+ end
+ end
+ end
+
def click_settings
within_sidebar do
click_on 'Settings'
diff --git a/qa/qa/resource/group.rb b/qa/qa/resource/group.rb
index 0b567a474c8..44d9dc8f296 100644
--- a/qa/qa/resource/group.rb
+++ b/qa/qa/resource/group.rb
@@ -67,6 +67,10 @@ module QA
visibility: 'public'
}
end
+
+ def full_path
+ sandbox.path + ' / ' + path
+ end
end
end
end
diff --git a/qa/qa/resource/issue.rb b/qa/qa/resource/issue.rb
index 9c57a0f5afb..51b2af8b4ef 100644
--- a/qa/qa/resource/issue.rb
+++ b/qa/qa/resource/issue.rb
@@ -16,6 +16,10 @@ module QA
attribute :labels
attribute :title
+ def initialize
+ @labels = []
+ end
+
def fabricate!
project.visit!
@@ -38,7 +42,7 @@ module QA
def api_post_body
{
- labels: [labels],
+ labels: labels,
title: title
}
end
diff --git a/qa/qa/resource/kubernetes_cluster.rb b/qa/qa/resource/kubernetes_cluster.rb
index 27ab7b60211..1dd93dd5b88 100644
--- a/qa/qa/resource/kubernetes_cluster.rb
+++ b/qa/qa/resource/kubernetes_cluster.rb
@@ -47,7 +47,7 @@ module QA
page.install!(:runner) if @install_runner
page.await_installed(:ingress) if @install_ingress
- page.await_installed(:prometheus) if @install_prometheus
+ page.await_uninstallable(:prometheus) if @install_prometheus
page.await_installed(:runner) if @install_runner
if @install_ingress
diff --git a/qa/qa/runtime/browser.rb b/qa/qa/runtime/browser.rb
index ed0779b93cc..2987bb1a213 100644
--- a/qa/qa/runtime/browser.rb
+++ b/qa/qa/runtime/browser.rb
@@ -13,6 +13,8 @@ module QA
NotRespondingError = Class.new(RuntimeError)
+ CAPYBARA_MAX_WAIT_TIME = 10
+
def initialize
self.class.configure!
end
@@ -43,6 +45,8 @@ module QA
end
end
+ Capybara.server_port = 9887 + ENV['TEST_ENV_NUMBER'].to_i
+
return if Capybara.drivers.include?(:chrome)
Capybara.register_driver QA::Runtime::Env.browser do |app|
@@ -119,7 +123,7 @@ module QA
Capybara.configure do |config|
config.default_driver = QA::Runtime::Env.browser
config.javascript_driver = QA::Runtime::Env.browser
- config.default_max_wait_time = 10
+ config.default_max_wait_time = CAPYBARA_MAX_WAIT_TIME
# https://github.com/mattheworiordan/capybara-screenshot/issues/164
config.save_path = ::File.expand_path('../../tmp', __dir__)
end
diff --git a/qa/qa/runtime/env.rb b/qa/qa/runtime/env.rb
index 96f337dc081..d50f618ff82 100644
--- a/qa/qa/runtime/env.rb
+++ b/qa/qa/runtime/env.rb
@@ -1,5 +1,7 @@
# frozen_string_literal: true
+require 'gitlab/qa'
+
module QA
module Runtime
module Env
@@ -7,6 +9,8 @@ module QA
attr_writer :personal_access_token, :ldap_username, :ldap_password
+ ENV_VARIABLES = Gitlab::QA::Runtime::Env::ENV_VARIABLES
+
# The environment variables used to indicate if the environment under test
# supports the given feature
SUPPORTED_FEATURES = {
@@ -201,6 +205,10 @@ module QA
enabled?(ENV[SUPPORTED_FEATURES[feature]], default: true)
end
+ def runtime_scenario_attributes
+ ENV['QA_RUNTIME_SCENARIO_ATTRIBUTES']
+ end
+
private
def remote_grid_credentials
diff --git a/qa/qa/runtime/scenario.rb b/qa/qa/runtime/scenario.rb
index 5067322804b..3662ebe671b 100644
--- a/qa/qa/runtime/scenario.rb
+++ b/qa/qa/runtime/scenario.rb
@@ -1,5 +1,7 @@
# frozen_string_literal: true
+require 'json'
+
module QA
module Runtime
##
@@ -24,6 +26,10 @@ module QA
end
end
+ def from_env(var)
+ JSON.parse(Runtime::Env.runtime_scenario_attributes).each { |k, v| define(k, v) }
+ end
+
def method_missing(name, *)
raise ArgumentError, "Scenario attribute `#{name}` not defined!"
end
diff --git a/qa/qa/scenario/shared_attributes.rb b/qa/qa/scenario/shared_attributes.rb
index 40d5c6b1ff1..52f50ec8c27 100644
--- a/qa/qa/scenario/shared_attributes.rb
+++ b/qa/qa/scenario/shared_attributes.rb
@@ -7,6 +7,7 @@ module QA
attribute :gitlab_address, '--address URL', 'Address of the instance to test'
attribute :enable_feature, '--enable-feature FEATURE_FLAG', 'Enable a feature before running tests'
+ attribute :parallel, '--parallel', 'Execute tests in parallel'
end
end
end
diff --git a/qa/qa/service/shellout.rb b/qa/qa/service/shellout.rb
index 7065ab0e7f3..217df669db3 100644
--- a/qa/qa/service/shellout.rb
+++ b/qa/qa/service/shellout.rb
@@ -19,7 +19,7 @@ module QA
Open3.popen2e(*command) do |stdin, out, wait|
stdin.puts(stdin_data) if stdin_data
stdin.close if stdin_data
- out.each { |line| puts line }
+ out.each_char { |char| print char }
if wait.value.exited? && wait.value.exitstatus.nonzero?
raise CommandError, "Command `#{command}` failed!"
diff --git a/qa/qa/specs/features/browser_ui/1_manage/group/transfer_project_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/group/transfer_project_spec.rb
new file mode 100644
index 00000000000..a9de64e357a
--- /dev/null
+++ b/qa/qa/specs/features/browser_ui/1_manage/group/transfer_project_spec.rb
@@ -0,0 +1,57 @@
+# frozen_string_literal: true
+
+module QA
+ context 'Manage' do
+ describe 'Project transfer between groups' do
+ it 'user transfers a project between groups' do
+ Runtime::Browser.visit(:gitlab, Page::Main::Login)
+ Page::Main::Login.act { sign_in_using_credentials }
+
+ source_group = Resource::Group.fabricate! do |group|
+ group.path = 'source-group'
+ end
+
+ target_group = Resource::Group.fabricate! do |group|
+ group.path = 'target-group'
+ end
+
+ project = Resource::Project.fabricate! do |project|
+ project.group = source_group
+ project.name = 'transfer-project'
+ project.initialize_with_readme = true
+ end
+
+ project.visit!
+
+ Page::Project::Show.perform do |project|
+ project.click_file('README.md')
+ end
+
+ Page::File::Show.perform(&:click_edit)
+
+ edited_readme_content = 'Here is the edited content.'
+
+ Page::File::Edit.perform do |file|
+ file.remove_content
+ file.add_content(edited_readme_content)
+ file.commit_changes
+ end
+
+ Page::File::Show.perform(&:go_to_general_settings)
+
+ Page::Project::Settings::Main.perform(&:expand_advanced_settings)
+
+ Page::Project::Settings::Advanced.perform do |advanced|
+ advanced.transfer_project!(project.name, target_group.full_path)
+ end
+
+ Page::Project::Settings::Main.perform(&:click_project)
+
+ Page::Project::Show.perform do |project|
+ expect(project).to have_text(target_group.path)
+ expect(project).to have_text(edited_readme_content)
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/specs/features/browser_ui/2_plan/issue/check_mentions_for_xss_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/issue/check_mentions_for_xss_spec.rb
new file mode 100644
index 00000000000..5eceeb9661c
--- /dev/null
+++ b/qa/qa/specs/features/browser_ui/2_plan/issue/check_mentions_for_xss_spec.rb
@@ -0,0 +1,44 @@
+# frozen_string_literal: true
+
+module QA
+ context 'Plan' do
+ describe 'check xss occurence in @mentions in issues' do
+ let(:issue_title) { 'issue title' }
+
+ it 'user mentions a user in comment' do
+ Runtime::Browser.visit(:gitlab, Page::Main::Login)
+ Page::Main::Login.perform(&:sign_in_using_credentials)
+
+ user = Resource::User.fabricate_via_api! do |user|
+ user.name = "eve <img src=x onerror=alert(2)&lt;img src=x onerror=alert(1)&gt;"
+ user.password = "test1234"
+ end
+
+ project = Resource::Project.fabricate_via_api! do |resource|
+ resource.name = 'xss-test-for-mentions-project'
+ end
+ project.visit!
+
+ Page::Project::Show.perform(&:go_to_members_settings)
+ Page::Project::Settings::Members.perform do |page|
+ page.add_member(user.username)
+ end
+
+ issue = Resource::Issue.fabricate_via_api! do |issue|
+ issue.title = issue_title
+ issue.project = project
+ end
+ issue.visit!
+
+ Page::Project::Issue::Show.perform do |show_page|
+ show_page.select_all_activities_filter
+ show_page.comment('cc-ing you here @eve')
+
+ expect do
+ expect(show_page).to have_content("cc-ing you here")
+ end.not_to raise_error # Selenium::WebDriver::Error::UnhandledAlertError
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/specs/features/browser_ui/2_plan/issue/collapse_comments_in_discussions_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/issue/collapse_comments_in_discussions_spec.rb
index 4478ea41662..2101311f065 100644
--- a/qa/qa/specs/features/browser_ui/2_plan/issue/collapse_comments_in_discussions_spec.rb
+++ b/qa/qa/specs/features/browser_ui/2_plan/issue/collapse_comments_in_discussions_spec.rb
@@ -9,27 +9,33 @@ module QA
Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.perform(&:sign_in_using_credentials)
- Resource::Issue.fabricate_via_browser_ui! do |issue|
+ issue = Resource::Issue.fabricate_via_api! do |issue|
issue.title = issue_title
end
+ issue.visit!
+
expect(page).to have_content(issue_title)
Page::Project::Issue::Show.perform do |show_page|
+ my_first_discussion = "My first discussion"
+ my_first_reply = "My First Reply"
+ one_reply = "1 reply"
+
show_page.select_all_activities_filter
- show_page.start_discussion("My first discussion")
- expect(show_page).to have_content("My first discussion")
+ show_page.start_discussion(my_first_discussion)
+ expect(show_page).to have_content(my_first_discussion)
- show_page.reply_to_discussion("My First Reply")
- expect(show_page).to have_content("My First Reply")
+ show_page.reply_to_discussion(my_first_reply)
+ expect(show_page).to have_content(my_first_reply)
show_page.collapse_replies
- expect(show_page).to have_content("1 reply")
- expect(show_page).not_to have_content("My First Reply")
+ expect(show_page).to have_content(one_reply)
+ expect(show_page).not_to have_content(my_first_reply)
show_page.expand_replies
- expect(show_page).to have_content("My First Reply")
- expect(show_page).not_to have_content("1 reply")
+ expect(show_page).to have_content(my_first_reply)
+ expect(show_page).not_to have_content(one_reply)
end
end
end
diff --git a/qa/qa/specs/features/browser_ui/2_plan/issue/filter_issue_comments_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/issue/filter_issue_comments_spec.rb
index ad2773b41ac..301836f5ce8 100644
--- a/qa/qa/specs/features/browser_ui/2_plan/issue/filter_issue_comments_spec.rb
+++ b/qa/qa/specs/features/browser_ui/2_plan/issue/filter_issue_comments_spec.rb
@@ -9,28 +9,33 @@ module QA
Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.act { sign_in_using_credentials }
- Resource::Issue.fabricate_via_browser_ui! do |issue|
+ issue = Resource::Issue.fabricate_via_api! do |issue|
issue.title = issue_title
end
+ issue.visit!
+
expect(page).to have_content(issue_title)
Page::Project::Issue::Show.perform do |show_page|
+ my_own_comment = "My own comment"
+ made_the_issue_confidential = "made the issue confidential"
+
show_page.comment('/confidential', filter: :comments_only)
- show_page.comment('My own comment', filter: :comments_only)
+ show_page.comment(my_own_comment, filter: :comments_only)
- expect(show_page).not_to have_content("made the issue confidential")
- expect(show_page).to have_content("My own comment")
+ expect(show_page).not_to have_content(made_the_issue_confidential)
+ expect(show_page).to have_content(my_own_comment)
show_page.select_all_activities_filter
- expect(show_page).to have_content("made the issue confidential")
- expect(show_page).to have_content("My own comment")
+ expect(show_page).to have_content(made_the_issue_confidential)
+ expect(show_page).to have_content(my_own_comment)
show_page.select_history_only_filter
- expect(show_page).to have_content("made the issue confidential")
- expect(show_page).not_to have_content("My own comment")
+ expect(show_page).to have_content(made_the_issue_confidential)
+ expect(show_page).not_to have_content(my_own_comment)
end
end
end
diff --git a/qa/qa/specs/features/browser_ui/2_plan/issue/issue_suggestions_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/issue/issue_suggestions_spec.rb
index 530fc684437..24dcb32f63f 100644
--- a/qa/qa/specs/features/browser_ui/2_plan/issue/issue_suggestions_spec.rb
+++ b/qa/qa/specs/features/browser_ui/2_plan/issue/issue_suggestions_spec.rb
@@ -14,7 +14,7 @@ module QA
resource.description = 'project for issue suggestions'
end
- Resource::Issue.fabricate_via_browser_ui! do |issue|
+ Resource::Issue.fabricate_via_api! do |issue|
issue.title = issue_title
issue.project = project
end
diff --git a/qa/qa/specs/features/browser_ui/3_create/merge_request/view_merge_request_diff_patch_spec.rb b/qa/qa/specs/features/browser_ui/3_create/merge_request/view_merge_request_diff_patch_spec.rb
index db33c6330ff..9e48ee7ca2a 100644
--- a/qa/qa/specs/features/browser_ui/3_create/merge_request/view_merge_request_diff_patch_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/merge_request/view_merge_request_diff_patch_spec.rb
@@ -1,8 +1,7 @@
# frozen_string_literal: true
module QA
- # https://gitlab.com/gitlab-org/quality/staging/issues/55
- context 'Create', :quarantine do
+ context 'Create' do
describe 'Download merge request patch and diff' do
before(:context) do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/push_mirroring_over_http_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/push_mirroring_over_http_spec.rb
index 23008a58af8..448d4980727 100644
--- a/qa/qa/specs/features/browser_ui/3_create/repository/push_mirroring_over_http_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/repository/push_mirroring_over_http_spec.rb
@@ -1,8 +1,7 @@
# frozen_string_literal: true
module QA
- # https://gitlab.com/gitlab-org/quality/staging/issues/40
- context 'Create', :quarantine do
+ context 'Create' do
describe 'Push mirror a repository over HTTP' do
it 'configures and syncs a (push) mirrored repository' do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/push_over_http_file_size_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/push_over_http_file_size_spec.rb
index 247cde38e52..11fd570d131 100644
--- a/qa/qa/specs/features/browser_ui/3_create/repository/push_over_http_file_size_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/repository/push_over_http_file_size_spec.rb
@@ -1,7 +1,8 @@
# frozen_string_literal: true
module QA
- context 'Create', :requires_admin do
+ # Failure issue: https://gitlab.com/gitlab-org/quality/nightly/issues/113
+ context 'Create', :requires_admin, :quarantine do
describe 'push after setting the file size limit via admin/application_settings' do
before(:context) do
@project = Resource::Project.fabricate_via_api! do |p|
diff --git a/qa/qa/specs/features/browser_ui/7_configure/auto_devops/create_project_with_auto_devops_spec.rb b/qa/qa/specs/features/browser_ui/7_configure/auto_devops/create_project_with_auto_devops_spec.rb
index 5ca9ddb6b19..99f0838b864 100644
--- a/qa/qa/specs/features/browser_ui/7_configure/auto_devops/create_project_with_auto_devops_spec.rb
+++ b/qa/qa/specs/features/browser_ui/7_configure/auto_devops/create_project_with_auto_devops_spec.rb
@@ -9,6 +9,52 @@ module QA
Page::Main::Login.perform(&:sign_in_using_credentials)
end
+ def disable_optional_jobs(project)
+ # Disable code_quality check in Auto DevOps pipeline as it takes
+ # too long and times out the test
+ Resource::CiVariable.fabricate_via_api! do |resource|
+ resource.project = project
+ resource.key = 'CODE_QUALITY_DISABLED'
+ resource.value = '1'
+ resource.masked = false
+ end
+
+ Resource::CiVariable.fabricate_via_api! do |resource|
+ resource.project = project
+ resource.key = 'LICENSE_MANAGEMENT_DISABLED'
+ resource.value = '1'
+ resource.masked = false
+ end
+
+ Resource::CiVariable.fabricate_via_api! do |resource|
+ resource.project = project
+ resource.key = 'SAST_DISABLED'
+ resource.value = '1'
+ resource.masked = false
+ end
+
+ Resource::CiVariable.fabricate_via_api! do |resource|
+ resource.project = project
+ resource.key = 'DEPENDENCY_SCANNING_DISABLED'
+ resource.value = '1'
+ resource.masked = false
+ end
+
+ Resource::CiVariable.fabricate_via_api! do |resource|
+ resource.project = project
+ resource.key = 'CONTAINER_SCANNING_DISABLED'
+ resource.value = '1'
+ resource.masked = false
+ end
+
+ Resource::CiVariable.fabricate_via_api! do |resource|
+ resource.project = project
+ resource.key = 'DAST_DISABLED'
+ resource.value = '1'
+ resource.masked = false
+ end
+ end
+
# Failure issue: https://gitlab.com/gitlab-org/quality/nightly/issues/108
describe 'Auto DevOps support', :orchestrated, :kubernetes, :quarantine do
context 'when rbac is enabled' do
@@ -28,14 +74,7 @@ module QA
p.description = 'Project with Auto DevOps'
end
- # Disable code_quality check in Auto DevOps pipeline as it takes
- # too long and times out the test
- Resource::CiVariable.fabricate! do |resource|
- resource.project = @project
- resource.key = 'CODE_QUALITY_DISABLED'
- resource.value = '1'
- resource.masked = false
- end
+ disable_optional_jobs(@project)
# Set an application secret CI variable (prefixed with K8S_SECRET_)
Resource::CiVariable.fabricate! do |resource|
diff --git a/qa/qa/specs/parallel_runner.rb b/qa/qa/specs/parallel_runner.rb
new file mode 100644
index 00000000000..b92fdb610b6
--- /dev/null
+++ b/qa/qa/specs/parallel_runner.rb
@@ -0,0 +1,33 @@
+# frozen_string_literal: true
+
+require 'open3'
+
+module QA
+ module Specs
+ module ParallelRunner
+ module_function
+
+ def run(args)
+ unless args.include?('--')
+ index = args.index { |opt| opt.include?('features') }
+
+ args.insert(index, '--') if index
+ end
+
+ env = {}
+ Runtime::Env::ENV_VARIABLES.each_key do |key|
+ env[key] = ENV[key] if ENV[key]
+ end
+ env['QA_RUNTIME_SCENARIO_ATTRIBUTES'] = Runtime::Scenario.attributes.to_json
+ env['GITLAB_QA_ACCESS_TOKEN'] = Runtime::API::Client.new(:gitlab).personal_access_token unless env['GITLAB_QA_ACCESS_TOKEN']
+
+ cmd = "bundle exec parallel_test -t rspec --combine-stderr --serialize-stdout -- #{args.flatten.join(' ')}"
+ ::Open3.popen2e(env, cmd) do |_, out, wait|
+ out.each { |line| puts line }
+
+ exit wait.value.exitstatus
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/specs/runner.rb b/qa/qa/specs/runner.rb
index f1cb9378de8..6aa08cf77b4 100644
--- a/qa/qa/specs/runner.rb
+++ b/qa/qa/specs/runner.rb
@@ -1,8 +1,8 @@
# frozen_string_literal: true
+require 'knapsack'
require 'rspec/core'
require 'rspec/expectations'
-require 'knapsack'
module QA
module Specs
@@ -17,44 +17,56 @@ module QA
@options = []
end
- def perform
- args = []
- args.push('--tty') if tty
+ def paths_from_knapsack
+ allocator = Knapsack::AllocatorBuilder.new(Knapsack::Adapters::RSpecAdapter).allocator
+
+ QA::Runtime::Logger.info ''
+ QA::Runtime::Logger.info 'Report specs:'
+ QA::Runtime::Logger.info allocator.report_node_tests.join(', ')
+ QA::Runtime::Logger.info ''
+ QA::Runtime::Logger.info 'Leftover specs:'
+ QA::Runtime::Logger.info allocator.leftover_node_tests.join(', ')
+ QA::Runtime::Logger.info ''
+
+ ['--', allocator.node_tests]
+ end
+
+ def rspec_tags
+ tags_for_rspec = []
if tags.any?
- tags.each { |tag| args.push(['--tag', tag.to_s]) }
+ tags.each { |tag| tags_for_rspec.push(['--tag', tag.to_s]) }
else
- args.push(%w[--tag ~orchestrated]) unless (%w[-t --tag] & options).any?
+ tags_for_rspec.push(%w[--tag ~orchestrated]) unless (%w[-t --tag] & options).any?
end
- args.push(%w[--tag ~skip_signup_disabled]) if QA::Runtime::Env.signup_disabled?
+ tags_for_rspec.push(%w[--tag ~skip_signup_disabled]) if QA::Runtime::Env.signup_disabled?
QA::Runtime::Env.supported_features.each_key do |key|
- args.push(["--tag", "~requires_#{key}"]) unless QA::Runtime::Env.can_test? key
+ tags_for_rspec.push(%W[--tag ~requires_#{key}]) unless QA::Runtime::Env.can_test? key
end
- args.push(options)
+ tags_for_rspec
+ end
- Runtime::Browser.configure!
+ def perform
+ args = []
+ args.push('--tty') if tty
+ args.push(rspec_tags)
+ args.push(options)
if Runtime::Env.knapsack?
- allocator = Knapsack::AllocatorBuilder.new(Knapsack::Adapters::RSpecAdapter).allocator
-
- QA::Runtime::Logger.info ''
- QA::Runtime::Logger.info 'Report specs:'
- QA::Runtime::Logger.info allocator.report_node_tests.join(', ')
- QA::Runtime::Logger.info ''
- QA::Runtime::Logger.info 'Leftover specs:'
- QA::Runtime::Logger.info allocator.leftover_node_tests.join(', ')
- QA::Runtime::Logger.info ''
-
- args.push(['--', allocator.node_tests])
+ args.push(paths_from_knapsack)
else
args.push(DEFAULT_TEST_PATH_ARGS) unless options.any? { |opt| opt =~ %r{/features/} }
end
- RSpec::Core::Runner.run(args.flatten, $stderr, $stdout).tap do |status|
- abort if status.nonzero?
+ if Runtime::Scenario.attributes[:parallel]
+ ParallelRunner.run(args.flatten)
+ else
+ RSpec::Core::Runner.run(args.flatten, $stderr, $stdout).tap do |status|
+ abort if status.nonzero?
+ end
end
end
end
diff --git a/qa/qa/tools/generate_perf_testdata.rb b/qa/qa/tools/generate_perf_testdata.rb
index b0477951967..26bcb2fe958 100644
--- a/qa/qa/tools/generate_perf_testdata.rb
+++ b/qa/qa/tools/generate_perf_testdata.rb
@@ -59,8 +59,8 @@ module QA
group_search_response = create_a_group_api_req(@group_name, @visibility)
group = JSON.parse(group_search_response.body)
@urls[:group_page] = group["web_url"]
- group["id"]
STDOUT.puts "Created a group: #{@urls[:group_page]}"
+ group["id"]
end
def create_project(group_id)
@@ -196,6 +196,7 @@ module QA
project_path = "#{@group_name}%2F#{@project_name}"
branch_name = "branch_with_many_commits-#{SecureRandom.hex(8)}"
file_name = "file_for_many_commits.txt"
+
create_a_branch_api_req(branch_name, project_path)
create_a_new_file_api_req(file_name, branch_name, project_path, "Initial commit for new file", "Initial file content")
create_mr_response = create_a_merge_request_api_req(project_path, branch_name, "master", "MR with many commits-#{SecureRandom.hex(8)}")
@@ -203,7 +204,7 @@ module QA
100.times do |i|
update_file_api_req(file_name, branch_name, project_path, Faker::Lorem.sentences(5).join(" "), Faker::Lorem.sentences(500).join("\n"))
end
- STDOUT.puts "Created an MR with many commits: #{@urls[:mr_with_many_commits]}"
+ STDOUT.puts "Using branch: #{branch_name}, created an MR with many commits: #{@urls[:mr_with_many_commits]}"
end
private
@@ -211,56 +212,88 @@ module QA
# API Requests
def create_a_discussion_on_issue_api_req(project_path_or_id, issue_id, body)
- post Runtime::API::Request.new(@api_client, "/projects/#{project_path_or_id}/issues/#{issue_id}/discussions").url, "body=\"#{body}\""
+ call_api(expected_response_code: 201) do
+ post Runtime::API::Request.new(@api_client, "/projects/#{project_path_or_id}/issues/#{issue_id}/discussions").url, "body=\"#{body}\""
+ end
end
def update_a_discussion_on_issue_api_req(project_path_or_id, mr_iid, discussion_id, resolved_status)
- put Runtime::API::Request.new(@api_client, "/projects/#{project_path_or_id}/merge_requests/#{mr_iid}/discussions/#{discussion_id}").url, "resolved=#{resolved_status}"
+ call_api(expected_response_code: 200) do
+ put Runtime::API::Request.new(@api_client, "/projects/#{project_path_or_id}/merge_requests/#{mr_iid}/discussions/#{discussion_id}").url, "resolved=#{resolved_status}"
+ end
end
def create_a_discussion_on_mr_api_req(project_path_or_id, mr_iid, body)
- post Runtime::API::Request.new(@api_client, "/projects/#{project_path_or_id}/merge_requests/#{mr_iid}/discussions").url,
- "body=\"#{body}\""
+ call_api(expected_response_code: 201) do
+ post Runtime::API::Request.new(@api_client, "/projects/#{project_path_or_id}/merge_requests/#{mr_iid}/discussions").url, "body=\"#{body}\""
+ end
end
def create_a_label_api_req(project_path_or_id, name, color)
- post Runtime::API::Request.new(@api_client, "/projects/#{project_path_or_id}/labels").url, "name=#{name}&color=#{color}"
+ call_api(expected_response_code: 201) do
+ post Runtime::API::Request.new(@api_client, "/projects/#{project_path_or_id}/labels").url, "name=#{name}&color=#{color}"
+ end
end
def create_a_todo_api_req(project_path_or_id, issue_id)
- post Runtime::API::Request.new(@api_client, "/projects/#{project_path_or_id}/issues/#{issue_id}/todo").url, nil
+ call_api(expected_response_code: 201) do
+ post Runtime::API::Request.new(@api_client, "/projects/#{project_path_or_id}/issues/#{issue_id}/todo").url, nil
+ end
end
def create_an_issue_api_req(project_path_or_id, title, description)
- post Runtime::API::Request.new(@api_client, "/projects/#{project_path_or_id}/issues").url, "title=#{title}&description=#{description}"
+ call_api(expected_response_code: 201) do
+ post Runtime::API::Request.new(@api_client, "/projects/#{project_path_or_id}/issues").url, "title=#{title}&description=#{description}"
+ end
end
def update_an_issue_api_req(project_path_or_id, issue_id, description, labels_list)
- put Runtime::API::Request.new(@api_client, "/projects/#{project_path_or_id}/issues/#{issue_id}").url, "description=#{description}&labels=#{labels_list}"
+ call_api(expected_response_code: 200) do
+ put Runtime::API::Request.new(@api_client, "/projects/#{project_path_or_id}/issues/#{issue_id}").url, "description=#{description}&labels=#{labels_list}"
+ end
end
def create_a_project_api_req(project_name, group_id, visibility)
- post Runtime::API::Request.new(@api_client, "/projects").url, "name=#{project_name}&namespace_id=#{group_id}&visibility=#{visibility}"
+ call_api(expected_response_code: 201) do
+ post Runtime::API::Request.new(@api_client, "/projects").url, "name=#{project_name}&namespace_id=#{group_id}&visibility=#{visibility}"
+ end
end
def create_a_group_api_req(group_name, visibility)
- post Runtime::API::Request.new(@api_client, "/groups").url, "name=#{group_name}&path=#{group_name}&visibility=#{visibility}"
+ call_api(expected_response_code: 201) do
+ post Runtime::API::Request.new(@api_client, "/groups").url, "name=#{group_name}&path=#{group_name}&visibility=#{visibility}"
+ end
end
def create_a_branch_api_req(branch_name, project_path_or_id)
- post Runtime::API::Request.new(@api_client, "/projects/#{project_path_or_id}/repository/branches").url, "branch=#{branch_name}&ref=master"
+ call_api(expected_response_code: 201) do
+ post Runtime::API::Request.new(@api_client, "/projects/#{project_path_or_id}/repository/branches").url, "branch=#{branch_name}&ref=master"
+ end
end
def create_a_new_file_api_req(file_path, branch_name, project_path_or_id, commit_message, content)
- post Runtime::API::Request.new(@api_client, "/projects/#{project_path_or_id}/repository/files/#{file_path}").url, "branch=#{branch_name}&commit_message=\"#{commit_message}\"&content=\"#{content}\""
+ call_api(expected_response_code: 201) do
+ post Runtime::API::Request.new(@api_client, "/projects/#{project_path_or_id}/repository/files/#{file_path}").url, "branch=#{branch_name}&commit_message=\"#{commit_message}\"&content=\"#{content}\""
+ end
end
def create_a_merge_request_api_req(project_path_or_id, source_branch, target_branch, mr_title)
- post Runtime::API::Request.new(@api_client, "/projects/#{project_path_or_id}/merge_requests").url, "source_branch=#{source_branch}&target_branch=#{target_branch}&title=#{mr_title}"
+ call_api(expected_response_code: 201) do
+ post Runtime::API::Request.new(@api_client, "/projects/#{project_path_or_id}/merge_requests").url, "source_branch=#{source_branch}&target_branch=#{target_branch}&title=#{mr_title}"
+ end
end
def update_file_api_req(file_path, branch_name, project_path_or_id, commit_message, content)
- put Runtime::API::Request.new(@api_client, "/projects/#{project_path_or_id}/repository/files/#{file_path}").url, "branch=#{branch_name}&commit_message=\"#{commit_message}\"&content=\"#{content}\""
+ call_api(expected_response_code: 200) do
+ put Runtime::API::Request.new(@api_client, "/projects/#{project_path_or_id}/repository/files/#{file_path}").url, "branch=#{branch_name}&commit_message=\"#{commit_message}\"&content=\"#{content}\""
+ end
+ end
+
+ def call_api(expected_response_code: 200)
+ response = yield
+ raise "API call failed with response code: #{response.code} and body: #{response.body}" unless response.code == expected_response_code
+
+ response
end
end
end
diff --git a/qa/spec/page/logging_spec.rb b/qa/spec/page/logging_spec.rb
index 0f1ed039149..92a4f7b40e6 100644
--- a/qa/spec/page/logging_spec.rb
+++ b/qa/spec/page/logging_spec.rb
@@ -91,26 +91,26 @@ describe QA::Support::Page::Logging do
it 'logs has_element?' do
expect { subject.has_element?(:element) }
- .to output(/has_element\? :element \(wait: 2\) returned: true/).to_stdout_from_any_process
+ .to output(/has_element\? :element \(wait: #{QA::Runtime::Browser::CAPYBARA_MAX_WAIT_TIME}\) returned: true/).to_stdout_from_any_process
end
it 'logs has_element? with text' do
expect { subject.has_element?(:element, text: "some text") }
- .to output(/has_element\? :element with text \"some text\" \(wait: 2\) returned: true/).to_stdout_from_any_process
+ .to output(/has_element\? :element with text \"some text\" \(wait: #{QA::Runtime::Browser::CAPYBARA_MAX_WAIT_TIME}\) returned: true/).to_stdout_from_any_process
end
it 'logs has_no_element?' do
allow(page).to receive(:has_no_css?).and_return(true)
expect { subject.has_no_element?(:element) }
- .to output(/has_no_element\? :element \(wait: 2\) returned: true/).to_stdout_from_any_process
+ .to output(/has_no_element\? :element \(wait: #{QA::Runtime::Browser::CAPYBARA_MAX_WAIT_TIME}\) returned: true/).to_stdout_from_any_process
end
it 'logs has_no_element? with text' do
allow(page).to receive(:has_no_css?).and_return(true)
expect { subject.has_no_element?(:element, text: "more text") }
- .to output(/has_no_element\? :element with text \"more text\" \(wait: 2\) returned: true/).to_stdout_from_any_process
+ .to output(/has_no_element\? :element with text \"more text\" \(wait: #{QA::Runtime::Browser::CAPYBARA_MAX_WAIT_TIME}\) returned: true/).to_stdout_from_any_process
end
it 'logs has_text?' do
diff --git a/qa/spec/spec_helper.rb b/qa/spec/spec_helper.rb
index f25dbf3a8ab..21bfd2876a9 100644
--- a/qa/spec/spec_helper.rb
+++ b/qa/spec/spec_helper.rb
@@ -8,6 +8,10 @@ if ENV['CI'] && QA::Runtime::Env.knapsack? && !ENV['NO_KNAPSACK']
Knapsack::Adapters::RSpecAdapter.bind
end
+QA::Runtime::Browser.configure!
+
+QA::Runtime::Scenario.from_env(QA::Runtime::Env.runtime_scenario_attributes) if QA::Runtime::Env.runtime_scenario_attributes
+
%w[helpers shared_examples].each do |d|
Dir[::File.join(__dir__, d, '**', '*.rb')].each { |f| require f }
end
diff --git a/qa/spec/specs/parallel_runner_spec.rb b/qa/spec/specs/parallel_runner_spec.rb
new file mode 100644
index 00000000000..67d94a1f648
--- /dev/null
+++ b/qa/spec/specs/parallel_runner_spec.rb
@@ -0,0 +1,58 @@
+# frozen_string_literal: true
+
+describe QA::Specs::ParallelRunner do
+ include Helpers::StubENV
+
+ before do
+ allow(QA::Runtime::Scenario).to receive(:attributes).and_return(parallel: true)
+ stub_env('GITLAB_QA_ACCESS_TOKEN', 'skip_token_creation')
+ end
+
+ it 'passes args to parallel_tests' do
+ expect_cli_arguments(['--tag', '~orchestrated', *QA::Specs::Runner::DEFAULT_TEST_PATH_ARGS])
+
+ subject.run(['--tag', '~orchestrated', *QA::Specs::Runner::DEFAULT_TEST_PATH_ARGS])
+ end
+
+ it 'passes a given test path to parallel_tests and adds a separator' do
+ expect_cli_arguments(%w[-- qa/specs/features/foo])
+
+ subject.run(%w[qa/specs/features/foo])
+ end
+
+ it 'passes tags and test paths to parallel_tests and adds a separator' do
+ expect_cli_arguments(%w[--tag smoke -- qa/specs/features/foo qa/specs/features/bar])
+
+ subject.run(%w[--tag smoke qa/specs/features/foo qa/specs/features/bar])
+ end
+
+ it 'passes tags and test paths with separators to parallel_tests' do
+ expect_cli_arguments(%w[-- --tag smoke -- qa/specs/features/foo qa/specs/features/bar])
+
+ subject.run(%w[-- --tag smoke -- qa/specs/features/foo qa/specs/features/bar])
+ end
+
+ it 'passes supported environment variables' do
+ # Test only env vars starting with GITLAB because some of the others
+ # affect how the runner behaves, and we're not concerned with those
+ # behaviors in this test
+ gitlab_env_vars = QA::Runtime::Env::ENV_VARIABLES.reject { |v| !v.start_with?('GITLAB') }
+
+ gitlab_env_vars.each do |k, v|
+ stub_env(k, v)
+ end
+
+ gitlab_env_vars['QA_RUNTIME_SCENARIO_ATTRIBUTES'] = '{"parallel":true}'
+
+ expect_cli_arguments([], gitlab_env_vars)
+
+ subject.run([])
+ end
+
+ def expect_cli_arguments(arguments, env = { 'QA_RUNTIME_SCENARIO_ATTRIBUTES' => '{"parallel":true}' })
+ cmd = "bundle exec parallel_test -t rspec --combine-stderr --serialize-stdout -- #{arguments.join(' ')}"
+ expect(Open3).to receive(:popen2e)
+ .with(hash_including(env), cmd)
+ .and_return(0)
+ end
+end
diff --git a/qa/spec/specs/runner_spec.rb b/qa/spec/specs/runner_spec.rb
index f94145d148e..6c533c6dc7d 100644
--- a/qa/spec/specs/runner_spec.rb
+++ b/qa/spec/specs/runner_spec.rb
@@ -58,11 +58,11 @@ describe QA::Specs::Runner do
end
end
- context 'when "-- qa/specs/features/foo" is set as options' do
- subject { described_class.new.tap { |runner| runner.options = %w[-- qa/specs/features/foo] } }
+ context 'when "--tag smoke" and "qa/specs/features/foo" are set as options' do
+ subject { described_class.new.tap { |runner| runner.options = %w[--tag smoke qa/specs/features/foo] } }
- it 'passes the given tests path and excludes the orchestrated tag' do
- expect_rspec_runner_arguments(['--tag', '~orchestrated', '--', 'qa/specs/features/foo'])
+ it 'focuses on the given tag and includes the path without excluding the orchestrated tag' do
+ expect_rspec_runner_arguments(['--tag', 'smoke', 'qa/specs/features/foo'])
subject.perform
end
diff --git a/rubocop/cop/graphql/authorize_types.rb b/rubocop/cop/graphql/authorize_types.rb
new file mode 100644
index 00000000000..93fe80c3edf
--- /dev/null
+++ b/rubocop/cop/graphql/authorize_types.rb
@@ -0,0 +1,61 @@
+# frozen_string_literal: true
+
+require_relative '../../spec_helpers'
+
+module RuboCop
+ module Cop
+ module Graphql
+ class AuthorizeTypes < RuboCop::Cop::Cop
+ include SpecHelpers
+
+ MSG = 'Add an `authorize :ability` call to the type: '\
+ 'https://docs.gitlab.com/ee/development/api_graphql_styleguide.html#type-authorization'
+
+ TYPES_DIR = 'app/graphql/types'
+
+ # We want to exclude our own basetypes and scalars
+ WHITELISTED_TYPES = %w[BaseEnum BaseScalar BasePermissionType MutationType
+ QueryType GraphQL::Schema BaseUnion].freeze
+
+ def_node_search :authorize?, <<~PATTERN
+ (send nil? :authorize ...)
+ PATTERN
+
+ def on_class(node)
+ return unless in_type?(node)
+ return if whitelisted?(class_constant(node))
+ return if whitelisted?(superclass_constant(node))
+
+ add_offense(node, location: :expression) unless authorize?(node)
+ end
+
+ private
+
+ def in_type?(node)
+ return if in_spec?(node)
+
+ path = node.location.expression.source_buffer.name
+
+ path.include?(TYPES_DIR)
+ end
+
+ def whitelisted?(class_node)
+ return false unless class_node&.const_name
+
+ WHITELISTED_TYPES.any? { |whitelisted| class_node.const_name.include?(whitelisted) }
+ end
+
+ def class_constant(node)
+ node.descendants.first
+ end
+
+ def superclass_constant(class_node)
+ # First one is the class name itself, second is it's superclass
+ _class_constant, *others = class_node.descendants
+
+ others.find { |node| node.const_type? && node&.const_name != 'Types' }
+ end
+ end
+ end
+ end
+end
diff --git a/rubocop/rubocop.rb b/rubocop/rubocop.rb
index e2a19978839..27c63d92ae5 100644
--- a/rubocop/rubocop.rb
+++ b/rubocop/rubocop.rb
@@ -43,3 +43,4 @@ require_relative 'cop/code_reuse/serializer'
require_relative 'cop/code_reuse/active_record'
require_relative 'cop/group_public_or_visible_to_user'
require_relative 'cop/inject_enterprise_edition_module'
+require_relative 'cop/graphql/authorize_types'
diff --git a/scripts/generate-memory-metrics-on-boot b/scripts/generate-memory-metrics-on-boot
new file mode 100755
index 00000000000..5197a8fcdcd
--- /dev/null
+++ b/scripts/generate-memory-metrics-on-boot
@@ -0,0 +1,11 @@
+#!/usr/bin/env ruby
+
+abort "usage: #{__FILE__} <memory_bundle_mem_file_name>" unless ARGV.length == 1
+memory_bundle_mem_file_name = ARGV.first
+
+full_report = File.open(memory_bundle_mem_file_name).read
+
+stats = /TOP: (?<total_mibs_str>.*) MiB/.match(full_report)
+abort 'failed to process the benchmark output' unless stats
+
+puts "total_memory_used_by_dependencies_on_boot_prod_env_mb #{stats[:total_mibs_str].to_f.round(1)}"
diff --git a/scripts/prepare_build.sh b/scripts/prepare_build.sh
index 9b0d5d4f719..0950ec272a5 100644
--- a/scripts/prepare_build.sh
+++ b/scripts/prepare_build.sh
@@ -35,9 +35,11 @@ sed -i 's/username: root/username: gitlab/g' config/database.yml
if [ "$GITLAB_DATABASE" = 'postgresql' ]; then
sed -i 's/localhost/postgres/g' config/database.yml
+ sed -i 's/username: git/username: postgres/g' config/database.yml
if [ -f config/database_geo.yml ]; then
sed -i 's/localhost/postgres/g' config/database_geo.yml
+ sed -i 's/username: git/username: postgres/g' config/database_geo.yml
fi
else # Assume it's mysql
sed -i 's/localhost/mysql/g' config/database.yml
@@ -48,16 +50,16 @@ else # Assume it's mysql
fi
cp config/resque.yml.example config/resque.yml
-sed -i 's/localhost/redis/g' config/resque.yml
+sed -i 's|url:.*$|url: redis://redis:6379|g' config/resque.yml
cp config/redis.cache.yml.example config/redis.cache.yml
-sed -i 's/localhost/redis/g' config/redis.cache.yml
+sed -i 's|url:.*$|url: redis://redis:6379/10|g' config/redis.cache.yml
cp config/redis.queues.yml.example config/redis.queues.yml
-sed -i 's/localhost/redis/g' config/redis.queues.yml
+sed -i 's|url:.*$|url: redis://redis:6379/11|g' config/redis.queues.yml
cp config/redis.shared_state.yml.example config/redis.shared_state.yml
-sed -i 's/localhost/redis/g' config/redis.shared_state.yml
+sed -i 's|url:.*$|url: redis://redis:6379/12|g' config/redis.shared_state.yml
if [ "$SETUP_DB" != "false" ]; then
setup_db
diff --git a/scripts/review_apps/review-apps.sh b/scripts/review_apps/review-apps.sh
index 633ea28e96c..2bf654b1e24 100755
--- a/scripts/review_apps/review-apps.sh
+++ b/scripts/review_apps/review-apps.sh
@@ -131,6 +131,7 @@ function install_external_dns() {
if ! deploy_exists "${KUBE_NAMESPACE}" "${release_name}" || previous_deploy_failed "${release_name}" ; then
echoinfo "Installing external-dns Helm chart"
helm repo update
+ # Default requested: CPU => 0, memory => 0
helm install stable/external-dns \
-n "${release_name}" \
--namespace "${KUBE_NAMESPACE}" \
@@ -141,7 +142,11 @@ function install_external_dns() {
--set domainFilters[0]="${domain}" \
--set txtOwnerId="${KUBE_NAMESPACE}" \
--set rbac.create="true" \
- --set policy="sync"
+ --set policy="sync" \
+ --set resources.requests.cpu=50m \
+ --set resources.limits.cpu=100m \
+ --set resources.requests.memory=100M \
+ --set resources.limits.memory=200M
else
echoinfo "The external-dns Helm chart is already successfully deployed."
fi
@@ -196,45 +201,122 @@ HELM_CMD=$(cat << EOF
helm upgrade --install \
--wait \
--timeout 600 \
- --set global.appConfig.enableUsagePing=false \
--set releaseOverride="$CI_ENVIRONMENT_SLUG" \
+ --set global.appConfig.enableUsagePing=false \
--set global.imagePullPolicy=Always \
--set global.hosts.hostSuffix="$HOST_SUFFIX" \
--set global.hosts.domain="$REVIEW_APPS_DOMAIN" \
- --set certmanager.install=false \
- --set prometheus.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 certmanager.install=false \
+ --set prometheus.install=false \
--set nginx-ingress.controller.service.enableHttp=false \
- --set nginx-ingress.defaultBackend.resources.requests.memory=7Mi \
- --set nginx-ingress.controller.resources.requests.memory=440M \
--set nginx-ingress.controller.replicaCount=2 \
- --set gitlab.unicorn.resources.requests.cpu=200m \
- --set gitlab.sidekiq.resources.requests.cpu=100m \
- --set gitlab.sidekiq.resources.requests.memory=800M \
- --set gitlab.gitlab-shell.resources.requests.cpu=100m \
- --set redis.resources.requests.cpu=100m \
- --set minio.resources.requests.cpu=100m \
+ --set nginx-ingress.controller.config.ssl-ciphers="ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4" \
--set gitlab.migrations.image.repository="$gitlab_migrations_image_repository" \
--set gitlab.migrations.image.tag="$CI_COMMIT_REF_SLUG" \
- --set gitlab.sidekiq.image.repository="$gitlab_sidekiq_image_repository" \
- --set gitlab.sidekiq.image.tag="$CI_COMMIT_REF_SLUG" \
- --set gitlab.unicorn.image.repository="$gitlab_unicorn_image_repository" \
- --set gitlab.unicorn.image.tag="$CI_COMMIT_REF_SLUG" \
- --set gitlab.task-runner.image.repository="$gitlab_task_runner_image_repository" \
- --set gitlab.task-runner.image.tag="$CI_COMMIT_REF_SLUG" \
--set gitlab.gitaly.image.repository="$gitlab_gitaly_image_repository" \
--set gitlab.gitaly.image.tag="v$GITALY_VERSION" \
--set gitlab.gitlab-shell.image.repository="$gitlab_shell_image_repository" \
--set gitlab.gitlab-shell.image.tag="v$GITLAB_SHELL_VERSION" \
+ --set gitlab.sidekiq.image.repository="$gitlab_sidekiq_image_repository" \
+ --set gitlab.sidekiq.image.tag="$CI_COMMIT_REF_SLUG" \
+ --set gitlab.unicorn.image.repository="$gitlab_unicorn_image_repository" \
+ --set gitlab.unicorn.image.tag="$CI_COMMIT_REF_SLUG" \
--set gitlab.unicorn.workhorse.image="$gitlab_workhorse_image_repository" \
--set gitlab.unicorn.workhorse.tag="$CI_COMMIT_REF_SLUG" \
- --set nginx-ingress.controller.config.ssl-ciphers="ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4" \
- --namespace="$KUBE_NAMESPACE" \
- --version="$CI_PIPELINE_ID-$CI_JOB_ID" \
- "$name" \
- .
+ --set gitlab.task-runner.image.repository="$gitlab_task_runner_image_repository" \
+ --set gitlab.task-runner.image.tag="$CI_COMMIT_REF_SLUG"
+EOF
+)
+
+# Default requested: CPU => 100m, memory => 100Mi
+HELM_CMD=$(cat << EOF
+ $HELM_CMD \
+ --set nginx-ingress.controller.resources.limits.cpu=200m \
+ --set nginx-ingress.controller.resources.requests.memory=210M \
+ --set nginx-ingress.controller.resources.limits.memory=420M
+EOF
+)
+
+# Default requested: CPU => 5m, memory => 5Mi
+HELM_CMD=$(cat << EOF
+ $HELM_CMD \
+ --set nginx-ingress.defaultBackend.resources.limits.cpu=10m \
+ --set nginx-ingress.defaultBackend.resources.requests.memory=12M \
+ --set nginx-ingress.defaultBackend.resources.limits.memory=24M
+EOF
+)
+
+# Default requested: CPU => 100m, memory => 200Mi
+HELM_CMD=$(cat << EOF
+ $HELM_CMD \
+ --set gitlab.gitaly.resources.requests.cpu=150m \
+ --set gitlab.gitaly.resources.limits.cpu=300m \
+ --set gitlab.gitaly.resources.limits.memory=420M
+EOF
+)
+
+# Default requested: CPU => 0, memory => 6M
+HELM_CMD=$(cat << EOF
+ $HELM_CMD \
+ --set gitlab.gitlab-shell.resources.requests.cpu=70m \
+ --set gitlab.gitlab-shell.resources.limits.cpu=140m \
+ --set gitlab.gitlab-shell.resources.requests.memory=20M \
+ --set gitlab.gitlab-shell.resources.limits.memory=40M
+EOF
+)
+
+# Default requested: CPU => 50m, memory => 650M
+HELM_CMD=$(cat << EOF
+ $HELM_CMD \
+ --set gitlab.sidekiq.resources.requests.cpu=200m \
+ --set gitlab.sidekiq.resources.limits.cpu=300m \
+ --set gitlab.sidekiq.resources.requests.memory=800M \
+ --set gitlab.sidekiq.resources.limits.memory=1.2G
+EOF
+)
+
+# Default requested: CPU => 300m + 100m (workhorse), memory => 1.2G + 100M (workhorse)
+HELM_CMD=$(cat << EOF
+ $HELM_CMD \
+ --set gitlab.unicorn.resources.limits.cpu=800m \
+ --set gitlab.unicorn.resources.limits.memory=2.6G
+EOF
+)
+
+# Default requested: CPU => 100m, memory => 64Mi
+HELM_CMD=$(cat << EOF
+ $HELM_CMD \
+ --set redis.resources.limits.cpu=200m \
+ --set redis.resources.limits.memory=130M
+EOF
+)
+
+# Default requested: CPU => 100m, memory => 128Mi
+HELM_CMD=$(cat << EOF
+ $HELM_CMD \
+ --set minio.resources.limits.cpu=200m \
+ --set minio.resources.limits.memory=280M
+EOF
+)
+
+# Default requested: CPU => 0, memory => 0
+HELM_CMD=$(cat << EOF
+ $HELM_CMD \
+ --set gitlab-runner.resources.requests.cpu=300m \
+ --set gitlab-runner.resources.limits.cpu=600m \
+ --set gitlab-runner.resources.requests.memory=300M \
+ --set gitlab-runner.resources.limits.memory=600M
+EOF
+)
+
+HELM_CMD=$(cat << EOF
+ $HELM_CMD \
+ --namespace="$KUBE_NAMESPACE" \
+ --version="$CI_PIPELINE_ID-$CI_JOB_ID" \
+ "$name" .
EOF
)
diff --git a/scripts/trigger-build-docs b/scripts/trigger-build-docs
index dfc8ee6050a..0fc8f6fbd4b 100755
--- a/scripts/trigger-build-docs
+++ b/scripts/trigger-build-docs
@@ -105,8 +105,8 @@ def trigger_pipeline
puts ""
puts app_url
puts ""
- puts "=> For more information, read the documentation"
- puts "=> https://docs.gitlab.com/ee/development/writing_documentation.html#previewing-the-changes-live"
+ puts "=> For more information, see the documentation"
+ puts "=> https://docs.gitlab.com/ee/development/documentation/index.html#previewing-the-changes-live"
puts ""
puts "=> If something doesn't work, drop a line in the #docs chat channel."
puts ""
diff --git a/spec/controllers/dashboard/projects_controller_spec.rb b/spec/controllers/dashboard/projects_controller_spec.rb
index ea68eae12ed..6591901a9dc 100644
--- a/spec/controllers/dashboard/projects_controller_spec.rb
+++ b/spec/controllers/dashboard/projects_controller_spec.rb
@@ -11,8 +11,10 @@ describe Dashboard::ProjectsController do
end
context 'user logged in' do
+ let(:user) { create(:user) }
+
before do
- sign_in create(:user)
+ sign_in(user)
end
context 'external authorization' do
@@ -24,6 +26,20 @@ describe Dashboard::ProjectsController do
expect(response).to have_gitlab_http_status(200)
end
end
+
+ it 'orders the projects by last activity by default' do
+ project = create(:project)
+ project.add_developer(user)
+ project.update!(last_repository_updated_at: 3.days.ago, last_activity_at: 3.days.ago)
+
+ project2 = create(:project)
+ project2.add_developer(user)
+ project2.update!(last_repository_updated_at: 10.days.ago, last_activity_at: 10.days.ago)
+
+ get :index
+
+ expect(assigns(:projects)).to eq([project, project2])
+ end
end
end
diff --git a/spec/controllers/groups_controller_spec.rb b/spec/controllers/groups_controller_spec.rb
index 47d7e278183..d2faef5b12b 100644
--- a/spec/controllers/groups_controller_spec.rb
+++ b/spec/controllers/groups_controller_spec.rb
@@ -125,11 +125,14 @@ describe GroupsController do
end
context 'as json' do
- it 'includes all projects in event feed' do
- 3.times do
+ it 'includes all projects from groups and subgroups in event feed' do
+ 2.times do
project = create(:project, group: group)
create(:event, project: project)
end
+ subgroup = create(:group, parent: group)
+ project = create(:project, group: subgroup)
+ create(:event, project: project)
get :activity, params: { id: group.to_param }, format: :json
diff --git a/spec/controllers/projects/branches_controller_spec.rb b/spec/controllers/projects/branches_controller_spec.rb
index 287ea9f425d..b30966e70a7 100644
--- a/spec/controllers/projects/branches_controller_spec.rb
+++ b/spec/controllers/projects/branches_controller_spec.rb
@@ -92,7 +92,7 @@ describe Projects::BranchesController do
end
it 'posts a system note' do
- expect(SystemNoteService).to receive(:new_issue_branch).with(issue, project, user, "1-feature-branch")
+ expect(SystemNoteService).to receive(:new_issue_branch).with(issue, project, user, "1-feature-branch", branch_project: project)
post :create,
params: {
@@ -103,6 +103,75 @@ describe Projects::BranchesController do
}
end
+ context 'confidential_issue_project_id is present' do
+ let(:confidential_issue_project) { create(:project) }
+
+ def create_branch_with_confidential_issue_project
+ post(
+ :create,
+ params: {
+ namespace_id: project.namespace,
+ project_id: project,
+ branch_name: branch,
+ confidential_issue_project_id: confidential_issue_project.id,
+ issue_iid: issue.iid
+ }
+ )
+ end
+
+ context 'create_confidential_merge_request feature is enabled' do
+ before do
+ stub_feature_flags(create_confidential_merge_request: true)
+ end
+
+ context 'user cannot update issue' do
+ let(:issue) { create(:issue, project: confidential_issue_project) }
+
+ it 'does not post a system note' do
+ expect(SystemNoteService).not_to receive(:new_issue_branch)
+
+ create_branch_with_confidential_issue_project
+ end
+ end
+
+ context 'user can update issue' do
+ before do
+ confidential_issue_project.add_reporter(user)
+ end
+
+ context 'issue is under the specified project' do
+ let(:issue) { create(:issue, project: confidential_issue_project) }
+
+ it 'posts a system note' do
+ expect(SystemNoteService).to receive(:new_issue_branch).with(issue, confidential_issue_project, user, "1-feature-branch", branch_project: project)
+
+ create_branch_with_confidential_issue_project
+ end
+ end
+
+ context 'issue is not under the specified project' do
+ it 'does not post a system note' do
+ expect(SystemNoteService).not_to receive(:new_issue_branch)
+
+ create_branch_with_confidential_issue_project
+ end
+ end
+ end
+ end
+
+ context 'create_confidential_merge_request feature is disabled' do
+ before do
+ stub_feature_flags(create_confidential_merge_request: false)
+ end
+
+ it 'posts a system note on project' do
+ expect(SystemNoteService).to receive(:new_issue_branch).with(issue, project, user, "1-feature-branch", branch_project: project)
+
+ create_branch_with_confidential_issue_project
+ end
+ end
+ end
+
context 'repository-less project' do
let(:project) { create :project }
diff --git a/spec/controllers/projects/deployments_controller_spec.rb b/spec/controllers/projects/deployments_controller_spec.rb
index 95417936df4..b9ee69a617b 100644
--- a/spec/controllers/projects/deployments_controller_spec.rb
+++ b/spec/controllers/projects/deployments_controller_spec.rb
@@ -41,34 +41,26 @@ describe Projects::DeploymentsController do
describe 'GET #metrics' do
let(:deployment) { create(:deployment, :success, project: project, environment: environment) }
- before do
- allow(controller).to receive(:deployment).and_return(deployment)
- end
-
context 'when metrics are disabled' do
- before do
- allow(deployment).to receive(:has_metrics?).and_return false
- end
-
it 'responds with not found' do
- get :metrics, params: deployment_params(id: deployment.id)
+ get :metrics, params: deployment_params(id: deployment.to_param)
expect(response).to be_not_found
end
end
context 'when metrics are enabled' do
- before do
- allow(deployment).to receive(:has_metrics?).and_return true
- end
-
context 'when environment has no metrics' do
before do
- expect(deployment).to receive(:metrics).and_return(nil)
+ expect_next_instance_of(DeploymentMetrics) do |deployment_metrics|
+ allow(deployment_metrics).to receive(:has_metrics?).and_return(true)
+
+ expect(deployment_metrics).to receive(:metrics).and_return(nil)
+ end
end
it 'returns a empty response 204 resposne' do
- get :metrics, params: deployment_params(id: deployment.id)
+ get :metrics, params: deployment_params(id: deployment.to_param)
expect(response).to have_gitlab_http_status(204)
expect(response.body).to eq('')
end
@@ -84,11 +76,15 @@ describe Projects::DeploymentsController do
end
before do
- expect(deployment).to receive(:metrics).and_return(empty_metrics)
+ expect_next_instance_of(DeploymentMetrics) do |deployment_metrics|
+ allow(deployment_metrics).to receive(:has_metrics?).and_return(true)
+
+ expect(deployment_metrics).to receive(:metrics).and_return(empty_metrics)
+ end
end
it 'returns a metrics JSON document' do
- get :metrics, params: deployment_params(id: deployment.id)
+ get :metrics, params: deployment_params(id: deployment.to_param)
expect(response).to be_ok
expect(json_response['success']).to be(true)
@@ -96,54 +92,32 @@ describe Projects::DeploymentsController do
expect(json_response['last_update']).to eq(42)
end
end
-
- context 'when metrics service does not implement deployment metrics' do
- before do
- allow(deployment).to receive(:metrics).and_raise(NotImplementedError)
- end
-
- it 'responds with not found' do
- get :metrics, params: deployment_params(id: deployment.id)
-
- expect(response).to be_not_found
- end
- end
end
end
describe 'GET #additional_metrics' do
let(:deployment) { create(:deployment, :success, project: project, environment: environment) }
- before do
- allow(controller).to receive(:deployment).and_return(deployment)
- end
-
context 'when metrics are disabled' do
- before do
- allow(deployment).to receive(:has_metrics?).and_return false
- end
-
it 'responds with not found' do
- get :metrics, params: deployment_params(id: deployment.id)
+ get :metrics, params: deployment_params(id: deployment.to_param)
expect(response).to be_not_found
end
end
context 'when metrics are enabled' do
- let(:prometheus_adapter) { double('prometheus_adapter', can_query?: true) }
-
- before do
- allow(deployment).to receive(:prometheus_adapter).and_return(prometheus_adapter)
- end
-
context 'when environment has no metrics' do
before do
- expect(deployment).to receive(:additional_metrics).and_return({})
+ expect_next_instance_of(DeploymentMetrics) do |deployment_metrics|
+ allow(deployment_metrics).to receive(:has_metrics?).and_return(true)
+
+ expect(deployment_metrics).to receive(:additional_metrics).and_return({})
+ end
end
it 'returns a empty response 204 response' do
- get :additional_metrics, params: deployment_params(id: deployment.id, format: :json)
+ get :additional_metrics, params: deployment_params(id: deployment.to_param, format: :json)
expect(response).to have_gitlab_http_status(204)
expect(response.body).to eq('')
end
@@ -159,11 +133,15 @@ describe Projects::DeploymentsController do
end
before do
- expect(deployment).to receive(:additional_metrics).and_return(empty_metrics)
+ expect_next_instance_of(DeploymentMetrics) do |deployment_metrics|
+ allow(deployment_metrics).to receive(:has_metrics?).and_return(true)
+
+ expect(deployment_metrics).to receive(:additional_metrics).and_return(empty_metrics)
+ end
end
it 'returns a metrics JSON document' do
- get :additional_metrics, params: deployment_params(id: deployment.id, format: :json)
+ get :additional_metrics, params: deployment_params(id: deployment.to_param, format: :json)
expect(response).to be_ok
expect(json_response['success']).to be(true)
diff --git a/spec/controllers/projects/issues_controller_spec.rb b/spec/controllers/projects/issues_controller_spec.rb
index f82e3c8c7dc..bc5e0b4671e 100644
--- a/spec/controllers/projects/issues_controller_spec.rb
+++ b/spec/controllers/projects/issues_controller_spec.rb
@@ -3,6 +3,8 @@
require 'spec_helper'
describe Projects::IssuesController do
+ include ProjectForksHelper
+
let(:project) { create(:project) }
let(:user) { create(:user) }
let(:issue) { create(:issue, project: project) }
@@ -1130,6 +1132,7 @@ describe Projects::IssuesController do
end
describe 'POST create_merge_request' do
+ let(:target_project_id) { nil }
let(:project) { create(:project, :repository, :public) }
before do
@@ -1163,13 +1166,42 @@ describe Projects::IssuesController do
expect(response).to have_gitlab_http_status(404)
end
+ context 'target_project_id is set' do
+ let(:target_project) { fork_project(project, user, repository: true) }
+ let(:target_project_id) { target_project.id }
+
+ context 'create_confidential_merge_request feature is enabled' do
+ before do
+ stub_feature_flags(create_confidential_merge_request: true)
+ end
+
+ it 'creates a new merge request' do
+ expect { create_merge_request }.to change(target_project.merge_requests, :count).by(1)
+ end
+ end
+
+ context 'create_confidential_merge_request feature is disabled' do
+ before do
+ stub_feature_flags(create_confidential_merge_request: false)
+ end
+
+ it 'creates a new merge request' do
+ expect { create_merge_request }.to change(project.merge_requests, :count).by(1)
+ end
+ end
+ end
+
def create_merge_request
- post :create_merge_request, params: {
- namespace_id: project.namespace.to_param,
- project_id: project.to_param,
- id: issue.to_param
- },
- format: :json
+ post(
+ :create_merge_request,
+ params: {
+ namespace_id: project.namespace.to_param,
+ project_id: project.to_param,
+ id: issue.to_param,
+ target_project_id: target_project_id
+ },
+ format: :json
+ )
end
end
diff --git a/spec/controllers/projects/merge_requests_controller_spec.rb b/spec/controllers/projects/merge_requests_controller_spec.rb
index 0eca663a683..9878f88a395 100644
--- a/spec/controllers/projects/merge_requests_controller_spec.rb
+++ b/spec/controllers/projects/merge_requests_controller_spec.rb
@@ -878,6 +878,22 @@ describe Projects::MergeRequestsController do
expect(control_count).to be <= 137
end
+ it 'has no N+1 issues for environments', :request_store, retry: 0 do
+ # First run to insert test data from lets, which does take up some 30 queries
+ get_ci_environments_status
+
+ control_count = ActiveRecord::QueryRecorder.new(skip_cached: false) { get_ci_environments_status }.count
+
+ environment2 = create(:environment, project: forked)
+ create(:deployment, :succeed, environment: environment2, sha: sha, ref: 'master', deployable: build)
+
+ # TODO address the last 11 queries
+ # See https://gitlab.com/gitlab-org/gitlab-ce/issues/63952 (5 queries)
+ # And https://gitlab.com/gitlab-org/gitlab-ce/issues/64105 (6 queries)
+ leeway = 11
+ expect { get_ci_environments_status }.not_to exceed_all_query_limit(control_count + leeway)
+ end
+
def get_ci_environments_status(extra_params = {})
params = {
namespace_id: merge_request.project.namespace.to_param,
diff --git a/spec/controllers/projects/notes_controller_spec.rb b/spec/controllers/projects/notes_controller_spec.rb
index 6ec84f5c528..1db1963476c 100644
--- a/spec/controllers/projects/notes_controller_spec.rb
+++ b/spec/controllers/projects/notes_controller_spec.rb
@@ -252,7 +252,7 @@ describe Projects::NotesController do
before do
service_params = ActionController::Parameters.new({
note: 'some note',
- noteable_id: merge_request.id.to_s,
+ noteable_id: merge_request.id,
noteable_type: 'MergeRequest',
commit_id: nil,
merge_request_diff_head_sha: 'sha'
diff --git a/spec/controllers/projects/settings/repository_controller_spec.rb b/spec/controllers/projects/settings/repository_controller_spec.rb
index b34053fc993..7f67f67e775 100644
--- a/spec/controllers/projects/settings/repository_controller_spec.rb
+++ b/spec/controllers/projects/settings/repository_controller_spec.rb
@@ -32,4 +32,24 @@ describe Projects::Settings::RepositoryController do
expect(RepositoryCleanupWorker).to have_received(:perform_async).once
end
end
+
+ describe 'POST create_deploy_token' do
+ let(:deploy_token_params) do
+ {
+ name: 'deployer_token',
+ expires_at: 1.month.from_now.to_date.to_s,
+ username: 'deployer',
+ read_repository: '1'
+ }
+ end
+
+ subject(:create_deploy_token) { post :create_deploy_token, params: { namespace_id: project.namespace, project_id: project, deploy_token: deploy_token_params } }
+
+ it 'creates deploy token' do
+ expect { create_deploy_token }.to change { DeployToken.active.count }.by(1)
+
+ expect(response).to have_gitlab_http_status(200)
+ expect(response).to render_template(:show)
+ end
+ end
end
diff --git a/spec/controllers/projects/templates_controller_spec.rb b/spec/controllers/projects/templates_controller_spec.rb
index bebf17728c0..9e7d34b10c0 100644
--- a/spec/controllers/projects/templates_controller_spec.rb
+++ b/spec/controllers/projects/templates_controller_spec.rb
@@ -3,49 +3,101 @@
require 'spec_helper'
describe Projects::TemplatesController do
- let(:project) { create(:project, :repository) }
+ let(:project) { create(:project, :repository, :private) }
let(:user) { create(:user) }
- let(:user2) { create(:user) }
- let(:file_path_1) { '.gitlab/issue_templates/bug.md' }
+ let(:file_path_1) { '.gitlab/issue_templates/issue_template.md' }
+ let(:file_path_2) { '.gitlab/merge_request_templates/merge_request_template.md' }
let(:body) { JSON.parse(response.body) }
+ let!(:file_1) { project.repository.create_file(user, file_path_1, 'issue content', message: 'message', branch_name: 'master') }
+ let!(:file_2) { project.repository.create_file(user, file_path_2, 'merge request content', message: 'message', branch_name: 'master') }
- before do
- project.add_developer(user)
- sign_in(user)
- end
+ describe '#show' do
+ shared_examples 'renders issue templates as json' do
+ it do
+ get(:show, params: { namespace_id: project.namespace, template_type: 'issue', key: 'issue_template', project_id: project }, format: :json)
- before do
- project.add_user(user, Gitlab::Access::MAINTAINER)
- project.repository.create_file(user, file_path_1, 'something valid',
- message: 'test 3', branch_name: 'master')
- end
+ expect(response.status).to eq(200)
+ expect(body['name']).to eq('issue_template')
+ expect(body['content']).to eq('issue content')
+ end
+ end
- describe '#show' do
- it 'renders template name and content as json' do
- get(:show, params: { namespace_id: project.namespace.to_param, template_type: "issue", key: "bug", project_id: project }, format: :json)
+ shared_examples 'renders merge request templates as json' do
+ it do
+ get(:show, params: { namespace_id: project.namespace, template_type: 'merge_request', key: 'merge_request_template', project_id: project }, format: :json)
+
+ expect(response.status).to eq(200)
+ expect(body['name']).to eq('merge_request_template')
+ expect(body['content']).to eq('merge request content')
+ end
+ end
+
+ shared_examples 'renders 404 when requesting an issue template' do
+ it do
+ get(:show, params: { namespace_id: project.namespace, template_type: 'issue', key: 'issue_template', project_id: project }, format: :json)
+
+ expect(response.status).to eq(404)
+ end
+ end
+
+ shared_examples 'renders 404 when requesting a merge request template' do
+ it do
+ get(:show, params: { namespace_id: project.namespace, template_type: 'merge_request', key: 'merge_request_template', project_id: project }, format: :json)
- expect(response.status).to eq(200)
- expect(body["name"]).to eq("bug")
- expect(body["content"]).to eq("something valid")
+ expect(response.status).to eq(404)
+ end
end
- it 'renders 404 when unauthorized' do
- sign_in(user2)
- get(:show, params: { namespace_id: project.namespace.to_param, template_type: "issue", key: "bug", project_id: project }, format: :json)
+ shared_examples 'renders 404 when params are invalid' do
+ it 'does not route when the template type is invalid' do
+ expect do
+ get(:show, params: { namespace_id: project.namespace, template_type: 'invalid_type', key: 'issue_template', project_id: project }, format: :json)
+ end.to raise_error(ActionController::UrlGenerationError)
+ end
+
+ it 'renders 404 when the format type is invalid' do
+ get(:show, params: { namespace_id: project.namespace, template_type: 'issue', key: 'issue_template', project_id: project }, format: :html)
+
+ expect(response.status).to eq(404)
+ end
+
+ it 'renders 404 when the key is unknown' do
+ get(:show, params: { namespace_id: project.namespace, template_type: 'issue', key: 'unknown_template', project_id: project }, format: :json)
- expect(response.status).to eq(404)
+ expect(response.status).to eq(404)
+ end
end
- it 'renders 404 when template type is not found' do
- sign_in(user)
- get(:show, params: { namespace_id: project.namespace.to_param, template_type: "dont_exist", key: "bug", project_id: project }, format: :json)
+ context 'when the user is not a member of the project' do
+ before do
+ sign_in(user)
+ end
- expect(response.status).to eq(404)
+ include_examples 'renders 404 when requesting an issue template'
+ include_examples 'renders 404 when requesting a merge request template'
+ include_examples 'renders 404 when params are invalid'
end
- it 'renders 404 without errors' do
- sign_in(user)
- expect { get(:show, params: { namespace_id: project.namespace.to_param, template_type: "dont_exist", key: "bug", project_id: project }, format: :json) }.not_to raise_error
+ context 'when user is a member of the project' do
+ before do
+ project.add_developer(user)
+ sign_in(user)
+ end
+
+ include_examples 'renders issue templates as json'
+ include_examples 'renders merge request templates as json'
+ include_examples 'renders 404 when params are invalid'
+ end
+
+ context 'when user is a guest of the project' do
+ before do
+ project.add_guest(user)
+ sign_in(user)
+ end
+
+ include_examples 'renders issue templates as json'
+ include_examples 'renders 404 when requesting a merge request template'
+ include_examples 'renders 404 when params are invalid'
end
end
end
diff --git a/spec/controllers/projects_controller_spec.rb b/spec/controllers/projects_controller_spec.rb
index 8d2412f97ef..4e1cac67d23 100644
--- a/spec/controllers/projects_controller_spec.rb
+++ b/spec/controllers/projects_controller_spec.rb
@@ -318,6 +318,53 @@ describe ProjectsController do
end
end
+ describe '#housekeeping' do
+ let(:group) { create(:group) }
+ let(:project) { create(:project, group: group) }
+ let(:housekeeping) { Projects::HousekeepingService.new(project) }
+
+ context 'when authenticated as owner' do
+ before do
+ group.add_owner(user)
+ sign_in(user)
+
+ allow(Projects::HousekeepingService).to receive(:new).with(project, :gc).and_return(housekeeping)
+ end
+
+ it 'forces a full garbage collection' do
+ expect(housekeeping).to receive(:execute).once
+
+ post :housekeeping,
+ params: {
+ namespace_id: project.namespace.path,
+ id: project.path
+ }
+
+ expect(response).to have_gitlab_http_status(302)
+ end
+ end
+
+ context 'when authenticated as developer' do
+ let(:developer) { create(:user) }
+
+ before do
+ group.add_developer(developer)
+ end
+
+ it 'does not execute housekeeping' do
+ expect(housekeeping).not_to receive(:execute)
+
+ post :housekeeping,
+ params: {
+ namespace_id: project.namespace.path,
+ id: project.path
+ }
+
+ expect(response).to have_gitlab_http_status(302)
+ end
+ end
+ end
+
describe "#update" do
render_views
diff --git a/spec/controllers/snippets/notes_controller_spec.rb b/spec/controllers/snippets/notes_controller_spec.rb
index 936d7c7dae4..586d59c2d09 100644
--- a/spec/controllers/snippets/notes_controller_spec.rb
+++ b/spec/controllers/snippets/notes_controller_spec.rb
@@ -119,6 +119,119 @@ describe Snippets::NotesController do
end
end
+ describe 'POST create' do
+ context 'when a snippet is public' do
+ let(:request_params) do
+ {
+ note: attributes_for(:note_on_personal_snippet, noteable: public_snippet),
+ snippet_id: public_snippet.id
+ }
+ end
+
+ before do
+ sign_in user
+ end
+
+ it 'returns status 302' do
+ post :create, params: request_params
+
+ expect(response).to have_gitlab_http_status(302)
+ end
+
+ it 'creates the note' do
+ expect { post :create, params: request_params }.to change { Note.count }.by(1)
+ end
+ end
+
+ context 'when a snippet is internal' do
+ let(:request_params) do
+ {
+ note: attributes_for(:note_on_personal_snippet, noteable: internal_snippet),
+ snippet_id: internal_snippet.id
+ }
+ end
+
+ before do
+ sign_in user
+ end
+
+ it 'returns status 302' do
+ post :create, params: request_params
+
+ expect(response).to have_gitlab_http_status(302)
+ end
+
+ it 'creates the note' do
+ expect { post :create, params: request_params }.to change { Note.count }.by(1)
+ end
+ end
+
+ context 'when a snippet is private' do
+ let(:request_params) do
+ {
+ note: attributes_for(:note_on_personal_snippet, noteable: private_snippet),
+ snippet_id: private_snippet.id
+ }
+ end
+
+ before do
+ sign_in user
+ end
+
+ context 'when user is not the author' do
+ before do
+ sign_in(user)
+ end
+
+ it 'returns status 404' do
+ post :create, params: request_params
+
+ expect(response).to have_gitlab_http_status(404)
+ end
+
+ it 'does not create the note' do
+ expect { post :create, params: request_params }.not_to change { Note.count }
+ end
+
+ context 'when user sends a snippet_id for a public snippet' do
+ let(:request_params) do
+ {
+ note: attributes_for(:note_on_personal_snippet, noteable: private_snippet),
+ snippet_id: public_snippet.id
+ }
+ end
+
+ it 'returns status 302' do
+ post :create, params: request_params
+
+ expect(response).to have_gitlab_http_status(302)
+ end
+
+ it 'creates the note on the public snippet' do
+ expect { post :create, params: request_params }.to change { Note.count }.by(1)
+ expect(Note.last.noteable).to eq public_snippet
+ end
+ end
+ end
+
+ context 'when user is the author' do
+ before do
+ sign_in(private_snippet.author)
+ end
+
+ it 'returns status 302' do
+ post :create, params: request_params
+
+ expect(response).to have_gitlab_http_status(302)
+ end
+
+ it 'creates the note' do
+ expect { post :create, params: request_params }.to change { Note.count }.by(1)
+ end
+ end
+ end
+ end
+
describe 'DELETE destroy' do
let(:request_params) do
{
diff --git a/spec/controllers/snippets_controller_spec.rb b/spec/controllers/snippets_controller_spec.rb
index f8666a1986f..3aba02bf3ff 100644
--- a/spec/controllers/snippets_controller_spec.rb
+++ b/spec/controllers/snippets_controller_spec.rb
@@ -209,8 +209,8 @@ describe SnippetsController do
context 'when the snippet description contains a file' do
include FileMoverHelpers
- let(:picture_file) { '/-/system/temp/secret56/picture.jpg' }
- let(:text_file) { '/-/system/temp/secret78/text.txt' }
+ let(:picture_file) { "/-/system/user/#{user.id}/secret56/picture.jpg" }
+ let(:text_file) { "/-/system/user/#{user.id}/secret78/text.txt" }
let(:description) do
"Description with picture: ![picture](/uploads#{picture_file}) and "\
"text: [text.txt](/uploads#{text_file})"
diff --git a/spec/controllers/uploads_controller_spec.rb b/spec/controllers/uploads_controller_spec.rb
index d27658e02cb..0876502a899 100644
--- a/spec/controllers/uploads_controller_spec.rb
+++ b/spec/controllers/uploads_controller_spec.rb
@@ -24,121 +24,160 @@ describe UploadsController do
let!(:user) { create(:user, avatar: fixture_file_upload("spec/fixtures/dk.png", "image/png")) }
describe 'POST create' do
- let(:model) { 'personal_snippet' }
- let(:snippet) { create(:personal_snippet, :public) }
let(:jpg) { fixture_file_upload('spec/fixtures/rails_sample.jpg', 'image/jpg') }
let(:txt) { fixture_file_upload('spec/fixtures/doc_sample.txt', 'text/plain') }
- context 'when a user does not have permissions to upload a file' do
- it "returns 401 when the user is not logged in" do
- post :create, params: { model: model, id: snippet.id }, format: :json
+ context 'snippet uploads' do
+ let(:model) { 'personal_snippet' }
+ let(:snippet) { create(:personal_snippet, :public) }
- expect(response).to have_gitlab_http_status(401)
- end
+ context 'when a user does not have permissions to upload a file' do
+ it "returns 401 when the user is not logged in" do
+ post :create, params: { model: model, id: snippet.id }, format: :json
- it "returns 404 when user can't comment on a snippet" do
- private_snippet = create(:personal_snippet, :private)
+ expect(response).to have_gitlab_http_status(401)
+ end
- sign_in(user)
- post :create, params: { model: model, id: private_snippet.id }, format: :json
+ it "returns 404 when user can't comment on a snippet" do
+ private_snippet = create(:personal_snippet, :private)
- expect(response).to have_gitlab_http_status(404)
- end
- end
+ sign_in(user)
+ post :create, params: { model: model, id: private_snippet.id }, format: :json
- context 'when a user is logged in' do
- before do
- sign_in(user)
+ expect(response).to have_gitlab_http_status(404)
+ end
end
- it "returns an error without file" do
- post :create, params: { model: model, id: snippet.id }, format: :json
+ context 'when a user is logged in' do
+ before do
+ sign_in(user)
+ end
- expect(response).to have_gitlab_http_status(422)
- end
+ it "returns an error without file" do
+ post :create, params: { model: model, id: snippet.id }, format: :json
- it "returns an error with invalid model" do
- expect { post :create, params: { model: 'invalid', id: snippet.id }, format: :json }
- .to raise_error(ActionController::UrlGenerationError)
- end
+ expect(response).to have_gitlab_http_status(422)
+ end
- it "returns 404 status when object not found" do
- post :create, params: { model: model, id: 9999 }, format: :json
+ it "returns an error with invalid model" do
+ expect { post :create, params: { model: 'invalid', id: snippet.id }, format: :json }
+ .to raise_error(ActionController::UrlGenerationError)
+ end
- expect(response).to have_gitlab_http_status(404)
- end
+ it "returns 404 status when object not found" do
+ post :create, params: { model: model, id: 9999 }, format: :json
- context 'with valid image' do
- before do
- post :create, params: { model: 'personal_snippet', id: snippet.id, file: jpg }, format: :json
+ expect(response).to have_gitlab_http_status(404)
end
- it 'returns a content with original filename, new link, and correct type.' do
- expect(response.body).to match '\"alt\":\"rails_sample\"'
- expect(response.body).to match "\"url\":\"/uploads"
+ context 'with valid image' do
+ before do
+ post :create, params: { model: 'personal_snippet', id: snippet.id, file: jpg }, format: :json
+ end
+
+ it 'returns a content with original filename, new link, and correct type.' do
+ expect(response.body).to match '\"alt\":\"rails_sample\"'
+ expect(response.body).to match "\"url\":\"/uploads"
+ end
+
+ it 'creates a corresponding Upload record' do
+ upload = Upload.last
+
+ aggregate_failures do
+ expect(upload).to exist
+ expect(upload.model).to eq snippet
+ end
+ end
end
- it 'creates a corresponding Upload record' do
- upload = Upload.last
+ context 'with valid non-image file' do
+ before do
+ post :create, params: { model: 'personal_snippet', id: snippet.id, file: txt }, format: :json
+ end
- aggregate_failures do
- expect(upload).to exist
- expect(upload.model).to eq snippet
+ it 'returns a content with original filename, new link, and correct type.' do
+ expect(response.body).to match '\"alt\":\"doc_sample.txt\"'
+ expect(response.body).to match "\"url\":\"/uploads"
+ end
+
+ it 'creates a corresponding Upload record' do
+ upload = Upload.last
+
+ aggregate_failures do
+ expect(upload).to exist
+ expect(upload.model).to eq snippet
+ end
end
end
end
+ end
+
+ context 'user uploads' do
+ let(:model) { 'user' }
+
+ it 'returns 401 when the user has no access' do
+ post :create, params: { model: 'user', id: user.id }, format: :json
- context 'with valid non-image file' do
+ expect(response).to have_gitlab_http_status(401)
+ end
+
+ context 'when user is logged in' do
before do
- post :create, params: { model: 'personal_snippet', id: snippet.id, file: txt }, format: :json
+ sign_in(user)
+ end
+
+ subject do
+ post :create, params: { model: model, id: user.id, file: jpg }, format: :json
end
it 'returns a content with original filename, new link, and correct type.' do
- expect(response.body).to match '\"alt\":\"doc_sample.txt\"'
- expect(response.body).to match "\"url\":\"/uploads"
+ subject
+
+ expect(response.body).to match '\"alt\":\"rails_sample\"'
+ expect(response.body).to match "\"url\":\"/uploads/-/system/user/#{user.id}/"
end
it 'creates a corresponding Upload record' do
+ expect { subject }.to change { Upload.count }
+
upload = Upload.last
aggregate_failures do
expect(upload).to exist
- expect(upload.model).to eq snippet
+ expect(upload.model).to eq user
end
end
- end
- context 'temporal with valid image' do
- subject do
- post :create, params: { model: 'personal_snippet', file: jpg }, format: :json
- end
+ context 'with valid non-image file' do
+ subject do
+ post :create, params: { model: model, id: user.id, file: txt }, format: :json
+ end
- it 'returns a content with original filename, new link, and correct type.' do
- subject
+ it 'returns a content with original filename, new link, and correct type.' do
+ subject
- expect(response.body).to match '\"alt\":\"rails_sample\"'
- expect(response.body).to match "\"url\":\"/uploads/-/system/temp"
- end
+ expect(response.body).to match '\"alt\":\"doc_sample.txt\"'
+ expect(response.body).to match "\"url\":\"/uploads/-/system/user/#{user.id}/"
+ end
- it 'does not create an Upload record' do
- expect { subject }.not_to change { Upload.count }
- end
- end
+ it 'creates a corresponding Upload record' do
+ expect { subject }.to change { Upload.count }
- context 'temporal with valid non-image file' do
- subject do
- post :create, params: { model: 'personal_snippet', file: txt }, format: :json
+ upload = Upload.last
+
+ aggregate_failures do
+ expect(upload).to exist
+ expect(upload.model).to eq user
+ end
+ end
end
- it 'returns a content with original filename, new link, and correct type.' do
- subject
+ it 'returns 404 when given user is not the logged in one' do
+ another_user = create(:user)
- expect(response.body).to match '\"alt\":\"doc_sample.txt\"'
- expect(response.body).to match "\"url\":\"/uploads/-/system/temp"
- end
+ post :create, params: { model: model, id: another_user.id, file: txt }, format: :json
- it 'does not create an Upload record' do
- expect { subject }.not_to change { Upload.count }
+ expect(response).to have_gitlab_http_status(404)
end
end
end
diff --git a/spec/factories/clusters/clusters.rb b/spec/factories/clusters/clusters.rb
index 6eb0194b710..ab332fc238b 100644
--- a/spec/factories/clusters/clusters.rb
+++ b/spec/factories/clusters/clusters.rb
@@ -13,7 +13,7 @@ FactoryBot.define do
cluster_type { Clusters::Cluster.cluster_types[:project_type] }
before(:create) do |cluster, evaluator|
- cluster.projects << create(:project, :repository) unless cluster.projects.present?
+ cluster.projects << create(:project) unless cluster.projects.present?
end
end
diff --git a/spec/factories/project_statistics.rb b/spec/factories/project_statistics.rb
index 2d0f698475d..3d4174eb852 100644
--- a/spec/factories/project_statistics.rb
+++ b/spec/factories/project_statistics.rb
@@ -6,5 +6,20 @@ FactoryBot.define do
# statistics are automatically created when a project is created
project&.statistics || new
end
+
+ transient do
+ with_data { false }
+ size_multiplier { 1 }
+ end
+
+ after(:build) do |project_statistics, evaluator|
+ if evaluator.with_data
+ project_statistics.repository_size = evaluator.size_multiplier
+ project_statistics.wiki_size = evaluator.size_multiplier * 2
+ project_statistics.lfs_objects_size = evaluator.size_multiplier * 3
+ project_statistics.build_artifacts_size = evaluator.size_multiplier * 4
+ project_statistics.packages_size = evaluator.size_multiplier * 5
+ end
+ end
end
end
diff --git a/spec/factories/releases.rb b/spec/factories/releases.rb
index cab6b4a811f..4cacc77c182 100644
--- a/spec/factories/releases.rb
+++ b/spec/factories/releases.rb
@@ -6,6 +6,7 @@ FactoryBot.define do
description "Awesome release"
project
author
+ released_at { Time.zone.parse('2018-10-20T18:00:00Z') }
trait :legacy do
sha nil
diff --git a/spec/factories/services.rb b/spec/factories/services.rb
index 763909f30bd..ecb481ed84a 100644
--- a/spec/factories/services.rb
+++ b/spec/factories/services.rb
@@ -6,8 +6,6 @@ FactoryBot.define do
factory :custom_issue_tracker_service, class: CustomIssueTrackerService do
project
- type 'CustomIssueTrackerService'
- category 'issue_tracker'
active true
properties(
project_url: 'https://project.url.com',
@@ -54,6 +52,38 @@ FactoryBot.define do
)
end
+ factory :bugzilla_service do
+ project
+ active true
+ issue_tracker
+ end
+
+ factory :redmine_service do
+ project
+ active true
+ issue_tracker
+ end
+
+ factory :youtrack_service do
+ project
+ active true
+ issue_tracker
+ end
+
+ factory :gitlab_issue_tracker_service do
+ project
+ active true
+ issue_tracker
+ end
+
+ trait :issue_tracker do
+ properties(
+ project_url: 'http://issue-tracker.example.com',
+ issues_url: 'http://issue-tracker.example.com',
+ new_issue_url: 'http://issue-tracker.example.com'
+ )
+ end
+
factory :jira_cloud_service, class: JiraService do
project
active true
diff --git a/spec/features/admin/admin_sees_project_statistics_spec.rb b/spec/features/admin/admin_sees_project_statistics_spec.rb
index b5323a1c76d..ecd0aab925b 100644
--- a/spec/features/admin/admin_sees_project_statistics_spec.rb
+++ b/spec/features/admin/admin_sees_project_statistics_spec.rb
@@ -15,7 +15,7 @@ describe "Admin > Admin sees project statistics" do
let(:project) { create(:project, :repository) }
it "shows project statistics" do
- expect(page).to have_content("Storage: 0 Bytes (0 Bytes repositories, 0 Bytes wikis, 0 Bytes build artifacts, 0 Bytes LFS)")
+ expect(page).to have_content("Storage: 0 Bytes (Repository: 0 Bytes / Wikis: 0 Bytes / Build Artifacts: 0 Bytes / LFS: 0 Bytes)")
end
end
diff --git a/spec/features/admin/admin_settings_spec.rb b/spec/features/admin/admin_settings_spec.rb
index 45ef5d07ff0..4a9037afb43 100644
--- a/spec/features/admin/admin_settings_spec.rb
+++ b/spec/features/admin/admin_settings_spec.rb
@@ -40,7 +40,7 @@ describe 'Admin updates settings' do
end
it 'Modify import sources' do
- expect(Gitlab::CurrentSettings.import_sources).not_to be_empty
+ expect(current_settings.import_sources).not_to be_empty
page.within('.as-visibility-access') do
Gitlab::ImportSources.options.map do |name, _|
@@ -51,7 +51,7 @@ describe 'Admin updates settings' do
end
expect(page).to have_content "Application settings saved successfully"
- expect(Gitlab::CurrentSettings.import_sources).to be_empty
+ expect(current_settings.import_sources).to be_empty
page.within('.as-visibility-access') do
check "Repo by URL"
@@ -59,7 +59,7 @@ describe 'Admin updates settings' do
end
expect(page).to have_content "Application settings saved successfully"
- expect(Gitlab::CurrentSettings.import_sources).to eq(['git'])
+ expect(current_settings.import_sources).to eq(['git'])
end
it 'Change Visibility and Access Controls' do
@@ -68,7 +68,7 @@ describe 'Admin updates settings' do
click_button 'Save changes'
end
- expect(Gitlab::CurrentSettings.project_export_enabled).to be_falsey
+ expect(current_settings.project_export_enabled).to be_falsey
expect(page).to have_content "Application settings saved successfully"
end
@@ -96,7 +96,7 @@ describe 'Admin updates settings' do
click_button 'Save changes'
end
- expect(Gitlab::CurrentSettings.gravatar_enabled).to be_falsey
+ expect(current_settings.gravatar_enabled).to be_falsey
expect(page).to have_content "Application settings saved successfully"
end
@@ -118,7 +118,7 @@ describe 'Admin updates settings' do
click_button 'Save changes'
end
- expect(Gitlab::CurrentSettings.home_page_url).to eq "https://about.gitlab.com/"
+ expect(current_settings.home_page_url).to eq "https://about.gitlab.com/"
expect(page).to have_content "Application settings saved successfully"
end
@@ -133,13 +133,13 @@ describe 'Admin updates settings' do
click_button 'Save changes'
end
- expect(Gitlab::CurrentSettings.enforce_terms).to be(true)
- expect(Gitlab::CurrentSettings.terms).to eq 'Be nice!'
+ expect(current_settings.enforce_terms).to be(true)
+ expect(current_settings.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
+ expect(current_settings.disabled_oauth_sign_in_sources).to be_empty
page.within('.as-signin') do
uncheck 'Google'
@@ -147,7 +147,7 @@ describe 'Admin updates settings' do
end
expect(page).to have_content "Application settings saved successfully"
- expect(Gitlab::CurrentSettings.disabled_oauth_sign_in_sources).to include('google_oauth2')
+ expect(current_settings.disabled_oauth_sign_in_sources).to include('google_oauth2')
page.within('.as-signin') do
check "Google"
@@ -155,11 +155,11 @@ describe 'Admin updates settings' do
end
expect(page).to have_content "Application settings saved successfully"
- expect(Gitlab::CurrentSettings.disabled_oauth_sign_in_sources).not_to include('google_oauth2')
+ expect(current_settings.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
+ expect(current_settings.disabled_oauth_sign_in_sources).to be_empty
page.within('.as-signin') do
uncheck 'Google'
@@ -167,7 +167,7 @@ describe 'Admin updates settings' do
end
expect(page).to have_content "Application settings saved successfully"
- expect(Gitlab::CurrentSettings.disabled_oauth_sign_in_sources).to include('google_oauth2')
+ expect(current_settings.disabled_oauth_sign_in_sources).to include('google_oauth2')
# Remove google_oauth2 from the Omniauth strategies
allow(Devise).to receive(:omniauth_providers).and_return([])
@@ -178,7 +178,7 @@ describe 'Admin updates settings' do
end
expect(page).to have_content "Application settings saved successfully"
- expect(Gitlab::CurrentSettings.disabled_oauth_sign_in_sources).to include('google_oauth2')
+ expect(current_settings.disabled_oauth_sign_in_sources).to include('google_oauth2')
end
it 'Configure web terminal' do
@@ -188,7 +188,7 @@ describe 'Admin updates settings' do
end
expect(page).to have_content "Application settings saved successfully"
- expect(Gitlab::CurrentSettings.terminal_max_session_time).to eq(15)
+ expect(current_settings.terminal_max_session_time).to eq(15)
end
end
@@ -204,7 +204,7 @@ describe 'Admin updates settings' do
end
expect(page).to have_content "Application settings saved successfully"
- expect(Gitlab::CurrentSettings.hide_third_party_offers).to be true
+ expect(current_settings.hide_third_party_offers).to be true
end
it 'Change Slack Notifications Service template settings' do
@@ -249,8 +249,8 @@ describe 'Admin updates settings' do
click_button 'Save changes'
end
- expect(Gitlab::CurrentSettings.auto_devops_enabled?).to be true
- expect(Gitlab::CurrentSettings.auto_devops_domain).to eq('domain.com')
+ expect(current_settings.auto_devops_enabled?).to be true
+ expect(current_settings.auto_devops_domain).to eq('domain.com')
expect(page).to have_content "Application settings saved successfully"
end
end
@@ -268,8 +268,8 @@ describe 'Admin updates settings' do
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)
+ expect(current_settings.recaptcha_enabled).to be true
+ expect(current_settings.unique_ips_limit_per_user).to eq(15)
end
end
@@ -284,7 +284,7 @@ describe 'Admin updates settings' do
click_button 'Save changes'
end
- expect(Gitlab::CurrentSettings.metrics_enabled?).to be true
+ expect(current_settings.metrics_enabled?).to be true
expect(page).to have_content "Application settings saved successfully"
end
@@ -294,7 +294,7 @@ describe 'Admin updates settings' do
click_button 'Save changes'
end
- expect(Gitlab::CurrentSettings.prometheus_metrics_enabled?).to be true
+ expect(current_settings.prometheus_metrics_enabled?).to be true
expect(page).to have_content "Application settings saved successfully"
end
@@ -343,8 +343,8 @@ describe 'Admin updates settings' do
end
expect(page).to have_content "Application settings saved successfully"
- expect(Gitlab::CurrentSettings.allow_local_requests_from_hooks_and_services).to be true
- expect(Gitlab::CurrentSettings.dns_rebinding_protection_enabled).to be false
+ expect(current_settings.allow_local_requests_from_hooks_and_services).to be true
+ expect(current_settings.dns_rebinding_protection_enabled).to be false
end
end
@@ -361,9 +361,9 @@ describe 'Admin updates settings' do
click_button 'Save changes'
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(current_settings.help_page_text).to eq "Example text"
+ expect(current_settings.help_page_hide_commercial_content).to be_truthy
+ expect(current_settings.help_page_support_url).to eq "http://example.com/help"
expect(page).to have_content "Application settings saved successfully"
end
@@ -374,8 +374,8 @@ describe 'Admin updates settings' do
click_button 'Save changes'
end
- expect(Gitlab::CurrentSettings.max_pages_size).to eq 15
- expect(Gitlab::CurrentSettings.pages_domain_verification_enabled?).to be_truthy
+ expect(current_settings.max_pages_size).to eq 15
+ expect(current_settings.pages_domain_verification_enabled?).to be_truthy
expect(page).to have_content "Application settings saved successfully"
end
@@ -385,7 +385,7 @@ describe 'Admin updates settings' do
click_button 'Save changes'
end
- expect(Gitlab::CurrentSettings.polling_interval_multiplier).to eq 5.0
+ expect(current_settings.polling_interval_multiplier).to eq 5.0
expect(page).to have_content "Application settings saved successfully"
end
@@ -395,7 +395,7 @@ describe 'Admin updates settings' do
click_button 'Save changes'
end
- expect(Gitlab::CurrentSettings.polling_interval_multiplier).not_to eq(-1.0)
+ expect(current_settings.polling_interval_multiplier).not_to eq(-1.0)
expect(page)
.to have_content "The form contains the following error: Polling interval multiplier must be greater than or equal to 0"
end
@@ -413,8 +413,8 @@ describe 'Admin updates settings' do
click_button 'Save changes'
end
- expect(Gitlab::CurrentSettings.lets_encrypt_notification_email).to eq 'my@test.example.com'
- expect(Gitlab::CurrentSettings.lets_encrypt_terms_of_service_accepted).to eq true
+ expect(current_settings.lets_encrypt_notification_email).to eq 'my@test.example.com'
+ expect(current_settings.lets_encrypt_terms_of_service_accepted).to eq true
end
end
@@ -445,4 +445,8 @@ describe 'Admin updates settings' do
page.check('Wiki page')
page.check('Deployment')
end
+
+ def current_settings
+ ApplicationSetting.current_without_cache
+ end
end
diff --git a/spec/features/container_registry_spec.rb b/spec/features/container_registry_spec.rb
index 21d97aba0c5..1b5943bd5d8 100644
--- a/spec/features/container_registry_spec.rb
+++ b/spec/features/container_registry_spec.rb
@@ -19,7 +19,7 @@ describe "Container Registry", :js do
it 'user visits container registry main page' do
visit_container_registry
- expect(page).to have_content 'No container images'
+ expect(page).to have_content 'no container images'
end
end
diff --git a/spec/features/dashboard/shortcuts_spec.rb b/spec/features/dashboard/shortcuts_spec.rb
index 55f5ff04d01..254bb12573c 100644
--- a/spec/features/dashboard/shortcuts_spec.rb
+++ b/spec/features/dashboard/shortcuts_spec.rb
@@ -22,7 +22,7 @@ describe 'Dashboard shortcuts', :js do
find('body').send_keys([:shift, 'T'])
- check_page_title('Todos')
+ check_page_title('To-Do List')
find('body').send_keys([:shift, 'P'])
diff --git a/spec/features/dashboard/todos/todos_spec.rb b/spec/features/dashboard/todos/todos_spec.rb
index d58e3b2841e..c48229fc0a0 100644
--- a/spec/features/dashboard/todos/todos_spec.rb
+++ b/spec/features/dashboard/todos/todos_spec.rb
@@ -13,7 +13,7 @@ describe 'Dashboard Todos' do
end
it 'shows "All done" message' do
- expect(page).to have_content 'Todos let you see what you should do next'
+ expect(page).to have_content 'Your To-Do List shows what to work on next'
end
end
@@ -72,7 +72,7 @@ describe 'Dashboard Todos' do
end
it 'updates todo count' do
- expect(page).to have_content 'Todos 0'
+ expect(page).to have_content 'To Do 0'
expect(page).to have_content 'Done 1'
end
@@ -101,7 +101,7 @@ describe 'Dashboard Todos' do
end
it 'updates todo count' do
- expect(page).to have_content 'Todos 1'
+ expect(page).to have_content 'To Do 1'
expect(page).to have_content 'Done 0'
end
end
@@ -211,7 +211,7 @@ describe 'Dashboard Todos' do
describe 'restoring the todo' do
before do
within first('.todo') do
- click_link 'Add todo'
+ click_link 'Add a To Do'
end
end
@@ -220,7 +220,7 @@ describe 'Dashboard Todos' do
end
it 'updates todo count' do
- expect(page).to have_content 'Todos 1'
+ expect(page).to have_content 'To Do 1'
expect(page).to have_content 'Done 0'
end
end
@@ -276,7 +276,7 @@ describe 'Dashboard Todos' do
end
it 'shows "All done" message!' do
- expect(page).to have_content 'Todos 0'
+ expect(page).to have_content 'To Do 0'
expect(page).to have_content "You're all done!"
expect(page).not_to have_selector('.gl-pagination')
end
@@ -303,7 +303,7 @@ describe 'Dashboard Todos' do
it 'updates todo count' do
mark_all_and_undo
- expect(page).to have_content 'Todos 2'
+ expect(page).to have_content 'To Do 2'
expect(page).to have_content 'Done 0'
end
diff --git a/spec/features/discussion_comments/commit_spec.rb b/spec/features/discussion_comments/commit_spec.rb
index ea720cee74e..b3f1731ec95 100644
--- a/spec/features/discussion_comments/commit_spec.rb
+++ b/spec/features/discussion_comments/commit_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe 'Discussion Comments Commit', :js do
+describe 'Thread Comments Commit', :js do
include RepoHelpers
let(:user) { create(:user) }
@@ -16,7 +16,7 @@ describe 'Discussion Comments Commit', :js do
visit project_commit_path(project, sample_commit.id)
end
- it_behaves_like 'discussion comments', 'commit'
+ it_behaves_like 'thread comments', 'commit'
it 'has class .js-note-emoji' do
expect(page).to have_css('.js-note-emoji')
diff --git a/spec/features/discussion_comments/issue_spec.rb b/spec/features/discussion_comments/issue_spec.rb
index 5ec19460bbd..d71a1ee4731 100644
--- a/spec/features/discussion_comments/issue_spec.rb
+++ b/spec/features/discussion_comments/issue_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe 'Discussion Comments Issue', :js do
+describe 'Thread Comments Issue', :js do
let(:user) { create(:user) }
let(:project) { create(:project) }
let(:issue) { create(:issue, project: project) }
@@ -12,5 +12,5 @@ describe 'Discussion Comments Issue', :js do
visit project_issue_path(project, issue)
end
- it_behaves_like 'discussion comments', 'issue'
+ it_behaves_like 'thread comments', 'issue'
end
diff --git a/spec/features/discussion_comments/merge_request_spec.rb b/spec/features/discussion_comments/merge_request_spec.rb
index f940e973923..86e3507a3ee 100644
--- a/spec/features/discussion_comments/merge_request_spec.rb
+++ b/spec/features/discussion_comments/merge_request_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe 'Discussion Comments Merge Request', :js do
+describe 'Thread Comments Merge Request', :js do
let(:user) { create(:user) }
let(:project) { create(:project, :repository) }
let(:merge_request) { create(:merge_request, source_project: project) }
@@ -12,5 +12,5 @@ describe 'Discussion Comments Merge Request', :js do
visit project_merge_request_path(project, merge_request)
end
- it_behaves_like 'discussion comments', 'merge request'
+ it_behaves_like 'thread comments', 'merge request'
end
diff --git a/spec/features/discussion_comments/snippets_spec.rb b/spec/features/discussion_comments/snippets_spec.rb
index d330e89505e..29aa3e4366c 100644
--- a/spec/features/discussion_comments/snippets_spec.rb
+++ b/spec/features/discussion_comments/snippets_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe 'Discussion Comments Snippet', :js do
+describe 'Thread Comments Snippet', :js do
let(:user) { create(:user) }
let(:project) { create(:project) }
let(:snippet) { create(:project_snippet, :private, project: project, author: user) }
@@ -12,5 +12,5 @@ describe 'Discussion Comments Snippet', :js do
visit project_snippet_path(project, snippet)
end
- it_behaves_like 'discussion comments', 'snippet'
+ it_behaves_like 'thread comments', 'snippet'
end
diff --git a/spec/features/groups/issues_spec.rb b/spec/features/groups/issues_spec.rb
index c000165ccd9..0ada530781c 100644
--- a/spec/features/groups/issues_spec.rb
+++ b/spec/features/groups/issues_spec.rb
@@ -150,6 +150,25 @@ describe 'Group issues page' do
check_issue_order
end
+ it 'issues should not be draggable when user is not logged in', :js do
+ sign_out(user_in_group)
+
+ visit issues_group_path(group, sort: 'relative_position')
+
+ drag_to(selector: '.manual-ordering',
+ from_index: 0,
+ to_index: 2)
+
+ wait_for_requests
+
+ # Issue order should remain the same
+ page.within('.manual-ordering') do
+ expect(find('.issue:nth-child(1) .title')).to have_content('Issue #1')
+ expect(find('.issue:nth-child(2) .title')).to have_content('Issue #2')
+ expect(find('.issue:nth-child(3) .title')).to have_content('Issue #3')
+ end
+ end
+
def check_issue_order
page.within('.manual-ordering') do
expect(find('.issue:nth-child(1) .title')).to have_content('Issue #2')
diff --git a/spec/features/issues/create_issue_for_discussions_in_merge_request_spec.rb b/spec/features/issues/create_issue_for_discussions_in_merge_request_spec.rb
index ada57285abf..f6dccb5e98a 100644
--- a/spec/features/issues/create_issue_for_discussions_in_merge_request_spec.rb
+++ b/spec/features/issues/create_issue_for_discussions_in_merge_request_spec.rb
@@ -1,13 +1,13 @@
require 'rails_helper'
-describe 'Resolving all open discussions in a merge request from an issue', :js do
+describe 'Resolving all open threads in a merge request from an issue', :js do
let(:user) { create(:user) }
let(:project) { create(:project, :repository) }
let(:merge_request) { create(:merge_request, source_project: project) }
let!(:discussion) { create(:diff_note_on_merge_request, noteable: merge_request, project: project).to_discussion }
def resolve_all_discussions_link_selector
- text = "Resolve all discussions in new issue"
+ text = "Resolve all threads in new issue"
url = new_project_issue_path(project, merge_request_to_resolve_discussions_of: merge_request.iid)
%Q{a[data-original-title="#{text}"][href="#{url}"]}
end
@@ -19,15 +19,15 @@ describe 'Resolving all open discussions in a merge request from an issue', :js
visit project_merge_request_path(project, merge_request)
end
- it 'shows a button to resolve all discussions by creating a new issue' do
+ it 'shows a button to resolve all threads by creating a new issue' do
within('.line-resolve-all-container') do
expect(page).to have_selector resolve_all_discussions_link_selector
end
end
- context 'resolving the discussion' do
+ context 'resolving the thread' do
before do
- click_button 'Resolve discussion'
+ click_button 'Resolve thread'
end
it 'hides the link for creating a new issue' do
@@ -35,15 +35,15 @@ describe 'Resolving all open discussions in a merge request from an issue', :js
end
end
- context 'creating an issue for discussions' do
+ context 'creating an issue for threads' do
before do
find(resolve_all_discussions_link_selector).click
end
- it_behaves_like 'creating an issue for a discussion'
+ it_behaves_like 'creating an issue for a thread'
end
- context 'for a project where all discussions need to be resolved before merging' do
+ context 'for a project where all threads need to be resolved before merging' do
before do
project.update_attribute(:only_allow_merge_if_all_discussions_are_resolved, true)
end
@@ -59,27 +59,27 @@ describe 'Resolving all open discussions in a merge request from an issue', :js
end
end
- context 'merge request has discussions that need to be resolved' do
+ context 'merge request has threads that need to be resolved' do
before do
visit project_merge_request_path(project, merge_request)
end
- it 'shows a warning that the merge request contains unresolved discussions' do
- expect(page).to have_content 'There are unresolved discussions.'
+ it 'shows a warning that the merge request contains unresolved threads' do
+ expect(page).to have_content 'There are unresolved threads.'
end
- it 'has a link to resolve all discussions by creating an issue' do
+ it 'has a link to resolve all threads by creating an issue' do
page.within '.mr-widget-body' do
expect(page).to have_link 'Create an issue to resolve them later', href: new_project_issue_path(project, merge_request_to_resolve_discussions_of: merge_request.iid)
end
end
- context 'creating an issue for discussions' do
+ context 'creating an issue for threads' do
before do
page.click_link 'Create an issue to resolve them later', href: new_project_issue_path(project, merge_request_to_resolve_discussions_of: merge_request.iid)
end
- it_behaves_like 'creating an issue for a discussion'
+ it_behaves_like 'creating an issue for a thread'
end
end
end
@@ -92,8 +92,8 @@ describe 'Resolving all open discussions in a merge request from an issue', :js
visit new_project_issue_path(project, merge_request_to_resolve_discussions_of: merge_request.iid)
end
- it 'Shows a notice to ask someone else to resolve the discussions' do
- expect(page).to have_content("The discussions at #{merge_request.to_reference} will stay unresolved. Ask someone with permission to resolve them.")
+ it 'Shows a notice to ask someone else to resolve the threads' do
+ expect(page).to have_content("The threads at #{merge_request.to_reference} will stay unresolved. Ask someone with permission to resolve them.")
end
end
end
diff --git a/spec/features/issues/create_issue_for_single_discussion_in_merge_request_spec.rb b/spec/features/issues/create_issue_for_single_discussion_in_merge_request_spec.rb
index b20730bdb22..1b1a31d0723 100644
--- a/spec/features/issues/create_issue_for_single_discussion_in_merge_request_spec.rb
+++ b/spec/features/issues/create_issue_for_single_discussion_in_merge_request_spec.rb
@@ -1,13 +1,13 @@
require 'rails_helper'
-describe 'Resolve an open discussion in a merge request by creating an issue', :js do
+describe 'Resolve an open thread in a merge request by creating an issue', :js do
let(:user) { create(:user) }
let(:project) { create(:project, :repository, only_allow_merge_if_all_discussions_are_resolved: true) }
let(:merge_request) { create(:merge_request, source_project: project) }
let!(:discussion) { create(:diff_note_on_merge_request, noteable: merge_request, project: project).to_discussion }
def resolve_discussion_selector
- title = 'Resolve this discussion in a new issue'
+ title = 'Resolve this thread in a new issue'
url = new_project_issue_path(project, discussion_to_resolve: discussion.id, merge_request_to_resolve_discussions_of: merge_request.iid)
"a[data-original-title=\"#{title}\"][href=\"#{url}\"]"
end
@@ -30,40 +30,40 @@ describe 'Resolve an open discussion in a merge request by creating an issue', :
end
end
- context 'resolving the discussion' do
+ context 'resolving the thread' do
before do
- click_button 'Resolve discussion'
+ click_button 'Resolve thread'
end
it 'hides the link for creating a new issue' do
expect(page).not_to have_css resolve_discussion_selector
end
- it 'shows the link for creating a new issue when unresolving a discussion' do
+ it 'shows the link for creating a new issue when unresolving a thread' do
page.within '.diff-content' do
- click_button 'Unresolve discussion'
+ click_button 'Unresolve thread'
end
expect(page).to have_css resolve_discussion_selector
end
end
- it 'has a link to create a new issue for a discussion' do
+ it 'has a link to create a new issue for a thread' do
expect(page).to have_css resolve_discussion_selector
end
context 'creating the issue' do
before do
- find(resolve_discussion_selector).click
+ find(resolve_discussion_selector, match: :first).click
end
- it 'has a hidden field for the discussion' do
+ it 'has a hidden field for the thread' do
discussion_field = find('#discussion_to_resolve', visible: false)
expect(discussion_field.value).to eq(discussion.id.to_s)
end
- it_behaves_like 'creating an issue for a discussion'
+ it_behaves_like 'creating an issue for a thread'
end
end
@@ -75,8 +75,8 @@ describe 'Resolve an open discussion in a merge request by creating an issue', :
discussion_to_resolve: discussion.id)
end
- it 'Shows a notice to ask someone else to resolve the discussions' do
- expect(page).to have_content("The discussion at #{merge_request.to_reference}"\
+ it 'Shows a notice to ask someone else to resolve the threads' do
+ expect(page).to have_content("The thread at #{merge_request.to_reference}"\
" (discussion #{discussion.first_note.id}) will stay unresolved."\
" Ask someone with permission to resolve it.")
end
diff --git a/spec/features/issues/todo_spec.rb b/spec/features/issues/todo_spec.rb
index 0114178b9be..07ae159eef4 100644
--- a/spec/features/issues/todo_spec.rb
+++ b/spec/features/issues/todo_spec.rb
@@ -13,8 +13,8 @@ describe 'Manually create a todo item from issue', :js do
it 'creates todo when clicking button' do
page.within '.issuable-sidebar' do
- click_button 'Add todo'
- expect(page).to have_content 'Mark todo as done'
+ click_button 'Add a To Do'
+ expect(page).to have_content 'Mark as done'
end
page.within '.header-content .todos-count' do
@@ -30,8 +30,8 @@ describe 'Manually create a todo item from issue', :js do
it 'marks a todo as done' do
page.within '.issuable-sidebar' do
- click_button 'Add todo'
- click_button 'Mark todo as done'
+ click_button 'Add a To Do'
+ click_button 'Mark as done'
end
expect(page).to have_selector('.todos-count', visible: false)
diff --git a/spec/features/issues/user_creates_confidential_merge_request_spec.rb b/spec/features/issues/user_creates_confidential_merge_request_spec.rb
new file mode 100644
index 00000000000..7ae4af4667b
--- /dev/null
+++ b/spec/features/issues/user_creates_confidential_merge_request_spec.rb
@@ -0,0 +1,54 @@
+require 'rails_helper'
+
+describe 'User creates confidential merge request on issue page', :js do
+ include ProjectForksHelper
+
+ let(:user) { create(:user) }
+ let(:project) { create(:project, :repository, :public) }
+ let(:issue) { create(:issue, project: project, confidential: true) }
+
+ def visit_confidential_issue
+ sign_in(user)
+ visit project_issue_path(project, issue)
+ wait_for_requests
+ end
+
+ before do
+ project.add_developer(user)
+ end
+
+ context 'user has no private fork' do
+ before do
+ fork_project(project, user, repository: true)
+ visit_confidential_issue
+ end
+
+ it 'shows that user has no fork available' do
+ click_button 'Create confidential merge request'
+
+ page.within '.create-confidential-merge-request-dropdown-menu' do
+ expect(page).to have_content('No forks available to you')
+ end
+ end
+ end
+
+ describe 'user has private fork' do
+ let(:forked_project) { fork_project(project, user, repository: true) }
+
+ before do
+ forked_project.update(visibility: Gitlab::VisibilityLevel::PRIVATE)
+ visit_confidential_issue
+ end
+
+ it 'create merge request in fork' do
+ click_button 'Create confidential merge request'
+
+ page.within '.create-confidential-merge-request-dropdown-menu' do
+ expect(page).to have_button(forked_project.name_with_namespace)
+ click_button 'Create confidential merge request'
+ end
+
+ expect(page).to have_content(forked_project.namespace.name)
+ end
+ end
+end
diff --git a/spec/features/merge_request/user_comments_on_merge_request_spec.rb b/spec/features/merge_request/user_comments_on_merge_request_spec.rb
index 69bdab85d81..e6bc3780b5c 100644
--- a/spec/features/merge_request/user_comments_on_merge_request_spec.rb
+++ b/spec/features/merge_request/user_comments_on_merge_request_spec.rb
@@ -37,7 +37,7 @@ describe 'User comments on a merge request', :js do
wait_for_requests
page.within('.notes .discussion') do
- expect(page).to have_content("#{user.name} #{user.to_reference} started a discussion")
+ expect(page).to have_content("#{user.name} #{user.to_reference} started a thread")
expect(page).to have_content(sample_commit.line_code_path)
expect(page).to have_content('Line is wrong')
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 260eec7a9ed..10fe60cb075 100644
--- a/spec/features/merge_request/user_resolves_diff_notes_and_discussions_resolve_spec.rb
+++ b/spec/features/merge_request/user_resolves_diff_notes_and_discussions_resolve_spec.rb
@@ -1,6 +1,6 @@
require 'rails_helper'
-describe 'Merge request > User resolves diff notes and discussions', :js do
+describe 'Merge request > User resolves diff notes and threads', :js do
let(:project) { create(:project, :public, :repository) }
let(:user) { project.creator }
let(:guest) { create(:user) }
@@ -17,7 +17,7 @@ describe 'Merge request > User resolves diff notes and discussions', :js do
)
end
- context 'no discussions' do
+ context 'no threads' do
before do
project.add_maintainer(user)
sign_in(user)
@@ -25,8 +25,8 @@ describe 'Merge request > User resolves diff notes and discussions', :js do
visit_merge_request
end
- it 'displays no discussion resolved data' do
- expect(page).not_to have_content('discussion resolved')
+ it 'displays no thread resolved data' do
+ expect(page).not_to have_content('thread resolved')
expect(page).not_to have_selector('.discussion-next-btn')
end
end
@@ -38,10 +38,10 @@ describe 'Merge request > User resolves diff notes and discussions', :js do
visit_merge_request
end
- context 'single discussion' do
- it 'shows text with how many discussions' do
+ context 'single thread' do
+ it 'shows text with how many threads' do
page.within '.line-resolve-all-container' do
- expect(page).to have_content('0/1 discussion resolved')
+ expect(page).to have_content('0/1 thread resolved')
end
end
@@ -54,18 +54,18 @@ describe 'Merge request > User resolves diff notes and discussions', :js do
end
page.within '.diff-content' do
- expect(page).to have_selector('.btn', text: 'Unresolve discussion')
+ expect(page).to have_selector('.btn', text: 'Unresolve thread')
end
page.within '.line-resolve-all-container' do
- expect(page).to have_content('1/1 discussion resolved')
+ expect(page).to have_content('1/1 thread resolved')
expect(page).to have_selector('.line-resolve-btn.is-active')
end
end
- it 'allows user to mark discussion as resolved' do
+ it 'allows user to mark thread as resolved' do
page.within '.diff-content' do
- click_button 'Resolve discussion'
+ click_button 'Resolve thread'
end
expect(page).to have_selector('.discussion-body', visible: false)
@@ -75,38 +75,38 @@ describe 'Merge request > User resolves diff notes and discussions', :js do
end
page.within '.line-resolve-all-container' do
- expect(page).to have_content('1/1 discussion resolved')
+ expect(page).to have_content('1/1 thread resolved')
expect(page).to have_selector('.line-resolve-btn.is-active')
end
end
- it 'allows user to unresolve discussion' do
+ it 'allows user to unresolve thread' do
page.within '.diff-content' do
- click_button 'Resolve discussion'
- click_button 'Unresolve discussion'
+ click_button 'Resolve thread'
+ click_button 'Unresolve thread'
end
page.within '.line-resolve-all-container' do
- expect(page).to have_content('0/1 discussion resolved')
+ expect(page).to have_content('0/1 thread resolved')
end
end
- describe 'resolved discussion' do
+ describe 'resolved thread' do
before do
page.within '.diff-content' do
- click_button 'Resolve discussion'
+ click_button 'Resolve thread'
end
visit_merge_request
end
describe 'timeline view' do
- it 'hides when resolve discussion is clicked' do
+ it 'hides when resolve thread is clicked' do
expect(page).to have_selector('.discussion-header')
expect(page).not_to have_selector('.discussion-body')
end
- it 'shows resolved discussion when toggled' do
+ it 'shows resolved thread when toggled' do
find(".timeline-content .discussion[data-discussion-id='#{note.discussion_id}'] .discussion-toggle-button").click
expect(page.find(".line-holder-placeholder")).to be_visible
@@ -130,11 +130,11 @@ describe 'Merge request > User resolves diff notes and discussions', :js do
page.find('#parallel-diff-btn').click
end
- it 'hides when resolve discussion is clicked' do
+ it 'hides when resolve thread is clicked' do
expect(page).not_to have_selector('.diffs .diff-file .notes_holder')
end
- it 'shows resolved discussion when toggled' do
+ it 'shows resolved thread when toggled' do
find('.diff-comment-avatar-holders').click
expect(find('.diffs .diff-file .notes_holder')).to be_visible
@@ -143,7 +143,7 @@ describe 'Merge request > User resolves diff notes and discussions', :js do
describe 'reply form' do
before do
- click_button 'Toggle discussion'
+ click_button 'Toggle thread'
page.within '.diff-content' do
click_button 'Reply...'
@@ -160,34 +160,34 @@ describe 'Merge request > User resolves diff notes and discussions', :js do
end
page.within '.line-resolve-all-container' do
- expect(page).to have_content('1/1 discussion resolved')
+ expect(page).to have_content('1/1 thread resolved')
end
end
it 'allows user to unresolve from reply form without a comment' do
page.within '.diff-content' do
- click_button 'Unresolve discussion'
+ click_button 'Unresolve thread'
wait_for_requests
end
page.within '.line-resolve-all-container' do
- expect(page).to have_content('0/1 discussion resolved')
+ expect(page).to have_content('0/1 thread resolved')
expect(page).not_to have_selector('.line-resolve-btn.is-active')
end
end
- it 'allows user to comment & unresolve discussion' do
+ it 'allows user to comment & unresolve thread' do
page.within '.diff-content' do
find('.js-note-text').set 'testing'
- click_button 'Comment & unresolve discussion'
+ click_button 'Comment & unresolve thread'
wait_for_requests
end
page.within '.line-resolve-all-container' do
- expect(page).to have_content('0/1 discussion resolved')
+ expect(page).to have_content('0/1 thread resolved')
end
end
end
@@ -197,31 +197,31 @@ describe 'Merge request > User resolves diff notes and discussions', :js do
page.within '.diff-content' do
click_button 'Reply...'
- click_button 'Resolve discussion'
+ click_button 'Resolve thread'
end
page.within '.line-resolve-all-container' do
- expect(page).to have_content('1/1 discussion resolved')
+ expect(page).to have_content('1/1 thread resolved')
expect(page).to have_selector('.line-resolve-btn.is-active')
end
end
- it 'allows user to comment & resolve discussion' do
+ it 'allows user to comment & resolve thread' do
page.within '.diff-content' do
click_button 'Reply...'
find('.js-note-text').set 'testing'
- click_button 'Comment & resolve discussion'
+ click_button 'Comment & resolve thread'
end
page.within '.line-resolve-all-container' do
- expect(page).to have_content('1/1 discussion resolved')
+ expect(page).to have_content('1/1 thread resolved')
expect(page).to have_selector('.line-resolve-btn.is-active')
end
end
- it 'allows user to quickly scroll to next unresolved discussion' do
+ it 'allows user to quickly scroll to next unresolved thread' do
page.within '.line-resolve-all-container' do
page.find('.discussion-next-btn').click
end
@@ -231,7 +231,7 @@ describe 'Merge request > User resolves diff notes and discussions', :js do
it 'hides jump to next button when all resolved' do
page.within '.diff-content' do
- click_button 'Resolve discussion'
+ click_button 'Resolve thread'
end
expect(page).to have_selector('.discussion-next-btn', visible: false)
@@ -248,7 +248,7 @@ describe 'Merge request > User resolves diff notes and discussions', :js do
end
end
- it 'hides jump to next discussion button' do
+ it 'hides jump to next thread button' do
page.within '.discussion-reply-holder' do
expect(page).not_to have_selector('.discussion-next-btn')
end
@@ -261,7 +261,7 @@ describe 'Merge request > User resolves diff notes and discussions', :js do
visit_merge_request
end
- it 'does not mark discussion as resolved when resolving single note' do
+ it 'does not mark thread as resolved when resolving single note' do
page.within("#note_#{note.id}") do
first('.line-resolve-btn').click
@@ -273,11 +273,11 @@ describe 'Merge request > User resolves diff notes and discussions', :js do
expect(page).to have_content('Last updated')
page.within '.line-resolve-all-container' do
- expect(page).to have_content('0/1 discussion resolved')
+ expect(page).to have_content('0/1 thread resolved')
end
end
- it 'resolves discussion' do
+ it 'resolves thread' do
resolve_buttons = page.all('.note .line-resolve-btn', count: 2)
resolve_buttons.each do |button|
button.click
@@ -290,28 +290,28 @@ describe 'Merge request > User resolves diff notes and discussions', :js do
end
page.within '.line-resolve-all-container' do
- expect(page).to have_content('1/1 discussion resolved')
+ expect(page).to have_content('1/1 thread resolved')
end
end
end
- context 'muliple discussions' do
+ context 'muliple threads' do
before do
create(:diff_note_on_merge_request, project: project, position: position, noteable: merge_request)
visit_merge_request
end
- it 'shows text with how many discussions' do
+ it 'shows text with how many threads' do
page.within '.line-resolve-all-container' do
- expect(page).to have_content('0/2 discussions resolved')
+ expect(page).to have_content('0/2 threads resolved')
end
end
it 'allows user to mark a single note as resolved' do
- click_button('Resolve discussion', match: :first)
+ click_button('Resolve thread', match: :first)
page.within '.line-resolve-all-container' do
- expect(page).to have_content('1/2 discussions resolved')
+ expect(page).to have_content('1/2 threads resolved')
end
end
@@ -321,27 +321,27 @@ describe 'Merge request > User resolves diff notes and discussions', :js do
end
page.within '.line-resolve-all-container' do
- expect(page).to have_content('2/2 discussions resolved')
+ expect(page).to have_content('2/2 threads resolved')
expect(page).to have_selector('.line-resolve-btn.is-active')
end
end
- it 'allows user to mark all discussions as resolved' do
+ it 'allows user to mark all threads as resolved' do
page.all('.discussion-reply-holder', count: 2).each do |reply_holder|
page.within reply_holder do
- click_button 'Resolve discussion'
+ click_button 'Resolve thread'
end
end
page.within '.line-resolve-all-container' do
- expect(page).to have_content('2/2 discussions resolved')
+ expect(page).to have_content('2/2 threads resolved')
expect(page).to have_selector('.line-resolve-btn.is-active')
end
end
- it 'allows user to quickly scroll to next unresolved discussion' do
+ it 'allows user to quickly scroll to next unresolved thread' do
page.within('.discussion-reply-holder', match: :first) do
- click_button 'Resolve discussion'
+ click_button 'Resolve thread'
end
page.within '.line-resolve-all-container' do
@@ -362,25 +362,25 @@ describe 'Merge request > User resolves diff notes and discussions', :js do
end
end
- it 'shows jump to next discussion button on all discussions' do
+ it 'shows jump to next thread button except on last thread' do
wait_for_requests
all_discussion_replies = page.all('.discussion-reply-holder')
expect(all_discussion_replies.count).to eq(2)
- expect(all_discussion_replies.first.all('.discussion-next-btn').count).to eq(1)
- expect(all_discussion_replies.last.all('.discussion-next-btn').count).to eq(1)
+ expect(all_discussion_replies.first.all('.discussion-next-btn').count).to eq(2)
+ expect(all_discussion_replies.last.all('.discussion-next-btn').count).to eq(2)
end
- it 'displays next discussion even if hidden' do
+ it 'displays next thread even if hidden' do
page.all('.note-discussion', count: 2).each do |discussion|
page.within discussion do
- click_button 'Toggle discussion'
+ click_button 'Toggle thread'
end
end
page.within('.issuable-discussion #notes') do
- expect(page).not_to have_selector('.btn', text: 'Resolve discussion')
+ expect(page).not_to have_selector('.btn', text: 'Resolve thread')
end
page.within '.line-resolve-all-container' do
@@ -388,19 +388,19 @@ describe 'Merge request > User resolves diff notes and discussions', :js do
end
page.all('.note-discussion').first do
- expect(page.find('.discussion-with-resolve-btn')).to have_selector('.btn', text: 'Resolve discussion')
+ expect(page.find('.discussion-with-resolve-btn')).to have_selector('.btn', text: 'Resolve thread')
end
page.all('.note-discussion').last do
- expect(page.find('.discussion-with-resolve-btn')).not.to have_selector('.btn', text: 'Resolve discussion')
+ expect(page.find('.discussion-with-resolve-btn')).not.to have_selector('.btn', text: 'Resolve thread')
end
end
end
context 'changes tab' do
- it 'shows text with how many discussions' do
+ it 'shows text with how many threads' do
page.within '.line-resolve-all-container' do
- expect(page).to have_content('0/1 discussion resolved')
+ expect(page).to have_content('0/1 thread resolved')
end
end
@@ -412,18 +412,18 @@ describe 'Merge request > User resolves diff notes and discussions', :js do
end
page.within '.diff-content' do
- expect(page).to have_selector('.btn', text: 'Unresolve discussion')
+ expect(page).to have_selector('.btn', text: 'Unresolve thread')
end
page.within '.line-resolve-all-container' do
- expect(page).to have_content('1/1 discussion resolved')
+ expect(page).to have_content('1/1 thread resolved')
expect(page).to have_selector('.line-resolve-btn.is-active')
end
end
- it 'allows user to mark discussion as resolved' do
+ it 'allows user to mark thread as resolved' do
page.within '.diff-content' do
- click_button 'Resolve discussion'
+ click_button 'Resolve thread'
end
page.within '.diff-content .note' do
@@ -431,50 +431,50 @@ describe 'Merge request > User resolves diff notes and discussions', :js do
end
page.within '.line-resolve-all-container' do
- expect(page).to have_content('1/1 discussion resolved')
+ expect(page).to have_content('1/1 thread resolved')
expect(page).to have_selector('.line-resolve-btn.is-active')
end
end
- it 'allows user to unresolve discussion' do
+ it 'allows user to unresolve thread' do
page.within '.diff-content' do
- click_button 'Resolve discussion'
- click_button 'Unresolve discussion'
+ click_button 'Resolve thread'
+ click_button 'Unresolve thread'
end
page.within '.line-resolve-all-container' do
- expect(page).to have_content('0/1 discussion resolved')
+ expect(page).to have_content('0/1 thread resolved')
end
end
- it 'allows user to comment & resolve discussion' do
+ it 'allows user to comment & resolve thread' do
page.within '.diff-content' do
click_button 'Reply...'
find('.js-note-text').set 'testing'
- click_button 'Comment & resolve discussion'
+ click_button 'Comment & resolve thread'
end
page.within '.line-resolve-all-container' do
- expect(page).to have_content('1/1 discussion resolved')
+ expect(page).to have_content('1/1 thread resolved')
expect(page).to have_selector('.line-resolve-btn.is-active')
end
end
- it 'allows user to comment & unresolve discussion' do
+ it 'allows user to comment & unresolve thread' do
page.within '.diff-content' do
- click_button 'Resolve discussion'
+ click_button 'Resolve thread'
click_button 'Reply...'
find('.js-note-text').set 'testing'
- click_button 'Comment & unresolve discussion'
+ click_button 'Comment & unresolve thread'
end
page.within '.line-resolve-all-container' do
- expect(page).to have_content('0/1 discussion resolved')
+ expect(page).to have_content('0/1 thread resolved')
end
end
end
@@ -497,13 +497,13 @@ describe 'Merge request > User resolves diff notes and discussions', :js do
end
page.within '.line-resolve-all-container' do
- expect(page).to have_content('0/1 discussion resolved')
+ expect(page).to have_content('0/1 thread resolved')
end
end
- it 'does not allow user to mark discussion as resolved' do
+ it 'does not allow user to mark thread as resolved' do
page.within '.diff-content .note' do
- expect(page).not_to have_selector('.btn', text: 'Resolve discussion')
+ expect(page).not_to have_selector('.btn', text: 'Resolve thread')
end
end
end
@@ -523,11 +523,11 @@ describe 'Merge request > User resolves diff notes and discussions', :js do
end
page.within '.diff-content' do
- expect(page).to have_selector('.btn', text: 'Unresolve discussion')
+ expect(page).to have_selector('.btn', text: 'Unresolve thread')
end
page.within '.line-resolve-all-container' do
- expect(page).to have_content('1/1 discussion resolved')
+ expect(page).to have_content('1/1 thread resolved')
expect(page).to have_selector('.line-resolve-btn.is-active')
end
end
@@ -546,7 +546,7 @@ describe 'Merge request > User resolves diff notes and discussions', :js do
end
page.within '.line-resolve-all-container' do
- expect(page).to have_content('0/1 discussion resolved')
+ expect(page).to have_content('0/1 thread resolved')
end
end
end
@@ -558,15 +558,15 @@ describe 'Merge request > User resolves diff notes and discussions', :js do
end
it 'shows resolved icon' do
- expect(page).to have_content '1/1 discussion resolved'
+ expect(page).to have_content '1/1 thread resolved'
- click_button 'Toggle discussion'
+ click_button 'Toggle thread'
expect(page).to have_selector('.line-resolve-btn.is-active')
end
it 'does not allow user to click resolve button' do
expect(page).to have_selector('.line-resolve-btn.is-disabled')
- click_button 'Toggle discussion'
+ click_button 'Toggle thread'
expect(page).to have_selector('.line-resolve-btn.is-disabled')
end
diff --git a/spec/features/merge_request/user_sees_discussions_spec.rb b/spec/features/merge_request/user_sees_discussions_spec.rb
index 57be1d06708..39258b48295 100644
--- a/spec/features/merge_request/user_sees_discussions_spec.rb
+++ b/spec/features/merge_request/user_sees_discussions_spec.rb
@@ -1,6 +1,6 @@
require 'rails_helper'
-describe 'Merge request > User sees discussions', :js do
+describe 'Merge request > User sees threads', :js do
let(:project) { create(:project, :public, :repository) }
let(:user) { project.creator }
let(:merge_request) { create(:merge_request, source_project: project) }
@@ -30,7 +30,7 @@ describe 'Merge request > User sees discussions', :js do
visit project_merge_request_path(project, merge_request)
end
- context 'active discussions' do
+ context 'active threads' do
it 'shows a link to the diff' do
within(".discussion[data-discussion-id='#{active_discussion.id}']") do
path = diffs_project_merge_request_path(project, merge_request, anchor: active_discussion.line_code)
@@ -39,7 +39,7 @@ describe 'Merge request > User sees discussions', :js do
end
end
- context 'outdated discussions' do
+ context 'outdated threads' do
it 'shows a link to the outdated diff' do
within(".discussion[data-discussion-id='#{outdated_discussion.id}']") do
path = diffs_project_merge_request_path(project, merge_request, diff_id: old_merge_request_diff.id, anchor: outdated_discussion.line_code)
@@ -85,7 +85,7 @@ describe 'Merge request > User sees discussions', :js do
it_behaves_like 'a functional discussion'
it 'displays correct header' do
- expect(page).to have_content "started a discussion on commit #{note.commit_id[0...7]}"
+ expect(page).to have_content "started a thread on commit #{note.commit_id[0...7]}"
end
end
diff --git a/spec/features/merge_request/user_sees_merge_button_depending_on_unresolved_discussions_spec.rb b/spec/features/merge_request/user_sees_merge_button_depending_on_unresolved_discussions_spec.rb
index f6b771facf8..cf398a7df18 100644
--- a/spec/features/merge_request/user_sees_merge_button_depending_on_unresolved_discussions_spec.rb
+++ b/spec/features/merge_request/user_sees_merge_button_depending_on_unresolved_discussions_spec.rb
@@ -1,6 +1,6 @@
require 'rails_helper'
-describe 'Merge request > User sees merge button depending on unresolved discussions', :js do
+describe 'Merge request > User sees merge button depending on unresolved threads', :js do
let(:project) { create(:project, :repository) }
let(:user) { project.creator }
let!(:merge_request) { create(:merge_request_with_diff_notes, source_project: project, author: user) }
@@ -16,14 +16,14 @@ describe 'Merge request > User sees merge button depending on unresolved discuss
visit project_merge_request_path(project, merge_request)
end
- context 'with unresolved discussions' do
+ context 'with unresolved threads' do
it 'does not allow to merge' do
expect(page).not_to have_button 'Merge'
- expect(page).to have_content('There are unresolved discussions.')
+ expect(page).to have_content('There are unresolved threads.')
end
end
- context 'with all discussions resolved' do
+ context 'with all threads resolved' do
before do
merge_request.discussions.each { |d| d.resolve!(user) }
visit project_merge_request_path(project, merge_request)
@@ -41,13 +41,13 @@ describe 'Merge request > User sees merge button depending on unresolved discuss
visit project_merge_request_path(project, merge_request)
end
- context 'with unresolved discussions' do
+ context 'with unresolved threads' do
it 'does not allow to merge' do
expect(page).to have_button 'Merge'
end
end
- context 'with all discussions resolved' do
+ context 'with all threads resolved' do
before do
merge_request.discussions.each { |d| d.resolve!(user) }
visit project_merge_request_path(project, merge_request)
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 733e8aa3eba..30e30751693 100644
--- a/spec/features/merge_request/user_sees_merge_widget_spec.rb
+++ b/spec/features/merge_request/user_sees_merge_widget_spec.rb
@@ -519,6 +519,8 @@ describe 'Merge request > User sees merge widget', :js do
end
before do
+ allow_any_instance_of(TestSuiteComparerEntity)
+ .to receive(:max_tests).and_return(2)
allow_any_instance_of(MergeRequest)
.to receive(:has_test_reports?).and_return(true)
allow_any_instance_of(MergeRequest)
@@ -551,7 +553,7 @@ describe 'Merge request > User sees merge widget', :js do
expect(page).to have_content('rspec found no changed test results out of 1 total test')
expect(page).to have_content('junit found 1 failed test result out of 1 total test')
expect(page).to have_content('New')
- expect(page).to have_content('subtractTest')
+ expect(page).to have_content('addTest')
end
end
end
@@ -562,7 +564,7 @@ describe 'Merge request > User sees merge widget', :js do
click_button 'Expand'
within(".js-report-section-container") do
- click_button 'subtractTest'
+ click_button 'addTest'
expect(page).to have_content('6.66')
expect(page).to have_content(sample_java_failed_message.gsub!(/\s+/, ' ').strip)
@@ -596,7 +598,7 @@ describe 'Merge request > User sees merge widget', :js do
expect(page).to have_content('rspec found 1 failed test result out of 1 total test')
expect(page).to have_content('junit found no changed test results out of 1 total test')
expect(page).not_to have_content('New')
- expect(page).to have_content('Test#sum when a is 2 and b is 2 returns summary')
+ expect(page).to have_content('Test#sum when a is 1 and b is 3 returns summary')
end
end
end
@@ -607,7 +609,7 @@ describe 'Merge request > User sees merge widget', :js do
click_button 'Expand'
within(".js-report-section-container") do
- click_button 'Test#sum when a is 2 and b is 2 returns summary'
+ click_button 'Test#sum when a is 1 and b is 3 returns summary'
expect(page).to have_content('2.22')
expect(page).to have_content(sample_rspec_failed_message.gsub!(/\s+/, ' ').strip)
@@ -628,13 +630,7 @@ describe 'Merge request > User sees merge widget', :js do
let(:head_reports) do
Gitlab::Ci::Reports::TestReports.new.tap do |reports|
reports.get_suite('rspec').add_test_case(create_test_case_rspec_success)
- reports.get_suite('junit').add_test_case(create_test_case_java_resolved)
- end
- end
-
- let(:create_test_case_java_resolved) do
- create_test_case_java_failed.tap do |test_case|
- test_case.instance_variable_set("@status", Gitlab::Ci::Reports::TestCase::STATUS_SUCCESS)
+ reports.get_suite('junit').add_test_case(create_test_case_java_success)
end
end
@@ -646,7 +642,7 @@ describe 'Merge request > User sees merge widget', :js do
within(".js-report-section-container") do
expect(page).to have_content('rspec found no changed test results out of 1 total test')
expect(page).to have_content('junit found 1 fixed test result out of 1 total test')
- expect(page).to have_content('subtractTest')
+ expect(page).to have_content('addTest')
end
end
end
@@ -657,15 +653,53 @@ describe 'Merge request > User sees merge widget', :js do
click_button 'Expand'
within(".js-report-section-container") do
- click_button 'subtractTest'
+ click_button 'addTest'
- expect(page).to have_content('6.66')
+ expect(page).to have_content('5.55')
end
end
end
end
end
+ context 'properly truncates the report' do
+ let(:base_reports) do
+ Gitlab::Ci::Reports::TestReports.new.tap do |reports|
+ 10.times do |index|
+ reports.get_suite('rspec').add_test_case(
+ create_test_case_rspec_failed(index))
+ reports.get_suite('junit').add_test_case(
+ create_test_case_java_success(index))
+ end
+ end
+ end
+
+ let(:head_reports) do
+ Gitlab::Ci::Reports::TestReports.new.tap do |reports|
+ 10.times do |index|
+ reports.get_suite('rspec').add_test_case(
+ create_test_case_rspec_failed(index))
+ reports.get_suite('junit').add_test_case(
+ create_test_case_java_failed(index))
+ end
+ end
+ end
+
+ it 'shows test reports summary which includes the resolved failure' do
+ within(".js-reports-container") do
+ click_button 'Expand'
+
+ expect(page).to have_content('Test summary contained 20 failed test results out of 20 total tests')
+ within(".js-report-section-container") do
+ expect(page).to have_content('rspec found 10 failed test results out of 10 total tests')
+ expect(page).to have_content('junit found 10 failed test results out of 10 total tests')
+
+ expect(page).to have_content('Test#sum when a is 1 and b is 3 returns summary', count: 2)
+ end
+ end
+ end
+ end
+
def comparer
Gitlab::Ci::Reports::TestReportsComparer.new(base_reports, head_reports)
end
diff --git a/spec/features/merge_request/user_suggests_changes_on_diff_spec.rb b/spec/features/merge_request/user_suggests_changes_on_diff_spec.rb
index e8b4fc8f160..4363b359038 100644
--- a/spec/features/merge_request/user_suggests_changes_on_diff_spec.rb
+++ b/spec/features/merge_request/user_suggests_changes_on_diff_spec.rb
@@ -186,12 +186,12 @@ describe 'User comments on a diff', :js do
it 'resolves discussion when applied' do
page.within('.diff-discussions') do
- expect(page).not_to have_content('Unresolve discussion')
+ expect(page).not_to have_content('Unresolve thread')
click_button('Apply suggestion')
wait_for_requests
- expect(page).to have_content('Unresolve discussion')
+ expect(page).to have_content('Unresolve thread')
end
end
end
diff --git a/spec/features/oauth_login_spec.rb b/spec/features/oauth_login_spec.rb
index 5ebfc32952d..86331728f88 100644
--- a/spec/features/oauth_login_spec.rb
+++ b/spec/features/oauth_login_spec.rb
@@ -16,16 +16,8 @@ describe 'OAuth Login', :js, :allow_forgery_protection do
providers = [:github, :twitter, :bitbucket, :gitlab, :google_oauth2,
:facebook, :cas3, :auth0, :authentiq, :salesforce]
- before(:all) do
- # The OmniAuth `full_host` parameter doesn't get set correctly (it gets set to something like `http://localhost`
- # here), and causes integration tests to fail with 404s. We set the `full_host` by removing the request path (and
- # anything after it) from the request URI.
- @omniauth_config_full_host = OmniAuth.config.full_host
- OmniAuth.config.full_host = ->(request) { request['REQUEST_URI'].sub(/#{request['REQUEST_PATH']}.*/, '') }
- end
-
- after(:all) do
- OmniAuth.config.full_host = @omniauth_config_full_host
+ around(:all) do |example|
+ with_omniauth_full_host { example.run }
end
def login_with_provider(provider, enter_two_factor: false)
diff --git a/spec/features/projects/clusters/applications_spec.rb b/spec/features/projects/clusters/applications_spec.rb
index 527508b3519..c75259d1b0c 100644
--- a/spec/features/projects/clusters/applications_spec.rb
+++ b/spec/features/projects/clusters/applications_spec.rb
@@ -21,8 +21,7 @@ describe 'Clusters Applications', :js do
it 'user is unable to install applications' do
page.within('.js-cluster-application-row-helm') do
- expect(page.find(:css, '.js-cluster-application-install-button')['disabled']).to eq('true')
- expect(page).to have_css('.js-cluster-application-install-button', exact_text: 'Install')
+ expect(page).to have_css('.js-cluster-application-install-button[disabled]', exact_text: 'Install')
end
end
end
@@ -53,19 +52,16 @@ describe 'Clusters Applications', :js do
it 'they see status transition' do
page.within('.js-cluster-application-row-helm') do
# FE sends request and gets the response, then the buttons is "Installing"
- expect(page.find(:css, '.js-cluster-application-install-button')['disabled']).to eq('true')
- expect(page).to have_css('.js-cluster-application-install-button', exact_text: 'Installing')
+ expect(page).to have_css('.js-cluster-application-install-button[disabled]', exact_text: 'Installing')
Clusters::Cluster.last.application_helm.make_installing!
# FE starts polling and update the buttons to "Installing"
- expect(page.find(:css, '.js-cluster-application-install-button')['disabled']).to eq('true')
- expect(page).to have_css('.js-cluster-application-install-button', exact_text: 'Installing')
+ expect(page).to have_css('.js-cluster-application-install-button[disabled]', exact_text: 'Installing')
Clusters::Cluster.last.application_helm.make_installed!
- expect(page.find(:css, '.js-cluster-application-install-button')['disabled']).to eq('true')
- expect(page).to have_css('.js-cluster-application-install-button', exact_text: 'Installed')
+ expect(page).to have_css('.js-cluster-application-install-button[disabled]', exact_text: 'Installed')
end
expect(page).to have_content('Helm Tiller was successfully installed on your Kubernetes cluster')
@@ -212,26 +208,25 @@ describe 'Clusters Applications', :js do
it 'they see status transition' do
page.within('.js-cluster-application-row-ingress') do
# FE sends request and gets the response, then the buttons is "Installing"
- expect(page).to have_css('.js-cluster-application-install-button[disabled]')
- expect(page).to have_css('.js-cluster-application-install-button', exact_text: 'Installing')
+ expect(page).to have_css('.js-cluster-application-install-button[disabled]', exact_text: 'Installing')
Clusters::Cluster.last.application_ingress.make_installing!
# FE starts polling and update the buttons to "Installing"
- expect(page).to have_css('.js-cluster-application-install-button', exact_text: 'Installing')
- expect(page).to have_css('.js-cluster-application-install-button[disabled]')
+ expect(page).to have_css('.js-cluster-application-install-button[disabled]', exact_text: 'Installing')
# The application becomes installed but we keep waiting for external IP address
Clusters::Cluster.last.application_ingress.make_installed!
- expect(page).to have_css('.js-cluster-application-install-button', exact_text: 'Installed')
- expect(page).to have_css('.js-cluster-application-install-button[disabled]')
+ expect(page).to have_css('.js-cluster-application-install-button[disabled]', exact_text: 'Installed')
expect(page).to have_selector('.js-no-endpoint-message')
expect(page).to have_selector('.js-ingress-ip-loading-icon')
# We receive the external IP address and display
Clusters::Cluster.last.application_ingress.update!(external_ip: '192.168.1.100')
+ expect(page).not_to have_css('.js-cluster-application-install-button')
+ expect(page).to have_css('.js-cluster-application-uninstall-button:not([disabled])', exact_text: 'Uninstall')
expect(page).not_to have_selector('.js-no-endpoint-message')
expect(page.find('.js-endpoint').value).to eq('192.168.1.100')
end
diff --git a/spec/features/projects/releases/user_views_releases_spec.rb b/spec/features/projects/releases/user_views_releases_spec.rb
index 317ffb6a2ff..725d7173bce 100644
--- a/spec/features/projects/releases/user_views_releases_spec.rb
+++ b/spec/features/projects/releases/user_views_releases_spec.rb
@@ -16,6 +16,7 @@ describe 'User views releases', :js do
expect(page).to have_content(release.name)
expect(page).to have_content(release.tag)
+ expect(page).not_to have_content('Upcoming Release')
end
context 'when there is a link as an asset' do
@@ -43,4 +44,15 @@ describe 'User views releases', :js do
end
end
end
+
+ context 'with an upcoming release' do
+ let(:tomorrow) { Time.zone.now + 1.day }
+ let!(:release) { create(:release, project: project, released_at: tomorrow ) }
+
+ it 'sees the upcoming tag' do
+ visit project_releases_path(project)
+
+ expect(page).to have_content('Upcoming Release')
+ end
+ end
end
diff --git a/spec/features/projects/settings/repository_settings_spec.rb b/spec/features/projects/settings/repository_settings_spec.rb
index 8c7bc192c50..1edfee705c8 100644
--- a/spec/features/projects/settings/repository_settings_spec.rb
+++ b/spec/features/projects/settings/repository_settings_spec.rb
@@ -112,11 +112,17 @@ describe 'Projects > Settings > Repository settings' do
it 'add a new deploy token' do
fill_in 'deploy_token_name', with: 'new_deploy_key'
fill_in 'deploy_token_expires_at', with: (Date.today + 1.month).to_s
+ fill_in 'deploy_token_username', with: 'deployer'
check 'deploy_token_read_repository'
check 'deploy_token_read_registry'
click_button 'Create deploy token'
expect(page).to have_content('Your new project deploy token has been created')
+
+ within('.created-deploy-token-container') do
+ expect(page).to have_selector("input[name='deploy-token-user'][value='deployer']")
+ expect(page).to have_selector("input[name='deploy-token'][readonly='readonly']")
+ end
end
end
diff --git a/spec/features/search/user_uses_header_search_field_spec.rb b/spec/features/search/user_uses_header_search_field_spec.rb
index 1cc47cd6bd1..7ddd5c12cdf 100644
--- a/spec/features/search/user_uses_header_search_field_spec.rb
+++ b/spec/features/search/user_uses_header_search_field_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe 'User uses header search field' do
+describe 'User uses header search field', :js do
include FilteredSearchHelpers
let(:project) { create(:project) }
@@ -11,57 +11,12 @@ describe 'User uses header search field' do
sign_in(user)
end
- context 'when user is in a global scope', :js do
+ shared_examples 'search field examples' do
before do
- visit(root_path)
- page.find('#search').click
+ visit(url)
end
- context 'when clicking issues' do
- it 'shows assigned issues' do
- find('.search-input-container .dropdown-menu').click_link('Issues assigned to me')
-
- expect(page).to have_selector('.filtered-search')
- expect_tokens([assignee_token(user.name)])
- expect_filtered_search_input_empty
- end
-
- it 'shows created issues' do
- find('.search-input-container .dropdown-menu').click_link("Issues I've created")
-
- expect(page).to have_selector('.filtered-search')
- expect_tokens([author_token(user.name)])
- expect_filtered_search_input_empty
- end
- end
-
- context 'when clicking merge requests' do
- let!(:merge_request) { create(:merge_request, source_project: project, author: user, assignees: [user]) }
-
- it 'shows assigned merge requests' do
- find('.search-input-container .dropdown-menu').click_link('Merge requests assigned to me')
-
- expect(page).to have_selector('.filtered-search')
- expect_tokens([assignee_token(user.name)])
- expect_filtered_search_input_empty
- end
-
- it 'shows created merge requests' do
- find('.search-input-container .dropdown-menu').click_link("Merge requests I've created")
-
- expect(page).to have_selector('.filtered-search')
- expect_tokens([author_token(user.name)])
- expect_filtered_search_input_empty
- end
- end
- end
-
- context 'when user is in a project scope' do
- before do
- visit(project_path(project))
- end
-
- it 'starts searching by pressing the enter key', :js do
+ it 'starts searching by pressing the enter key' do
fill_in('search', with: 'gitlab')
find('#search').native.send_keys(:enter)
@@ -70,30 +25,31 @@ describe 'User uses header search field' do
end
end
- context 'when clicking the search field', :js do
+ context 'when clicking the search field' do
before do
page.find('#search').click
+ wait_for_all_requests
end
it 'shows category search dropdown' do
- expect(page).to have_selector('.dropdown-header', text: /#{project.name}/i)
+ expect(page).to have_selector('.dropdown-header', text: /#{scope_name}/i)
end
context 'when clicking issues' do
let!(:issue) { create(:issue, project: project, author: user, assignees: [user]) }
it 'shows assigned issues' do
- find('.dropdown-menu').click_link('Issues assigned to me')
+ find('.search-input-container .dropdown-menu').click_link('Issues assigned to me')
- expect(page).to have_selector('.filtered-search')
+ expect(page).to have_selector('.issues-list .issue')
expect_tokens([assignee_token(user.name)])
expect_filtered_search_input_empty
end
it 'shows created issues' do
- find('.dropdown-menu').click_link("Issues I've created")
+ find('.search-input-container .dropdown-menu').click_link("Issues I've created")
- expect(page).to have_selector('.filtered-search')
+ expect(page).to have_selector('.issues-list .issue')
expect_tokens([author_token(user.name)])
expect_filtered_search_input_empty
end
@@ -103,33 +59,77 @@ describe 'User uses header search field' do
let!(:merge_request) { create(:merge_request, source_project: project, author: user, assignees: [user]) }
it 'shows assigned merge requests' do
- find('.dropdown-menu').click_link('Merge requests assigned to me')
+ find('.search-input-container .dropdown-menu').click_link('Merge requests assigned to me')
- expect(page).to have_selector('.merge-requests-holder')
+ expect(page).to have_selector('.mr-list .merge-request')
expect_tokens([assignee_token(user.name)])
expect_filtered_search_input_empty
end
it 'shows created merge requests' do
- find('.dropdown-menu').click_link("Merge requests I've created")
+ find('.search-input-container .dropdown-menu').click_link("Merge requests I've created")
- expect(page).to have_selector('.merge-requests-holder')
+ expect(page).to have_selector('.mr-list .merge-request')
expect_tokens([author_token(user.name)])
expect_filtered_search_input_empty
end
end
end
- context 'when entering text into the search field', :js do
+ context 'when entering text into the search field' do
before do
page.within('.search-input-wrap') do
- fill_in('search', with: project.name[0..3])
+ fill_in('search', with: scope_name.first(4))
end
end
it 'does not display the category search dropdown' do
- expect(page).not_to have_selector('.dropdown-header', text: /#{project.name}/i)
+ expect(page).not_to have_selector('.dropdown-header', text: /#{scope_name}/i)
end
end
end
+
+ context 'when user is in a global scope' do
+ include_examples 'search field examples' do
+ let(:url) { root_path }
+ let(:scope_name) { 'All GitLab' }
+ end
+ end
+
+ context 'when user is in a project scope' do
+ include_examples 'search field examples' do
+ let(:url) { project_path(project) }
+ let(:scope_name) { project.name }
+ end
+ end
+
+ context 'when user is in a group scope' do
+ let(:group) { create(:group) }
+ let(:project) { create(:project, namespace: group) }
+
+ before do
+ group.add_maintainer(user)
+ end
+
+ include_examples 'search field examples' do
+ let(:url) { group_path(group) }
+ let(:scope_name) { group.name }
+ end
+ end
+
+ context 'when user is in a subgroup scope' do
+ let(:group) { create(:group) }
+ let(:subgroup) { create(:group, :public, parent: group) }
+ let(:project) { create(:project, namespace: subgroup) }
+
+ before do
+ group.add_owner(user)
+ subgroup.add_owner(user)
+ end
+
+ include_examples 'search field examples' do
+ let(:url) { group_path(subgroup) }
+ let(:scope_name) { subgroup.name }
+ end
+ end
end
diff --git a/spec/features/snippets/user_creates_snippet_spec.rb b/spec/features/snippets/user_creates_snippet_spec.rb
index 1c97d5ec5b4..93d77d5b5ce 100644
--- a/spec/features/snippets/user_creates_snippet_spec.rb
+++ b/spec/features/snippets/user_creates_snippet_spec.rb
@@ -41,7 +41,7 @@ describe 'User creates snippet', :js do
expect(page).to have_content('My Snippet')
link = find('a.no-attachment-icon img[alt="banana_sample"]')['src']
- expect(link).to match(%r{/uploads/-/system/temp/\h{32}/banana_sample\.gif\z})
+ expect(link).to match(%r{/uploads/-/system/user/#{user.id}/\h{32}/banana_sample\.gif\z})
reqs = inspect_requests { visit(link) }
expect(reqs.first.status_code).to eq(200)
diff --git a/spec/features/users/terms_spec.rb b/spec/features/users/terms_spec.rb
index 84df1016594..a770309e6b0 100644
--- a/spec/features/users/terms_spec.rb
+++ b/spec/features/users/terms_spec.rb
@@ -81,15 +81,18 @@ describe 'Users > Terms' do
enforce_terms
- within('.nav-sidebar') do
- click_link 'Issues'
- end
+ # Application settings are cached for a minute
+ Timecop.travel 2.minutes do
+ within('.nav-sidebar') do
+ click_link 'Issues'
+ end
- expect_to_be_on_terms_page
+ expect_to_be_on_terms_page
- click_button('Accept terms')
+ click_button('Accept terms')
- expect(current_path).to eq(project_issues_path(project))
+ expect(current_path).to eq(project_issues_path(project))
+ end
end
# Disabled until https://gitlab.com/gitlab-org/gitlab-ce/issues/37162 is solved properly
diff --git a/spec/finders/releases_finder_spec.rb b/spec/finders/releases_finder_spec.rb
index 32ee15134a2..5ffb8c74bf5 100644
--- a/spec/finders/releases_finder_spec.rb
+++ b/spec/finders/releases_finder_spec.rb
@@ -12,8 +12,8 @@ describe ReleasesFinder do
subject { described_class.new(project, user)}
before do
- v1_0_0.update_attribute(:created_at, 2.days.ago)
- v1_1_0.update_attribute(:created_at, 1.day.ago)
+ v1_0_0.update_attribute(:released_at, 2.days.ago)
+ v1_1_0.update_attribute(:released_at, 1.day.ago)
end
describe '#execute' do
@@ -30,7 +30,7 @@ describe ReleasesFinder do
project.add_developer(user)
end
- it 'sorts by creation date' do
+ it 'sorts by release date' do
releases = subject.execute
expect(releases).to be_present
diff --git a/spec/finders/runner_jobs_finder_spec.rb b/spec/finders/runner_jobs_finder_spec.rb
index 97304170c4e..01f45a37ba8 100644
--- a/spec/finders/runner_jobs_finder_spec.rb
+++ b/spec/finders/runner_jobs_finder_spec.rb
@@ -35,5 +35,27 @@ describe RunnerJobsFinder do
end
end
end
+
+ context 'when order_by and sort are specified' do
+ context 'when order_by id and sort is asc' do
+ let(:params) { { order_by: 'id', sort: 'asc' } }
+ let!(:jobs) { create_list(:ci_build, 2, runner: runner, project: project, user: create(:user)) }
+
+ it 'sorts as id: :asc' do
+ is_expected.to eq(jobs.sort_by(&:id))
+ end
+ end
+ end
+
+ context 'when order_by is specified and sort is not specified' do
+ context 'when order_by id and sort is not specified' do
+ let(:params) { { order_by: 'id' } }
+ let!(:jobs) { create_list(:ci_build, 2, runner: runner, project: project, user: create(:user)) }
+
+ it 'sorts as id: :desc' do
+ is_expected.to eq(jobs.sort_by(&:id).reverse)
+ end
+ end
+ end
end
end
diff --git a/spec/fixtures/api/schemas/public_api/v4/release.json b/spec/fixtures/api/schemas/public_api/v4/release.json
index 6ea0781c1ed..ec3fa59cdb1 100644
--- a/spec/fixtures/api/schemas/public_api/v4/release.json
+++ b/spec/fixtures/api/schemas/public_api/v4/release.json
@@ -1,12 +1,14 @@
{
"type": "object",
- "required": ["name", "tag_name", "commit"],
+ "required": ["name", "tag_name", "commit", "released_at"],
"properties": {
"name": { "type": "string" },
"tag_name": { "type": "string" },
"description": { "type": "string" },
"description_html": { "type": "string" },
"created_at": { "type": "date" },
+ "released_at": { "type": "date" },
+ "upcoming_release": { "type": "boolean" },
"commit": {
"oneOf": [{ "type": "null" }, { "$ref": "commit/basic.json" }]
},
diff --git a/spec/fixtures/api/schemas/public_api/v4/release/release_for_guest.json b/spec/fixtures/api/schemas/public_api/v4/release/release_for_guest.json
index e78398ad1d5..0c1e8fd5fb3 100644
--- a/spec/fixtures/api/schemas/public_api/v4/release/release_for_guest.json
+++ b/spec/fixtures/api/schemas/public_api/v4/release/release_for_guest.json
@@ -1,11 +1,13 @@
{
"type": "object",
- "required": ["name"],
+ "required": ["name", "released_at"],
"properties": {
"name": { "type": "string" },
"description": { "type": "string" },
"description_html": { "type": "string" },
"created_at": { "type": "date" },
+ "released_at": { "type": "date" },
+ "upcoming_release": { "type": "boolean" },
"author": {
"oneOf": [{ "type": "null" }, { "$ref": "../user/basic.json" }]
},
diff --git a/spec/frontend/api_spec.js b/spec/frontend/api_spec.js
index 0188d12a57d..7004373be0e 100644
--- a/spec/frontend/api_spec.js
+++ b/spec/frontend/api_spec.js
@@ -412,6 +412,22 @@ describe('Api', () => {
});
});
+ describe('user counts', () => {
+ it('fetches single user counts', done => {
+ const expectedUrl = `${dummyUrlRoot}/api/${dummyApiVersion}/user_counts`;
+ mock.onGet(expectedUrl).reply(200, {
+ merge_requests: 4,
+ });
+
+ Api.userCounts()
+ .then(({ data }) => {
+ expect(data.merge_requests).toBe(4);
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+ });
+
describe('user status', () => {
it('fetches single user status', done => {
const userId = '123456';
diff --git a/spec/frontend/boards/services/board_service_spec.js b/spec/frontend/boards/services/board_service_spec.js
index de9fc998360..a8a322e7237 100644
--- a/spec/frontend/boards/services/board_service_spec.js
+++ b/spec/frontend/boards/services/board_service_spec.js
@@ -2,6 +2,7 @@ import BoardService from '~/boards/services/board_service';
import { TEST_HOST } from 'helpers/test_constants';
import AxiosMockAdapter from 'axios-mock-adapter';
import axios from '~/lib/utils/axios_utils';
+import boardsStore from '~/boards/stores/boards_store';
describe('BoardService', () => {
const dummyResponse = "without type checking this doesn't matter";
@@ -18,10 +19,11 @@ describe('BoardService', () => {
beforeEach(() => {
axiosMock = new AxiosMockAdapter(axios);
- service = new BoardService({
+ boardsStore.setEndpoints({
...endpoints,
boardId,
});
+ service = new BoardService();
});
describe('all', () => {
diff --git a/spec/frontend/branches/divergence_graph_spec.js b/spec/frontend/branches/divergence_graph_spec.js
new file mode 100644
index 00000000000..8283bc966e4
--- /dev/null
+++ b/spec/frontend/branches/divergence_graph_spec.js
@@ -0,0 +1,40 @@
+import MockAdapter from 'axios-mock-adapter';
+import axios from '~/lib/utils/axios_utils';
+import init from '~/branches/divergence_graph';
+
+describe('Divergence graph', () => {
+ let mock;
+
+ beforeEach(() => {
+ mock = new MockAdapter(axios);
+
+ mock.onGet('/-/diverging_counts').reply(200, {
+ master: { ahead: 1, behind: 1 },
+ 'test/hello-world': { ahead: 1, behind: 1 },
+ });
+
+ jest.spyOn(axios, 'get');
+
+ document.body.innerHTML = `
+ <div class="js-branch-item" data-name="master"><div class="js-branch-divergence-graph"></div></div>
+ <div class="js-branch-item" data-name="test/hello-world"><div class="js-branch-divergence-graph"></div></div>
+ `;
+ });
+
+ afterEach(() => {
+ mock.restore();
+ });
+
+ it('calls axos get with list of branch names', () =>
+ init('/-/diverging_counts').then(() => {
+ expect(axios.get).toHaveBeenCalledWith('/-/diverging_counts', {
+ params: { names: ['master', 'test/hello-world'] },
+ });
+ }));
+
+ it('creates Vue components', () =>
+ init('/-/diverging_counts').then(() => {
+ expect(document.querySelector('[data-name="master"]').innerHTML).not.toEqual('');
+ expect(document.querySelector('[data-name="test/hello-world"]').innerHTML).not.toEqual('');
+ }));
+});
diff --git a/spec/frontend/commons/nav/user_merge_requests_spec.js b/spec/frontend/commons/nav/user_merge_requests_spec.js
new file mode 100644
index 00000000000..4da6d53557a
--- /dev/null
+++ b/spec/frontend/commons/nav/user_merge_requests_spec.js
@@ -0,0 +1,113 @@
+import {
+ openUserCountsBroadcast,
+ closeUserCountsBroadcast,
+ refreshUserMergeRequestCounts,
+} from '~/commons/nav/user_merge_requests';
+import Api from '~/api';
+
+jest.mock('~/api');
+
+const TEST_COUNT = 1000;
+const MR_COUNT_CLASS = 'merge-requests-count';
+
+describe('User Merge Requests', () => {
+ let channelMock;
+ let newBroadcastChannelMock;
+
+ beforeEach(() => {
+ global.gon.current_user_id = 123;
+
+ channelMock = {
+ postMessage: jest.fn(),
+ close: jest.fn(),
+ };
+ newBroadcastChannelMock = jest.fn().mockImplementation(() => channelMock);
+
+ global.BroadcastChannel = newBroadcastChannelMock;
+ setFixtures(`<div class="${MR_COUNT_CLASS}">0</div>`);
+ });
+
+ const findMRCountText = () => document.body.querySelector(`.${MR_COUNT_CLASS}`).textContent;
+
+ describe('refreshUserMergeRequestCounts', () => {
+ beforeEach(() => {
+ Api.userCounts.mockReturnValue(
+ Promise.resolve({
+ data: { merge_requests: TEST_COUNT },
+ }),
+ );
+ });
+
+ describe('with open broadcast channel', () => {
+ beforeEach(() => {
+ openUserCountsBroadcast();
+
+ return refreshUserMergeRequestCounts();
+ });
+
+ it('updates the top count of merge requests', () => {
+ expect(findMRCountText()).toEqual(TEST_COUNT.toLocaleString());
+ });
+
+ it('calls the API', () => {
+ expect(Api.userCounts).toHaveBeenCalled();
+ });
+
+ it('posts count to BroadcastChannel', () => {
+ expect(channelMock.postMessage).toHaveBeenCalledWith(TEST_COUNT);
+ });
+ });
+
+ describe('without open broadcast channel', () => {
+ beforeEach(() => refreshUserMergeRequestCounts());
+
+ it('does not post anything', () => {
+ expect(channelMock.postMessage).not.toHaveBeenCalled();
+ });
+ });
+ });
+
+ describe('openUserCountsBroadcast', () => {
+ beforeEach(() => {
+ openUserCountsBroadcast();
+ });
+
+ it('creates BroadcastChannel that updates DOM on message received', () => {
+ expect(findMRCountText()).toEqual('0');
+
+ channelMock.onmessage({ data: TEST_COUNT });
+
+ expect(findMRCountText()).toEqual(TEST_COUNT.toLocaleString());
+ });
+
+ it('closes if called while already open', () => {
+ expect(channelMock.close).not.toHaveBeenCalled();
+
+ openUserCountsBroadcast();
+
+ expect(channelMock.close).toHaveBeenCalled();
+ });
+ });
+
+ describe('closeUserCountsBroadcast', () => {
+ describe('when not opened', () => {
+ it('does nothing', () => {
+ expect(channelMock.close).not.toHaveBeenCalled();
+ });
+ });
+
+ describe('when opened', () => {
+ beforeEach(() => {
+ openUserCountsBroadcast();
+ });
+
+ it('closes', () => {
+ expect(channelMock.close).not.toHaveBeenCalled();
+
+ closeUserCountsBroadcast();
+
+ expect(channelMock.close).toHaveBeenCalled();
+ });
+ });
+ });
+});
diff --git a/spec/frontend/confidential_merge_request/components/__snapshots__/project_form_group_spec.js.snap b/spec/frontend/confidential_merge_request/components/__snapshots__/project_form_group_spec.js.snap
new file mode 100644
index 00000000000..fd307ce5ab3
--- /dev/null
+++ b/spec/frontend/confidential_merge_request/components/__snapshots__/project_form_group_spec.js.snap
@@ -0,0 +1,67 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Confidential merge request project form group component renders empty state when response is empty 1`] = `
+<div
+ class="form-group"
+>
+ <label>
+ Project
+ </label>
+
+ <div>
+ <!---->
+
+ <p
+ class="text-muted mt-1 mb-0"
+ >
+
+ No forks available to you.
+ <br />
+
+ <span>
+ To protect this issue's confidentiality,
+ <a
+ class="help-link"
+ href="https://test.com"
+ >
+ fork the project
+ </a>
+ and set the forks visiblity to private.
+ </span>
+ </p>
+ </div>
+</div>
+`;
+
+exports[`Confidential merge request project form group component renders fork dropdown 1`] = `
+<div
+ class="form-group"
+>
+ <label>
+ Project
+ </label>
+
+ <div>
+ <!---->
+
+ <p
+ class="text-muted mt-1 mb-0"
+ >
+
+ No forks available to you.
+ <br />
+
+ <span>
+ To protect this issue's confidentiality,
+ <a
+ class="help-link"
+ href="https://test.com"
+ >
+ fork the project
+ </a>
+ and set the forks visiblity to private.
+ </span>
+ </p>
+ </div>
+</div>
+`;
diff --git a/spec/frontend/confidential_merge_request/components/dropdown_spec.js b/spec/frontend/confidential_merge_request/components/dropdown_spec.js
new file mode 100644
index 00000000000..69495f3c161
--- /dev/null
+++ b/spec/frontend/confidential_merge_request/components/dropdown_spec.js
@@ -0,0 +1,56 @@
+import { mount } from '@vue/test-utils';
+import { GlDropdownItem } from '@gitlab/ui';
+import Dropdown from '~/confidential_merge_request/components/dropdown.vue';
+
+let vm;
+
+function factory(projects = []) {
+ vm = mount(Dropdown, {
+ propsData: {
+ projects,
+ selectedProject: projects[0],
+ },
+ });
+}
+
+describe('Confidential merge request project dropdown component', () => {
+ afterEach(() => {
+ vm.destroy();
+ });
+
+ it('renders dropdown items', () => {
+ factory([
+ {
+ id: 1,
+ name: 'test',
+ },
+ {
+ id: 2,
+ name: 'test',
+ },
+ ]);
+
+ expect(vm.findAll(GlDropdownItem).length).toBe(2);
+ });
+
+ it('renders selected project icon', () => {
+ factory([
+ {
+ id: 1,
+ name: 'test',
+ },
+ {
+ id: 2,
+ name: 'test 2',
+ },
+ ]);
+
+ expect(vm.find('.js-active-project-check').classes()).not.toContain('icon');
+ expect(
+ vm
+ .findAll('.js-active-project-check')
+ .at(1)
+ .classes(),
+ ).toContain('icon');
+ });
+});
diff --git a/spec/frontend/confidential_merge_request/components/project_form_group_spec.js b/spec/frontend/confidential_merge_request/components/project_form_group_spec.js
new file mode 100644
index 00000000000..3001363f7b9
--- /dev/null
+++ b/spec/frontend/confidential_merge_request/components/project_form_group_spec.js
@@ -0,0 +1,77 @@
+import { shallowMount, createLocalVue } from '@vue/test-utils';
+import MockAdapter from 'axios-mock-adapter';
+import axios from '~/lib/utils/axios_utils';
+import ProjectFormGroup from '~/confidential_merge_request/components/project_form_group.vue';
+
+const localVue = createLocalVue();
+const mockData = [
+ {
+ id: 1,
+ name_with_namespace: 'root / gitlab-ce',
+ path_with_namespace: 'root/gitlab-ce',
+ namespace: {
+ full_path: 'root',
+ },
+ },
+ {
+ id: 2,
+ name_with_namespace: 'test / gitlab-ce',
+ path_with_namespace: 'test/gitlab-ce',
+ namespace: {
+ full_path: 'test',
+ },
+ },
+];
+let vm;
+let mock;
+
+function factory(projects = mockData) {
+ mock = new MockAdapter(axios);
+ mock.onGet(/api\/(.*)\/projects\/gitlab-org%2Fgitlab-ce\/forks/).reply(200, projects);
+
+ vm = shallowMount(ProjectFormGroup, {
+ localVue,
+ propsData: {
+ namespacePath: 'gitlab-org',
+ projectPath: 'gitlab-org/gitlab-ce',
+ newForkPath: 'https://test.com',
+ helpPagePath: '/help',
+ },
+ });
+}
+
+describe('Confidential merge request project form group component', () => {
+ afterEach(() => {
+ mock.restore();
+ vm.destroy();
+ });
+
+ it('renders fork dropdown', () => {
+ factory();
+
+ return localVue.nextTick(() => {
+ expect(vm.element).toMatchSnapshot();
+ });
+ });
+
+ it('sets selected project as first fork', () => {
+ factory();
+
+ return localVue.nextTick(() => {
+ expect(vm.vm.selectedProject).toEqual({
+ id: 1,
+ name: 'root / gitlab-ce',
+ pathWithNamespace: 'root/gitlab-ce',
+ namespaceFullpath: 'root',
+ });
+ });
+ });
+
+ it('renders empty state when response is empty', () => {
+ factory([]);
+
+ return localVue.nextTick(() => {
+ expect(vm.element).toMatchSnapshot();
+ });
+ });
+});
diff --git a/spec/frontend/create_merge_request_dropdown_spec.js b/spec/frontend/create_merge_request_dropdown_spec.js
new file mode 100644
index 00000000000..6e41fdabdce
--- /dev/null
+++ b/spec/frontend/create_merge_request_dropdown_spec.js
@@ -0,0 +1,69 @@
+import axios from '~/lib/utils/axios_utils';
+import MockAdapter from 'axios-mock-adapter';
+import CreateMergeRequestDropdown from '~/create_merge_request_dropdown';
+import { TEST_HOST } from './helpers/test_constants';
+
+describe('CreateMergeRequestDropdown', () => {
+ let axiosMock;
+ let dropdown;
+
+ beforeEach(() => {
+ axiosMock = new MockAdapter(axios);
+
+ document.body.innerHTML = `
+ <div id="dummy-wrapper-element">
+ <div class="available"></div>
+ <div class="unavailable">
+ <div class="fa"></div>
+ <div class="text"></div>
+ </div>
+ <div class="js-ref"></div>
+ <div class="js-create-mr"></div>
+ <div class="js-create-merge-request"></div>
+ <div class="js-create-target"></div>
+ <div class="js-dropdown-toggle"></div>
+ </div>
+ `;
+
+ const dummyElement = document.getElementById('dummy-wrapper-element');
+ dropdown = new CreateMergeRequestDropdown(dummyElement);
+ dropdown.refsPath = `${TEST_HOST}/dummy/refs?search=`;
+ });
+
+ afterEach(() => {
+ axiosMock.restore();
+ });
+
+ describe('getRef', () => {
+ it('escapes branch names correctly', done => {
+ const endpoint = `${dropdown.refsPath}contains%23hash`;
+ jest.spyOn(axios, 'get');
+ axiosMock.onGet(endpoint).replyOnce({});
+
+ dropdown
+ .getRef('contains#hash')
+ .then(() => {
+ expect(axios.get).toHaveBeenCalledWith(endpoint);
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+ });
+
+ describe('updateCreatePaths', () => {
+ it('escapes branch names correctly', () => {
+ dropdown.createBranchPath = `${TEST_HOST}/branches?branch_name=some-branch&issue=42`;
+ dropdown.createMrPath = `${TEST_HOST}/create_merge_request?branch_name=some-branch&ref=master`;
+
+ dropdown.updateCreatePaths('branch', 'contains#hash');
+
+ expect(dropdown.createBranchPath).toBe(
+ `${TEST_HOST}/branches?branch_name=contains%23hash&issue=42`,
+ );
+
+ expect(dropdown.createMrPath).toBe(
+ `${TEST_HOST}/create_merge_request?branch_name=contains%23hash&ref=master`,
+ );
+ });
+ });
+});
diff --git a/spec/frontend/diffs/components/diff_discussion_reply_spec.js b/spec/frontend/diffs/components/diff_discussion_reply_spec.js
new file mode 100644
index 00000000000..28689ab07de
--- /dev/null
+++ b/spec/frontend/diffs/components/diff_discussion_reply_spec.js
@@ -0,0 +1,90 @@
+import { shallowMount, createLocalVue } from '@vue/test-utils';
+import Vuex from 'vuex';
+import DiffDiscussionReply from '~/diffs/components/diff_discussion_reply.vue';
+import ReplyPlaceholder from '~/notes/components/discussion_reply_placeholder.vue';
+import NoteSignedOutWidget from '~/notes/components/note_signed_out_widget.vue';
+
+const localVue = createLocalVue();
+localVue.use(Vuex);
+
+describe('DiffDiscussionReply', () => {
+ let wrapper;
+ let getters;
+ let store;
+
+ const createComponent = (props = {}, slots = {}) => {
+ wrapper = shallowMount(DiffDiscussionReply, {
+ store,
+ localVue,
+ sync: false,
+ propsData: {
+ ...props,
+ },
+ slots: {
+ ...slots,
+ },
+ });
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ describe('if user can reply', () => {
+ beforeEach(() => {
+ getters = {
+ userCanReply: () => true,
+ getUserData: () => ({
+ path: 'test-path',
+ avatar_url: 'avatar_url',
+ name: 'John Doe',
+ }),
+ };
+
+ store = new Vuex.Store({
+ getters,
+ });
+ });
+
+ it('should render a form if component has form', () => {
+ createComponent(
+ {
+ renderReplyPlaceholder: false,
+ hasForm: true,
+ },
+ {
+ form: `<div id="test-form"></div>`,
+ },
+ );
+
+ expect(wrapper.find('#test-form').exists()).toBe(true);
+ });
+
+ it('should render a reply placeholder if there is no form', () => {
+ createComponent({
+ renderReplyPlaceholder: true,
+ hasForm: false,
+ });
+
+ expect(wrapper.find(ReplyPlaceholder).exists()).toBe(true);
+ });
+ });
+
+ it('renders a signed out widget when user is not logged in', () => {
+ getters = {
+ userCanReply: () => false,
+ getUserData: () => null,
+ };
+
+ store = new Vuex.Store({
+ getters,
+ });
+
+ createComponent({
+ renderReplyPlaceholder: false,
+ hasForm: false,
+ });
+
+ expect(wrapper.find(NoteSignedOutWidget).exists()).toBe(true);
+ });
+});
diff --git a/spec/frontend/diffs/components/diff_gutter_avatars_spec.js b/spec/frontend/diffs/components/diff_gutter_avatars_spec.js
new file mode 100644
index 00000000000..48ee5c63f35
--- /dev/null
+++ b/spec/frontend/diffs/components/diff_gutter_avatars_spec.js
@@ -0,0 +1,113 @@
+import { shallowMount, createLocalVue } from '@vue/test-utils';
+import DiffGutterAvatars from '~/diffs/components/diff_gutter_avatars.vue';
+import discussionsMockData from '../mock_data/diff_discussions';
+
+const localVue = createLocalVue();
+const getDiscussionsMockData = () => [Object.assign({}, discussionsMockData)];
+
+describe('DiffGutterAvatars', () => {
+ let wrapper;
+
+ const findCollapseButton = () => wrapper.find('.diff-notes-collapse');
+ const findMoreCount = () => wrapper.find('.diff-comments-more-count');
+ const findUserAvatars = () => wrapper.findAll('.diff-comment-avatar');
+
+ const createComponent = (props = {}) => {
+ wrapper = shallowMount(DiffGutterAvatars, {
+ localVue,
+ sync: false,
+ propsData: {
+ ...props,
+ },
+ });
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ describe('when expanded', () => {
+ beforeEach(() => {
+ createComponent({
+ discussions: getDiscussionsMockData(),
+ discussionsExpanded: true,
+ });
+ });
+
+ it('renders a collapse button when discussions are expanded', () => {
+ expect(findCollapseButton().exists()).toBe(true);
+ });
+
+ it('should emit toggleDiscussions event on button click', () => {
+ findCollapseButton().trigger('click');
+
+ expect(wrapper.emitted().toggleLineDiscussions).toBeTruthy();
+ });
+ });
+
+ describe('when collapsed', () => {
+ beforeEach(() => {
+ createComponent({
+ discussions: getDiscussionsMockData(),
+ discussionsExpanded: false,
+ });
+ });
+
+ it('renders user avatars and moreCount text', () => {
+ expect(findUserAvatars().exists()).toBe(true);
+ expect(findMoreCount().exists()).toBe(true);
+ });
+
+ it('renders correct amount of user avatars', () => {
+ expect(findUserAvatars().length).toBe(3);
+ });
+
+ it('renders correct moreCount number', () => {
+ expect(findMoreCount().text()).toBe('+2');
+ });
+
+ it('should emit toggleDiscussions event on avatars click', () => {
+ findUserAvatars()
+ .at(0)
+ .trigger('click');
+
+ expect(wrapper.emitted().toggleLineDiscussions).toBeTruthy();
+ });
+
+ it('should emit toggleDiscussions event on more count text click', () => {
+ findMoreCount().trigger('click');
+
+ expect(wrapper.emitted().toggleLineDiscussions).toBeTruthy();
+ });
+ });
+
+ it('renders an empty more count string if there are no discussions', () => {
+ createComponent({
+ discussions: [],
+ discussionsExpanded: false,
+ });
+
+ expect(findMoreCount().exists()).toBe(false);
+ });
+
+ describe('tooltip text', () => {
+ beforeEach(() => {
+ createComponent({
+ discussions: getDiscussionsMockData(),
+ discussionsExpanded: false,
+ });
+ });
+
+ it('returns original comment if it is shorter than max length', () => {
+ const note = wrapper.vm.discussions[0].notes[0];
+
+ expect(wrapper.vm.getTooltipText(note)).toEqual('Administrator: comment 1');
+ });
+
+ it('returns truncated version of comment if it is longer than max length', () => {
+ const note = wrapper.vm.discussions[0].notes[1];
+
+ expect(wrapper.vm.getTooltipText(note)).toEqual('Fatih Acet: comment 2 is r...');
+ });
+ });
+});
diff --git a/spec/frontend/diffs/mock_data/diff_discussions.js b/spec/frontend/diffs/mock_data/diff_discussions.js
new file mode 100644
index 00000000000..711ab543411
--- /dev/null
+++ b/spec/frontend/diffs/mock_data/diff_discussions.js
@@ -0,0 +1,529 @@
+export default {
+ id: '6b232e05bea388c6b043ccc243ba505faac04ea8',
+ reply_id: '6b232e05bea388c6b043ccc243ba505faac04ea8',
+ position: {
+ old_line: null,
+ new_line: 2,
+ old_path: 'CHANGELOG',
+ new_path: 'CHANGELOG',
+ base_sha: 'e63f41fe459e62e1228fcef60d7189127aeba95a',
+ start_sha: 'd9eaefe5a676b820c57ff18cf5b68316025f7962',
+ head_sha: 'c48ee0d1bf3b30453f5b32250ce03134beaa6d13',
+ },
+ line_code: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_1_2',
+ expanded: true,
+ notes: [
+ {
+ id: '1749',
+ type: 'DiffNote',
+ attachment: null,
+ author: {
+ id: 1,
+ name: 'Administrator',
+ username: 'root',
+ state: 'active',
+ avatar_url:
+ 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
+ path: '/root',
+ },
+ created_at: '2018-04-03T21:06:21.521Z',
+ updated_at: '2018-04-08T08:50:41.762Z',
+ system: false,
+ noteable_id: 51,
+ noteable_type: 'MergeRequest',
+ noteable_iid: 20,
+ human_access: 'Owner',
+ note: 'comment 1',
+ note_html: '<p dir="auto">comment 1</p>',
+ last_edited_at: '2018-04-08T08:50:41.762Z',
+ last_edited_by: {
+ id: 1,
+ name: 'Administrator',
+ username: 'root',
+ state: 'active',
+ avatar_url:
+ 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
+ path: '/root',
+ },
+ current_user: {
+ can_edit: true,
+ can_award_emoji: true,
+ },
+ resolved: false,
+ resolvable: true,
+ resolved_by: null,
+ discussion_id: '6b232e05bea388c6b043ccc243ba505faac04ea8',
+ emoji_awardable: true,
+ award_emoji: [],
+ toggle_award_path: '/gitlab-org/gitlab-test/notes/1749/toggle_award_emoji',
+ report_abuse_path:
+ '/abuse_reports/new?ref_url=http%3A%2F%2Flocalhost%3A3000%2Fgitlab-org%2Fgitlab-test%2Fmerge_requests%2F20%23note_1749&user_id=1',
+ path: '/gitlab-org/gitlab-test/notes/1749',
+ noteable_note_url: 'http://localhost:3000/gitlab-org/gitlab-test/merge_requests/20#note_1749',
+ resolve_path:
+ '/gitlab-org/gitlab-test/merge_requests/20/discussions/6b232e05bea388c6b043ccc243ba505faac04ea8/resolve',
+ resolve_with_issue_path:
+ '/gitlab-org/gitlab-test/issues/new?discussion_to_resolve=6b232e05bea388c6b043ccc243ba505faac04ea8&merge_request_to_resolve_discussions_of=20',
+ },
+ {
+ id: '1753',
+ type: 'DiffNote',
+ attachment: null,
+ author: {
+ id: 1,
+ name: 'Fatih Acet',
+ username: 'fatihacet',
+ state: 'active',
+ avatar_url:
+ 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
+ path: '/fatihacevt',
+ },
+ created_at: '2018-04-08T08:49:35.804Z',
+ updated_at: '2018-04-08T08:50:45.915Z',
+ system: false,
+ noteable_id: 51,
+ noteable_type: 'MergeRequest',
+ noteable_iid: 20,
+ human_access: 'Owner',
+ note: 'comment 2 is really long one',
+ note_html: '<p dir="auto">comment 2 is really long one</p>',
+ last_edited_at: '2018-04-08T08:50:45.915Z',
+ last_edited_by: {
+ id: 1,
+ name: 'Administrator',
+ username: 'root',
+ state: 'active',
+ avatar_url:
+ 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
+ path: '/root',
+ },
+ current_user: {
+ can_edit: true,
+ can_award_emoji: true,
+ },
+ resolved: false,
+ resolvable: true,
+ resolved_by: null,
+ discussion_id: '6b232e05bea388c6b043ccc243ba505faac04ea8',
+ emoji_awardable: true,
+ award_emoji: [],
+ toggle_award_path: '/gitlab-org/gitlab-test/notes/1753/toggle_award_emoji',
+ report_abuse_path:
+ '/abuse_reports/new?ref_url=http%3A%2F%2Flocalhost%3A3000%2Fgitlab-org%2Fgitlab-test%2Fmerge_requests%2F20%23note_1753&user_id=1',
+ path: '/gitlab-org/gitlab-test/notes/1753',
+ noteable_note_url: 'http://localhost:3000/gitlab-org/gitlab-test/merge_requests/20#note_1753',
+ resolve_path:
+ '/gitlab-org/gitlab-test/merge_requests/20/discussions/6b232e05bea388c6b043ccc243ba505faac04ea8/resolve',
+ resolve_with_issue_path:
+ '/gitlab-org/gitlab-test/issues/new?discussion_to_resolve=6b232e05bea388c6b043ccc243ba505faac04ea8&merge_request_to_resolve_discussions_of=20',
+ },
+ {
+ id: '1754',
+ type: 'DiffNote',
+ attachment: null,
+ author: {
+ id: 1,
+ name: 'Administrator',
+ username: 'root',
+ state: 'active',
+ avatar_url:
+ 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
+ path: '/root',
+ },
+ created_at: '2018-04-08T08:50:48.294Z',
+ updated_at: '2018-04-08T08:50:48.294Z',
+ system: false,
+ noteable_id: 51,
+ noteable_type: 'MergeRequest',
+ noteable_iid: 20,
+ human_access: 'Owner',
+ note: 'comment 3',
+ note_html: '<p dir="auto">comment 3</p>',
+ current_user: {
+ can_edit: true,
+ can_award_emoji: true,
+ },
+ resolved: false,
+ resolvable: true,
+ resolved_by: null,
+ discussion_id: '6b232e05bea388c6b043ccc243ba505faac04ea8',
+ emoji_awardable: true,
+ award_emoji: [],
+ toggle_award_path: '/gitlab-org/gitlab-test/notes/1754/toggle_award_emoji',
+ report_abuse_path:
+ '/abuse_reports/new?ref_url=http%3A%2F%2Flocalhost%3A3000%2Fgitlab-org%2Fgitlab-test%2Fmerge_requests%2F20%23note_1754&user_id=1',
+ path: '/gitlab-org/gitlab-test/notes/1754',
+ noteable_note_url: 'http://localhost:3000/gitlab-org/gitlab-test/merge_requests/20#note_1754',
+ resolve_path:
+ '/gitlab-org/gitlab-test/merge_requests/20/discussions/6b232e05bea388c6b043ccc243ba505faac04ea8/resolve',
+ resolve_with_issue_path:
+ '/gitlab-org/gitlab-test/issues/new?discussion_to_resolve=6b232e05bea388c6b043ccc243ba505faac04ea8&merge_request_to_resolve_discussions_of=20',
+ },
+ {
+ id: '1755',
+ type: 'DiffNote',
+ attachment: null,
+ author: {
+ id: 1,
+ name: 'Administrator',
+ username: 'root',
+ state: 'active',
+ avatar_url:
+ 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
+ path: '/root',
+ },
+ created_at: '2018-04-08T08:50:50.911Z',
+ updated_at: '2018-04-08T08:50:50.911Z',
+ system: false,
+ noteable_id: 51,
+ noteable_type: 'MergeRequest',
+ noteable_iid: 20,
+ human_access: 'Owner',
+ note: 'comment 4',
+ note_html: '<p dir="auto">comment 4</p>',
+ current_user: {
+ can_edit: true,
+ can_award_emoji: true,
+ },
+ resolved: false,
+ resolvable: true,
+ resolved_by: null,
+ discussion_id: '6b232e05bea388c6b043ccc243ba505faac04ea8',
+ emoji_awardable: true,
+ award_emoji: [],
+ toggle_award_path: '/gitlab-org/gitlab-test/notes/1755/toggle_award_emoji',
+ report_abuse_path:
+ '/abuse_reports/new?ref_url=http%3A%2F%2Flocalhost%3A3000%2Fgitlab-org%2Fgitlab-test%2Fmerge_requests%2F20%23note_1755&user_id=1',
+ path: '/gitlab-org/gitlab-test/notes/1755',
+ noteable_note_url: 'http://localhost:3000/gitlab-org/gitlab-test/merge_requests/20#note_1755',
+ resolve_path:
+ '/gitlab-org/gitlab-test/merge_requests/20/discussions/6b232e05bea388c6b043ccc243ba505faac04ea8/resolve',
+ resolve_with_issue_path:
+ '/gitlab-org/gitlab-test/issues/new?discussion_to_resolve=6b232e05bea388c6b043ccc243ba505faac04ea8&merge_request_to_resolve_discussions_of=20',
+ },
+ {
+ id: '1756',
+ type: 'DiffNote',
+ attachment: null,
+ author: {
+ id: 1,
+ name: 'Administrator',
+ username: 'root',
+ state: 'active',
+ avatar_url:
+ 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
+ path: '/root',
+ },
+ created_at: '2018-04-08T08:50:53.895Z',
+ updated_at: '2018-04-08T08:50:53.895Z',
+ system: false,
+ noteable_id: 51,
+ noteable_type: 'MergeRequest',
+ noteable_iid: 20,
+ human_access: 'Owner',
+ note: 'comment 5',
+ note_html: '<p dir="auto">comment 5</p>',
+ current_user: {
+ can_edit: true,
+ can_award_emoji: true,
+ },
+ resolved: false,
+ resolvable: true,
+ resolved_by: null,
+ discussion_id: '6b232e05bea388c6b043ccc243ba505faac04ea8',
+ emoji_awardable: true,
+ award_emoji: [],
+ toggle_award_path: '/gitlab-org/gitlab-test/notes/1756/toggle_award_emoji',
+ report_abuse_path:
+ '/abuse_reports/new?ref_url=http%3A%2F%2Flocalhost%3A3000%2Fgitlab-org%2Fgitlab-test%2Fmerge_requests%2F20%23note_1756&user_id=1',
+ path: '/gitlab-org/gitlab-test/notes/1756',
+ noteable_note_url: 'http://localhost:3000/gitlab-org/gitlab-test/merge_requests/20#note_1756',
+ resolve_path:
+ '/gitlab-org/gitlab-test/merge_requests/20/discussions/6b232e05bea388c6b043ccc243ba505faac04ea8/resolve',
+ resolve_with_issue_path:
+ '/gitlab-org/gitlab-test/issues/new?discussion_to_resolve=6b232e05bea388c6b043ccc243ba505faac04ea8&merge_request_to_resolve_discussions_of=20',
+ },
+ ],
+ individual_note: false,
+ resolvable: true,
+ resolved: false,
+ resolve_path:
+ '/gitlab-org/gitlab-test/merge_requests/20/discussions/6b232e05bea388c6b043ccc243ba505faac04ea8/resolve',
+ resolve_with_issue_path:
+ '/gitlab-org/gitlab-test/issues/new?discussion_to_resolve=6b232e05bea388c6b043ccc243ba505faac04ea8&merge_request_to_resolve_discussions_of=20',
+ diff_file: {
+ submodule: false,
+ submodule_link: null,
+ blob: {
+ id: '9e10516ca50788acf18c518a231914a21e5f16f7',
+ path: 'CHANGELOG',
+ name: 'CHANGELOG',
+ mode: '100644',
+ readable_text: true,
+ icon: 'file-text-o',
+ },
+ blob_path: 'CHANGELOG',
+ blob_name: 'CHANGELOG',
+ blob_icon: '<i aria-hidden="true" data-hidden="true" class="fa fa-file-text-o fa-fw"></i>',
+ file_hash: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a',
+ file_path: 'CHANGELOG.rb',
+ new_file: false,
+ deleted_file: false,
+ renamed_file: false,
+ old_path: 'CHANGELOG',
+ new_path: 'CHANGELOG',
+ mode_changed: false,
+ a_mode: '100644',
+ b_mode: '100644',
+ text: true,
+ added_lines: 2,
+ removed_lines: 0,
+ diff_refs: {
+ base_sha: 'e63f41fe459e62e1228fcef60d7189127aeba95a',
+ start_sha: 'd9eaefe5a676b820c57ff18cf5b68316025f7962',
+ head_sha: 'c48ee0d1bf3b30453f5b32250ce03134beaa6d13',
+ },
+ content_sha: 'c48ee0d1bf3b30453f5b32250ce03134beaa6d13',
+ stored_externally: null,
+ external_storage: null,
+ old_path_html: 'CHANGELOG_OLD',
+ new_path_html: 'CHANGELOG',
+ is_fully_expanded: true,
+ context_lines_path:
+ '/gitlab-org/gitlab-test/blob/c48ee0d1bf3b30453f5b32250ce03134beaa6d13/CHANGELOG/diff',
+ highlighted_diff_lines: [
+ {
+ line_code: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_1_1',
+ type: 'new',
+ old_line: null,
+ new_line: 1,
+ text: '<span id="LC1" class="line" lang="plaintext"> - Bad dates</span>\n',
+ rich_text: '<span id="LC1" class="line" lang="plaintext"> - Bad dates</span>\n',
+ meta_data: null,
+ },
+ {
+ line_code: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_1_2',
+ type: 'new',
+ old_line: null,
+ new_line: 2,
+ text: '<span id="LC2" class="line" lang="plaintext"></span>\n',
+ rich_text: '<span id="LC2" class="line" lang="plaintext"></span>\n',
+ meta_data: null,
+ },
+ {
+ line_code: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_1_3',
+ type: null,
+ old_line: 1,
+ new_line: 3,
+ text: '<span id="LC3" class="line" lang="plaintext">v6.8.0</span>\n',
+ rich_text: '<span id="LC3" class="line" lang="plaintext">v6.8.0</span>\n',
+ meta_data: null,
+ },
+ {
+ line_code: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_2_4',
+ type: null,
+ old_line: 2,
+ new_line: 4,
+ text: '<span id="LC4" class="line" lang="plaintext"></span>\n',
+ rich_text: '<span id="LC4" class="line" lang="plaintext"></span>\n',
+ meta_data: null,
+ },
+ {
+ line_code: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_3_5',
+ type: null,
+ old_line: 3,
+ new_line: 5,
+ text: ' <span id="LC5" class="line" lang="plaintext">v6.7.0</span>\n',
+ rich_text: ' <span id="LC5" class="line" lang="plaintext">v6.7.0</span>\n',
+ meta_data: null,
+ },
+ {
+ line_code: null,
+ type: 'match',
+ old_line: null,
+ new_line: null,
+ text: '',
+ rich_text: '',
+ meta_data: {
+ old_pos: 3,
+ new_pos: 5,
+ },
+ },
+ {
+ line_code: null,
+ type: 'match',
+ old_line: null,
+ new_line: null,
+ text: '',
+ rich_text: '',
+ meta_data: {
+ old_pos: 3,
+ new_pos: 5,
+ },
+ },
+ {
+ line_code: null,
+ type: 'match',
+ old_line: null,
+ new_line: null,
+ text: '',
+ rich_text: '',
+ meta_data: {
+ old_pos: 3,
+ new_pos: 5,
+ },
+ },
+ ],
+ parallel_diff_lines: [
+ {
+ left: null,
+ right: {
+ line_code: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_1_1',
+ type: 'new',
+ old_line: null,
+ new_line: 1,
+ text: '<span id="LC1" class="line" lang="plaintext"> - Bad dates</span>\n',
+ rich_text: '<span id="LC1" class="line" lang="plaintext"> - Bad dates</span>\n',
+ meta_data: null,
+ },
+ },
+ {
+ left: null,
+ right: {
+ line_code: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_1_2',
+ type: 'new',
+ old_line: null,
+ new_line: 2,
+ text: '<span id="LC2" class="line" lang="plaintext"></span>\n',
+ rich_text: '<span id="LC2" class="line" lang="plaintext"></span>\n',
+ meta_data: null,
+ },
+ },
+ {
+ left: {
+ line_code: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_1_3',
+ type: null,
+ old_line: 1,
+ new_line: 3,
+ text: '<span id="LC3" class="line" lang="plaintext">v6.8.0</span>\n',
+ rich_text: '<span id="LC3" class="line" lang="plaintext">v6.8.0</span>\n',
+ meta_data: null,
+ },
+ right: {
+ line_code: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_1_3',
+ type: null,
+ old_line: 1,
+ new_line: 3,
+ text: '<span id="LC3" class="line" lang="plaintext">v6.8.0</span>\n',
+ rich_text: '<span id="LC3" class="line" lang="plaintext">v6.8.0</span>\n',
+ meta_data: null,
+ },
+ },
+ {
+ left: {
+ line_code: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_2_4',
+ type: null,
+ old_line: 2,
+ new_line: 4,
+ text: '<span id="LC4" class="line" lang="plaintext"></span>\n',
+ rich_text: '<span id="LC4" class="line" lang="plaintext"></span>\n',
+ meta_data: null,
+ },
+ right: {
+ line_code: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_2_4',
+ type: null,
+ old_line: 2,
+ new_line: 4,
+ text: '<span id="LC4" class="line" lang="plaintext"></span>\n',
+ rich_text: '<span id="LC4" class="line" lang="plaintext"></span>\n',
+ meta_data: null,
+ },
+ },
+ {
+ left: {
+ line_code: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_3_5',
+ type: null,
+ old_line: 3,
+ new_line: 5,
+ text: ' <span id="LC5" class="line" lang="plaintext">v6.7.0</span>\n',
+ rich_text: ' <span id="LC5" class="line" lang="plaintext">v6.7.0</span>\n',
+ meta_data: null,
+ },
+ right: {
+ line_code: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_3_5',
+ type: null,
+ old_line: 3,
+ new_line: 5,
+ text: ' <span id="LC5" class="line" lang="plaintext">v6.7.0</span>\n',
+ rich_text: ' <span id="LC5" class="line" lang="plaintext">v6.7.0</span>\n',
+ meta_data: null,
+ },
+ },
+ {
+ left: {
+ line_code: null,
+ type: 'match',
+ old_line: null,
+ new_line: null,
+ text: '',
+ rich_text: '',
+ meta_data: {
+ old_pos: 3,
+ new_pos: 5,
+ },
+ },
+ right: {
+ line_code: null,
+ type: 'match',
+ old_line: null,
+ new_line: null,
+ text: '',
+ rich_text: '',
+ meta_data: {
+ old_pos: 3,
+ new_pos: 5,
+ },
+ },
+ },
+ ],
+ viewer: {
+ name: 'text',
+ error: null,
+ },
+ },
+ diff_discussion: true,
+ truncated_diff_lines: [
+ {
+ text: 'line',
+ rich_text:
+ '<tr class="line_holder new" id="">\n<td class="diff-line-num new old_line" data-linenumber="1">\n \n</td>\n<td class="diff-line-num new new_line" data-linenumber="1">\n1\n</td>\n<td class="line_content new"><span id="LC1" class="line" lang="plaintext"> - Bad dates</span>\n</td>\n</tr>\n<tr class="line_holder new" id="">\n<td class="diff-line-num new old_line" data-linenumber="1">\n \n</td>\n<td class="diff-line-num new new_line" data-linenumber="2">\n2\n</td>\n<td class="line_content new"><span id="LC2" class="line" lang="plaintext"></span>\n</td>\n</tr>\n',
+ can_receive_suggestion: true,
+ line_code: '6f209374f7e565f771b95720abf46024c41d1885_1_1',
+ type: 'new',
+ old_line: null,
+ new_line: 1,
+ meta_data: null,
+ },
+ ],
+};
+
+export const imageDiffDiscussions = [
+ {
+ id: '1',
+ position: {
+ x: 10,
+ y: 10,
+ width: 100,
+ height: 200,
+ },
+ },
+ {
+ id: '2',
+ position: {
+ x: 5,
+ y: 5,
+ width: 100,
+ height: 200,
+ },
+ },
+];
diff --git a/spec/frontend/error_tracking_settings/components/app_spec.js b/spec/frontend/error_tracking_settings/components/app_spec.js
new file mode 100644
index 00000000000..022f12ef191
--- /dev/null
+++ b/spec/frontend/error_tracking_settings/components/app_spec.js
@@ -0,0 +1,63 @@
+import Vuex from 'vuex';
+import { createLocalVue, shallowMount } from '@vue/test-utils';
+import ErrorTrackingSettings from '~/error_tracking_settings/components/app.vue';
+import ErrorTrackingForm from '~/error_tracking_settings/components/error_tracking_form.vue';
+import ProjectDropdown from '~/error_tracking_settings/components/project_dropdown.vue';
+import createStore from '~/error_tracking_settings/store';
+import { TEST_HOST } from 'helpers/test_constants';
+
+const localVue = createLocalVue();
+localVue.use(Vuex);
+
+describe('error tracking settings app', () => {
+ let store;
+ let wrapper;
+
+ function mountComponent() {
+ wrapper = shallowMount(ErrorTrackingSettings, {
+ localVue,
+ store, // Override the imported store
+ propsData: {
+ initialEnabled: 'true',
+ initialApiHost: TEST_HOST,
+ initialToken: 'someToken',
+ initialProject: null,
+ listProjectsEndpoint: TEST_HOST,
+ operationsSettingsEndpoint: TEST_HOST,
+ },
+ });
+ }
+
+ beforeEach(() => {
+ store = createStore();
+
+ mountComponent();
+ });
+
+ afterEach(() => {
+ if (wrapper) {
+ wrapper.destroy();
+ }
+ });
+
+ describe('section', () => {
+ it('renders the form and dropdown', () => {
+ expect(wrapper.find(ErrorTrackingForm).exists()).toBeTruthy();
+ expect(wrapper.find(ProjectDropdown).exists()).toBeTruthy();
+ });
+
+ it('renders the Save Changes button', () => {
+ expect(wrapper.find('.js-error-tracking-button').exists()).toBeTruthy();
+ });
+
+ it('enables the button by default', () => {
+ expect(wrapper.find('.js-error-tracking-button').attributes('disabled')).toBeFalsy();
+ });
+
+ it('disables the button when saving', () => {
+ store.state.settingsLoading = true;
+
+ expect(wrapper.find('.js-error-tracking-button').attributes('disabled')).toBeTruthy();
+ });
+ });
+});
diff --git a/spec/javascripts/error_tracking_settings/components/error_tracking_form_spec.js b/spec/frontend/error_tracking_settings/components/error_tracking_form_spec.js
index 23e57c4bbf1..23e57c4bbf1 100644
--- a/spec/javascripts/error_tracking_settings/components/error_tracking_form_spec.js
+++ b/spec/frontend/error_tracking_settings/components/error_tracking_form_spec.js
diff --git a/spec/javascripts/error_tracking_settings/components/project_dropdown_spec.js b/spec/frontend/error_tracking_settings/components/project_dropdown_spec.js
index 8e5dbe28452..8e5dbe28452 100644
--- a/spec/javascripts/error_tracking_settings/components/project_dropdown_spec.js
+++ b/spec/frontend/error_tracking_settings/components/project_dropdown_spec.js
diff --git a/spec/frontend/error_tracking_settings/mock.js b/spec/frontend/error_tracking_settings/mock.js
new file mode 100644
index 00000000000..42233f82d54
--- /dev/null
+++ b/spec/frontend/error_tracking_settings/mock.js
@@ -0,0 +1,92 @@
+import createStore from '~/error_tracking_settings/store';
+import { TEST_HOST } from '../helpers/test_constants';
+
+const defaultStore = createStore();
+
+export const projectList = [
+ {
+ name: 'name',
+ slug: 'slug',
+ organizationName: 'organizationName',
+ organizationSlug: 'organizationSlug',
+ },
+ {
+ name: 'name2',
+ slug: 'slug2',
+ organizationName: 'organizationName2',
+ organizationSlug: 'organizationSlug2',
+ },
+];
+
+export const staleProject = {
+ name: 'staleName',
+ slug: 'staleSlug',
+ organizationName: 'staleOrganizationName',
+ organizationSlug: 'staleOrganizationSlug',
+};
+
+export const normalizedProject = {
+ name: 'name',
+ slug: 'slug',
+ organizationName: 'organization_name',
+ organizationSlug: 'organization_slug',
+};
+
+export const sampleBackendProject = {
+ name: normalizedProject.name,
+ slug: normalizedProject.slug,
+ organization_name: normalizedProject.organizationName,
+ organization_slug: normalizedProject.organizationSlug,
+};
+
+export const sampleFrontendSettings = {
+ apiHost: 'apiHost',
+ enabled: false,
+ token: 'token',
+ selectedProject: {
+ slug: normalizedProject.slug,
+ name: normalizedProject.name,
+ organizationName: normalizedProject.organizationName,
+ organizationSlug: normalizedProject.organizationSlug,
+ },
+};
+
+export const transformedSettings = {
+ api_host: 'apiHost',
+ enabled: false,
+ token: 'token',
+ project: {
+ slug: normalizedProject.slug,
+ name: normalizedProject.name,
+ organization_name: normalizedProject.organizationName,
+ organization_slug: normalizedProject.organizationSlug,
+ },
+};
+
+export const defaultProps = {
+ ...defaultStore.state,
+ ...defaultStore.getters,
+};
+
+export const initialEmptyState = {
+ apiHost: '',
+ enabled: false,
+ project: null,
+ token: '',
+ listProjectsEndpoint: TEST_HOST,
+ operationsSettingsEndpoint: TEST_HOST,
+};
+
+export const initialPopulatedState = {
+ apiHost: 'apiHost',
+ enabled: true,
+ project: JSON.stringify(projectList[0]),
+ token: 'token',
+ listProjectsEndpoint: TEST_HOST,
+ operationsSettingsEndpoint: TEST_HOST,
+};
+
+export const projectWithHtmlTemplate = {
+ ...projectList[0],
+ name: '<strong>bold</strong>',
+};
diff --git a/spec/frontend/error_tracking_settings/store/actions_spec.js b/spec/frontend/error_tracking_settings/store/actions_spec.js
new file mode 100644
index 00000000000..1eab0f7470b
--- /dev/null
+++ b/spec/frontend/error_tracking_settings/store/actions_spec.js
@@ -0,0 +1,194 @@
+import MockAdapter from 'axios-mock-adapter';
+import testAction from 'helpers/vuex_action_helper';
+import { TEST_HOST } from 'helpers/test_constants';
+import axios from '~/lib/utils/axios_utils';
+import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
+import { refreshCurrentPage } from '~/lib/utils/url_utility';
+import * as actions from '~/error_tracking_settings/store/actions';
+import * as types from '~/error_tracking_settings/store/mutation_types';
+import defaultState from '~/error_tracking_settings/store/state';
+import { projectList } from '../mock';
+
+jest.mock('~/lib/utils/url_utility');
+
+describe('error tracking settings actions', () => {
+ let state;
+
+ describe('project list actions', () => {
+ let mock;
+
+ beforeEach(() => {
+ mock = new MockAdapter(axios);
+ state = { ...defaultState(), listProjectsEndpoint: TEST_HOST };
+ });
+
+ afterEach(() => {
+ mock.restore();
+ refreshCurrentPage.mockClear();
+ });
+
+ it('should request and transform the project list', done => {
+ mock.onPost(TEST_HOST).reply(() => [200, { projects: projectList }]);
+ testAction(
+ actions.fetchProjects,
+ null,
+ state,
+ [],
+ [
+ { type: 'requestProjects' },
+ {
+ type: 'receiveProjectsSuccess',
+ payload: projectList.map(convertObjectPropsToCamelCase),
+ },
+ ],
+ () => {
+ expect(mock.history.post.length).toBe(1);
+ done();
+ },
+ );
+ });
+
+ it('should handle a server error', done => {
+ mock.onPost(`${TEST_HOST}.json`).reply(() => [400]);
+ testAction(
+ actions.fetchProjects,
+ null,
+ state,
+ [],
+ [
+ { type: 'requestProjects' },
+ {
+ type: 'receiveProjectsError',
+ },
+ ],
+ () => {
+ expect(mock.history.post.length).toBe(1);
+ done();
+ },
+ );
+ });
+
+ it('should request projects correctly', done => {
+ testAction(actions.requestProjects, null, state, [{ type: types.RESET_CONNECT }], [], done);
+ });
+
+ it('should receive projects correctly', done => {
+ const testPayload = [];
+ testAction(
+ actions.receiveProjectsSuccess,
+ testPayload,
+ state,
+ [
+ { type: types.UPDATE_CONNECT_SUCCESS },
+ { type: types.RECEIVE_PROJECTS, payload: testPayload },
+ ],
+ [],
+ done,
+ );
+ });
+
+ it('should handle errors when receiving projects', done => {
+ const testPayload = [];
+ testAction(
+ actions.receiveProjectsError,
+ testPayload,
+ state,
+ [{ type: types.UPDATE_CONNECT_ERROR }, { type: types.CLEAR_PROJECTS }],
+ [],
+ done,
+ );
+ });
+ });
+
+ describe('save changes actions', () => {
+ let mock;
+
+ beforeEach(() => {
+ mock = new MockAdapter(axios);
+ state = {
+ operationsSettingsEndpoint: TEST_HOST,
+ };
+ });
+
+ afterEach(() => {
+ mock.restore();
+ });
+
+ it('should save the page', done => {
+ mock.onPatch(TEST_HOST).reply(200);
+ testAction(actions.updateSettings, null, state, [], [{ type: 'requestSettings' }], () => {
+ expect(mock.history.patch.length).toBe(1);
+ expect(refreshCurrentPage).toHaveBeenCalled();
+ done();
+ });
+ });
+
+ it('should handle a server error', done => {
+ mock.onPatch(TEST_HOST).reply(400);
+ testAction(
+ actions.updateSettings,
+ null,
+ state,
+ [],
+ [
+ { type: 'requestSettings' },
+ {
+ type: 'receiveSettingsError',
+ payload: new Error('Request failed with status code 400'),
+ },
+ ],
+ () => {
+ expect(mock.history.patch.length).toBe(1);
+ done();
+ },
+ );
+ });
+
+ it('should request to save the page', done => {
+ testAction(
+ actions.requestSettings,
+ null,
+ state,
+ [{ type: types.UPDATE_SETTINGS_LOADING, payload: true }],
+ [],
+ done,
+ );
+ });
+
+ it('should handle errors when requesting to save the page', done => {
+ testAction(
+ actions.receiveSettingsError,
+ {},
+ state,
+ [{ type: types.UPDATE_SETTINGS_LOADING, payload: false }],
+ [],
+ done,
+ );
+ });
+ });
+
+ describe('generic actions to update the store', () => {
+ const testData = 'test';
+ it('should reset the `connect success` flag when updating the api host', done => {
+ testAction(
+ actions.updateApiHost,
+ testData,
+ state,
+ [{ type: types.UPDATE_API_HOST, payload: testData }, { type: types.RESET_CONNECT }],
+ [],
+ done,
+ );
+ });
+
+ it('should reset the `connect success` flag when updating the token', done => {
+ testAction(
+ actions.updateToken,
+ testData,
+ state,
+ [{ type: types.UPDATE_TOKEN, payload: testData }, { type: types.RESET_CONNECT }],
+ [],
+ done,
+ );
+ });
+ });
+});
diff --git a/spec/javascripts/error_tracking_settings/store/getters_spec.js b/spec/frontend/error_tracking_settings/store/getters_spec.js
index 2c5ff084b8a..2c5ff084b8a 100644
--- a/spec/javascripts/error_tracking_settings/store/getters_spec.js
+++ b/spec/frontend/error_tracking_settings/store/getters_spec.js
diff --git a/spec/frontend/error_tracking_settings/store/mutation_spec.js b/spec/frontend/error_tracking_settings/store/mutation_spec.js
new file mode 100644
index 00000000000..fa188462c3f
--- /dev/null
+++ b/spec/frontend/error_tracking_settings/store/mutation_spec.js
@@ -0,0 +1,82 @@
+import { TEST_HOST } from 'helpers/test_constants';
+import mutations from '~/error_tracking_settings/store/mutations';
+import defaultState from '~/error_tracking_settings/store/state';
+import * as types from '~/error_tracking_settings/store/mutation_types';
+import {
+ initialEmptyState,
+ initialPopulatedState,
+ projectList,
+ sampleBackendProject,
+ normalizedProject,
+} from '../mock';
+
+describe('error tracking settings mutations', () => {
+ describe('mutations', () => {
+ let state;
+
+ beforeEach(() => {
+ state = defaultState();
+ });
+
+ it('should create an empty initial state correctly', () => {
+ mutations[types.SET_INITIAL_STATE](state, {
+ ...initialEmptyState,
+ });
+
+ expect(state.apiHost).toEqual('');
+ expect(state.enabled).toEqual(false);
+ expect(state.selectedProject).toEqual(null);
+ expect(state.token).toEqual('');
+ expect(state.listProjectsEndpoint).toEqual(TEST_HOST);
+ expect(state.operationsSettingsEndpoint).toEqual(TEST_HOST);
+ });
+
+ it('should populate the initial state correctly', () => {
+ mutations[types.SET_INITIAL_STATE](state, {
+ ...initialPopulatedState,
+ });
+
+ expect(state.apiHost).toEqual('apiHost');
+ expect(state.enabled).toEqual(true);
+ expect(state.selectedProject).toEqual(projectList[0]);
+ expect(state.token).toEqual('token');
+ expect(state.listProjectsEndpoint).toEqual(TEST_HOST);
+ expect(state.operationsSettingsEndpoint).toEqual(TEST_HOST);
+ });
+
+ it('should receive projects successfully', () => {
+ mutations[types.RECEIVE_PROJECTS](state, [sampleBackendProject]);
+
+ expect(state.projects).toEqual([normalizedProject]);
+ });
+
+ it('should strip out unnecessary project properties', () => {
+ mutations[types.RECEIVE_PROJECTS](state, [
+ { ...sampleBackendProject, extra_property: 'extra_property' },
+ ]);
+
+ expect(state.projects).toEqual([normalizedProject]);
+ });
+
+ it('should update state when connect is successful', () => {
+ mutations[types.UPDATE_CONNECT_SUCCESS](state);
+
+ expect(state.connectSuccessful).toBe(true);
+ expect(state.connectError).toBe(false);
+ });
+
+ it('should update state when connect fails', () => {
+ mutations[types.UPDATE_CONNECT_ERROR](state);
+
+ expect(state.connectSuccessful).toBe(false);
+ expect(state.connectError).toBe(true);
+ });
+
+ it('should update state when connect is reset', () => {
+ mutations[types.RESET_CONNECT](state);
+
+ expect(state.connectSuccessful).toBe(false);
+ expect(state.connectError).toBe(false);
+ });
+ });
+});
diff --git a/spec/javascripts/error_tracking_settings/utils_spec.js b/spec/frontend/error_tracking_settings/utils_spec.js
index 4b144f7daf1..4b144f7daf1 100644
--- a/spec/javascripts/error_tracking_settings/utils_spec.js
+++ b/spec/frontend/error_tracking_settings/utils_spec.js
diff --git a/spec/frontend/ide/lib/files_spec.js b/spec/frontend/ide/lib/files_spec.js
index aa1fa0373db..08a31318544 100644
--- a/spec/frontend/ide/lib/files_spec.js
+++ b/spec/frontend/ide/lib/files_spec.js
@@ -12,6 +12,7 @@ const createEntries = paths => {
const { name, parent } = splitParent(path);
const parentEntry = acc[parent];
+ const previewMode = viewerInformationForPath(name);
acc[path] = {
...decorateData({
@@ -22,7 +23,8 @@ const createEntries = paths => {
path,
url: createUrl(`/${TEST_PROJECT_ID}/${type}/${TEST_BRANCH_ID}/-/${escapeFileUrl(path)}`),
type,
- previewMode: viewerInformationForPath(path),
+ previewMode,
+ binary: (previewMode && previewMode.binary) || false,
parentPath: parent,
parentTreeUrl: parentEntry
? parentEntry.url
diff --git a/spec/frontend/lib/utils/text_utility_spec.js b/spec/frontend/lib/utils/text_utility_spec.js
index 9e920d59093..dc886d0db3b 100644
--- a/spec/frontend/lib/utils/text_utility_spec.js
+++ b/spec/frontend/lib/utils/text_utility_spec.js
@@ -55,9 +55,24 @@ describe('text_utility', () => {
});
});
- describe('slugifyWithHyphens', () => {
+ describe('slugify', () => {
+ it('should remove accents and convert to lower case', () => {
+ expect(textUtils.slugify('João')).toEqual('jo-o');
+ });
it('should replaces whitespaces with hyphens and convert to lower case', () => {
- expect(textUtils.slugifyWithHyphens('My Input String')).toEqual('my-input-string');
+ expect(textUtils.slugify('My Input String')).toEqual('my-input-string');
+ });
+ it('should remove trailing whitespace and replace whitespaces within string with a hyphen', () => {
+ expect(textUtils.slugify(' a new project ')).toEqual('a-new-project');
+ });
+ it('should only remove non-allowed special characters', () => {
+ expect(textUtils.slugify('test!_pro-ject~')).toEqual('test-_pro-ject-');
+ });
+ it('should squash multiple hypens', () => {
+ expect(textUtils.slugify('test!!!!_pro-ject~')).toEqual('test-_pro-ject-');
+ });
+ it('should return empty string if only non-allowed characters', () => {
+ expect(textUtils.slugify('здрасти')).toEqual('');
});
});
diff --git a/spec/frontend/monitoring/__snapshots__/dashboard_state_spec.js.snap b/spec/frontend/monitoring/__snapshots__/dashboard_state_spec.js.snap
new file mode 100644
index 00000000000..5f24bab600c
--- /dev/null
+++ b/spec/frontend/monitoring/__snapshots__/dashboard_state_spec.js.snap
@@ -0,0 +1,37 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`EmptyState shows gettingStarted state 1`] = `
+<glemptystate-stub
+ description="Stay updated about the performance and health of your environment by configuring Prometheus to monitor your deployments."
+ primarybuttonlink="/clustersPath"
+ primarybuttontext="Install on clusters"
+ secondarybuttonlink="/settingsPath"
+ secondarybuttontext="Configure existing installation"
+ svgpath="/path/to/getting-started.svg"
+ title="Get started with performance monitoring"
+/>
+`;
+
+exports[`EmptyState shows loading state 1`] = `
+<glemptystate-stub
+ description="Creating graphs uses the data from the Prometheus server. If this takes a long time, ensure that data is available."
+ primarybuttonlink="/documentationPath"
+ primarybuttontext="View documentation"
+ secondarybuttonlink=""
+ secondarybuttontext=""
+ svgpath="/path/to/loading.svg"
+ title="Waiting for performance data"
+/>
+`;
+
+exports[`EmptyState shows unableToConnect state 1`] = `
+<glemptystate-stub
+ description="Ensure connectivity is available from the GitLab server to the Prometheus server"
+ primarybuttonlink="/documentationPath"
+ primarybuttontext="View documentation"
+ secondarybuttonlink="/settingsPath"
+ secondarybuttontext="Configure Prometheus"
+ svgpath="/path/to/unable-to-connect.svg"
+ title="Unable to connect to Prometheus server"
+/>
+`;
diff --git a/spec/frontend/monitoring/dashboard_state_spec.js b/spec/frontend/monitoring/dashboard_state_spec.js
new file mode 100644
index 00000000000..950422911eb
--- /dev/null
+++ b/spec/frontend/monitoring/dashboard_state_spec.js
@@ -0,0 +1,43 @@
+import { shallowMount } from '@vue/test-utils';
+import EmptyState from '~/monitoring/components/empty_state.vue';
+
+function createComponent(props) {
+ return shallowMount(EmptyState, {
+ propsData: {
+ ...props,
+ settingsPath: '/settingsPath',
+ clustersPath: '/clustersPath',
+ documentationPath: '/documentationPath',
+ emptyGettingStartedSvgPath: '/path/to/getting-started.svg',
+ emptyLoadingSvgPath: '/path/to/loading.svg',
+ emptyNoDataSvgPath: '/path/to/no-data.svg',
+ emptyUnableToConnectSvgPath: '/path/to/unable-to-connect.svg',
+ },
+ });
+}
+
+describe('EmptyState', () => {
+ it('shows gettingStarted state', () => {
+ const wrapper = createComponent({
+ selectedState: 'gettingStarted',
+ });
+
+ expect(wrapper.element).toMatchSnapshot();
+ });
+
+ it('shows loading state', () => {
+ const wrapper = createComponent({
+ selectedState: 'loading',
+ });
+
+ expect(wrapper.element).toMatchSnapshot();
+ });
+
+ it('shows unableToConnect state', () => {
+ const wrapper = createComponent({
+ selectedState: 'unableToConnect',
+ });
+
+ expect(wrapper.element).toMatchSnapshot();
+ });
+});
diff --git a/spec/frontend/notes/components/discussion_notes_replies_wrapper_spec.js b/spec/frontend/notes/components/discussion_notes_replies_wrapper_spec.js
new file mode 100644
index 00000000000..279ca017b44
--- /dev/null
+++ b/spec/frontend/notes/components/discussion_notes_replies_wrapper_spec.js
@@ -0,0 +1,51 @@
+import { mount } from '@vue/test-utils';
+import DiscussionNotesRepliesWrapper from '~/notes/components/discussion_notes_replies_wrapper.vue';
+
+const TEST_CHILDREN = '<li>Hello!</li><li>World!</li>';
+
+// We have to wrap our SUT with a TestComponent because multiple roots are possible
+// because it's a functional component.
+const TestComponent = {
+ components: { DiscussionNotesRepliesWrapper },
+ template: `<ul><discussion-notes-replies-wrapper v-bind="$attrs">${TEST_CHILDREN}</discussion-notes-replies-wrapper></ul>`,
+};
+
+describe('DiscussionNotesRepliesWrapper', () => {
+ let wrapper;
+
+ const createComponent = (props = {}) => {
+ wrapper = mount(TestComponent, {
+ propsData: props,
+ sync: false,
+ });
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ describe('when normal discussion', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('renders children directly', () => {
+ expect(wrapper.html()).toEqual(`<ul>${TEST_CHILDREN}</ul>`);
+ });
+ });
+
+ describe('when diff discussion', () => {
+ beforeEach(() => {
+ createComponent({
+ isDiffDiscussion: true,
+ });
+ });
+
+ it('wraps children with notes', () => {
+ const notes = wrapper.find('li.discussion-collapsible ul.notes');
+
+ expect(notes.exists()).toBe(true);
+ expect(notes.html()).toEqual(`<ul class="notes">${TEST_CHILDREN}</ul>`);
+ });
+ });
+});
diff --git a/spec/frontend/notes/components/discussion_notes_spec.js b/spec/frontend/notes/components/discussion_notes_spec.js
index 394666403ee..58d367077e8 100644
--- a/spec/frontend/notes/components/discussion_notes_spec.js
+++ b/spec/frontend/notes/components/discussion_notes_spec.js
@@ -87,7 +87,7 @@ describe('DiscussionNotes', () => {
discussion.notes[0],
];
discussion.notes = notesData;
- createComponent({ discussion });
+ createComponent({ discussion, shouldRenderDiffs: true });
const notes = wrapper.findAll('.notes > li');
expect(notes.at(0).is(PlaceholderSystemNote)).toBe(true);
diff --git a/spec/frontend/notes/components/discussion_reply_placeholder_spec.js b/spec/frontend/notes/components/discussion_reply_placeholder_spec.js
index 07a366cf339..e008f4ed093 100644
--- a/spec/frontend/notes/components/discussion_reply_placeholder_spec.js
+++ b/spec/frontend/notes/components/discussion_reply_placeholder_spec.js
@@ -2,13 +2,19 @@ import ReplyPlaceholder from '~/notes/components/discussion_reply_placeholder.vu
import { shallowMount, createLocalVue } from '@vue/test-utils';
const localVue = createLocalVue();
+const buttonText = 'Test Button Text';
describe('ReplyPlaceholder', () => {
let wrapper;
+ const findButton = () => wrapper.find({ ref: 'button' });
+
beforeEach(() => {
wrapper = shallowMount(ReplyPlaceholder, {
localVue,
+ propsData: {
+ buttonText,
+ },
});
});
@@ -17,9 +23,7 @@ describe('ReplyPlaceholder', () => {
});
it('emits onClick even on button click', () => {
- const button = wrapper.find({ ref: 'button' });
-
- button.trigger('click');
+ findButton().trigger('click');
expect(wrapper.emitted()).toEqual({
onClick: [[]],
@@ -27,8 +31,6 @@ describe('ReplyPlaceholder', () => {
});
it('should render reply button', () => {
- const button = wrapper.find({ ref: 'button' });
-
- expect(button.text()).toEqual('Reply...');
+ expect(findButton().text()).toEqual(buttonText);
});
});
diff --git a/spec/frontend/vue_shared/components/markdown/header_spec.js b/spec/frontend/vue_shared/components/markdown/header_spec.js
new file mode 100644
index 00000000000..aa0b544f948
--- /dev/null
+++ b/spec/frontend/vue_shared/components/markdown/header_spec.js
@@ -0,0 +1,107 @@
+import Vue from 'vue';
+import $ from 'jquery';
+import headerComponent from '~/vue_shared/components/markdown/header.vue';
+
+describe('Markdown field header component', () => {
+ let vm;
+
+ beforeEach(done => {
+ const Component = Vue.extend(headerComponent);
+
+ vm = new Component({
+ propsData: {
+ previewMarkdown: false,
+ },
+ }).$mount();
+
+ Vue.nextTick(done);
+ });
+
+ it('renders markdown header buttons', () => {
+ const buttons = [
+ 'Add bold text',
+ 'Add italic text',
+ 'Insert a quote',
+ 'Insert suggestion',
+ 'Insert code',
+ 'Add a link',
+ 'Add a bullet list',
+ 'Add a numbered list',
+ 'Add a task list',
+ 'Add a table',
+ 'Go full screen',
+ ];
+ const elements = vm.$el.querySelectorAll('.toolbar-btn');
+
+ elements.forEach((buttonEl, index) => {
+ expect(buttonEl.getAttribute('data-original-title')).toBe(buttons[index]);
+ });
+ });
+
+ it('renders `write` link as active when previewMarkdown is false', () => {
+ expect(vm.$el.querySelector('li:nth-child(1)').classList.contains('active')).toBeTruthy();
+ });
+
+ it('renders `preview` link as active when previewMarkdown is true', done => {
+ vm.previewMarkdown = true;
+
+ Vue.nextTick(() => {
+ expect(vm.$el.querySelector('li:nth-child(2)').classList.contains('active')).toBeTruthy();
+
+ done();
+ });
+ });
+
+ it('emits toggle markdown event when clicking preview', () => {
+ jest.spyOn(vm, '$emit').mockImplementation();
+
+ vm.$el.querySelector('.js-preview-link').click();
+
+ expect(vm.$emit).toHaveBeenCalledWith('preview-markdown');
+
+ vm.$el.querySelector('.js-write-link').click();
+
+ expect(vm.$emit).toHaveBeenCalledWith('write-markdown');
+ });
+
+ it('does not emit toggle markdown event when triggered from another form', () => {
+ jest.spyOn(vm, '$emit').mockImplementation();
+
+ $(document).triggerHandler('markdown-preview:show', [
+ $(
+ '<form><div class="js-vue-markdown-field"><textarea class="markdown-area"></textarea></div></form>',
+ ),
+ ]);
+
+ expect(vm.$emit).not.toHaveBeenCalled();
+ });
+
+ it('blurs preview link after click', () => {
+ const link = vm.$el.querySelector('li:nth-child(2) button');
+ jest.spyOn(HTMLElement.prototype, 'blur').mockImplementation();
+
+ link.click();
+
+ expect(link.blur).toHaveBeenCalled();
+ });
+
+ it('renders markdown table template', () => {
+ expect(vm.mdTable).toEqual(
+ '| header | header |\n| ------ | ------ |\n| cell | cell |\n| cell | cell |',
+ );
+ });
+
+ it('renders suggestion template', () => {
+ vm.lineContent = 'Some content';
+
+ expect(vm.mdSuggestion).toEqual('```suggestion:-0+0\n{text}\n```');
+ });
+
+ it('does not render suggestion button if `canSuggest` is set to false', () => {
+ vm.canSuggest = false;
+
+ Vue.nextTick(() => {
+ expect(vm.$el.querySelector('.qa-suggestion-btn')).toBe(null);
+ });
+ });
+});
diff --git a/spec/graphql/gitlab_schema_spec.rb b/spec/graphql/gitlab_schema_spec.rb
index d36e428a8ee..93b86b9b812 100644
--- a/spec/graphql/gitlab_schema_spec.rb
+++ b/spec/graphql/gitlab_schema_spec.rb
@@ -21,6 +21,10 @@ describe GitlabSchema do
expect(field_instrumenters).to include(instance_of(::Gitlab::Graphql::Present::Instrumentation))
end
+ it 'enables using gitaly call checker' do
+ expect(field_instrumenters).to include(instance_of(::Gitlab::Graphql::CallsGitaly::Instrumentation))
+ end
+
it 'has the base mutation' do
expect(described_class.mutation).to eq(::Types::MutationType.to_graphql)
end
diff --git a/spec/graphql/types/base_field_spec.rb b/spec/graphql/types/base_field_spec.rb
index 0d3c3e37daf..77ef8933717 100644
--- a/spec/graphql/types/base_field_spec.rb
+++ b/spec/graphql/types/base_field_spec.rb
@@ -22,6 +22,24 @@ describe Types::BaseField do
expect(field.to_graphql.complexity).to eq 1
end
+ describe '#base_complexity' do
+ context 'with no gitaly calls' do
+ it 'defaults to 1' do
+ field = described_class.new(name: 'test', type: GraphQL::STRING_TYPE, null: true)
+
+ expect(field.base_complexity).to eq 1
+ end
+ end
+
+ context 'with a gitaly call' do
+ it 'adds 1 to the default value' do
+ field = described_class.new(name: 'test', type: GraphQL::STRING_TYPE, null: true, calls_gitaly: true)
+
+ expect(field.base_complexity).to eq 2
+ end
+ end
+ end
+
it 'has specified value' do
field = described_class.new(name: 'test', type: GraphQL::STRING_TYPE, null: true, complexity: 12)
@@ -52,5 +70,46 @@ describe Types::BaseField do
end
end
end
+
+ context 'calls_gitaly' do
+ context 'for fields with a resolver' do
+ it 'adds 1 if true' do
+ with_gitaly_field = described_class.new(name: 'test', type: GraphQL::STRING_TYPE, resolver_class: resolver, null: true, calls_gitaly: true)
+ without_gitaly_field = described_class.new(name: 'test', type: GraphQL::STRING_TYPE, resolver_class: resolver, null: true)
+ base_result = without_gitaly_field.to_graphql.complexity.call({}, {}, 2)
+
+ expect(with_gitaly_field.to_graphql.complexity.call({}, {}, 2)).to eq base_result + 1
+ end
+ end
+
+ context 'for fields without a resolver' do
+ it 'adds 1 if true' do
+ field = described_class.new(name: 'test', type: GraphQL::STRING_TYPE, null: true, calls_gitaly: true)
+
+ expect(field.to_graphql.complexity).to eq 2
+ end
+ end
+
+ it 'defaults to false' do
+ field = described_class.new(name: 'test', type: GraphQL::STRING_TYPE, null: true)
+
+ expect(field.base_complexity).to eq Types::BaseField::DEFAULT_COMPLEXITY
+ end
+
+ context 'with declared constant complexity value' do
+ it 'has complexity set to that constant' do
+ field = described_class.new(name: 'test', type: GraphQL::STRING_TYPE, null: true, complexity: 12)
+
+ expect(field.to_graphql.complexity).to eq 12
+ end
+
+ it 'does not raise an error even with Gitaly calls' do
+ allow(Gitlab::GitalyClient).to receive(:get_request_count).and_return([0, 1])
+ field = described_class.new(name: 'test', type: GraphQL::STRING_TYPE, null: true, complexity: 12)
+
+ expect(field.to_graphql.complexity).to eq 12
+ end
+ end
+ end
end
end
diff --git a/spec/graphql/types/label_type_spec.rb b/spec/graphql/types/label_type_spec.rb
index f498b32f9ed..8e7b2c69eff 100644
--- a/spec/graphql/types/label_type_spec.rb
+++ b/spec/graphql/types/label_type_spec.rb
@@ -7,4 +7,6 @@ describe GitlabSchema.types['Label'] do
is_expected.to have_graphql_fields(*expected_fields)
end
+
+ it { is_expected.to require_graphql_authorizations(:read_label) }
end
diff --git a/spec/graphql/types/metadata_type_spec.rb b/spec/graphql/types/metadata_type_spec.rb
index 55205bf5b6a..5236380e477 100644
--- a/spec/graphql/types/metadata_type_spec.rb
+++ b/spec/graphql/types/metadata_type_spec.rb
@@ -2,4 +2,5 @@ require 'spec_helper'
describe GitlabSchema.types['Metadata'] do
it { expect(described_class.graphql_name).to eq('Metadata') }
+ it { is_expected.to require_graphql_authorizations(:read_instance_metadata) }
end
diff --git a/spec/graphql/types/namespace_type_spec.rb b/spec/graphql/types/namespace_type_spec.rb
index 77fd590586e..e1153832cc9 100644
--- a/spec/graphql/types/namespace_type_spec.rb
+++ b/spec/graphql/types/namespace_type_spec.rb
@@ -13,4 +13,6 @@ describe GitlabSchema.types['Namespace'] do
is_expected.to have_graphql_fields(*expected_fields)
end
+
+ it { is_expected.to require_graphql_authorizations(:read_namespace) }
end
diff --git a/spec/graphql/types/query_type_spec.rb b/spec/graphql/types/query_type_spec.rb
index af1972a2513..bc3b8a42392 100644
--- a/spec/graphql/types/query_type_spec.rb
+++ b/spec/graphql/types/query_type_spec.rb
@@ -34,9 +34,5 @@ describe GitlabSchema.types['Query'] do
is_expected.to have_graphql_type(Types::MetadataType)
is_expected.to have_graphql_resolver(Resolvers::MetadataResolver)
end
-
- it 'authorizes with read_instance_metadata' do
- is_expected.to require_graphql_authorizations(:read_instance_metadata)
- end
end
end
diff --git a/spec/helpers/markup_helper_spec.rb b/spec/helpers/markup_helper_spec.rb
index 597c8f836a9..6c6410cee9b 100644
--- a/spec/helpers/markup_helper_spec.rb
+++ b/spec/helpers/markup_helper_spec.rb
@@ -50,6 +50,43 @@ describe MarkupHelper do
expect(markdown(actual, project: second_project)).to match(expected)
end
end
+
+ describe 'uploads' do
+ let(:text) { "![ImageTest](/uploads/test.png)" }
+ let(:group) { create(:group) }
+
+ subject { helper.markdown(text) }
+
+ describe 'inside a project' do
+ it 'renders uploads relative to project' do
+ expect(subject).to include("#{project.full_path}/uploads/test.png")
+ end
+ end
+
+ describe 'inside a group' do
+ before do
+ helper.instance_variable_set(:@group, group)
+ helper.instance_variable_set(:@project, nil)
+ end
+
+ it 'renders uploads relative to the group' do
+ expect(subject).to include("#{group.full_path}/-/uploads/test.png")
+ end
+ end
+
+ describe "with a group in the context" do
+ let(:project_in_group) { create(:project, group: group) }
+
+ before do
+ helper.instance_variable_set(:@group, group)
+ helper.instance_variable_set(:@project, project_in_group)
+ end
+
+ it 'renders uploads relative to project' do
+ expect(subject).to include("#{project_in_group.path_with_namespace}/uploads/test.png")
+ end
+ end
+ end
end
describe '#markdown_field' do
diff --git a/spec/helpers/onboarding_experiment_helper_spec.rb b/spec/helpers/onboarding_experiment_helper_spec.rb
new file mode 100644
index 00000000000..5b7d9b1c2e6
--- /dev/null
+++ b/spec/helpers/onboarding_experiment_helper_spec.rb
@@ -0,0 +1,38 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe OnboardingExperimentHelper, type: :helper do
+ describe '.allow_access_to_onboarding?' do
+ context "when we're not gitlab.com" do
+ it 'returns false' do
+ allow(::Gitlab).to receive(:com?).and_return(false)
+
+ expect(helper.allow_access_to_onboarding?).to be(false)
+ end
+ end
+
+ context "when we're gitlab.com" do
+ before do
+ allow(::Gitlab).to receive(:com?).and_return(true)
+ end
+
+ context 'and the :user_onboarding feature is not enabled' do
+ it 'returns false' do
+ stub_feature_flags(user_onboarding: false)
+
+ expect(helper.allow_access_to_onboarding?).to be(false)
+ end
+ end
+
+ context 'and the :user_onboarding feature is enabled' do
+ it 'returns true' do
+ stub_feature_flags(user_onboarding: true)
+ allow(helper).to receive(:current_user).and_return(create(:user))
+
+ expect(helper.allow_access_to_onboarding?).to be(true)
+ end
+ end
+ end
+ end
+end
diff --git a/spec/helpers/preferences_helper_spec.rb b/spec/helpers/preferences_helper_spec.rb
index db0d45c3692..554c08add2d 100644
--- a/spec/helpers/preferences_helper_spec.rb
+++ b/spec/helpers/preferences_helper_spec.rb
@@ -28,7 +28,7 @@ describe PreferencesHelper do
["Your Projects' Activity", 'project_activity'],
["Starred Projects' Activity", 'starred_project_activity'],
["Your Groups", 'groups'],
- ["Your Todos", 'todos'],
+ ["Your To-Do List", 'todos'],
["Assigned Issues", 'issues'],
["Assigned Merge Requests", 'merge_requests']
]
diff --git a/spec/helpers/storage_helper_spec.rb b/spec/helpers/storage_helper_spec.rb
index 62c00964524..4bd0fbb76ca 100644
--- a/spec/helpers/storage_helper_spec.rb
+++ b/spec/helpers/storage_helper_spec.rb
@@ -31,7 +31,7 @@ describe StorageHelper do
build_artifacts_size: 30.megabytes))
end
- let(:message) { '10 KB repositories, 10 Bytes wikis, 30 MB build artifacts, 20 GB LFS' }
+ let(:message) { 'Repository: 10 KB / Wikis: 10 Bytes / Build Artifacts: 30 MB / LFS: 20 GB' }
it 'works on ProjectStatistics' do
expect(helper.storage_counters_details(project.statistics)).to eq(message)
diff --git a/spec/initializers/6_validations_spec.rb b/spec/initializers/6_validations_spec.rb
index f96e5a2133f..73fbd4c7a44 100644
--- a/spec/initializers/6_validations_spec.rb
+++ b/spec/initializers/6_validations_spec.rb
@@ -2,16 +2,6 @@ require 'spec_helper'
require_relative '../../config/initializers/6_validations.rb'
describe '6_validations' do
- before :all do
- FileUtils.mkdir_p('tmp/tests/paths/a/b/c/d')
- FileUtils.mkdir_p('tmp/tests/paths/a/b/c2')
- FileUtils.mkdir_p('tmp/tests/paths/a/b/d')
- end
-
- after :all do
- FileUtils.rm_rf('tmp/tests/paths')
- end
-
describe 'validate_storages_config' do
context 'with correct settings' do
before do
@@ -23,16 +13,6 @@ describe '6_validations' do
end
end
- context 'when one of the settings is incorrect' do
- before do
- mock_storages('foo' => Gitlab::GitalyClient::StorageSettings.new('path' => 'tmp/tests/paths/a/b/c', 'failure_count_threshold' => 'not a number'))
- end
-
- it 'throws an error' do
- expect { validate_storages_config }.to raise_error(/failure_count_threshold/)
- end
- end
-
context 'with invalid storage names' do
before do
mock_storages('name with spaces' => Gitlab::GitalyClient::StorageSettings.new('path' => 'tmp/tests/paths/a/b/c'))
diff --git a/spec/javascripts/boards/mock_data.js b/spec/javascripts/boards/mock_data.js
index 9854cf49e97..ea22ae5c4e7 100644
--- a/spec/javascripts/boards/mock_data.js
+++ b/spec/javascripts/boards/mock_data.js
@@ -1,4 +1,5 @@
import BoardService from '~/boards/services/board_service';
+import boardsStore from '~/boards/stores/boards_store';
export const boardObj = {
id: 1,
@@ -76,12 +77,14 @@ export const mockBoardService = (opts = {}) => {
const bulkUpdatePath = opts.bulkUpdatePath || '';
const boardId = opts.boardId || '1';
- return new BoardService({
+ boardsStore.setEndpoints({
boardsEndpoint,
listsEndpoint,
bulkUpdatePath,
boardId,
});
+
+ return new BoardService();
};
export const mockAssigneesList = [
diff --git a/spec/javascripts/collapsed_sidebar_todo_spec.js b/spec/javascripts/collapsed_sidebar_todo_spec.js
index bb90e53e525..f75d63c8f57 100644
--- a/spec/javascripts/collapsed_sidebar_todo_spec.js
+++ b/spec/javascripts/collapsed_sidebar_todo_spec.js
@@ -58,7 +58,7 @@ describe('Issuable right sidebar collapsed todo toggle', () => {
it('sets default tooltip title', () => {
expect(
document.querySelector('.js-issuable-todo.sidebar-collapsed-icon').getAttribute('title'),
- ).toBe('Add todo');
+ ).toBe('Add a To Do');
});
it('toggle todo state', done => {
@@ -85,7 +85,7 @@ describe('Issuable right sidebar collapsed todo toggle', () => {
setTimeout(() => {
expect(
document.querySelector('.issuable-sidebar-header .js-issuable-todo').textContent.trim(),
- ).toBe('Mark todo as done');
+ ).toBe('Mark as done');
done();
});
@@ -99,7 +99,7 @@ describe('Issuable right sidebar collapsed todo toggle', () => {
document
.querySelector('.js-issuable-todo.sidebar-collapsed-icon')
.getAttribute('data-original-title'),
- ).toBe('Mark todo as done');
+ ).toBe('Mark as done');
done();
});
@@ -124,13 +124,13 @@ describe('Issuable right sidebar collapsed todo toggle', () => {
expect(
document.querySelector('.issuable-sidebar-header .js-issuable-todo').textContent.trim(),
- ).toBe('Add todo');
+ ).toBe('Add a To Do');
})
.then(done)
.catch(done.fail);
});
- it('updates aria-label to mark todo as done', done => {
+ it('updates aria-label to Mark as done', done => {
document.querySelector('.js-issuable-todo.sidebar-collapsed-icon').click();
setTimeout(() => {
@@ -138,7 +138,7 @@ describe('Issuable right sidebar collapsed todo toggle', () => {
document
.querySelector('.js-issuable-todo.sidebar-collapsed-icon')
.getAttribute('aria-label'),
- ).toBe('Mark todo as done');
+ ).toBe('Mark as done');
done();
});
@@ -153,7 +153,7 @@ describe('Issuable right sidebar collapsed todo toggle', () => {
document
.querySelector('.js-issuable-todo.sidebar-collapsed-icon')
.getAttribute('aria-label'),
- ).toBe('Mark todo as done');
+ ).toBe('Mark as done');
document.querySelector('.js-issuable-todo.sidebar-collapsed-icon').click();
})
@@ -163,7 +163,7 @@ describe('Issuable right sidebar collapsed todo toggle', () => {
document
.querySelector('.js-issuable-todo.sidebar-collapsed-icon')
.getAttribute('aria-label'),
- ).toBe('Add todo');
+ ).toBe('Add a To Do');
})
.then(done)
.catch(done.fail);
diff --git a/spec/javascripts/create_merge_request_dropdown_spec.js b/spec/javascripts/create_merge_request_dropdown_spec.js
deleted file mode 100644
index 00fe3f451f5..00000000000
--- a/spec/javascripts/create_merge_request_dropdown_spec.js
+++ /dev/null
@@ -1,68 +0,0 @@
-import axios from '~/lib/utils/axios_utils';
-import MockAdapter from 'axios-mock-adapter';
-import CreateMergeRequestDropdown from '~/create_merge_request_dropdown';
-import { TEST_HOST } from 'spec/test_constants';
-
-describe('CreateMergeRequestDropdown', () => {
- let axiosMock;
- let dropdown;
-
- beforeEach(() => {
- axiosMock = new MockAdapter(axios);
-
- setFixtures(`
- <div id="dummy-wrapper-element">
- <div class="available"></div>
- <div class="unavailable">
- <div class="fa"></div>
- <div class="text"></div>
- </div>
- <div class="js-ref"></div>
- <div class="js-create-merge-request"></div>
- <div class="js-create-target"></div>
- <div class="js-dropdown-toggle"></div>
- </div>
- `);
-
- const dummyElement = document.getElementById('dummy-wrapper-element');
- dropdown = new CreateMergeRequestDropdown(dummyElement);
- dropdown.refsPath = `${TEST_HOST}/dummy/refs?search=`;
- });
-
- afterEach(() => {
- axiosMock.restore();
- });
-
- describe('getRef', () => {
- it('escapes branch names correctly', done => {
- const endpoint = `${dropdown.refsPath}contains%23hash`;
- spyOn(axios, 'get').and.callThrough();
- axiosMock.onGet(endpoint).replyOnce({});
-
- dropdown
- .getRef('contains#hash')
- .then(() => {
- expect(axios.get).toHaveBeenCalledWith(endpoint);
- })
- .then(done)
- .catch(done.fail);
- });
- });
-
- describe('updateCreatePaths', () => {
- it('escapes branch names correctly', () => {
- dropdown.createBranchPath = `${TEST_HOST}/branches?branch_name=some-branch&issue=42`;
- dropdown.createMrPath = `${TEST_HOST}/create_merge_request?branch_name=some-branch&ref=master`;
-
- dropdown.updateCreatePaths('branch', 'contains#hash');
-
- expect(dropdown.createBranchPath).toBe(
- `${TEST_HOST}/branches?branch_name=contains%23hash&issue=42`,
- );
-
- expect(dropdown.createMrPath).toBe(
- `${TEST_HOST}/create_merge_request?branch_name=contains%23hash&ref=master`,
- );
- });
- });
-});
diff --git a/spec/javascripts/diffs/components/diff_file_header_spec.js b/spec/javascripts/diffs/components/diff_file_header_spec.js
index 596a1ba5ad2..d4280d3ec2c 100644
--- a/spec/javascripts/diffs/components/diff_file_header_spec.js
+++ b/spec/javascripts/diffs/components/diff_file_header_spec.js
@@ -521,7 +521,7 @@ describe('diff_file_header', () => {
});
describe('with discussions', () => {
- it('dispatches toggleFileDiscussions when user clicks on toggle discussions button', () => {
+ it('dispatches toggleFileDiscussionWrappers when user clicks on toggle discussions button', () => {
const propsCopy = Object.assign({}, props);
propsCopy.diffFile.submodule = false;
propsCopy.diffFile.blob = {
@@ -552,11 +552,11 @@ describe('diff_file_header', () => {
}),
});
- spyOn(vm, 'toggleFileDiscussions');
+ spyOn(vm, 'toggleFileDiscussionWrappers');
vm.$el.querySelector('.js-btn-vue-toggle-comments').click();
- expect(vm.toggleFileDiscussions).toHaveBeenCalled();
+ expect(vm.toggleFileDiscussionWrappers).toHaveBeenCalled();
});
});
});
diff --git a/spec/javascripts/diffs/components/diff_gutter_avatars_spec.js b/spec/javascripts/diffs/components/diff_gutter_avatars_spec.js
deleted file mode 100644
index cdd30919b09..00000000000
--- a/spec/javascripts/diffs/components/diff_gutter_avatars_spec.js
+++ /dev/null
@@ -1,146 +0,0 @@
-import Vue from 'vue';
-import DiffGutterAvatarsComponent from '~/diffs/components/diff_gutter_avatars.vue';
-import { COUNT_OF_AVATARS_IN_GUTTER } from '~/diffs/constants';
-import store from '~/mr_notes/stores';
-import { createComponentWithStore } from 'spec/helpers/vue_mount_component_helper';
-import discussionsMockData from '../mock_data/diff_discussions';
-
-describe('DiffGutterAvatars', () => {
- let component;
- const getDiscussionsMockData = () => [Object.assign({}, discussionsMockData)];
-
- beforeEach(() => {
- component = createComponentWithStore(Vue.extend(DiffGutterAvatarsComponent), store, {
- discussions: getDiscussionsMockData(),
- }).$mount();
- });
-
- describe('computed', () => {
- describe('discussionsExpanded', () => {
- it('should return true when all discussions are expanded', () => {
- expect(component.discussionsExpanded).toEqual(true);
- });
-
- it('should return false when all discussions are not expanded', () => {
- component.discussions[0].expanded = false;
-
- expect(component.discussionsExpanded).toEqual(false);
- });
- });
-
- describe('allDiscussions', () => {
- it('should return an array of notes', () => {
- expect(component.allDiscussions).toEqual([...component.discussions[0].notes]);
- });
- });
-
- describe('notesInGutter', () => {
- it('should return a subset of discussions to show in gutter', () => {
- expect(component.notesInGutter.length).toEqual(COUNT_OF_AVATARS_IN_GUTTER);
- expect(component.notesInGutter[0]).toEqual({
- note: component.discussions[0].notes[0].note,
- author: component.discussions[0].notes[0].author,
- });
- });
- });
-
- describe('moreCount', () => {
- it('should return count of remaining discussions from gutter', () => {
- expect(component.moreCount).toEqual(2);
- });
- });
-
- describe('moreText', () => {
- it('should return proper text if moreCount > 0', () => {
- expect(component.moreText).toEqual('2 more comments');
- });
-
- it('should return empty string if there is no discussion', () => {
- component.discussions = [];
-
- expect(component.moreText).toEqual('');
- });
- });
- });
-
- describe('methods', () => {
- describe('getTooltipText', () => {
- it('should return original comment if it is shorter than max length', () => {
- const note = component.discussions[0].notes[0];
-
- expect(component.getTooltipText(note)).toEqual('Administrator: comment 1');
- });
-
- it('should return truncated version of comment', () => {
- const note = component.discussions[0].notes[1];
-
- expect(component.getTooltipText(note)).toEqual('Fatih Acet: comment 2 is r...');
- });
- });
-
- describe('toggleDiscussions', () => {
- it('should toggle all discussions', () => {
- expect(component.discussions[0].expanded).toEqual(true);
-
- component.$store.dispatch('setInitialNotes', getDiscussionsMockData());
- component.discussions = component.$store.state.notes.discussions;
- component.toggleDiscussions();
-
- expect(component.discussions[0].expanded).toEqual(false);
- component.$store.dispatch('setInitialNotes', []);
- });
-
- it('forces expansion of all discussions', () => {
- spyOn(component.$store, 'dispatch');
-
- component.discussions[0].expanded = true;
- component.discussions.push({
- ...component.discussions[0],
- id: '123test',
- expanded: false,
- });
-
- component.toggleDiscussions();
-
- expect(component.$store.dispatch.calls.argsFor(0)).toEqual([
- 'toggleDiscussion',
- {
- discussionId: component.discussions[0].id,
- forceExpanded: true,
- },
- ]);
-
- expect(component.$store.dispatch.calls.argsFor(1)).toEqual([
- 'toggleDiscussion',
- {
- discussionId: component.discussions[1].id,
- forceExpanded: true,
- },
- ]);
- });
- });
- });
-
- describe('template', () => {
- const buttonSelector = '.js-diff-comment-button';
- const svgSelector = `${buttonSelector} svg`;
- const avatarSelector = '.js-diff-comment-avatar';
- const plusCountSelector = '.js-diff-comment-plus';
-
- it('should have button to collapse discussions when the discussions expanded', () => {
- expect(component.$el.querySelector(buttonSelector)).toBeDefined();
- expect(component.$el.querySelector(svgSelector)).toBeDefined();
- });
-
- it('should have user avatars when discussions collapsed', () => {
- component.discussions[0].expanded = false;
-
- Vue.nextTick(() => {
- expect(component.$el.querySelector(buttonSelector)).toBeNull();
- expect(component.$el.querySelectorAll(avatarSelector).length).toEqual(4);
- expect(component.$el.querySelector(plusCountSelector)).toBeDefined();
- expect(component.$el.querySelector(plusCountSelector).textContent).toEqual('+2');
- });
- });
- });
-});
diff --git a/spec/javascripts/diffs/components/inline_diff_view_spec.js b/spec/javascripts/diffs/components/inline_diff_view_spec.js
index 4452106580a..9b61dbe7975 100644
--- a/spec/javascripts/diffs/components/inline_diff_view_spec.js
+++ b/spec/javascripts/diffs/components/inline_diff_view_spec.js
@@ -10,6 +10,7 @@ describe('InlineDiffView', () => {
let component;
const getDiffFileMock = () => Object.assign({}, diffFileMockData);
const getDiscussionsMockData = () => [Object.assign({}, discussionsMockData)];
+ const notesLength = getDiscussionsMockData()[0].notes.length;
beforeEach(done => {
const diffFile = getDiffFileMock();
@@ -36,10 +37,11 @@ describe('InlineDiffView', () => {
it('should render discussions', done => {
const el = component.$el;
component.diffLines[1].discussions = getDiscussionsMockData();
+ component.diffLines[1].discussionsExpanded = true;
Vue.nextTick(() => {
expect(el.querySelectorAll('.notes_holder').length).toEqual(1);
- expect(el.querySelectorAll('.notes_holder .note-discussion li').length).toEqual(5);
+ expect(el.querySelectorAll('.notes_holder .note').length).toEqual(notesLength + 1);
expect(el.innerText.indexOf('comment 5')).toBeGreaterThan(-1);
component.$store.dispatch('setInitialNotes', []);
diff --git a/spec/javascripts/diffs/store/actions_spec.js b/spec/javascripts/diffs/store/actions_spec.js
index f973728cfe1..f8872a3eb13 100644
--- a/spec/javascripts/diffs/store/actions_spec.js
+++ b/spec/javascripts/diffs/store/actions_spec.js
@@ -206,6 +206,7 @@ describe('DiffsStoreActions', () => {
position_type: 'text',
},
},
+ hash: 'diff-content-1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a',
},
},
],
diff --git a/spec/javascripts/environments/environment_terminal_button_spec.js b/spec/javascripts/environments/environment_terminal_button_spec.js
index 56e18db59c5..fc98e656efe 100644
--- a/spec/javascripts/environments/environment_terminal_button_spec.js
+++ b/spec/javascripts/environments/environment_terminal_button_spec.js
@@ -12,36 +12,24 @@ describe('Stop Component', () => {
}).$mount();
};
- describe('enabled', () => {
- beforeEach(() => {
- mountWithProps({ terminalPath });
- });
-
- describe('computed', () => {
- it('title', () => {
- expect(component.title).toEqual('Terminal');
- });
- });
-
- it('should render a link to open a web terminal with the provided path', () => {
- expect(component.$el.tagName).toEqual('A');
- expect(component.$el.getAttribute('data-original-title')).toEqual('Terminal');
- expect(component.$el.getAttribute('aria-label')).toEqual('Terminal');
- expect(component.$el.getAttribute('href')).toEqual(terminalPath);
- });
+ beforeEach(() => {
+ mountWithProps({ terminalPath });
+ });
- it('should render a non-disabled button', () => {
- expect(component.$el.classList).not.toContain('disabled');
+ describe('computed', () => {
+ it('title', () => {
+ expect(component.title).toEqual('Terminal');
});
});
- describe('disabled', () => {
- beforeEach(() => {
- mountWithProps({ terminalPath, disabled: true });
- });
+ it('should render a link to open a web terminal with the provided path', () => {
+ expect(component.$el.tagName).toEqual('A');
+ expect(component.$el.getAttribute('data-original-title')).toEqual('Terminal');
+ expect(component.$el.getAttribute('aria-label')).toEqual('Terminal');
+ expect(component.$el.getAttribute('href')).toEqual(terminalPath);
+ });
- it('should render a disabled button', () => {
- expect(component.$el.classList).toContain('disabled');
- });
+ it('should render a non-disabled button', () => {
+ expect(component.$el.classList).not.toContain('disabled');
});
});
diff --git a/spec/javascripts/error_tracking_settings/components/app_spec.js b/spec/javascripts/error_tracking_settings/components/app_spec.js
deleted file mode 100644
index 2e52a45fd34..00000000000
--- a/spec/javascripts/error_tracking_settings/components/app_spec.js
+++ /dev/null
@@ -1,63 +0,0 @@
-import Vuex from 'vuex';
-import { createLocalVue, shallowMount } from '@vue/test-utils';
-import ErrorTrackingSettings from '~/error_tracking_settings/components/app.vue';
-import ErrorTrackingForm from '~/error_tracking_settings/components/error_tracking_form.vue';
-import ProjectDropdown from '~/error_tracking_settings/components/project_dropdown.vue';
-import createStore from '~/error_tracking_settings/store';
-import { TEST_HOST } from 'spec/test_constants';
-
-const localVue = createLocalVue();
-localVue.use(Vuex);
-
-describe('error tracking settings app', () => {
- let store;
- let wrapper;
-
- function mountComponent() {
- wrapper = shallowMount(ErrorTrackingSettings, {
- localVue,
- store, // Override the imported store
- propsData: {
- initialEnabled: 'true',
- initialApiHost: TEST_HOST,
- initialToken: 'someToken',
- initialProject: null,
- listProjectsEndpoint: TEST_HOST,
- operationsSettingsEndpoint: TEST_HOST,
- },
- });
- }
-
- beforeEach(() => {
- store = createStore();
-
- mountComponent();
- });
-
- afterEach(() => {
- if (wrapper) {
- wrapper.destroy();
- }
- });
-
- describe('section', () => {
- it('renders the form and dropdown', () => {
- expect(wrapper.find(ErrorTrackingForm).exists()).toBeTruthy();
- expect(wrapper.find(ProjectDropdown).exists()).toBeTruthy();
- });
-
- it('renders the Save Changes button', () => {
- expect(wrapper.find('.js-error-tracking-button').exists()).toBeTruthy();
- });
-
- it('enables the button by default', () => {
- expect(wrapper.find('.js-error-tracking-button').attributes('disabled')).toBeFalsy();
- });
-
- it('disables the button when saving', () => {
- store.state.settingsLoading = true;
-
- expect(wrapper.find('.js-error-tracking-button').attributes('disabled')).toBeTruthy();
- });
- });
-});
diff --git a/spec/javascripts/error_tracking_settings/mock.js b/spec/javascripts/error_tracking_settings/mock.js
deleted file mode 100644
index 32cdba33c14..00000000000
--- a/spec/javascripts/error_tracking_settings/mock.js
+++ /dev/null
@@ -1,92 +0,0 @@
-import createStore from '~/error_tracking_settings/store';
-import { TEST_HOST } from 'spec/test_constants';
-
-const defaultStore = createStore();
-
-export const projectList = [
- {
- name: 'name',
- slug: 'slug',
- organizationName: 'organizationName',
- organizationSlug: 'organizationSlug',
- },
- {
- name: 'name2',
- slug: 'slug2',
- organizationName: 'organizationName2',
- organizationSlug: 'organizationSlug2',
- },
-];
-
-export const staleProject = {
- name: 'staleName',
- slug: 'staleSlug',
- organizationName: 'staleOrganizationName',
- organizationSlug: 'staleOrganizationSlug',
-};
-
-export const normalizedProject = {
- name: 'name',
- slug: 'slug',
- organizationName: 'organization_name',
- organizationSlug: 'organization_slug',
-};
-
-export const sampleBackendProject = {
- name: normalizedProject.name,
- slug: normalizedProject.slug,
- organization_name: normalizedProject.organizationName,
- organization_slug: normalizedProject.organizationSlug,
-};
-
-export const sampleFrontendSettings = {
- apiHost: 'apiHost',
- enabled: false,
- token: 'token',
- selectedProject: {
- slug: normalizedProject.slug,
- name: normalizedProject.name,
- organizationName: normalizedProject.organizationName,
- organizationSlug: normalizedProject.organizationSlug,
- },
-};
-
-export const transformedSettings = {
- api_host: 'apiHost',
- enabled: false,
- token: 'token',
- project: {
- slug: normalizedProject.slug,
- name: normalizedProject.name,
- organization_name: normalizedProject.organizationName,
- organization_slug: normalizedProject.organizationSlug,
- },
-};
-
-export const defaultProps = {
- ...defaultStore.state,
- ...defaultStore.getters,
-};
-
-export const initialEmptyState = {
- apiHost: '',
- enabled: false,
- project: null,
- token: '',
- listProjectsEndpoint: TEST_HOST,
- operationsSettingsEndpoint: TEST_HOST,
-};
-
-export const initialPopulatedState = {
- apiHost: 'apiHost',
- enabled: true,
- project: JSON.stringify(projectList[0]),
- token: 'token',
- listProjectsEndpoint: TEST_HOST,
- operationsSettingsEndpoint: TEST_HOST,
-};
-
-export const projectWithHtmlTemplate = {
- ...projectList[0],
- name: '<strong>bold</strong>',
-};
diff --git a/spec/javascripts/error_tracking_settings/store/actions_spec.js b/spec/javascripts/error_tracking_settings/store/actions_spec.js
deleted file mode 100644
index 0255b3a7aa4..00000000000
--- a/spec/javascripts/error_tracking_settings/store/actions_spec.js
+++ /dev/null
@@ -1,191 +0,0 @@
-import MockAdapter from 'axios-mock-adapter';
-import testAction from 'spec/helpers/vuex_action_helper';
-import { TEST_HOST } from 'spec/test_constants';
-import axios from '~/lib/utils/axios_utils';
-import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
-import actionsDefaultExport, * as actions from '~/error_tracking_settings/store/actions';
-import * as types from '~/error_tracking_settings/store/mutation_types';
-import defaultState from '~/error_tracking_settings/store/state';
-import { projectList } from '../mock';
-
-describe('error tracking settings actions', () => {
- let state;
-
- describe('project list actions', () => {
- let mock;
-
- beforeEach(() => {
- mock = new MockAdapter(axios);
- state = { ...defaultState(), listProjectsEndpoint: TEST_HOST };
- });
-
- afterEach(() => {
- mock.restore();
- });
-
- it('should request and transform the project list', done => {
- mock.onPost(TEST_HOST).reply(() => [200, { projects: projectList }]);
- testAction(
- actions.fetchProjects,
- null,
- state,
- [],
- [
- { type: 'requestProjects' },
- {
- type: 'receiveProjectsSuccess',
- payload: projectList.map(convertObjectPropsToCamelCase),
- },
- ],
- () => {
- expect(mock.history.post.length).toBe(1);
- done();
- },
- );
- });
-
- it('should handle a server error', done => {
- mock.onPost(`${TEST_HOST}.json`).reply(() => [400]);
- testAction(
- actions.fetchProjects,
- null,
- state,
- [],
- [
- { type: 'requestProjects' },
- {
- type: 'receiveProjectsError',
- },
- ],
- () => {
- expect(mock.history.post.length).toBe(1);
- done();
- },
- );
- });
-
- it('should request projects correctly', done => {
- testAction(actions.requestProjects, null, state, [{ type: types.RESET_CONNECT }], [], done);
- });
-
- it('should receive projects correctly', done => {
- const testPayload = [];
- testAction(
- actions.receiveProjectsSuccess,
- testPayload,
- state,
- [
- { type: types.UPDATE_CONNECT_SUCCESS },
- { type: types.RECEIVE_PROJECTS, payload: testPayload },
- ],
- [],
- done,
- );
- });
-
- it('should handle errors when receiving projects', done => {
- const testPayload = [];
- testAction(
- actions.receiveProjectsError,
- testPayload,
- state,
- [{ type: types.UPDATE_CONNECT_ERROR }, { type: types.CLEAR_PROJECTS }],
- [],
- done,
- );
- });
- });
-
- describe('save changes actions', () => {
- let mock;
-
- beforeEach(() => {
- mock = new MockAdapter(axios);
- state = {
- operationsSettingsEndpoint: TEST_HOST,
- };
- });
-
- afterEach(() => {
- mock.restore();
- });
-
- it('should save the page', done => {
- const refreshCurrentPage = spyOnDependency(actionsDefaultExport, 'refreshCurrentPage');
- mock.onPatch(TEST_HOST).reply(200);
- testAction(actions.updateSettings, null, state, [], [{ type: 'requestSettings' }], () => {
- expect(mock.history.patch.length).toBe(1);
- expect(refreshCurrentPage).toHaveBeenCalled();
- done();
- });
- });
-
- it('should handle a server error', done => {
- mock.onPatch(TEST_HOST).reply(400);
- testAction(
- actions.updateSettings,
- null,
- state,
- [],
- [
- { type: 'requestSettings' },
- {
- type: 'receiveSettingsError',
- payload: new Error('Request failed with status code 400'),
- },
- ],
- () => {
- expect(mock.history.patch.length).toBe(1);
- done();
- },
- );
- });
-
- it('should request to save the page', done => {
- testAction(
- actions.requestSettings,
- null,
- state,
- [{ type: types.UPDATE_SETTINGS_LOADING, payload: true }],
- [],
- done,
- );
- });
-
- it('should handle errors when requesting to save the page', done => {
- testAction(
- actions.receiveSettingsError,
- {},
- state,
- [{ type: types.UPDATE_SETTINGS_LOADING, payload: false }],
- [],
- done,
- );
- });
- });
-
- describe('generic actions to update the store', () => {
- const testData = 'test';
- it('should reset the `connect success` flag when updating the api host', done => {
- testAction(
- actions.updateApiHost,
- testData,
- state,
- [{ type: types.UPDATE_API_HOST, payload: testData }, { type: types.RESET_CONNECT }],
- [],
- done,
- );
- });
-
- it('should reset the `connect success` flag when updating the token', done => {
- testAction(
- actions.updateToken,
- testData,
- state,
- [{ type: types.UPDATE_TOKEN, payload: testData }, { type: types.RESET_CONNECT }],
- [],
- done,
- );
- });
- });
-});
diff --git a/spec/javascripts/error_tracking_settings/store/mutation_spec.js b/spec/javascripts/error_tracking_settings/store/mutation_spec.js
deleted file mode 100644
index bb1f1da784e..00000000000
--- a/spec/javascripts/error_tracking_settings/store/mutation_spec.js
+++ /dev/null
@@ -1,82 +0,0 @@
-import { TEST_HOST } from 'spec/test_constants';
-import mutations from '~/error_tracking_settings/store/mutations';
-import defaultState from '~/error_tracking_settings/store/state';
-import * as types from '~/error_tracking_settings/store/mutation_types';
-import {
- initialEmptyState,
- initialPopulatedState,
- projectList,
- sampleBackendProject,
- normalizedProject,
-} from '../mock';
-
-describe('error tracking settings mutations', () => {
- describe('mutations', () => {
- let state;
-
- beforeEach(() => {
- state = defaultState();
- });
-
- it('should create an empty initial state correctly', () => {
- mutations[types.SET_INITIAL_STATE](state, {
- ...initialEmptyState,
- });
-
- expect(state.apiHost).toEqual('');
- expect(state.enabled).toEqual(false);
- expect(state.selectedProject).toEqual(null);
- expect(state.token).toEqual('');
- expect(state.listProjectsEndpoint).toEqual(TEST_HOST);
- expect(state.operationsSettingsEndpoint).toEqual(TEST_HOST);
- });
-
- it('should populate the initial state correctly', () => {
- mutations[types.SET_INITIAL_STATE](state, {
- ...initialPopulatedState,
- });
-
- expect(state.apiHost).toEqual('apiHost');
- expect(state.enabled).toEqual(true);
- expect(state.selectedProject).toEqual(projectList[0]);
- expect(state.token).toEqual('token');
- expect(state.listProjectsEndpoint).toEqual(TEST_HOST);
- expect(state.operationsSettingsEndpoint).toEqual(TEST_HOST);
- });
-
- it('should receive projects successfully', () => {
- mutations[types.RECEIVE_PROJECTS](state, [sampleBackendProject]);
-
- expect(state.projects).toEqual([normalizedProject]);
- });
-
- it('should strip out unnecessary project properties', () => {
- mutations[types.RECEIVE_PROJECTS](state, [
- { ...sampleBackendProject, extra_property: 'extra_property' },
- ]);
-
- expect(state.projects).toEqual([normalizedProject]);
- });
-
- it('should update state when connect is successful', () => {
- mutations[types.UPDATE_CONNECT_SUCCESS](state);
-
- expect(state.connectSuccessful).toBe(true);
- expect(state.connectError).toBe(false);
- });
-
- it('should update state when connect fails', () => {
- mutations[types.UPDATE_CONNECT_ERROR](state);
-
- expect(state.connectSuccessful).toBe(false);
- expect(state.connectError).toBe(true);
- });
-
- it('should update state when connect is reset', () => {
- mutations[types.RESET_CONNECT](state);
-
- expect(state.connectSuccessful).toBe(false);
- expect(state.connectError).toBe(false);
- });
- });
-});
diff --git a/spec/javascripts/ide/components/repo_editor_spec.js b/spec/javascripts/ide/components/repo_editor_spec.js
index f832096701f..7dc5cb24981 100644
--- a/spec/javascripts/ide/components/repo_editor_spec.js
+++ b/spec/javascripts/ide/components/repo_editor_spec.js
@@ -30,6 +30,7 @@ describe('RepoEditor', () => {
Vue.set(vm.$store.state.entries, f.path, f);
spyOn(vm, 'getFileData').and.returnValue(Promise.resolve());
+ spyOn(vm, 'getRawFileData').and.returnValue(Promise.resolve());
vm.$mount();
@@ -407,6 +408,44 @@ describe('RepoEditor', () => {
});
});
+ describe('initEditor', () => {
+ beforeEach(() => {
+ spyOn(vm.editor, 'createInstance');
+ spyOnProperty(vm, 'shouldHideEditor').and.returnValue(true);
+ });
+
+ it('is being initialised for files without content even if shouldHideEditor is `true`', done => {
+ vm.file.content = '';
+ vm.file.raw = '';
+
+ vm.initEditor();
+ vm.$nextTick()
+ .then(() => {
+ expect(vm.getFileData).toHaveBeenCalled();
+ expect(vm.getRawFileData).toHaveBeenCalled();
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+
+ it('does not initialize editor for files already with content', done => {
+ expect(vm.getFileData.calls.count()).toEqual(1);
+ expect(vm.getRawFileData.calls.count()).toEqual(1);
+
+ vm.file.content = 'foo';
+
+ vm.initEditor();
+ vm.$nextTick()
+ .then(() => {
+ expect(vm.getFileData.calls.count()).toEqual(1);
+ expect(vm.getRawFileData.calls.count()).toEqual(1);
+ expect(vm.editor.createInstance).not.toHaveBeenCalled();
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+ });
+
it('calls removePendingTab when old file is pending', done => {
spyOnProperty(vm, 'shouldHideEditor').and.returnValue(true);
spyOn(vm, 'removePendingTab');
@@ -416,6 +455,7 @@ describe('RepoEditor', () => {
vm.$nextTick()
.then(() => {
vm.file = file('testing');
+ vm.file.content = 'foo'; // need to prevent full cycle of initEditor
return vm.$nextTick();
})
diff --git a/spec/javascripts/ide/stores/actions_spec.js b/spec/javascripts/ide/stores/actions_spec.js
index 2d105103c1c..8504fb3f42b 100644
--- a/spec/javascripts/ide/stores/actions_spec.js
+++ b/spec/javascripts/ide/stores/actions_spec.js
@@ -10,6 +10,7 @@ import actions, {
deleteEntry,
renameEntry,
getBranchData,
+ createTempEntry,
} from '~/ide/stores/actions';
import axios from '~/lib/utils/axios_utils';
import store from '~/ide/stores';
@@ -247,18 +248,30 @@ describe('Multi-file store actions', () => {
});
it('sets tmp file as active', done => {
- store
- .dispatch('createTempEntry', {
+ testAction(
+ createTempEntry,
+ {
name: 'test',
branchId: 'mybranch',
type: 'blob',
- })
- .then(f => {
- expect(f.active).toBeTruthy();
-
- done();
- })
- .catch(done.fail);
+ },
+ store.state,
+ [
+ { type: types.CREATE_TMP_ENTRY, payload: jasmine.any(Object) },
+ { type: types.TOGGLE_FILE_OPEN, payload: 'test' },
+ { type: types.ADD_FILE_TO_CHANGED, payload: 'test' },
+ ],
+ [
+ {
+ type: 'setFileActive',
+ payload: 'test',
+ },
+ {
+ type: 'triggerFilesChange',
+ },
+ ],
+ done,
+ );
});
it('creates flash message if file already exists', done => {
@@ -488,7 +501,11 @@ describe('Multi-file store actions', () => {
'path',
store.state,
[{ type: types.DELETE_ENTRY, payload: 'path' }],
- [{ type: 'burstUnusedSeal' }, { type: 'triggerFilesChange' }],
+ [
+ { type: 'burstUnusedSeal' },
+ { type: 'stageChange', payload: 'path' },
+ { type: 'triggerFilesChange' },
+ ],
done,
);
});
@@ -515,7 +532,11 @@ describe('Multi-file store actions', () => {
'testFolder/entry-to-delete',
store.state,
[{ type: types.DELETE_ENTRY, payload: 'testFolder/entry-to-delete' }],
- [{ type: 'burstUnusedSeal' }, { type: 'triggerFilesChange' }],
+ [
+ { type: 'burstUnusedSeal' },
+ { type: 'stageChange', payload: 'testFolder/entry-to-delete' },
+ { type: 'triggerFilesChange' },
+ ],
done,
);
});
diff --git a/spec/javascripts/ide/stores/mutations/file_spec.js b/spec/javascripts/ide/stores/mutations/file_spec.js
index efd0d86552b..7714f66c9a4 100644
--- a/spec/javascripts/ide/stores/mutations/file_spec.js
+++ b/spec/javascripts/ide/stores/mutations/file_spec.js
@@ -83,6 +83,26 @@ describe('IDE store file mutations', () => {
expect(localFile.raw).toBeNull();
expect(localFile.baseRaw).toBeNull();
});
+
+ it('sets extra file data to all arrays concerned', () => {
+ localState.stagedFiles = [localFile];
+ localState.changedFiles = [localFile];
+ localState.openFiles = [localFile];
+
+ const rawPath = 'foo/bar/blah.md';
+
+ mutations.SET_FILE_DATA(localState, {
+ data: {
+ raw_path: rawPath,
+ },
+ file: localFile,
+ });
+
+ expect(localState.stagedFiles[0].rawPath).toEqual(rawPath);
+ expect(localState.changedFiles[0].rawPath).toEqual(rawPath);
+ expect(localState.openFiles[0].rawPath).toEqual(rawPath);
+ expect(localFile.rawPath).toEqual(rawPath);
+ });
});
describe('SET_FILE_RAW_DATA', () => {
@@ -315,6 +335,19 @@ describe('IDE store file mutations', () => {
expect(localState.stagedFiles.length).toBe(1);
expect(localState.stagedFiles[0].raw).toEqual('testing 123');
});
+
+ it('adds already-staged file to `replacedFiles`', () => {
+ localFile.raw = 'already-staged';
+
+ mutations.STAGE_CHANGE(localState, localFile.path);
+
+ localFile.raw = 'testing 123';
+
+ mutations.STAGE_CHANGE(localState, localFile.path);
+
+ expect(localState.replacedFiles.length).toBe(1);
+ expect(localState.replacedFiles[0].raw).toEqual('already-staged');
+ });
});
describe('UNSTAGE_CHANGE', () => {
diff --git a/spec/javascripts/ide/stores/mutations_spec.js b/spec/javascripts/ide/stores/mutations_spec.js
index 460c5b01081..2470c99e300 100644
--- a/spec/javascripts/ide/stores/mutations_spec.js
+++ b/spec/javascripts/ide/stores/mutations_spec.js
@@ -79,6 +79,16 @@ describe('Multi-file store mutations', () => {
});
});
+ describe('CLEAR_REPLACED_FILES', () => {
+ it('clears replacedFiles array', () => {
+ localState.replacedFiles.push('a');
+
+ mutations.CLEAR_REPLACED_FILES(localState);
+
+ expect(localState.replacedFiles.length).toBe(0);
+ });
+ });
+
describe('UPDATE_VIEWER', () => {
it('sets viewer state', () => {
mutations.UPDATE_VIEWER(localState, 'diff');
@@ -109,6 +119,62 @@ describe('Multi-file store mutations', () => {
});
});
+ describe('CREATE_TMP_ENTRY', () => {
+ beforeEach(() => {
+ localState.currentProjectId = 'gitlab-ce';
+ localState.currentBranchId = 'master';
+ localState.trees['gitlab-ce/master'] = {
+ tree: [],
+ };
+ });
+
+ it('creates temp entry in the tree', () => {
+ const tmpFile = file('test');
+ mutations.CREATE_TMP_ENTRY(localState, {
+ data: {
+ entries: {
+ test: {
+ ...tmpFile,
+ tempFile: true,
+ changed: true,
+ },
+ },
+ treeList: [tmpFile],
+ },
+ projectId: 'gitlab-ce',
+ branchId: 'master',
+ });
+
+ expect(localState.trees['gitlab-ce/master'].tree.length).toEqual(1);
+ expect(localState.entries.test.tempFile).toEqual(true);
+ });
+
+ it('marks entry as replacing previous entry if the old one has been deleted', () => {
+ const tmpFile = file('test');
+ localState.entries.test = {
+ ...tmpFile,
+ deleted: true,
+ };
+ mutations.CREATE_TMP_ENTRY(localState, {
+ data: {
+ entries: {
+ test: {
+ ...tmpFile,
+ tempFile: true,
+ changed: true,
+ },
+ },
+ treeList: [tmpFile],
+ },
+ projectId: 'gitlab-ce',
+ branchId: 'master',
+ });
+
+ expect(localState.trees['gitlab-ce/master'].tree.length).toEqual(1);
+ expect(localState.entries.test.replaces).toEqual(true);
+ });
+ });
+
describe('UPDATE_TEMP_FLAG', () => {
beforeEach(() => {
localState.entries.test = {
@@ -252,6 +318,7 @@ describe('Multi-file store mutations', () => {
permalink: `${gl.TEST_HOST}/testing-123`,
commitsPath: `${gl.TEST_HOST}/testing-123`,
blamePath: `${gl.TEST_HOST}/testing-123`,
+ replaces: true,
};
localState.entries.test = f;
localState.changedFiles.push(f);
@@ -262,6 +329,7 @@ describe('Multi-file store mutations', () => {
expect(f.permalink).toBe(`${gl.TEST_HOST}/test`);
expect(f.commitsPath).toBe(`${gl.TEST_HOST}/test`);
expect(f.blamePath).toBe(`${gl.TEST_HOST}/test`);
+ expect(f.replaces).toBe(false);
});
});
diff --git a/spec/javascripts/ide/stores/utils_spec.js b/spec/javascripts/ide/stores/utils_spec.js
index e3bf6d40245..bceb3a8db91 100644
--- a/spec/javascripts/ide/stores/utils_spec.js
+++ b/spec/javascripts/ide/stores/utils_spec.js
@@ -92,6 +92,16 @@ describe('Multi-file store utils', () => {
path: 'deletedFile',
deleted: true,
},
+ {
+ ...file('renamedFile'),
+ path: 'renamedFile',
+ prevPath: 'prevPath',
+ },
+ {
+ ...file('replacingFile'),
+ path: 'replacingFile',
+ replaces: true,
+ },
],
currentBranchId: 'master',
};
@@ -131,6 +141,22 @@ describe('Multi-file store utils', () => {
last_commit_id: undefined,
previous_path: undefined,
},
+ {
+ action: commitActionTypes.move,
+ file_path: 'renamedFile',
+ content: null,
+ encoding: 'text',
+ last_commit_id: undefined,
+ previous_path: 'prevPath',
+ },
+ {
+ action: commitActionTypes.update,
+ file_path: 'replacingFile',
+ content: undefined,
+ encoding: 'text',
+ last_commit_id: undefined,
+ previous_path: undefined,
+ },
],
start_sha: undefined,
});
diff --git a/spec/javascripts/issuable_spec.js b/spec/javascripts/issuable_spec.js
index 25543053eba..4d57bfb1b33 100644
--- a/spec/javascripts/issuable_spec.js
+++ b/spec/javascripts/issuable_spec.js
@@ -2,14 +2,14 @@ import $ from 'jquery';
import MockAdaptor from 'axios-mock-adapter';
import axios from '~/lib/utils/axios_utils';
import IssuableIndex from '~/issuable_index';
+import issuableInitBulkUpdateSidebar from '~/issuable_init_bulk_update_sidebar';
describe('Issuable', () => {
- let Issuable;
describe('initBulkUpdate', () => {
it('should not set bulkUpdateSidebar', () => {
- Issuable = new IssuableIndex('issue_');
+ new IssuableIndex('issue_'); // eslint-disable-line no-new
- expect(Issuable.bulkUpdateSidebar).not.toBeDefined();
+ expect(issuableInitBulkUpdateSidebar.bulkUpdateSidebar).toBeNull();
});
it('should set bulkUpdateSidebar', () => {
@@ -17,9 +17,9 @@ describe('Issuable', () => {
element.classList.add('issues-bulk-update');
document.body.appendChild(element);
- Issuable = new IssuableIndex('issue_');
+ new IssuableIndex('issue_'); // eslint-disable-line no-new
- expect(Issuable.bulkUpdateSidebar).toBeDefined();
+ expect(issuableInitBulkUpdateSidebar.bulkUpdateSidebar).toBeDefined();
});
});
@@ -36,7 +36,7 @@ describe('Issuable', () => {
input.setAttribute('id', 'issuable_email');
document.body.appendChild(input);
- Issuable = new IssuableIndex('issue_');
+ new IssuableIndex('issue_'); // eslint-disable-line no-new
mock = new MockAdaptor(axios);
diff --git a/spec/javascripts/monitoring/dashboard_state_spec.js b/spec/javascripts/monitoring/dashboard_state_spec.js
deleted file mode 100644
index 6b2be83aa8c..00000000000
--- a/spec/javascripts/monitoring/dashboard_state_spec.js
+++ /dev/null
@@ -1,101 +0,0 @@
-import Vue from 'vue';
-import EmptyState from '~/monitoring/components/empty_state.vue';
-import { statePaths } from './mock_data';
-
-function createComponent(props) {
- const Component = Vue.extend(EmptyState);
-
- return new Component({
- propsData: {
- ...props,
- settingsPath: statePaths.settingsPath,
- clustersPath: statePaths.clustersPath,
- documentationPath: statePaths.documentationPath,
- emptyGettingStartedSvgPath: '/path/to/getting-started.svg',
- emptyLoadingSvgPath: '/path/to/loading.svg',
- emptyNoDataSvgPath: '/path/to/no-data.svg',
- emptyUnableToConnectSvgPath: '/path/to/unable-to-connect.svg',
- },
- }).$mount();
-}
-
-function getTextFromNode(component, selector) {
- return component.$el.querySelector(selector).firstChild.nodeValue.trim();
-}
-
-describe('EmptyState', () => {
- describe('Computed props', () => {
- it('currentState', () => {
- const component = createComponent({
- selectedState: 'gettingStarted',
- });
-
- expect(component.currentState).toBe(component.states.gettingStarted);
- });
-
- it('showButtonDescription returns a description with a link for the unableToConnect state', () => {
- const component = createComponent({
- selectedState: 'unableToConnect',
- });
-
- expect(component.showButtonDescription).toEqual(true);
- });
-
- it('showButtonDescription returns the description without a link for any other state', () => {
- const component = createComponent({
- selectedState: 'loading',
- });
-
- expect(component.showButtonDescription).toEqual(false);
- });
- });
-
- it('should show the gettingStarted state', () => {
- const component = createComponent({
- selectedState: 'gettingStarted',
- });
-
- expect(component.$el.querySelector('svg')).toBeDefined();
- expect(getTextFromNode(component, '.state-title')).toEqual(
- component.states.gettingStarted.title,
- );
-
- expect(getTextFromNode(component, '.state-description')).toEqual(
- component.states.gettingStarted.description,
- );
-
- expect(getTextFromNode(component, '.btn-success')).toEqual(
- component.states.gettingStarted.buttonText,
- );
- });
-
- it('should show the loading state', () => {
- const component = createComponent({
- selectedState: 'loading',
- });
-
- expect(component.$el.querySelector('svg')).toBeDefined();
- expect(getTextFromNode(component, '.state-title')).toEqual(component.states.loading.title);
- expect(getTextFromNode(component, '.state-description')).toEqual(
- component.states.loading.description,
- );
-
- expect(getTextFromNode(component, '.btn-success')).toEqual(component.states.loading.buttonText);
- });
-
- it('should show the unableToConnect state', () => {
- const component = createComponent({
- selectedState: 'unableToConnect',
- });
-
- expect(component.$el.querySelector('svg')).toBeDefined();
- expect(getTextFromNode(component, '.state-title')).toEqual(
- component.states.unableToConnect.title,
- );
-
- expect(component.$el.querySelector('.state-description a')).toBeDefined();
- expect(getTextFromNode(component, '.btn-success')).toEqual(
- component.states.unableToConnect.buttonText,
- );
- });
-});
diff --git a/spec/javascripts/monitoring/store/utils_spec.js b/spec/javascripts/monitoring/store/utils_spec.js
new file mode 100644
index 00000000000..73dd370ffb3
--- /dev/null
+++ b/spec/javascripts/monitoring/store/utils_spec.js
@@ -0,0 +1,37 @@
+import { groupQueriesByChartInfo } from '~/monitoring/stores/utils';
+
+describe('groupQueriesByChartInfo', () => {
+ let input;
+ let output;
+
+ it('groups metrics with the same chart title and y_axis label', () => {
+ input = [
+ { title: 'title', y_label: 'MB', queries: [{}] },
+ { title: 'title', y_label: 'MB', queries: [{}] },
+ { title: 'new title', y_label: 'MB', queries: [{}] },
+ ];
+
+ output = [
+ { title: 'title', y_label: 'MB', queries: [{ metricId: null }, { metricId: null }] },
+ { title: 'new title', y_label: 'MB', queries: [{ metricId: null }] },
+ ];
+
+ expect(groupQueriesByChartInfo(input)).toEqual(output);
+ });
+
+ // Functionality associated with the /additional_metrics endpoint
+ it("associates a chart's stringified metric_id with the metric", () => {
+ input = [{ id: 3, title: 'new title', y_label: 'MB', queries: [{}] }];
+ output = [{ id: 3, title: 'new title', y_label: 'MB', queries: [{ metricId: '3' }] }];
+
+ expect(groupQueriesByChartInfo(input)).toEqual(output);
+ });
+
+ // Functionality associated with the /metrics_dashboard endpoint
+ it('aliases a stringified metrics_id on the metric to the metricId key', () => {
+ input = [{ title: 'new title', y_label: 'MB', queries: [{ metric_id: 3 }] }];
+ output = [{ title: 'new title', y_label: 'MB', queries: [{ metricId: '3', metric_id: 3 }] }];
+
+ expect(groupQueriesByChartInfo(input)).toEqual(output);
+ });
+});
diff --git a/spec/javascripts/notes/components/comment_form_spec.js b/spec/javascripts/notes/components/comment_form_spec.js
index 362963ddaf4..88c86746992 100644
--- a/spec/javascripts/notes/components/comment_form_spec.js
+++ b/spec/javascripts/notes/components/comment_form_spec.js
@@ -251,6 +251,21 @@ describe('issue_comment_form component', () => {
});
});
});
+
+ describe('when toggling state', () => {
+ it('should update MR count', done => {
+ spyOn(vm, 'closeIssue').and.returnValue(Promise.resolve());
+
+ const updateMrCountSpy = spyOnDependency(CommentForm, 'refreshUserMergeRequestCounts');
+ vm.toggleIssueState();
+
+ Vue.nextTick(() => {
+ expect(updateMrCountSpy).toHaveBeenCalled();
+
+ done();
+ });
+ });
+ });
});
describe('issue is confidential', () => {
diff --git a/spec/javascripts/notes/components/noteable_discussion_spec.js b/spec/javascripts/notes/components/noteable_discussion_spec.js
index efa864e7d00..74805ca8c00 100644
--- a/spec/javascripts/notes/components/noteable_discussion_spec.js
+++ b/spec/javascripts/notes/components/noteable_discussion_spec.js
@@ -36,14 +36,20 @@ describe('noteable_discussion component', () => {
});
it('should render user avatar', () => {
+ const discussion = { ...discussionMock };
+ discussion.diff_file = mockDiffFile;
+ discussion.diff_discussion = true;
+
+ wrapper.setProps({ discussion, renderDiffFile: true });
+
expect(wrapper.find('.user-avatar-link').exists()).toBe(true);
});
- it('should not render discussion header for non diff discussions', () => {
+ it('should not render thread header for non diff threads', () => {
expect(wrapper.find('.discussion-header').exists()).toBe(false);
});
- it('should render discussion header', done => {
+ it('should render thread header', done => {
const discussion = { ...discussionMock };
discussion.diff_file = mockDiffFile;
discussion.diff_discussion = true;
@@ -90,16 +96,16 @@ describe('noteable_discussion component', () => {
.catch(done.fail);
});
- it('does not render jump to discussion button', () => {
- expect(
- wrapper.find('*[data-original-title="Jump to next unresolved discussion"]').exists(),
- ).toBe(false);
+ it('does not render jump to thread button', () => {
+ expect(wrapper.find('*[data-original-title="Jump to next unresolved thread"]').exists()).toBe(
+ false,
+ );
});
});
describe('methods', () => {
describe('jumpToNextDiscussion', () => {
- it('expands next unresolved discussion', done => {
+ it('expands next unresolved thread', done => {
const discussion2 = getJSONFixture(discussionWithTwoUnresolvedNotes)[0];
discussion2.resolved = false;
discussion2.active = true;
@@ -114,9 +120,7 @@ describe('noteable_discussion component', () => {
const nextDiscussionId = discussion2.id;
- setFixtures(`
- <div class="discussion" data-discussion-id="${nextDiscussionId}"></div>
- `);
+ setFixtures(`<div class="discussion" data-discussion-id="${nextDiscussionId}"></div>`);
wrapper.vm.jumpToNextDiscussion();
@@ -162,20 +166,20 @@ describe('noteable_discussion component', () => {
.catch(done.fail);
});
- describe('for commit discussions', () => {
- it('should display a monospace started a discussion on commit', () => {
- expect(wrapper.text()).toContain(`started a discussion on commit ${truncatedCommitId}`);
+ describe('for commit threads', () => {
+ it('should display a monospace started a thread on commit', () => {
+ expect(wrapper.text()).toContain(`started a thread on commit ${truncatedCommitId}`);
expect(commitElement.exists()).toBe(true);
expect(commitElement.text()).toContain(truncatedCommitId);
});
});
- describe('for diff discussion with a commit id', () => {
- it('should display started discussion on commit header', done => {
+ describe('for diff thread with a commit id', () => {
+ it('should display started thread on commit header', done => {
wrapper.vm.discussion.for_commit = false;
wrapper.vm.$nextTick(() => {
- expect(wrapper.text()).toContain(`started a discussion on commit ${truncatedCommitId}`);
+ expect(wrapper.text()).toContain(`started a thread on commit ${truncatedCommitId}`);
expect(commitElement).not.toBe(null);
@@ -189,7 +193,7 @@ describe('noteable_discussion component', () => {
wrapper.vm.$nextTick(() => {
expect(wrapper.text()).toContain(
- `started a discussion on an outdated change in commit ${truncatedCommitId}`,
+ `started a thread on an outdated change in commit ${truncatedCommitId}`,
);
expect(commitElement).not.toBe(null);
@@ -199,21 +203,21 @@ describe('noteable_discussion component', () => {
});
});
- describe('for diff discussions without a commit id', () => {
- it('should show started a discussion on the diff text', done => {
+ describe('for diff threads without a commit id', () => {
+ it('should show started a thread on the diff text', done => {
Object.assign(wrapper.vm.discussion, {
for_commit: false,
commit_id: null,
});
wrapper.vm.$nextTick(() => {
- expect(wrapper.text()).toContain('started a discussion on the diff');
+ expect(wrapper.text()).toContain('started a thread on the diff');
done();
});
});
- it('should show discussion on older version text', done => {
+ it('should show thread on older version text', done => {
Object.assign(wrapper.vm.discussion, {
for_commit: false,
commit_id: null,
@@ -221,7 +225,7 @@ describe('noteable_discussion component', () => {
});
wrapper.vm.$nextTick(() => {
- expect(wrapper.text()).toContain('started a discussion on an old version of the diff');
+ expect(wrapper.text()).toContain('started a thread on an old version of the diff');
done();
});
@@ -229,7 +233,7 @@ describe('noteable_discussion component', () => {
});
});
- describe('for resolved discussion', () => {
+ describe('for resolved thread', () => {
beforeEach(() => {
const discussion = getJSONFixture(discussionWithTwoUnresolvedNotes)[0];
wrapper.setProps({ discussion });
@@ -242,7 +246,7 @@ describe('noteable_discussion component', () => {
});
});
- describe('for unresolved discussion', () => {
+ describe('for unresolved thread', () => {
beforeEach(done => {
const discussion = {
...getJSONFixture(discussionWithTwoUnresolvedNotes)[0],
diff --git a/spec/javascripts/notes/stores/actions_spec.js b/spec/javascripts/notes/stores/actions_spec.js
index 7a9f32ddcff..c97ff5236ec 100644
--- a/spec/javascripts/notes/stores/actions_spec.js
+++ b/spec/javascripts/notes/stores/actions_spec.js
@@ -1,6 +1,7 @@
import Vue from 'vue';
import $ from 'jquery';
import _ from 'underscore';
+import Api from '~/api';
import { TEST_HOST } from 'spec/test_constants';
import { headersInterceptor } from 'spec/helpers/vue_resource_helper';
import actionsModule, * as actions from '~/notes/stores/actions';
@@ -8,7 +9,6 @@ import * as mutationTypes from '~/notes/stores/mutation_types';
import * as notesConstants from '~/notes/constants';
import createStore from '~/notes/stores';
import mrWidgetEventHub from '~/vue_merge_request_widget/event_hub';
-import service from '~/notes/services/notes_service';
import testAction from '../../helpers/vuex_action_helper';
import { resetStore } from '../helpers';
import {
@@ -373,7 +373,7 @@ describe('Actions Notes Store', () => {
type: 'updateMergeRequestWidget',
},
{
- type: 'updateResolvableDiscussonsCounts',
+ type: 'updateResolvableDiscussionsCounts',
},
],
done,
@@ -400,7 +400,7 @@ describe('Actions Notes Store', () => {
type: 'updateMergeRequestWidget',
},
{
- type: 'updateResolvableDiscussonsCounts',
+ type: 'updateResolvableDiscussionsCounts',
},
{
type: 'diffs/removeDiscussionsFromDiff',
@@ -452,7 +452,7 @@ describe('Actions Notes Store', () => {
type: 'startTaskList',
},
{
- type: 'updateResolvableDiscussonsCounts',
+ type: 'updateResolvableDiscussionsCounts',
},
],
done,
@@ -527,7 +527,7 @@ describe('Actions Notes Store', () => {
],
[
{
- type: 'updateResolvableDiscussonsCounts',
+ type: 'updateResolvableDiscussionsCounts',
},
{
type: 'updateMergeRequestWidget',
@@ -552,7 +552,7 @@ describe('Actions Notes Store', () => {
],
[
{
- type: 'updateResolvableDiscussonsCounts',
+ type: 'updateResolvableDiscussionsCounts',
},
{
type: 'updateMergeRequestWidget',
@@ -587,10 +587,10 @@ describe('Actions Notes Store', () => {
});
});
- describe('updateResolvableDiscussonsCounts', () => {
+ describe('updateResolvableDiscussionsCounts', () => {
it('commits UPDATE_RESOLVABLE_DISCUSSIONS_COUNTS', done => {
testAction(
- actions.updateResolvableDiscussonsCounts,
+ actions.updateResolvableDiscussionsCounts,
null,
{},
[{ type: 'UPDATE_RESOLVABLE_DISCUSSIONS_COUNTS' }],
@@ -712,7 +712,7 @@ describe('Actions Notes Store', () => {
[
{ type: 'updateMergeRequestWidget' },
{ type: 'startTaskList' },
- { type: 'updateResolvableDiscussonsCounts' },
+ { type: 'updateResolvableDiscussionsCounts' },
],
done,
);
@@ -846,9 +846,9 @@ describe('Actions Notes Store', () => {
let flashContainer;
beforeEach(() => {
- spyOn(service, 'applySuggestion');
+ spyOn(Api, 'applySuggestion');
dispatch.and.returnValue(Promise.resolve());
- service.applySuggestion.and.returnValue(Promise.resolve());
+ Api.applySuggestion.and.returnValue(Promise.resolve());
flashContainer = {};
});
@@ -877,7 +877,7 @@ describe('Actions Notes Store', () => {
it('when service fails, flashes error message', done => {
const response = { response: { data: { message: TEST_ERROR_MESSAGE } } };
- service.applySuggestion.and.returnValue(Promise.reject(response));
+ Api.applySuggestion.and.returnValue(Promise.reject(response));
testSubmitSuggestion(done, () => {
expect(commit).not.toHaveBeenCalled();
diff --git a/spec/javascripts/performance_bar/components/simple_metric_spec.js b/spec/javascripts/performance_bar/components/simple_metric_spec.js
deleted file mode 100644
index 98b843e9711..00000000000
--- a/spec/javascripts/performance_bar/components/simple_metric_spec.js
+++ /dev/null
@@ -1,47 +0,0 @@
-import Vue from 'vue';
-import simpleMetric from '~/performance_bar/components/simple_metric.vue';
-import mountComponent from 'spec/helpers/vue_mount_component_helper';
-
-describe('simpleMetric', () => {
- let vm;
-
- afterEach(() => {
- vm.$destroy();
- });
-
- describe('when the current request has no details', () => {
- beforeEach(() => {
- vm = mountComponent(Vue.extend(simpleMetric), {
- currentRequest: {},
- metric: 'gitaly',
- });
- });
-
- it('does not display details', () => {
- expect(vm.$el.innerText).not.toContain('/');
- });
-
- it('displays the metric name', () => {
- expect(vm.$el.innerText).toContain('gitaly');
- });
- });
-
- describe('when the current request has details', () => {
- beforeEach(() => {
- vm = mountComponent(Vue.extend(simpleMetric), {
- currentRequest: {
- details: { gitaly: { duration: '123ms', calls: '456' } },
- },
- metric: 'gitaly',
- });
- });
-
- it('diplays details', () => {
- expect(vm.$el.innerText.replace(/\s+/g, ' ')).toContain('123ms / 456');
- });
-
- it('displays the metric name', () => {
- expect(vm.$el.innerText).toContain('gitaly');
- });
- });
-});
diff --git a/spec/javascripts/pipelines/pipelines_spec.js b/spec/javascripts/pipelines/pipelines_spec.js
index 78187b69563..daa898ca687 100644
--- a/spec/javascripts/pipelines/pipelines_spec.js
+++ b/spec/javascripts/pipelines/pipelines_spec.js
@@ -736,10 +736,9 @@ describe('Pipelines', () => {
});
describe('when a request is being made', () => {
- it('stops polling, cancels the request, fetches pipelines & restarts polling', done => {
+ it('stops polling, cancels the request, & restarts polling', done => {
spyOn(vm.poll, 'stop');
spyOn(vm.poll, 'restart');
- spyOn(vm, 'getPipelines').and.returnValue(Promise.resolve());
spyOn(vm.service.cancelationSource, 'cancel').and.callThrough();
setTimeout(() => {
@@ -754,7 +753,6 @@ describe('Pipelines', () => {
expect(vm.poll.stop).toHaveBeenCalled();
setTimeout(() => {
- expect(vm.getPipelines).toHaveBeenCalled();
expect(vm.poll.restart).toHaveBeenCalled();
done();
}, 0);
@@ -765,10 +763,9 @@ describe('Pipelines', () => {
});
describe('when no request is being made', () => {
- it('stops polling, fetches pipelines & restarts polling', done => {
+ it('stops polling & restarts polling', done => {
spyOn(vm.poll, 'stop');
spyOn(vm.poll, 'restart');
- spyOn(vm, 'getPipelines').and.returnValue(Promise.resolve());
setTimeout(() => {
vm.$el.querySelector('.js-builds-dropdown-button').click();
@@ -776,7 +773,6 @@ describe('Pipelines', () => {
expect(vm.poll.stop).toHaveBeenCalled();
setTimeout(() => {
- expect(vm.getPipelines).toHaveBeenCalled();
expect(vm.poll.restart).toHaveBeenCalled();
done();
}, 0);
diff --git a/spec/javascripts/registry/components/app_spec.js b/spec/javascripts/registry/components/app_spec.js
index 76a17e6fb31..87237d2853d 100644
--- a/spec/javascripts/registry/components/app_spec.js
+++ b/spec/javascripts/registry/components/app_spec.js
@@ -8,6 +8,13 @@ import { reposServerResponse } from '../mock_data';
describe('Registry List', () => {
const Component = Vue.extend(registry);
+ const props = {
+ endpoint: `${TEST_HOST}/foo`,
+ helpPagePath: 'foo',
+ noContainersImage: 'foo',
+ containersErrorImage: 'foo',
+ repositoryUrl: 'foo',
+ };
let vm;
let mock;
@@ -24,7 +31,7 @@ describe('Registry List', () => {
beforeEach(() => {
mock.onGet(`${TEST_HOST}/foo`).replyOnce(200, reposServerResponse);
- vm = mountComponent(Component, { endpoint: `${TEST_HOST}/foo` });
+ vm = mountComponent(Component, { ...props });
});
it('should render a list of repos', done => {
@@ -72,7 +79,7 @@ describe('Registry List', () => {
beforeEach(() => {
mock.onGet(`${TEST_HOST}/foo`).replyOnce(200, []);
- vm = mountComponent(Component, { endpoint: `${TEST_HOST}/foo` });
+ vm = mountComponent(Component, { ...props });
});
it('should render empty message', done => {
@@ -83,7 +90,7 @@ describe('Registry List', () => {
.textContent.trim()
.replace(/[\r\n]+/g, ' '),
).toEqual(
- 'No container images stored for this project. Add one by following the instructions above.',
+ 'With the Container Registry, every project can have its own space to store its Docker images. Learn more about the Container Registry.',
);
done();
}, 0);
@@ -94,7 +101,7 @@ describe('Registry List', () => {
beforeEach(() => {
mock.onGet(`${TEST_HOST}/foo`).replyOnce(200, []);
- vm = mountComponent(Component, { endpoint: `${TEST_HOST}/foo` });
+ vm = mountComponent(Component, { ...props });
});
it('should render a loading spinner', done => {
@@ -104,4 +111,22 @@ describe('Registry List', () => {
});
});
});
+
+ describe('invalid characters in path', () => {
+ beforeEach(() => {
+ mock.onGet(`${TEST_HOST}/foo`).replyOnce(200, []);
+
+ vm = mountComponent(Component, {
+ ...props,
+ characterError: true,
+ });
+ });
+
+ it('should render invalid characters error message', done => {
+ setTimeout(() => {
+ expect(vm.$el.querySelector('.container-message')).not.toBe(null);
+ done();
+ });
+ });
+ });
});
diff --git a/spec/javascripts/releases/components/release_block_spec.js b/spec/javascripts/releases/components/release_block_spec.js
index e98c665f99d..f761a18e326 100644
--- a/spec/javascripts/releases/components/release_block_spec.js
+++ b/spec/javascripts/releases/components/release_block_spec.js
@@ -14,7 +14,7 @@ describe('Release block', () => {
description_html: '<div><h2>changelog</h2><ul><li>line1</li<li>line 2</li></ul></div>',
author_name: 'Release bot',
author_email: 'release-bot@example.com',
- created_at: '2012-05-28T05:00:00-07:00',
+ released_at: '2012-05-28T05:00:00-07:00',
author: {
avatar_url: 'uploads/-/system/user/avatar/johndoe/avatar.png',
id: 482476,
@@ -101,7 +101,7 @@ describe('Release block', () => {
});
it('renders release date', () => {
- expect(vm.$el.textContent).toContain(timeagoMixin.methods.timeFormated(release.created_at));
+ expect(vm.$el.textContent).toContain(timeagoMixin.methods.timeFormated(release.released_at));
});
it('renders number of assets provided', () => {
@@ -152,13 +152,13 @@ describe('Release block', () => {
});
});
- describe('with pre_release flag', () => {
+ describe('with upcoming_release flag', () => {
beforeEach(() => {
- vm = factory(Object.assign({}, release, { pre_release: true }));
+ vm = factory(Object.assign({}, release, { upcoming_release: true }));
});
- it('renders pre-release badge', () => {
- expect(vm.$el.textContent).toContain('Pre-release');
+ it('renders upcoming release badge', () => {
+ expect(vm.$el.textContent).toContain('Upcoming Release');
});
});
});
diff --git a/spec/javascripts/sidebar/todo_spec.js b/spec/javascripts/sidebar/todo_spec.js
index f46ea5a0499..e7abd19c865 100644
--- a/spec/javascripts/sidebar/todo_spec.js
+++ b/spec/javascripts/sidebar/todo_spec.js
@@ -53,14 +53,14 @@ describe('SidebarTodo', () => {
describe('buttonLabel', () => {
it('returns todo button text for marking todo as done when `isTodo` prop is `true`', () => {
- expect(vm.buttonLabel).toBe('Mark todo as done');
+ expect(vm.buttonLabel).toBe('Mark as done');
});
it('returns todo button text for add todo when `isTodo` prop is `false`', done => {
vm.isTodo = false;
Vue.nextTick()
.then(() => {
- expect(vm.buttonLabel).toBe('Add todo');
+ expect(vm.buttonLabel).toBe('Add a To Do');
})
.then(done)
.catch(done.fail);
@@ -131,14 +131,14 @@ describe('SidebarTodo', () => {
});
it('check button label computed property', () => {
- expect(vm.buttonLabel).toEqual('Mark todo as done');
+ expect(vm.buttonLabel).toEqual('Mark as done');
});
it('renders button label element when `collapsed` prop is `false`', () => {
const buttonLabelEl = vm.$el.querySelector('span.issuable-todo-inner');
expect(buttonLabelEl).not.toBeNull();
- expect(buttonLabelEl.innerText.trim()).toBe('Mark todo as done');
+ expect(buttonLabelEl.innerText.trim()).toBe('Mark as done');
});
it('renders button icon when `collapsed` prop is `true`', done => {
diff --git a/spec/javascripts/test_bundle.js b/spec/javascripts/test_bundle.js
index 2cc476ed52a..50741e249ca 100644
--- a/spec/javascripts/test_bundle.js
+++ b/spec/javascripts/test_bundle.js
@@ -8,7 +8,6 @@ import '~/commons';
import Vue from 'vue';
import VueResource from 'vue-resource';
import Translate from '~/vue_shared/translate';
-import CheckEE from '~/vue_shared/mixins/is_ee';
import jasmineDiff from 'jasmine-diff';
import { config as testUtilsConfig } from '@vue/test-utils';
@@ -48,7 +47,6 @@ Vue.config.errorHandler = function(err) {
Vue.use(VueResource);
Vue.use(Translate);
-Vue.use(CheckEE);
// enable test fixtures
jasmine.getFixtures().fixturesPath = FIXTURES_PATH;
diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_ready_to_merge_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_ready_to_merge_spec.js
index bb76616be56..ba3ba01944d 100644
--- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_ready_to_merge_spec.js
+++ b/spec/javascripts/vue_mr_widget/components/states/mr_widget_ready_to_merge_spec.js
@@ -58,9 +58,11 @@ const createComponent = (customConfig = {}) => {
describe('ReadyToMerge', () => {
let vm;
+ let updateMrCountSpy;
beforeEach(() => {
vm = createComponent();
+ updateMrCountSpy = spyOnDependency(ReadyToMerge, 'refreshUserMergeRequestCounts');
});
afterEach(() => {
@@ -461,6 +463,7 @@ describe('ReadyToMerge', () => {
expect(eventHub.$emit).toHaveBeenCalledWith('MRWidgetUpdateRequested');
expect(eventHub.$emit).toHaveBeenCalledWith('FetchActionsContent');
expect(vm.initiateRemoveSourceBranchPolling).toHaveBeenCalled();
+ expect(updateMrCountSpy).toHaveBeenCalled();
expect(cpc).toBeFalsy();
expect(spc).toBeTruthy();
diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_unresolved_discussions_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_unresolved_discussions_spec.js
index bd64d7b2926..5bd1af56bcc 100644
--- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_unresolved_discussions_spec.js
+++ b/spec/javascripts/vue_mr_widget/components/states/mr_widget_unresolved_discussions_spec.js
@@ -10,7 +10,7 @@ describe('UnresolvedDiscussions', () => {
vm.$destroy();
});
- describe('with discussions path', () => {
+ describe('with threads path', () => {
beforeEach(() => {
vm = mountComponent(Component, {
mr: {
@@ -21,7 +21,7 @@ describe('UnresolvedDiscussions', () => {
it('should have correct elements', () => {
expect(vm.$el.innerText).toContain(
- 'There are unresolved discussions. Please resolve these discussions',
+ 'There are unresolved threads. Please resolve these threads',
);
expect(vm.$el.innerText).toContain('Create an issue to resolve them later');
@@ -29,14 +29,14 @@ describe('UnresolvedDiscussions', () => {
});
});
- describe('without discussions path', () => {
+ describe('without threads path', () => {
beforeEach(() => {
vm = mountComponent(Component, { mr: {} });
});
it('should not show create issue link if user cannot create issue', () => {
expect(vm.$el.innerText).toContain(
- 'There are unresolved discussions. Please resolve these discussions',
+ 'There are unresolved threads. Please resolve these threads',
);
expect(vm.$el.querySelector('.js-create-issue')).toEqual(null);
diff --git a/spec/javascripts/vue_shared/components/file_row_spec.js b/spec/javascripts/vue_shared/components/file_row_spec.js
index 7da69e3fa84..6abcac5c0ff 100644
--- a/spec/javascripts/vue_shared/components/file_row_spec.js
+++ b/spec/javascripts/vue_shared/components/file_row_spec.js
@@ -90,6 +90,19 @@ describe('File row component', () => {
expect(vm.$el.querySelector('.js-file-row-header')).not.toBe(null);
});
+ it('is not rendered for `moved` entries in subfolders', () => {
+ createComponent({
+ file: {
+ path: 't5',
+ moved: true,
+ tree: [],
+ },
+ level: 2,
+ });
+
+ expect(vm.$el.nodeType).not.toEqual(1);
+ });
+
describe('new dropdown', () => {
beforeEach(() => {
createComponent({
diff --git a/spec/javascripts/vue_shared/components/markdown/header_spec.js b/spec/javascripts/vue_shared/components/markdown/header_spec.js
deleted file mode 100644
index af92e5f5ae2..00000000000
--- a/spec/javascripts/vue_shared/components/markdown/header_spec.js
+++ /dev/null
@@ -1,111 +0,0 @@
-import Vue from 'vue';
-import $ from 'jquery';
-import headerComponent from '~/vue_shared/components/markdown/header.vue';
-
-describe('Markdown field header component', () => {
- let vm;
-
- beforeEach(done => {
- const Component = Vue.extend(headerComponent);
-
- vm = new Component({
- propsData: {
- previewMarkdown: false,
- },
- }).$mount();
-
- Vue.nextTick(done);
- });
-
- it('renders markdown header buttons', () => {
- const buttons = [
- 'Add bold text',
- 'Add italic text',
- 'Insert a quote',
- 'Insert suggestion',
- 'Insert code',
- 'Add a link',
- 'Add a bullet list',
- 'Add a numbered list',
- 'Add a task list',
- 'Add a table',
- 'Go full screen',
- ];
- const elements = vm.$el.querySelectorAll('.toolbar-btn');
-
- elements.forEach((buttonEl, index) => {
- expect(buttonEl.getAttribute('data-original-title')).toBe(buttons[index]);
- });
- });
-
- it('renders `write` link as active when previewMarkdown is false', () => {
- expect(vm.$el.querySelector('li:nth-child(1)').classList.contains('active')).toBeTruthy();
- });
-
- it('renders `preview` link as active when previewMarkdown is true', done => {
- vm.previewMarkdown = true;
-
- Vue.nextTick(() => {
- expect(vm.$el.querySelector('li:nth-child(2)').classList.contains('active')).toBeTruthy();
-
- done();
- });
- });
-
- it('emits toggle markdown event when clicking preview', () => {
- spyOn(vm, '$emit');
-
- vm.$el.querySelector('.js-preview-link').click();
-
- expect(vm.$emit).toHaveBeenCalledWith('preview-markdown');
-
- vm.$el.querySelector('.js-write-link').click();
-
- expect(vm.$emit).toHaveBeenCalledWith('write-markdown');
- });
-
- it('does not emit toggle markdown event when triggered from another form', () => {
- spyOn(vm, '$emit');
-
- $(document).triggerHandler('markdown-preview:show', [
- $(
- '<form><div class="js-vue-markdown-field"><textarea class="markdown-area"></textarea></div></form>',
- ),
- ]);
-
- expect(vm.$emit).not.toHaveBeenCalled();
- });
-
- it('blurs preview link after click', done => {
- const link = vm.$el.querySelector('li:nth-child(2) button');
- spyOn(HTMLElement.prototype, 'blur');
-
- link.click();
-
- setTimeout(() => {
- expect(link.blur).toHaveBeenCalled();
-
- done();
- });
- });
-
- it('renders markdown table template', () => {
- expect(vm.mdTable).toEqual(
- '| header | header |\n| ------ | ------ |\n| cell | cell |\n| cell | cell |',
- );
- });
-
- it('renders suggestion template', () => {
- vm.lineContent = 'Some content';
-
- expect(vm.mdSuggestion).toEqual('```suggestion:-0+0\n{text}\n```');
- });
-
- it('does not render suggestion button if `canSuggest` is set to false', () => {
- vm.canSuggest = false;
-
- Vue.nextTick(() => {
- expect(vm.$el.querySelector('.qa-suggestion-btn')).toBe(null);
- });
- });
-});
diff --git a/spec/lib/banzai/filter/relative_link_filter_spec.rb b/spec/lib/banzai/filter/relative_link_filter_spec.rb
index 8ff971114d6..a714fa50f5f 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 explode with an escaped null byte' do
+ act = link("/%00")
+ 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
diff --git a/spec/lib/feature_spec.rb b/spec/lib/feature_spec.rb
index 6f05914f915..127463a57e8 100644
--- a/spec/lib/feature_spec.rb
+++ b/spec/lib/feature_spec.rb
@@ -40,7 +40,7 @@ describe Feature do
.once
.and_call_original
- expect(Rails.cache)
+ expect(Gitlab::ThreadMemoryCache.cache_backend)
.to receive(:fetch)
.once
.with('flipper:persisted_names', expires_in: 1.minute)
@@ -144,6 +144,68 @@ describe Feature do
expect(described_class.enabled?(:enabled_feature_flag)).to be_truthy
end
+ it { expect(described_class.l1_cache_backend).to eq(Gitlab::ThreadMemoryCache.cache_backend) }
+ it { expect(described_class.l2_cache_backend).to eq(Rails.cache) }
+
+ it 'caches the status in L1 and L2 caches',
+ :request_store, :use_clean_rails_memory_store_caching do
+ described_class.enable(:enabled_feature_flag)
+ flipper_key = "flipper/v1/feature/enabled_feature_flag"
+
+ expect(described_class.l2_cache_backend)
+ .to receive(:fetch)
+ .once
+ .with(flipper_key, expires_in: 1.hour)
+ .and_call_original
+
+ expect(described_class.l1_cache_backend)
+ .to receive(:fetch)
+ .once
+ .with(flipper_key, expires_in: 1.minute)
+ .and_call_original
+
+ 2.times do
+ expect(described_class.enabled?(:enabled_feature_flag)).to be_truthy
+ end
+ end
+
+ context 'cached feature flag', :request_store do
+ let(:flag) { :some_feature_flag }
+
+ before do
+ described_class.flipper.memoize = false
+ described_class.enabled?(flag)
+ end
+
+ it 'caches the status in L1 cache for the first minute' do
+ expect do
+ expect(described_class.l1_cache_backend).to receive(:fetch).once.and_call_original
+ expect(described_class.l2_cache_backend).not_to receive(:fetch)
+ expect(described_class.enabled?(flag)).to be_truthy
+ end.not_to exceed_query_limit(0)
+ end
+
+ it 'caches the status in L2 cache after 2 minutes' do
+ Timecop.travel 2.minutes do
+ expect do
+ expect(described_class.l1_cache_backend).to receive(:fetch).once.and_call_original
+ expect(described_class.l2_cache_backend).to receive(:fetch).once.and_call_original
+ expect(described_class.enabled?(flag)).to be_truthy
+ end.not_to exceed_query_limit(0)
+ end
+ end
+
+ it 'fetches the status after an hour' do
+ Timecop.travel 61.minutes do
+ expect do
+ expect(described_class.l1_cache_backend).to receive(:fetch).once.and_call_original
+ expect(described_class.l2_cache_backend).to receive(:fetch).once.and_call_original
+ expect(described_class.enabled?(flag)).to be_truthy
+ end.not_to exceed_query_limit(1)
+ end
+ end
+ end
+
context 'with an individual actor' do
CustomActor = Struct.new(:flipper_id)
diff --git a/spec/lib/gitlab/asciidoc_spec.rb b/spec/lib/gitlab/asciidoc_spec.rb
index 0f933ac5464..8f2434acd26 100644
--- a/spec/lib/gitlab/asciidoc_spec.rb
+++ b/spec/lib/gitlab/asciidoc_spec.rb
@@ -56,7 +56,7 @@ module Gitlab
},
'pre' => {
input: '```mypre"><script>alert(3)</script>',
- output: "<div>\n<div>\n<pre lang=\"mypre\">\"&gt;<code></code></pre>\n</div>\n</div>"
+ output: "<div>\n<div>\n<pre class=\"code highlight js-syntax-highlight plaintext\" lang=\"plaintext\" v-pre=\"true\"><code><span id=\"LC1\" class=\"line\" lang=\"plaintext\">\"&gt;</span></code></pre>\n</div>\n</div>"
}
}
@@ -67,6 +67,72 @@ module Gitlab
end
end
+ context 'with fenced block' do
+ it 'highlights syntax' do
+ input = <<~ADOC
+ ```js
+ console.log('hello world')
+ ```
+ ADOC
+
+ output = <<~HTML
+ <div>
+ <div>
+ <pre class="code highlight js-syntax-highlight javascript" lang="javascript" v-pre="true"><code><span id="LC1" class="line" lang="javascript"><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="dl">'</span><span class="s1">hello world</span><span class="dl">'</span><span class="p">)</span></span></code></pre>
+ </div>
+ </div>
+ HTML
+
+ expect(render(input, context)).to include(output.strip)
+ end
+ end
+
+ context 'with listing block' do
+ it 'highlights syntax' do
+ input = <<~ADOC
+ [source,c++]
+ .class.cpp
+ ----
+ #include <stdio.h>
+
+ for (int i = 0; i < 5; i++) {
+ std::cout<<"*"<<std::endl;
+ }
+ ----
+ ADOC
+
+ output = <<~HTML
+ <div>
+ <div>class.cpp</div>
+ <div>
+ <pre class="code highlight js-syntax-highlight cpp" lang="cpp" v-pre="true"><code><span id="LC1" class="line" lang="cpp"><span class="cp">#include &lt;stdio.h&gt;</span></span>
+ <span id="LC2" class="line" lang="cpp"></span>
+ <span id="LC3" class="line" lang="cpp"><span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="mi">5</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span></span>
+ <span id="LC4" class="line" lang="cpp"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span><span class="o">&lt;&lt;</span><span class="s">"*"</span><span class="o">&lt;&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span></span>
+ <span id="LC5" class="line" lang="cpp"><span class="p">}</span></span></code></pre>
+ </div>
+ </div>
+ HTML
+
+ expect(render(input, context)).to include(output.strip)
+ end
+ end
+
+ context 'with stem block' do
+ it 'does not apply syntax highlighting' do
+ input = <<~ADOC
+ [stem]
+ ++++
+ \sqrt{4} = 2
+ ++++
+ ADOC
+
+ output = "<div>\n<div>\n\\$ qrt{4} = 2\\$\n</div>\n</div>"
+
+ expect(render(input, context)).to include(output)
+ end
+ end
+
context 'external links' do
it 'adds the `rel` attribute to the link' do
output = render('link:https://google.com[Google]', context)
diff --git a/spec/lib/gitlab/auth_spec.rb b/spec/lib/gitlab/auth_spec.rb
index 3b5ca7c950c..d9c73cff01e 100644
--- a/spec/lib/gitlab/auth_spec.rb
+++ b/spec/lib/gitlab/auth_spec.rb
@@ -309,6 +309,15 @@ describe Gitlab::Auth do
.to eq(auth_success)
end
+ it 'succeeds when custom login and token are valid' do
+ deploy_token = create(:deploy_token, username: 'deployer', read_registry: false, projects: [project])
+ auth_success = Gitlab::Auth::Result.new(deploy_token, project, :deploy_token, [:download_code])
+
+ expect(gl_auth).to receive(:rate_limit!).with('ip', success: true, login: 'deployer')
+ expect(gl_auth.find_for_git_client('deployer', deploy_token.token, project: project, ip: 'ip'))
+ .to eq(auth_success)
+ end
+
it 'fails when login is not valid' do
expect(gl_auth).to receive(:rate_limit!).with('ip', success: false, login: 'random_login')
expect(gl_auth.find_for_git_client('random_login', deploy_token.token, project: project, ip: 'ip'))
diff --git a/spec/lib/gitlab/background_migration/create_fork_network_memberships_range_spec.rb b/spec/lib/gitlab/background_migration/create_fork_network_memberships_range_spec.rb
deleted file mode 100644
index 5076996474f..00000000000
--- a/spec/lib/gitlab/background_migration/create_fork_network_memberships_range_spec.rb
+++ /dev/null
@@ -1,125 +0,0 @@
-require 'spec_helper'
-
-describe Gitlab::BackgroundMigration::CreateForkNetworkMembershipsRange, :migration, schema: 20170929131201 do
- let(:migration) { described_class.new }
- let(:projects) { table(:projects) }
-
- let(:base1) { projects.create }
- let(:base1_fork1) { projects.create }
- let(:base1_fork2) { projects.create }
-
- let(:base2) { projects.create }
- let(:base2_fork1) { projects.create }
- let(:base2_fork2) { projects.create }
-
- let(:fork_of_fork) { projects.create }
- let(:fork_of_fork2) { projects.create }
- let(:second_level_fork) { projects.create }
- let(:third_level_fork) { projects.create }
-
- let(:fork_network1) { fork_networks.find_by(root_project_id: base1.id) }
- let(:fork_network2) { fork_networks.find_by(root_project_id: base2.id) }
-
- let!(:forked_project_links) { table(:forked_project_links) }
- let!(:fork_networks) { table(:fork_networks) }
- let!(:fork_network_members) { table(:fork_network_members) }
-
- before do
- # The fork-network relation created for the forked project
- fork_networks.create(id: 1, root_project_id: base1.id)
- fork_network_members.create(project_id: base1.id, fork_network_id: 1)
- fork_networks.create(id: 2, root_project_id: base2.id)
- fork_network_members.create(project_id: base2.id, fork_network_id: 2)
-
- # Normal fork links
- forked_project_links.create(id: 1, forked_from_project_id: base1.id, forked_to_project_id: base1_fork1.id)
- forked_project_links.create(id: 2, forked_from_project_id: base1.id, forked_to_project_id: base1_fork2.id)
- forked_project_links.create(id: 3, forked_from_project_id: base2.id, forked_to_project_id: base2_fork1.id)
- forked_project_links.create(id: 4, forked_from_project_id: base2.id, forked_to_project_id: base2_fork2.id)
-
- # Fork links
- forked_project_links.create(id: 5, forked_from_project_id: base1_fork1.id, forked_to_project_id: fork_of_fork.id)
- forked_project_links.create(id: 6, forked_from_project_id: base1_fork1.id, forked_to_project_id: fork_of_fork2.id)
-
- # Forks 3 levels down
- forked_project_links.create(id: 7, forked_from_project_id: fork_of_fork.id, forked_to_project_id: second_level_fork.id)
- forked_project_links.create(id: 8, forked_from_project_id: second_level_fork.id, forked_to_project_id: third_level_fork.id)
-
- migration.perform(1, 8)
- end
-
- it 'creates a memberships for the direct forks' do
- base1_fork1_membership = fork_network_members.find_by(fork_network_id: fork_network1.id,
- project_id: base1_fork1.id)
- base1_fork2_membership = fork_network_members.find_by(fork_network_id: fork_network1.id,
- project_id: base1_fork2.id)
- base2_fork1_membership = fork_network_members.find_by(fork_network_id: fork_network2.id,
- project_id: base2_fork1.id)
- base2_fork2_membership = fork_network_members.find_by(fork_network_id: fork_network2.id,
- project_id: base2_fork2.id)
-
- expect(base1_fork1_membership.forked_from_project_id).to eq(base1.id)
- expect(base1_fork2_membership.forked_from_project_id).to eq(base1.id)
- expect(base2_fork1_membership.forked_from_project_id).to eq(base2.id)
- expect(base2_fork2_membership.forked_from_project_id).to eq(base2.id)
- end
-
- it 'adds the fork network members for forks of forks' do
- fork_of_fork_membership = fork_network_members.find_by(project_id: fork_of_fork.id,
- fork_network_id: fork_network1.id)
- fork_of_fork2_membership = fork_network_members.find_by(project_id: fork_of_fork2.id,
- fork_network_id: fork_network1.id)
- second_level_fork_membership = fork_network_members.find_by(project_id: second_level_fork.id,
- fork_network_id: fork_network1.id)
- third_level_fork_membership = fork_network_members.find_by(project_id: third_level_fork.id,
- fork_network_id: fork_network1.id)
-
- expect(fork_of_fork_membership.forked_from_project_id).to eq(base1_fork1.id)
- expect(fork_of_fork2_membership.forked_from_project_id).to eq(base1_fork1.id)
- expect(second_level_fork_membership.forked_from_project_id).to eq(fork_of_fork.id)
- expect(third_level_fork_membership.forked_from_project_id).to eq(second_level_fork.id)
- end
-
- it 'reschedules itself when there are missing members' do
- allow(migration).to receive(:missing_members?).and_return(true)
-
- expect(BackgroundMigrationWorker)
- .to receive(:perform_in).with(described_class::RESCHEDULE_DELAY, "CreateForkNetworkMembershipsRange", [1, 3])
-
- migration.perform(1, 3)
- end
-
- it 'can be repeated without effect' do
- expect { fork_network_members.count }.not_to change { migration.perform(1, 7) }
- end
-
- it 'knows it is finished for this range' do
- expect(migration.missing_members?(1, 8)).to be_falsy
- end
-
- it 'does not miss members for forks of forks for which the root was deleted' do
- forked_project_links.create(id: 9, forked_from_project_id: base1_fork1.id, forked_to_project_id: projects.create.id)
- base1.destroy
-
- expect(migration.missing_members?(7, 10)).to be_falsy
- end
-
- context 'with more forks' do
- before do
- forked_project_links.create(id: 9, forked_from_project_id: fork_of_fork.id, forked_to_project_id: projects.create.id)
- forked_project_links.create(id: 10, forked_from_project_id: fork_of_fork.id, forked_to_project_id: projects.create.id)
- end
-
- it 'only processes a single batch of links at a time' do
- expect(fork_network_members.count).to eq(10)
-
- migration.perform(8, 10)
-
- expect(fork_network_members.count).to eq(12)
- end
-
- it 'knows when not all memberships within a batch have been created' do
- expect(migration.missing_members?(8, 10)).to be_truthy
- end
- end
-end
diff --git a/spec/lib/gitlab/background_migration/delete_conflicting_redirect_routes_range_spec.rb b/spec/lib/gitlab/background_migration/delete_conflicting_redirect_routes_range_spec.rb
deleted file mode 100644
index 9bae7e53b71..00000000000
--- a/spec/lib/gitlab/background_migration/delete_conflicting_redirect_routes_range_spec.rb
+++ /dev/null
@@ -1,35 +0,0 @@
-require 'spec_helper'
-
-describe Gitlab::BackgroundMigration::DeleteConflictingRedirectRoutesRange, :migration, schema: 20170907170235 do
- let!(:redirect_routes) { table(:redirect_routes) }
- let!(:routes) { table(:routes) }
-
- before do
- routes.create!(id: 1, source_id: 1, source_type: 'Namespace', path: 'foo1')
- routes.create!(id: 2, source_id: 2, source_type: 'Namespace', path: 'foo2')
- routes.create!(id: 3, source_id: 3, source_type: 'Namespace', path: 'foo3')
- routes.create!(id: 4, source_id: 4, source_type: 'Namespace', path: 'foo4')
- routes.create!(id: 5, source_id: 5, source_type: 'Namespace', path: 'foo5')
-
- # Valid redirects
- redirect_routes.create!(source_id: 1, source_type: 'Namespace', path: 'bar')
- redirect_routes.create!(source_id: 1, source_type: 'Namespace', path: 'bar2')
- redirect_routes.create!(source_id: 2, source_type: 'Namespace', path: 'bar3')
-
- # Conflicting redirects
- redirect_routes.create!(source_id: 2, source_type: 'Namespace', path: 'foo1')
- redirect_routes.create!(source_id: 1, source_type: 'Namespace', path: 'foo2')
- redirect_routes.create!(source_id: 1, source_type: 'Namespace', path: 'foo3')
- redirect_routes.create!(source_id: 1, source_type: 'Namespace', path: 'foo4')
- redirect_routes.create!(source_id: 1, source_type: 'Namespace', path: 'foo5')
- end
-
- # No-op. See https://gitlab.com/gitlab-com/infrastructure/issues/3460#note_53223252
- it 'NO-OP: does not delete any redirect_routes' do
- expect(redirect_routes.count).to eq(8)
-
- described_class.new.perform(1, 5)
-
- expect(redirect_routes.count).to eq(8)
- end
-end
diff --git a/spec/lib/gitlab/background_migration/migrate_events_to_push_event_payloads_spec.rb b/spec/lib/gitlab/background_migration/migrate_events_to_push_event_payloads_spec.rb
deleted file mode 100644
index 188969951a6..00000000000
--- a/spec/lib/gitlab/background_migration/migrate_events_to_push_event_payloads_spec.rb
+++ /dev/null
@@ -1,433 +0,0 @@
-require 'spec_helper'
-
-# rubocop:disable RSpec/FactoriesInMigrationSpecs
-describe Gitlab::BackgroundMigration::MigrateEventsToPushEventPayloads::Event, :migration, schema: 20170608152748 do
- describe '#commit_title' do
- it 'returns nil when there are no commits' do
- expect(described_class.new.commit_title).to be_nil
- end
-
- it 'returns nil when there are commits without commit messages' do
- event = described_class.new
-
- allow(event).to receive(:commits).and_return([{ id: '123' }])
-
- expect(event.commit_title).to be_nil
- end
-
- it 'returns the commit message when it is less than 70 characters long' do
- event = described_class.new
-
- allow(event).to receive(:commits).and_return([{ message: 'Hello world' }])
-
- expect(event.commit_title).to eq('Hello world')
- end
-
- it 'returns the first line of a commit message if multiple lines are present' do
- event = described_class.new
-
- allow(event).to receive(:commits).and_return([{ message: "Hello\n\nworld" }])
-
- expect(event.commit_title).to eq('Hello')
- end
-
- it 'truncates the commit to 70 characters when it is too long' do
- event = described_class.new
-
- allow(event).to receive(:commits).and_return([{ message: 'a' * 100 }])
-
- expect(event.commit_title).to eq(('a' * 67) + '...')
- end
- end
-
- describe '#commit_from_sha' do
- it 'returns nil when pushing to a new ref' do
- event = described_class.new
-
- allow(event).to receive(:create?).and_return(true)
-
- expect(event.commit_from_sha).to be_nil
- end
-
- it 'returns the ID of the first commit when pushing to an existing ref' do
- event = described_class.new
-
- allow(event).to receive(:create?).and_return(false)
- allow(event).to receive(:data).and_return(before: '123')
-
- expect(event.commit_from_sha).to eq('123')
- end
- end
-
- describe '#commit_to_sha' do
- it 'returns nil when removing an existing ref' do
- event = described_class.new
-
- allow(event).to receive(:remove?).and_return(true)
-
- expect(event.commit_to_sha).to be_nil
- end
-
- it 'returns the ID of the last commit when pushing to an existing ref' do
- event = described_class.new
-
- allow(event).to receive(:remove?).and_return(false)
- allow(event).to receive(:data).and_return(after: '123')
-
- expect(event.commit_to_sha).to eq('123')
- end
- end
-
- describe '#data' do
- it 'returns the deserialized data' do
- event = described_class.new(data: { before: '123' })
-
- expect(event.data).to eq(before: '123')
- end
-
- it 'returns an empty hash when no data is present' do
- event = described_class.new
-
- expect(event.data).to eq({})
- end
- end
-
- describe '#commits' do
- it 'returns an Array of commits' do
- event = described_class.new(data: { commits: [{ id: '123' }] })
-
- expect(event.commits).to eq([{ id: '123' }])
- end
-
- it 'returns an empty array when no data is present' do
- event = described_class.new
-
- expect(event.commits).to eq([])
- end
- end
-
- describe '#commit_count' do
- it 'returns the number of commits' do
- event = described_class.new(data: { total_commits_count: 2 })
-
- expect(event.commit_count).to eq(2)
- end
-
- it 'returns 0 when no data is present' do
- event = described_class.new
-
- expect(event.commit_count).to eq(0)
- end
- end
-
- describe '#ref' do
- it 'returns the name of the ref' do
- event = described_class.new(data: { ref: 'refs/heads/master' })
-
- expect(event.ref).to eq('refs/heads/master')
- end
- end
-
- describe '#trimmed_ref_name' do
- it 'returns the trimmed ref name for a branch' do
- event = described_class.new(data: { ref: 'refs/heads/master' })
-
- expect(event.trimmed_ref_name).to eq('master')
- end
-
- it 'returns the trimmed ref name for a tag' do
- event = described_class.new(data: { ref: 'refs/tags/v1.2' })
-
- expect(event.trimmed_ref_name).to eq('v1.2')
- end
- end
-
- describe '#create?' do
- it 'returns true when creating a new ref' do
- event = described_class.new(data: { before: described_class::BLANK_REF })
-
- expect(event.create?).to eq(true)
- end
-
- it 'returns false when pushing to an existing ref' do
- event = described_class.new(data: { before: '123' })
-
- expect(event.create?).to eq(false)
- end
- end
-
- describe '#remove?' do
- it 'returns true when removing an existing ref' do
- event = described_class.new(data: { after: described_class::BLANK_REF })
-
- expect(event.remove?).to eq(true)
- end
-
- it 'returns false when pushing to an existing ref' do
- event = described_class.new(data: { after: '123' })
-
- expect(event.remove?).to eq(false)
- end
- end
-
- describe '#push_action' do
- let(:event) { described_class.new }
-
- it 'returns :created when creating a new ref' do
- allow(event).to receive(:create?).and_return(true)
-
- expect(event.push_action).to eq(:created)
- end
-
- it 'returns :removed when removing an existing ref' do
- allow(event).to receive(:create?).and_return(false)
- allow(event).to receive(:remove?).and_return(true)
-
- expect(event.push_action).to eq(:removed)
- end
-
- it 'returns :pushed when pushing to an existing ref' do
- allow(event).to receive(:create?).and_return(false)
- allow(event).to receive(:remove?).and_return(false)
-
- expect(event.push_action).to eq(:pushed)
- end
- end
-
- describe '#ref_type' do
- let(:event) { described_class.new }
-
- it 'returns :tag for a tag' do
- allow(event).to receive(:ref).and_return('refs/tags/1.2')
-
- expect(event.ref_type).to eq(:tag)
- end
-
- it 'returns :branch for a branch' do
- allow(event).to receive(:ref).and_return('refs/heads/1.2')
-
- expect(event.ref_type).to eq(:branch)
- end
- end
-end
-
-##
-# The background migration relies on a temporary table, hence we're migrating
-# to a specific version of the database where said table is still present.
-#
-describe Gitlab::BackgroundMigration::MigrateEventsToPushEventPayloads, :migration, schema: 20170825154015 do
- let(:user_class) do
- Class.new(ActiveRecord::Base) do
- self.table_name = 'users'
- end
- end
-
- let(:migration) { described_class.new }
- let(:user_class) { table(:users) }
- let(:author) { build(:user).becomes(user_class).tap(&:save!).becomes(User) }
- let(:namespace) { create(:namespace, owner: author) }
- let(:projects) { table(:projects) }
- let(:project) { projects.create(namespace_id: namespace.id, creator_id: author.id) }
-
- # We can not rely on FactoryBot as the state of Event may change in ways that
- # the background migration does not expect, hence we use the Event class of
- # the migration itself.
- def create_push_event(project, author, data = nil)
- klass = Gitlab::BackgroundMigration::MigrateEventsToPushEventPayloads::Event
-
- klass.create!(
- action: klass::PUSHED,
- project_id: project.id,
- author_id: author.id,
- data: data
- )
- end
-
- describe '#perform' do
- it 'returns if data should not be migrated' do
- allow(migration).to receive(:migrate?).and_return(false)
-
- expect(migration).not_to receive(:find_events)
-
- migration.perform(1, 10)
- end
-
- it 'migrates the range of events if data is to be migrated' do
- event1 = create_push_event(project, author, { commits: [] })
- event2 = create_push_event(project, author, { commits: [] })
-
- allow(migration).to receive(:migrate?).and_return(true)
-
- expect(migration).to receive(:process_event).twice
-
- migration.perform(event1.id, event2.id)
- end
- end
-
- describe '#process_event' do
- it 'processes a regular event' do
- event = double(:event, push_event?: false)
-
- expect(migration).to receive(:replicate_event)
- expect(migration).not_to receive(:create_push_event_payload)
-
- migration.process_event(event)
- end
-
- it 'processes a push event' do
- event = double(:event, push_event?: true)
-
- expect(migration).to receive(:replicate_event)
- expect(migration).to receive(:create_push_event_payload)
-
- migration.process_event(event)
- end
-
- it 'handles an error gracefully' do
- event1 = create_push_event(project, author, { commits: [] })
-
- expect(migration).to receive(:replicate_event).and_call_original
- expect(migration).to receive(:create_push_event_payload).and_raise(ActiveRecord::InvalidForeignKey, 'invalid foreign key')
-
- migration.process_event(event1)
-
- expect(described_class::EventForMigration.all.count).to eq(0)
- end
- end
-
- describe '#replicate_event' do
- it 'replicates the event to the "events_for_migration" table' do
- event = create_push_event(
- project,
- author,
- data: { commits: [] },
- title: 'bla'
- )
-
- attributes = event
- .attributes.with_indifferent_access.except(:title, :data)
-
- expect(described_class::EventForMigration)
- .to receive(:create!)
- .with(attributes)
-
- migration.replicate_event(event)
- end
- end
-
- describe '#create_push_event_payload' do
- let(:push_data) do
- {
- commits: [],
- ref: 'refs/heads/master',
- before: '156e0e9adc587a383a7eeb5b21ddecb9044768a8',
- after: '0' * 40,
- total_commits_count: 1
- }
- end
-
- let(:event) do
- create_push_event(project, author, push_data)
- end
-
- before do
- # The foreign key in push_event_payloads at this point points to the
- # "events_for_migration" table so we need to make sure a row exists in
- # said table.
- migration.replicate_event(event)
- end
-
- it 'creates a push event payload for an event' do
- payload = migration.create_push_event_payload(event)
-
- expect(PushEventPayload.count).to eq(1)
- expect(payload.valid?).to eq(true)
- end
-
- it 'does not create push event payloads for removed events' do
- allow(event).to receive(:id).and_return(-1)
-
- expect { migration.create_push_event_payload(event) }.to raise_error(ActiveRecord::InvalidForeignKey)
-
- expect(PushEventPayload.count).to eq(0)
- end
-
- it 'encodes and decodes the commit IDs from and to binary data' do
- payload = migration.create_push_event_payload(event)
- packed = migration.pack(push_data[:before])
-
- expect(payload.commit_from).to eq(packed)
- expect(payload.commit_to).to be_nil
- end
- end
-
- describe '#find_events' do
- it 'returns the events for the given ID range' do
- event1 = create_push_event(project, author, { commits: [] })
- event2 = create_push_event(project, author, { commits: [] })
- event3 = create_push_event(project, author, { commits: [] })
- events = migration.find_events(event1.id, event2.id)
-
- expect(events.length).to eq(2)
- expect(events.pluck(:id)).not_to include(event3.id)
- end
- end
-
- describe '#migrate?' do
- it 'returns true when data should be migrated' do
- allow(described_class::Event)
- .to receive(:table_exists?).and_return(true)
-
- allow(described_class::PushEventPayload)
- .to receive(:table_exists?).and_return(true)
-
- allow(described_class::EventForMigration)
- .to receive(:table_exists?).and_return(true)
-
- expect(migration.migrate?).to eq(true)
- end
-
- it 'returns false if the "events" table does not exist' do
- allow(described_class::Event)
- .to receive(:table_exists?).and_return(false)
-
- expect(migration.migrate?).to eq(false)
- end
-
- it 'returns false if the "push_event_payloads" table does not exist' do
- allow(described_class::Event)
- .to receive(:table_exists?).and_return(true)
-
- allow(described_class::PushEventPayload)
- .to receive(:table_exists?).and_return(false)
-
- expect(migration.migrate?).to eq(false)
- end
-
- it 'returns false when the "events_for_migration" table does not exist' do
- allow(described_class::Event)
- .to receive(:table_exists?).and_return(true)
-
- allow(described_class::PushEventPayload)
- .to receive(:table_exists?).and_return(true)
-
- allow(described_class::EventForMigration)
- .to receive(:table_exists?).and_return(false)
-
- expect(migration.migrate?).to eq(false)
- end
- end
-
- describe '#pack' do
- it 'packs a SHA1 into a 20 byte binary string' do
- packed = migration.pack('156e0e9adc587a383a7eeb5b21ddecb9044768a8')
-
- expect(packed.bytesize).to eq(20)
- end
-
- it 'returns nil if the input value is nil' do
- expect(migration.pack(nil)).to be_nil
- end
- end
-end
-# rubocop:enable RSpec/FactoriesInMigrationSpecs
diff --git a/spec/lib/gitlab/background_migration/migrate_stage_status_spec.rb b/spec/lib/gitlab/background_migration/migrate_stage_status_spec.rb
deleted file mode 100644
index 89b56906ed0..00000000000
--- a/spec/lib/gitlab/background_migration/migrate_stage_status_spec.rb
+++ /dev/null
@@ -1,92 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-describe Gitlab::BackgroundMigration::MigrateStageStatus, :migration, schema: 20170711145320 do
- let(:projects) { table(:projects) }
- let(:pipelines) { table(:ci_pipelines) }
- let(:stages) { table(:ci_stages) }
- let(:jobs) { table(:ci_builds) }
-
- let(:statuses) do
- {
- created: 0,
- pending: 1,
- running: 2,
- success: 3,
- failed: 4,
- canceled: 5,
- skipped: 6,
- manual: 7
- }
- end
-
- before do
- projects.create!(id: 1, name: 'gitlab1', path: 'gitlab1')
- pipelines.create!(id: 1, project_id: 1, ref: 'master', sha: 'adf43c3a')
- stages.create!(id: 1, pipeline_id: 1, project_id: 1, name: 'test', status: nil)
- stages.create!(id: 2, pipeline_id: 1, project_id: 1, name: 'deploy', status: nil)
- end
-
- context 'when stage status is known' do
- before do
- create_job(project: 1, pipeline: 1, stage: 'test', status: 'success')
- create_job(project: 1, pipeline: 1, stage: 'test', status: 'running')
- create_job(project: 1, pipeline: 1, stage: 'deploy', status: 'failed')
- end
-
- it 'sets a correct stage status' do
- described_class.new.perform(1, 2)
-
- expect(stages.first.status).to eq statuses[:running]
- expect(stages.second.status).to eq statuses[:failed]
- end
- end
-
- context 'when stage status is not known' do
- it 'sets a skipped stage status' do
- described_class.new.perform(1, 2)
-
- expect(stages.first.status).to eq statuses[:skipped]
- expect(stages.second.status).to eq statuses[:skipped]
- end
- end
-
- context 'when stage status includes status of a retried job' do
- before do
- create_job(project: 1, pipeline: 1, stage: 'test', status: 'canceled')
- create_job(project: 1, pipeline: 1, stage: 'deploy', status: 'failed', retried: true)
- create_job(project: 1, pipeline: 1, stage: 'deploy', status: 'success')
- end
-
- it 'sets a correct stage status' do
- described_class.new.perform(1, 2)
-
- expect(stages.first.status).to eq statuses[:canceled]
- expect(stages.second.status).to eq statuses[:success]
- end
- end
-
- context 'when some job in the stage is blocked / manual' do
- before do
- create_job(project: 1, pipeline: 1, stage: 'test', status: 'failed')
- create_job(project: 1, pipeline: 1, stage: 'test', status: 'manual')
- create_job(project: 1, pipeline: 1, stage: 'deploy', status: 'success', when: 'manual')
- end
-
- it 'sets a correct stage status' do
- described_class.new.perform(1, 2)
-
- expect(stages.first.status).to eq statuses[:manual]
- expect(stages.second.status).to eq statuses[:success]
- end
- end
-
- def create_job(project:, pipeline:, stage:, status:, **opts)
- stages = { test: 1, build: 2, deploy: 3 }
-
- jobs.create!(project_id: project, commit_id: pipeline,
- stage_idx: stages[stage.to_sym], stage: stage,
- status: status, **opts)
- end
-end
diff --git a/spec/lib/gitlab/background_migration/migrate_system_uploads_to_new_folder_spec.rb b/spec/lib/gitlab/background_migration/migrate_system_uploads_to_new_folder_spec.rb
deleted file mode 100644
index ea8bdd48e72..00000000000
--- a/spec/lib/gitlab/background_migration/migrate_system_uploads_to_new_folder_spec.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-require 'spec_helper'
-
-# rubocop:disable RSpec/FactoriesInMigrationSpecs
-describe Gitlab::BackgroundMigration::MigrateSystemUploadsToNewFolder, :delete do
- let(:migration) { described_class.new }
-
- before do
- allow(migration).to receive(:logger).and_return(Logger.new(nil))
- end
-
- describe '#perform' do
- it 'renames the path of system-uploads' do
- upload = create(:upload, model: create(:project), path: 'uploads/system/project/avatar.jpg')
-
- migration.perform('uploads/system/', 'uploads/-/system/')
-
- expect(upload.reload.path).to eq('uploads/-/system/project/avatar.jpg')
- end
- end
-end
-# rubocop:enable RSpec/FactoriesInMigrationSpecs
diff --git a/spec/lib/gitlab/background_migration/move_personal_snippet_files_spec.rb b/spec/lib/gitlab/background_migration/move_personal_snippet_files_spec.rb
deleted file mode 100644
index 593486fc56c..00000000000
--- a/spec/lib/gitlab/background_migration/move_personal_snippet_files_spec.rb
+++ /dev/null
@@ -1,74 +0,0 @@
-require 'spec_helper'
-
-# rubocop:disable RSpec/FactoriesInMigrationSpecs
-describe Gitlab::BackgroundMigration::MovePersonalSnippetFiles do
- let(:test_dir) { File.join(Rails.root, 'tmp', 'tests', 'move_snippet_files_test') }
- let(:old_uploads_dir) { File.join('uploads', 'system', 'personal_snippet') }
- let(:new_uploads_dir) { File.join('uploads', '-', 'system', 'personal_snippet') }
- let(:snippet) do
- snippet = create(:personal_snippet)
- create_upload_for_snippet(snippet)
- snippet.update!(description: markdown_linking_file(snippet))
- snippet
- end
-
- let(:migration) { described_class.new }
-
- before do
- allow(migration).to receive(:base_directory) { test_dir }
- end
-
- describe '#perform' do
- it 'moves the file on the disk' do
- expected_path = File.join(test_dir, new_uploads_dir, snippet.id.to_s, "secret#{snippet.id}", 'upload.txt')
-
- migration.perform(old_uploads_dir, new_uploads_dir)
-
- expect(File.exist?(expected_path)).to be_truthy
- end
-
- it 'updates the markdown of the snippet' do
- expected_path = File.join(new_uploads_dir, snippet.id.to_s, "secret#{snippet.id}", 'upload.txt')
- expected_markdown = "[an upload](#{expected_path})"
-
- migration.perform(old_uploads_dir, new_uploads_dir)
-
- expect(snippet.reload.description).to eq(expected_markdown)
- end
-
- it 'updates the markdown of notes' do
- expected_path = File.join(new_uploads_dir, snippet.id.to_s, "secret#{snippet.id}", 'upload.txt')
- expected_markdown = "with [an upload](#{expected_path})"
-
- note = create(:note_on_personal_snippet, noteable: snippet, note: "with #{markdown_linking_file(snippet)}")
-
- migration.perform(old_uploads_dir, new_uploads_dir)
-
- expect(note.reload.note).to eq(expected_markdown)
- end
- end
-
- def create_upload_for_snippet(snippet)
- snippet_path = path_for_file_in_snippet(snippet)
- path = File.join(old_uploads_dir, snippet.id.to_s, snippet_path)
- absolute_path = File.join(test_dir, path)
-
- FileUtils.mkdir_p(File.dirname(absolute_path))
- FileUtils.touch(absolute_path)
-
- create(:upload, model: snippet, path: snippet_path, uploader: PersonalFileUploader)
- end
-
- def path_for_file_in_snippet(snippet)
- secret = "secret#{snippet.id}"
- filename = 'upload.txt'
-
- File.join(secret, filename)
- end
-
- def markdown_linking_file(snippet)
- path = File.join(old_uploads_dir, snippet.id.to_s, path_for_file_in_snippet(snippet))
- "[an upload](#{path})"
- end
-end
-# rubocop:enable RSpec/FactoriesInMigrationSpecs
diff --git a/spec/lib/gitlab/background_migration/normalize_ldap_extern_uids_range_spec.rb b/spec/lib/gitlab/background_migration/normalize_ldap_extern_uids_range_spec.rb
deleted file mode 100644
index dfbf1bb681a..00000000000
--- a/spec/lib/gitlab/background_migration/normalize_ldap_extern_uids_range_spec.rb
+++ /dev/null
@@ -1,36 +0,0 @@
-require 'spec_helper'
-
-describe Gitlab::BackgroundMigration::NormalizeLdapExternUidsRange, :migration, schema: 20170921101004 do
- let!(:identities) { table(:identities) }
-
- before do
- # LDAP identities
- (1..4).each do |i|
- identities.create!(id: i, provider: 'ldapmain', extern_uid: " uid = foo #{i}, ou = People, dc = example, dc = com ", user_id: i)
- end
-
- # Non-LDAP identity
- identities.create!(id: 5, provider: 'foo', extern_uid: " uid = foo 5, ou = People, dc = example, dc = com ", user_id: 5)
-
- # Another LDAP identity
- identities.create!(id: 6, provider: 'ldapmain', extern_uid: " uid = foo 6, ou = People, dc = example, dc = com ", user_id: 6)
- end
-
- it 'normalizes the LDAP identities in the range' do
- described_class.new.perform(1, 3)
- expect(identities.find(1).extern_uid).to eq("uid=foo 1,ou=people,dc=example,dc=com")
- expect(identities.find(2).extern_uid).to eq("uid=foo 2,ou=people,dc=example,dc=com")
- expect(identities.find(3).extern_uid).to eq("uid=foo 3,ou=people,dc=example,dc=com")
- expect(identities.find(4).extern_uid).to eq(" uid = foo 4, ou = People, dc = example, dc = com ")
- expect(identities.find(5).extern_uid).to eq(" uid = foo 5, ou = People, dc = example, dc = com ")
- expect(identities.find(6).extern_uid).to eq(" uid = foo 6, ou = People, dc = example, dc = com ")
-
- described_class.new.perform(4, 6)
- expect(identities.find(1).extern_uid).to eq("uid=foo 1,ou=people,dc=example,dc=com")
- expect(identities.find(2).extern_uid).to eq("uid=foo 2,ou=people,dc=example,dc=com")
- expect(identities.find(3).extern_uid).to eq("uid=foo 3,ou=people,dc=example,dc=com")
- expect(identities.find(4).extern_uid).to eq("uid=foo 4,ou=people,dc=example,dc=com")
- expect(identities.find(5).extern_uid).to eq(" uid = foo 5, ou = People, dc = example, dc = com ")
- expect(identities.find(6).extern_uid).to eq("uid=foo 6,ou=people,dc=example,dc=com")
- end
-end
diff --git a/spec/lib/gitlab/background_migration/populate_fork_networks_range_spec.rb b/spec/lib/gitlab/background_migration/populate_fork_networks_range_spec.rb
deleted file mode 100644
index 0e73c8c59c9..00000000000
--- a/spec/lib/gitlab/background_migration/populate_fork_networks_range_spec.rb
+++ /dev/null
@@ -1,97 +0,0 @@
-require 'spec_helper'
-
-describe Gitlab::BackgroundMigration::PopulateForkNetworksRange, :migration, schema: 20170929131201 do
- let(:migration) { described_class.new }
- let(:projects) { table(:projects) }
- let(:base1) { projects.create }
-
- let(:base2) { projects.create }
- let(:base2_fork1) { projects.create }
-
- let!(:forked_project_links) { table(:forked_project_links) }
- let!(:fork_networks) { table(:fork_networks) }
- let!(:fork_network_members) { table(:fork_network_members) }
-
- let(:fork_network1) { fork_networks.find_by(root_project_id: base1.id) }
- let(:fork_network2) { fork_networks.find_by(root_project_id: base2.id) }
-
- before do
- # A normal fork link
- forked_project_links.create(id: 1,
- forked_from_project_id: base1.id,
- forked_to_project_id: projects.create.id)
- forked_project_links.create(id: 2,
- forked_from_project_id: base1.id,
- forked_to_project_id: projects.create.id)
- forked_project_links.create(id: 3,
- forked_from_project_id: base2.id,
- forked_to_project_id: base2_fork1.id)
-
- # create a fork of a fork
- forked_project_links.create(id: 4,
- forked_from_project_id: base2_fork1.id,
- forked_to_project_id: projects.create.id)
- forked_project_links.create(id: 5,
- forked_from_project_id: projects.create.id,
- forked_to_project_id: projects.create.id)
-
- # Stub out the calls to the other migrations
- allow(BackgroundMigrationWorker).to receive(:perform_in)
-
- migration.perform(1, 3)
- end
-
- it 'creates the fork network' do
- expect(fork_network1).not_to be_nil
- expect(fork_network2).not_to be_nil
- end
-
- it 'does not create a fork network for a fork-of-fork' do
- # perfrom the entire batch
- migration.perform(1, 5)
-
- expect(fork_networks.find_by(root_project_id: base2_fork1.id)).to be_nil
- end
-
- it 'creates memberships for the root of fork networks' do
- base1_membership = fork_network_members.find_by(fork_network_id: fork_network1.id,
- project_id: base1.id)
- base2_membership = fork_network_members.find_by(fork_network_id: fork_network2.id,
- project_id: base2.id)
-
- expect(base1_membership).not_to be_nil
- expect(base2_membership).not_to be_nil
- end
-
- it 'creates a fork network for the fork of which the source was deleted' do
- fork = projects.create
- forked_project_links.create(id: 6, forked_from_project_id: 99999, forked_to_project_id: fork.id)
-
- migration.perform(5, 8)
-
- expect(fork_networks.find_by(root_project_id: 99999)).to be_nil
- expect(fork_networks.find_by(root_project_id: fork.id)).not_to be_nil
- expect(fork_network_members.find_by(project_id: fork.id)).not_to be_nil
- end
-
- it 'schedules a job for inserting memberships for forks-of-forks' do
- delay = Gitlab::BackgroundMigration::CreateForkNetworkMembershipsRange::RESCHEDULE_DELAY
-
- expect(BackgroundMigrationWorker)
- .to receive(:perform_in).with(delay, "CreateForkNetworkMembershipsRange", [1, 3])
-
- migration.perform(1, 3)
- end
-
- it 'only processes a single batch of links at a time' do
- expect(fork_networks.count).to eq(2)
-
- migration.perform(3, 5)
-
- expect(fork_networks.count).to eq(3)
- end
-
- it 'can be repeated without effect' do
- expect { migration.perform(1, 3) }.not_to change { fork_network_members.count }
- end
-end
diff --git a/spec/lib/gitlab/background_migration/populate_merge_requests_latest_merge_request_diff_id_spec.rb b/spec/lib/gitlab/background_migration/populate_merge_requests_latest_merge_request_diff_id_spec.rb
deleted file mode 100644
index 0cb753c5853..00000000000
--- a/spec/lib/gitlab/background_migration/populate_merge_requests_latest_merge_request_diff_id_spec.rb
+++ /dev/null
@@ -1,62 +0,0 @@
-require 'spec_helper'
-
-describe Gitlab::BackgroundMigration::PopulateMergeRequestsLatestMergeRequestDiffId, :migration, schema: 20171026082505 do
- let(:projects_table) { table(:projects) }
- let(:merge_requests_table) { table(:merge_requests) }
- let(:merge_request_diffs_table) { table(:merge_request_diffs) }
-
- let(:project) { projects_table.create!(name: 'gitlab', path: 'gitlab-org/gitlab-ce') }
-
- def create_mr!(name, diffs: 0)
- merge_request =
- merge_requests_table.create!(target_project_id: project.id,
- target_branch: 'master',
- source_project_id: project.id,
- source_branch: name,
- title: name)
-
- diffs.times do
- merge_request_diffs_table.create!(merge_request_id: merge_request.id)
- end
-
- merge_request
- end
-
- def diffs_for(merge_request)
- merge_request_diffs_table.where(merge_request_id: merge_request.id)
- end
-
- describe '#perform' do
- it 'ignores MRs without diffs' do
- merge_request_without_diff = create_mr!('without_diff')
- mr_id = merge_request_without_diff.id
-
- expect(merge_request_without_diff.latest_merge_request_diff_id).to be_nil
-
- expect { subject.perform(mr_id, mr_id) }
- .not_to change { merge_request_without_diff.reload.latest_merge_request_diff_id }
- end
-
- it 'ignores MRs that have a diff ID already set' do
- merge_request_with_multiple_diffs = create_mr!('with_multiple_diffs', diffs: 3)
- diff_id = diffs_for(merge_request_with_multiple_diffs).minimum(:id)
- mr_id = merge_request_with_multiple_diffs.id
-
- merge_request_with_multiple_diffs.update!(latest_merge_request_diff_id: diff_id)
-
- expect { subject.perform(mr_id, mr_id) }
- .not_to change { merge_request_with_multiple_diffs.reload.latest_merge_request_diff_id }
- end
-
- it 'migrates multiple MR diffs to the correct values' do
- merge_requests = Array.new(3).map.with_index { |_, i| create_mr!(i, diffs: 3) }
-
- subject.perform(merge_requests.first.id, merge_requests.last.id)
-
- merge_requests.each do |merge_request|
- expect(merge_request.reload.latest_merge_request_diff_id)
- .to eq(diffs_for(merge_request).maximum(:id))
- end
- end
- end
-end
diff --git a/spec/lib/gitlab/cache/ci/project_pipeline_status_spec.rb b/spec/lib/gitlab/cache/ci/project_pipeline_status_spec.rb
index 483c5ea9cff..972dd7e0d2b 100644
--- a/spec/lib/gitlab/cache/ci/project_pipeline_status_spec.rb
+++ b/spec/lib/gitlab/cache/ci/project_pipeline_status_spec.rb
@@ -26,6 +26,7 @@ describe Gitlab::Cache::Ci::ProjectPipelineStatus, :clean_gitlab_redis_cache do
end
it 'loads 10 projects without hitting Gitaly call limit', :request_store do
+ allow(Gitlab::GitalyClient).to receive(:can_access_disk?).and_return(false)
projects = Gitlab::GitalyClient.allow_n_plus_1_calls do
(1..10).map { create(:project, :repository) }
end
diff --git a/spec/lib/gitlab/ci/config_spec.rb b/spec/lib/gitlab/ci/config_spec.rb
index 7f336ee853e..4e8bff3d738 100644
--- a/spec/lib/gitlab/ci/config_spec.rb
+++ b/spec/lib/gitlab/ci/config_spec.rb
@@ -90,6 +90,27 @@ describe Gitlab::Ci::Config do
end
end
+ context 'when yml is too big' do
+ let(:yml) do
+ <<~YAML
+ --- &1
+ - hi
+ - *1
+ YAML
+ end
+
+ describe '.new' do
+ it 'raises error' do
+ expect(Gitlab::Sentry).to receive(:track_exception)
+
+ expect { config }.to raise_error(
+ described_class::ConfigError,
+ /The parsed YAML is too big/
+ )
+ end
+ end
+ end
+
context 'when config logic is incorrect' do
let(:yml) { 'before_script: "ls"' }
diff --git a/spec/lib/gitlab/ci/reports/test_reports_comparer_spec.rb b/spec/lib/gitlab/ci/reports/test_reports_comparer_spec.rb
index 71c61e0345f..36582204cc1 100644
--- a/spec/lib/gitlab/ci/reports/test_reports_comparer_spec.rb
+++ b/spec/lib/gitlab/ci/reports/test_reports_comparer_spec.rb
@@ -74,17 +74,11 @@ describe Gitlab::Ci::Reports::TestReportsComparer do
subject { comparer.resolved_count }
context 'when there is a resolved test case in head suites' do
- let(:create_test_case_java_resolved) do
- create_test_case_java_failed.tap do |test_case|
- test_case.instance_variable_set("@status", Gitlab::Ci::Reports::TestCase::STATUS_SUCCESS)
- end
- end
-
before do
base_reports.get_suite('rspec').add_test_case(create_test_case_rspec_success)
base_reports.get_suite('junit').add_test_case(create_test_case_java_failed)
head_reports.get_suite('rspec').add_test_case(create_test_case_rspec_success)
- head_reports.get_suite('junit').add_test_case(create_test_case_java_resolved)
+ head_reports.get_suite('junit').add_test_case(create_test_case_java_success)
end
it 'returns the correct count' do
diff --git a/spec/lib/gitlab/ci/reports/test_suite_comparer_spec.rb b/spec/lib/gitlab/ci/reports/test_suite_comparer_spec.rb
index 6ab16e5518d..579b3e6fd24 100644
--- a/spec/lib/gitlab/ci/reports/test_suite_comparer_spec.rb
+++ b/spec/lib/gitlab/ci/reports/test_suite_comparer_spec.rb
@@ -10,12 +10,6 @@ describe Gitlab::Ci::Reports::TestSuiteComparer do
let(:test_case_success) { create_test_case_rspec_success }
let(:test_case_failed) { create_test_case_rspec_failed }
- let(:test_case_resolved) do
- create_test_case_rspec_failed.tap do |test_case|
- test_case.instance_variable_set("@status", Gitlab::Ci::Reports::TestCase::STATUS_SUCCESS)
- end
- end
-
describe '#new_failures' do
subject { comparer.new_failures }
@@ -44,7 +38,7 @@ describe Gitlab::Ci::Reports::TestSuiteComparer do
context 'when head sutie has a success test case which failed in base' do
before do
base_suite.add_test_case(test_case_failed)
- head_suite.add_test_case(test_case_resolved)
+ head_suite.add_test_case(test_case_success)
end
it 'does not return the failed test case' do
@@ -81,7 +75,7 @@ describe Gitlab::Ci::Reports::TestSuiteComparer do
context 'when head sutie has a success test case which failed in base' do
before do
base_suite.add_test_case(test_case_failed)
- head_suite.add_test_case(test_case_resolved)
+ head_suite.add_test_case(test_case_success)
end
it 'does not return the failed test case' do
@@ -126,11 +120,11 @@ describe Gitlab::Ci::Reports::TestSuiteComparer do
context 'when head sutie has a success test case which failed in base' do
before do
base_suite.add_test_case(test_case_failed)
- head_suite.add_test_case(test_case_resolved)
+ head_suite.add_test_case(test_case_success)
end
it 'does not return the resolved test case' do
- is_expected.to eq([test_case_resolved])
+ is_expected.to eq([test_case_success])
end
it 'returns the correct resolved count' do
@@ -156,13 +150,8 @@ describe Gitlab::Ci::Reports::TestSuiteComparer do
context 'when there are a new failure and an existing failure' do
let(:test_case_1_success) { create_test_case_rspec_success }
- let(:test_case_2_failed) { create_test_case_rspec_failed }
-
- let(:test_case_1_failed) do
- create_test_case_rspec_success.tap do |test_case|
- test_case.instance_variable_set("@status", Gitlab::Ci::Reports::TestCase::STATUS_FAILED)
- end
- end
+ let(:test_case_1_failed) { create_test_case_rspec_failed }
+ let(:test_case_2_failed) { create_test_case_rspec_failed('case2') }
before do
base_suite.add_test_case(test_case_1_success)
diff --git a/spec/lib/gitlab/config/loader/yaml_spec.rb b/spec/lib/gitlab/config/loader/yaml_spec.rb
index 44c9a3896a8..0affeb01f6a 100644
--- a/spec/lib/gitlab/config/loader/yaml_spec.rb
+++ b/spec/lib/gitlab/config/loader/yaml_spec.rb
@@ -8,7 +8,7 @@ describe Gitlab::Config::Loader::Yaml do
describe '#valid?' do
it 'returns true' do
- expect(loader.valid?).to be true
+ expect(loader).to be_valid
end
end
@@ -24,7 +24,7 @@ describe Gitlab::Config::Loader::Yaml do
describe '#valid?' do
it 'returns false' do
- expect(loader.valid?).to be false
+ expect(loader).not_to be_valid
end
end
@@ -43,7 +43,10 @@ describe Gitlab::Config::Loader::Yaml do
describe '#initialize' do
it 'raises FormatError' do
- expect { loader }.to raise_error(Gitlab::Config::Loader::FormatError, 'Unknown alias: bad_alias')
+ expect { loader }.to raise_error(
+ Gitlab::Config::Loader::FormatError,
+ 'Unknown alias: bad_alias'
+ )
end
end
end
@@ -53,7 +56,68 @@ describe Gitlab::Config::Loader::Yaml do
describe '#valid?' do
it 'returns false' do
- expect(loader.valid?).to be false
+ expect(loader).not_to be_valid
+ end
+ end
+ end
+
+ # Prevent Billion Laughs attack: https://gitlab.com/gitlab-org/gitlab-ce/issues/56018
+ context 'when yaml size is too large' do
+ let(:yml) do
+ <<~YAML
+ a: &a ["lol","lol","lol","lol","lol","lol","lol","lol","lol"]
+ b: &b [*a,*a,*a,*a,*a,*a,*a,*a,*a]
+ c: &c [*b,*b,*b,*b,*b,*b,*b,*b,*b]
+ d: &d [*c,*c,*c,*c,*c,*c,*c,*c,*c]
+ e: &e [*d,*d,*d,*d,*d,*d,*d,*d,*d]
+ f: &f [*e,*e,*e,*e,*e,*e,*e,*e,*e]
+ g: &g [*f,*f,*f,*f,*f,*f,*f,*f,*f]
+ h: &h [*g,*g,*g,*g,*g,*g,*g,*g,*g]
+ i: &i [*h,*h,*h,*h,*h,*h,*h,*h,*h]
+ YAML
+ end
+
+ describe '#valid?' do
+ it 'returns false' do
+ expect(loader).not_to be_valid
+ end
+
+ it 'returns true if "ci_yaml_limit_size" feature flag is disabled' do
+ stub_feature_flags(ci_yaml_limit_size: false)
+
+ expect(loader).to be_valid
+ end
+ end
+
+ describe '#load!' do
+ it 'raises FormatError' do
+ expect { loader.load! }.to raise_error(
+ Gitlab::Config::Loader::FormatError,
+ 'The parsed YAML is too big'
+ )
+ end
+ end
+ end
+
+ # Prevent Billion Laughs attack: https://gitlab.com/gitlab-org/gitlab-ce/issues/56018
+ context 'when yaml has cyclic data structure' do
+ let(:yml) do
+ <<~YAML
+ --- &1
+ - hi
+ - *1
+ YAML
+ end
+
+ describe '#valid?' do
+ it 'returns false' do
+ expect(loader.valid?).to be(false)
+ end
+ end
+
+ describe '#load!' do
+ it 'raises FormatError' do
+ expect { loader.load! }.to raise_error(Gitlab::Config::Loader::FormatError, 'The parsed YAML is too big')
end
end
end
diff --git a/spec/lib/gitlab/cycle_analytics/test_stage_spec.rb b/spec/lib/gitlab/cycle_analytics/test_stage_spec.rb
index eacde22cd56..8633a63849f 100644
--- a/spec/lib/gitlab/cycle_analytics/test_stage_spec.rb
+++ b/spec/lib/gitlab/cycle_analytics/test_stage_spec.rb
@@ -3,6 +3,40 @@ require 'lib/gitlab/cycle_analytics/shared_stage_spec'
describe Gitlab::CycleAnalytics::TestStage do
let(:stage_name) { :test }
+ let(:project) { create(:project) }
+ let(:stage) { described_class.new(project: project, options: { from: 2.days.ago, current_user: project.creator }) }
it_behaves_like 'base stage'
+
+ describe '#median' do
+ before do
+ issue_1 = create(:issue, project: project, created_at: 90.minutes.ago)
+ issue_2 = create(:issue, project: project, created_at: 60.minutes.ago)
+ issue_3 = create(:issue, project: project, created_at: 60.minutes.ago)
+ mr_1 = create(:merge_request, :closed, source_project: project, created_at: 60.minutes.ago)
+ mr_2 = create(:merge_request, :closed, source_project: project, created_at: 40.minutes.ago, source_branch: 'A')
+ mr_3 = create(:merge_request, source_project: project, created_at: 10.minutes.ago, source_branch: 'B')
+ mr_4 = create(:merge_request, source_project: project, created_at: 10.minutes.ago, source_branch: 'C')
+ mr_5 = create(:merge_request, source_project: project, created_at: 10.minutes.ago, source_branch: 'D')
+ mr_1.metrics.update!(latest_build_started_at: 32.minutes.ago, latest_build_finished_at: 2.minutes.ago)
+ mr_2.metrics.update!(latest_build_started_at: 62.minutes.ago, latest_build_finished_at: 32.minutes.ago)
+ mr_3.metrics.update!(latest_build_started_at: nil, latest_build_finished_at: nil)
+ mr_4.metrics.update!(latest_build_started_at: nil, latest_build_finished_at: nil)
+ mr_5.metrics.update!(latest_build_started_at: nil, latest_build_finished_at: nil)
+
+ create(:merge_requests_closing_issues, merge_request: mr_1, issue: issue_1)
+ create(:merge_requests_closing_issues, merge_request: mr_2, issue: issue_2)
+ create(:merge_requests_closing_issues, merge_request: mr_3, issue: issue_3)
+ create(:merge_requests_closing_issues, merge_request: mr_4, issue: issue_3)
+ create(:merge_requests_closing_issues, merge_request: mr_5, issue: issue_3)
+ end
+
+ around do |example|
+ Timecop.freeze { example.run }
+ end
+
+ it 'counts median from issues with metrics' do
+ expect(stage.median).to eq(ISSUES_MEDIAN)
+ end
+ end
end
diff --git a/spec/lib/gitlab/danger/helper_spec.rb b/spec/lib/gitlab/danger/helper_spec.rb
index c8e65a3e59d..92d90ac2fef 100644
--- a/spec/lib/gitlab/danger/helper_spec.rb
+++ b/spec/lib/gitlab/danger/helper_spec.rb
@@ -87,13 +87,13 @@ describe Gitlab::Danger::Helper do
describe '#changes_by_category' do
it 'categorizes changed files' do
- expect(fake_git).to receive(:added_files) { %w[foo foo.md foo.rb foo.js db/foo qa/foo ee/changelogs/foo.yml] }
+ expect(fake_git).to receive(:added_files) { %w[foo foo.md foo.rb foo.js db/foo lib/gitlab/database/foo.rb qa/foo ee/changelogs/foo.yml] }
allow(fake_git).to receive(:modified_files) { [] }
allow(fake_git).to receive(:renamed_files) { [] }
expect(helper.changes_by_category).to eq(
backend: %w[foo.rb],
- database: %w[db/foo],
+ database: %w[db/foo lib/gitlab/database/foo.rb],
frontend: %w[foo.js],
none: %w[ee/changelogs/foo.yml foo.md],
qa: %w[qa/foo],
@@ -159,9 +159,22 @@ describe Gitlab::Danger::Helper do
'ee/FOO_VERSION' | :unknown
- 'db/foo' | :database
- 'qa/foo' | :qa
+ 'db/foo' | :database
+ 'ee/db/foo' | :database
+ 'app/models/project_authorization.rb' | :database
+ 'app/services/users/refresh_authorized_projects_service.rb' | :database
+ 'lib/gitlab/background_migration.rb' | :database
+ 'lib/gitlab/background_migration/foo' | :database
+ 'ee/lib/gitlab/background_migration/foo' | :database
+ 'lib/gitlab/database.rb' | :database
+ 'lib/gitlab/database/foo' | :database
+ 'ee/lib/gitlab/database/foo' | :database
+ 'lib/gitlab/github_import.rb' | :database
+ 'lib/gitlab/github_import/foo' | :database
+ 'lib/gitlab/sql/foo' | :database
+ 'rubocop/cop/migration/foo' | :database
+ 'qa/foo' | :qa
'ee/qa/foo' | :qa
'changelogs/foo' | :none
diff --git a/spec/lib/gitlab/diff/lines_unfolder_spec.rb b/spec/lib/gitlab/diff/lines_unfolder_spec.rb
index 8a470e12d04..3134ff3d817 100644
--- a/spec/lib/gitlab/diff/lines_unfolder_spec.rb
+++ b/spec/lib/gitlab/diff/lines_unfolder_spec.rb
@@ -842,4 +842,37 @@ describe Gitlab::Diff::LinesUnfolder do
end
end
end
+
+ context 'positioned on an image' do
+ let(:position) do
+ Gitlab::Diff::Position.new(
+ base_sha: '1c59dfa64afbea8c721bb09a06a9d326c952ea19',
+ start_sha: '1c59dfa64afbea8c721bb09a06a9d326c952ea19',
+ head_sha: '1487062132228de836236c522fe52fed4980a46c',
+ old_path: 'image.jpg',
+ new_path: 'image.jpg',
+ position_type: 'image'
+ )
+ end
+
+ before do
+ allow(old_blob).to receive(:binary?).and_return(binary?)
+ end
+
+ context 'diff file is not text' do
+ let(:binary?) { true }
+
+ it 'returns nil' do
+ expect(subject.unfolded_diff_lines).to be_nil
+ end
+ end
+
+ context 'diff file is text' do
+ let(:binary?) { false }
+
+ it 'returns nil' do
+ expect(subject.unfolded_diff_lines).to be_nil
+ end
+ end
+ end
end
diff --git a/spec/lib/gitlab/diff/position_spec.rb b/spec/lib/gitlab/diff/position_spec.rb
index aea02d21048..b755cd1aff0 100644
--- a/spec/lib/gitlab/diff/position_spec.rb
+++ b/spec/lib/gitlab/diff/position_spec.rb
@@ -610,4 +610,17 @@ describe Gitlab::Diff::Position do
it_behaves_like "diff position json"
end
end
+
+ describe "#file_hash" do
+ subject do
+ described_class.new(
+ old_path: "image.jpg",
+ new_path: "image.jpg"
+ )
+ end
+
+ it "returns SHA1 representation of the file_path" do
+ expect(subject.file_hash).to eq(Digest::SHA1.hexdigest(subject.file_path))
+ end
+ end
end
diff --git a/spec/lib/gitlab/diff/position_tracer/image_strategy_spec.rb b/spec/lib/gitlab/diff/position_tracer/image_strategy_spec.rb
new file mode 100644
index 00000000000..900816af53a
--- /dev/null
+++ b/spec/lib/gitlab/diff/position_tracer/image_strategy_spec.rb
@@ -0,0 +1,238 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Gitlab::Diff::PositionTracer::ImageStrategy do
+ include PositionTracerHelpers
+
+ let(:project) { create(:project, :repository) }
+ let(:current_user) { project.owner }
+ let(:file_name) { 'test-file' }
+ let(:new_file_name) { "#{file_name}-new" }
+ let(:second_file_name) { "#{file_name}-2" }
+ let(:branch_name) { 'position-tracer-test' }
+ let(:old_position) { position(old_path: file_name, new_path: file_name, position_type: 'image') }
+
+ let(:tracer) do
+ Gitlab::Diff::PositionTracer.new(
+ project: project,
+ old_diff_refs: old_diff_refs,
+ new_diff_refs: new_diff_refs
+ )
+ end
+
+ let(:strategy) { described_class.new(tracer) }
+
+ subject { strategy.trace(old_position) }
+
+ let(:initial_commit) do
+ project.commit(create_branch(branch_name, 'master')[:branch].name)
+ end
+
+ describe '#trace' do
+ describe 'diff scenarios' do
+ let(:create_file_commit) do
+ initial_commit
+
+ create_file(
+ branch_name,
+ file_name,
+ Base64.encode64('content')
+ )
+ end
+
+ let(:update_file_commit) do
+ create_file_commit
+
+ update_file(
+ branch_name,
+ file_name,
+ Base64.encode64('updatedcontent')
+ )
+ end
+
+ let(:update_file_again_commit) do
+ update_file_commit
+
+ update_file(
+ branch_name,
+ file_name,
+ Base64.encode64('updatedcontentagain')
+ )
+ end
+
+ let(:delete_file_commit) do
+ create_file_commit
+ delete_file(branch_name, file_name)
+ end
+
+ let(:rename_file_commit) do
+ delete_file_commit
+
+ create_file(
+ branch_name,
+ new_file_name,
+ Base64.encode64('renamedcontent')
+ )
+ end
+
+ let(:create_second_file_commit) do
+ create_file_commit
+
+ create_file(
+ branch_name,
+ second_file_name,
+ Base64.encode64('morecontent')
+ )
+ end
+
+ let(:create_another_file_commit) do
+ create_file(
+ branch_name,
+ second_file_name,
+ Base64.encode64('morecontent')
+ )
+ end
+
+ let(:update_another_file_commit) do
+ update_file(
+ branch_name,
+ second_file_name,
+ Base64.encode64('updatedmorecontent')
+ )
+ end
+
+ context 'when the file was created in the old diff' do
+ context 'when the file is unchanged between the old and the new diff' do
+ let(:old_diff_refs) { diff_refs(initial_commit, create_file_commit) }
+ let(:new_diff_refs) { diff_refs(initial_commit, create_second_file_commit) }
+
+ it 'returns the new position' do
+ expect_new_position(
+ old_path: file_name,
+ new_path: file_name
+ )
+ end
+ end
+
+ context 'when the file was updated between the old and the new diff' do
+ let(:old_diff_refs) { diff_refs(initial_commit, create_file_commit) }
+ let(:new_diff_refs) { diff_refs(initial_commit, update_file_commit) }
+ let(:change_diff_refs) { diff_refs(create_file_commit, update_file_commit) }
+
+ it 'returns the position of the change' do
+ expect_change_position(
+ old_path: file_name,
+ new_path: file_name
+ )
+ end
+ end
+
+ context 'when the file was renamed in between the old and the new diff' do
+ let(:old_diff_refs) { diff_refs(initial_commit, create_file_commit) }
+ let(:new_diff_refs) { diff_refs(initial_commit, rename_file_commit) }
+ let(:change_diff_refs) { diff_refs(create_file_commit, rename_file_commit) }
+
+ it 'returns the position of the change' do
+ expect_change_position(
+ old_path: file_name,
+ new_path: file_name
+ )
+ end
+ end
+
+ context 'when the file was removed in between the old and the new diff' do
+ let(:old_diff_refs) { diff_refs(initial_commit, create_file_commit) }
+ let(:new_diff_refs) { diff_refs(initial_commit, delete_file_commit) }
+ let(:change_diff_refs) { diff_refs(create_file_commit, delete_file_commit) }
+
+ it 'returns the position of the change' do
+ expect_change_position(
+ old_path: file_name,
+ new_path: file_name
+ )
+ end
+ end
+
+ context 'when the file is unchanged in the new diff' do
+ let(:old_diff_refs) { diff_refs(initial_commit, create_file_commit) }
+ let(:new_diff_refs) { diff_refs(create_another_file_commit, update_another_file_commit) }
+ let(:change_diff_refs) { diff_refs(initial_commit, create_another_file_commit) }
+
+ it 'returns the position of the change' do
+ expect_change_position(
+ old_path: file_name,
+ new_path: file_name
+ )
+ end
+ end
+ end
+
+ context 'when the file was changed in the old diff' do
+ context 'when the file is unchanged in between the old and the new diff' do
+ let(:old_diff_refs) { diff_refs(create_file_commit, update_file_commit) }
+ let(:new_diff_refs) { diff_refs(create_file_commit, create_second_file_commit) }
+
+ it 'returns the new position' do
+ expect_new_position(
+ old_path: file_name,
+ new_path: file_name
+ )
+ end
+ end
+
+ context 'when the file was updated in between the old and the new diff' do
+ let(:old_diff_refs) { diff_refs(create_file_commit, update_file_commit) }
+ let(:new_diff_refs) { diff_refs(create_file_commit, update_file_again_commit) }
+ let(:change_diff_refs) { diff_refs(update_file_commit, update_file_again_commit) }
+
+ it 'returns the position of the change' do
+ expect_change_position(
+ old_path: file_name,
+ new_path: file_name
+ )
+ end
+ end
+
+ context 'when the file was renamed in between the old and the new diff' do
+ let(:old_diff_refs) { diff_refs(create_file_commit, update_file_commit) }
+ let(:new_diff_refs) { diff_refs(create_file_commit, rename_file_commit) }
+ let(:change_diff_refs) { diff_refs(update_file_commit, rename_file_commit) }
+
+ it 'returns the position of the change' do
+ expect_change_position(
+ old_path: file_name,
+ new_path: file_name
+ )
+ end
+ end
+
+ context 'when the file was removed in between the old and the new diff' do
+ let(:old_diff_refs) { diff_refs(create_file_commit, update_file_commit) }
+ let(:new_diff_refs) { diff_refs(create_file_commit, delete_file_commit) }
+ let(:change_diff_refs) { diff_refs(update_file_commit, delete_file_commit) }
+
+ it 'returns the position of the change' do
+ expect_change_position(
+ old_path: file_name,
+ new_path: file_name
+ )
+ end
+ end
+
+ context 'when the file is unchanged in the new diff' do
+ let(:old_diff_refs) { diff_refs(create_file_commit, update_file_commit) }
+ let(:new_diff_refs) { diff_refs(create_another_file_commit, update_another_file_commit) }
+ let(:change_diff_refs) { diff_refs(create_file_commit, create_another_file_commit) }
+
+ it 'returns the position of the change' do
+ expect_change_position(
+ old_path: file_name,
+ new_path: file_name
+ )
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/diff/position_tracer/line_strategy_spec.rb b/spec/lib/gitlab/diff/position_tracer/line_strategy_spec.rb
new file mode 100644
index 00000000000..7f4902c5b86
--- /dev/null
+++ b/spec/lib/gitlab/diff/position_tracer/line_strategy_spec.rb
@@ -0,0 +1,1805 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Gitlab::Diff::PositionTracer::LineStrategy do
+ # Douwe's diary New York City, 2016-06-28
+ # --------------------------------------------------------------------------
+ #
+ # Dear diary,
+ #
+ # Ideally, we would have a test for every single diff scenario that can
+ # occur and that the PositionTracer should correctly trace a position
+ # through, across the following variables:
+ #
+ # - Old diff file type: created, changed, renamed, deleted, unchanged (5)
+ # - Old diff line type: added, removed, unchanged (3)
+ # - New diff file type: created, changed, renamed, deleted, unchanged (5)
+ # - New diff line type: added, removed, unchanged (3)
+ # - Old-to-new diff line change: kept, moved, undone (3)
+ #
+ # This adds up to 5 * 3 * 5 * 3 * 3 = 675 different potential scenarios,
+ # and 675 different tests to cover them all. In reality, it would be fewer,
+ # since one cannot have a removed line in a created file diff, for example,
+ # but for the sake of this diary entry, let's be pessimistic.
+ #
+ # Writing these tests is a manual and time consuming process, as every test
+ # requires the manual construction or finding of a combination of diffs that
+ # create the exact diff scenario we are looking for, and can take between
+ # 1 and 10 minutes, depending on the farfetchedness of the scenario and
+ # complexity of creating it.
+ #
+ # This means that writing tests to cover all of these scenarios would end up
+ # taking between 11 and 112 hours in total, which I do not believe is the
+ # best use of my time.
+ #
+ # A better course of action would be to think of scenarios that are likely
+ # to occur, but also potentially tricky to trace correctly, and only cover
+ # those, with a few more obvious scenarios thrown in to cover our bases.
+ #
+ # Unfortunately, I only came to the above realization once I was about
+ # 1/5th of the way through the process of writing ALL THE SPECS, having
+ # already wasted about 3 hours trying to be thorough.
+ #
+ # I did find 2 bugs while writing those though, so that's good.
+ #
+ # In any case, all of this means that the tests below will be extremely
+ # (excessively, unjustifiably) thorough for scenarios where "the file was
+ # created in the old diff" and then drop off to comparatively lackluster
+ # testing of other scenarios.
+ #
+ # I did still try to cover most of the obvious and potentially tricky
+ # scenarios, though.
+
+ include RepoHelpers
+ include PositionTracerHelpers
+
+ let(:project) { create(:project, :repository) }
+ let(:current_user) { project.owner }
+ let(:repository) { project.repository }
+ let(:file_name) { "test-file" }
+ let(:new_file_name) { "#{file_name}-new" }
+ let(:second_file_name) { "#{file_name}-2" }
+ let(:branch_name) { "position-tracer-test" }
+
+ let(:old_diff_refs) { raise NotImplementedError }
+ let(:new_diff_refs) { raise NotImplementedError }
+ let(:change_diff_refs) { raise NotImplementedError }
+ let(:old_position) { raise NotImplementedError }
+
+ let(:tracer) do
+ Gitlab::Diff::PositionTracer.new(
+ project: project,
+ old_diff_refs: old_diff_refs,
+ new_diff_refs: new_diff_refs
+ )
+ end
+
+ let(:strategy) { described_class.new(tracer) }
+
+ subject { strategy.trace(old_position) }
+
+ let(:initial_commit) do
+ project.commit(create_branch(branch_name, 'master')[:branch].name)
+ end
+
+ describe "#trace" do
+ describe "diff scenarios" do
+ let(:create_file_commit) do
+ initial_commit
+
+ create_file(
+ branch_name,
+ file_name,
+ <<-CONTENT.strip_heredoc
+ A
+ B
+ C
+ CONTENT
+ )
+ end
+
+ let(:create_second_file_commit) do
+ create_file_commit
+
+ create_file(
+ branch_name,
+ second_file_name,
+ <<-CONTENT.strip_heredoc
+ D
+ E
+ CONTENT
+ )
+ end
+
+ let(:update_line_commit) do
+ create_second_file_commit
+
+ update_file(
+ branch_name,
+ file_name,
+ <<-CONTENT.strip_heredoc
+ A
+ BB
+ C
+ CONTENT
+ )
+ end
+
+ let(:update_second_file_line_commit) do
+ update_line_commit
+
+ update_file(
+ branch_name,
+ second_file_name,
+ <<-CONTENT.strip_heredoc
+ D
+ EE
+ CONTENT
+ )
+ end
+
+ let(:move_line_commit) do
+ update_second_file_line_commit
+
+ update_file(
+ branch_name,
+ file_name,
+ <<-CONTENT.strip_heredoc
+ BB
+ A
+ C
+ CONTENT
+ )
+ end
+
+ let(:add_second_file_line_commit) do
+ move_line_commit
+
+ update_file(
+ branch_name,
+ second_file_name,
+ <<-CONTENT.strip_heredoc
+ D
+ EE
+ F
+ CONTENT
+ )
+ end
+
+ let(:move_second_file_line_commit) do
+ add_second_file_line_commit
+
+ update_file(
+ branch_name,
+ second_file_name,
+ <<-CONTENT.strip_heredoc
+ D
+ F
+ EE
+ CONTENT
+ )
+ end
+
+ let(:delete_line_commit) do
+ move_second_file_line_commit
+
+ update_file(
+ branch_name,
+ file_name,
+ <<-CONTENT.strip_heredoc
+ BB
+ A
+ CONTENT
+ )
+ end
+
+ let(:delete_second_file_line_commit) do
+ delete_line_commit
+
+ update_file(
+ branch_name,
+ second_file_name,
+ <<-CONTENT.strip_heredoc
+ D
+ F
+ CONTENT
+ )
+ end
+
+ let(:delete_file_commit) do
+ delete_second_file_line_commit
+
+ delete_file(branch_name, file_name)
+ end
+
+ let(:rename_file_commit) do
+ delete_file_commit
+
+ create_file(
+ branch_name,
+ new_file_name,
+ <<-CONTENT.strip_heredoc
+ BB
+ A
+ CONTENT
+ )
+ end
+
+ let(:update_line_again_commit) do
+ rename_file_commit
+
+ update_file(
+ branch_name,
+ new_file_name,
+ <<-CONTENT.strip_heredoc
+ BB
+ AA
+ CONTENT
+ )
+ end
+
+ let(:move_line_again_commit) do
+ update_line_again_commit
+
+ update_file(
+ branch_name,
+ new_file_name,
+ <<-CONTENT.strip_heredoc
+ AA
+ BB
+ CONTENT
+ )
+ end
+
+ let(:delete_line_again_commit) do
+ move_line_again_commit
+
+ update_file(
+ branch_name,
+ new_file_name,
+ <<-CONTENT.strip_heredoc
+ AA
+ CONTENT
+ )
+ end
+
+ context "when the file was created in the old diff" do
+ context "when the file is created in the new diff" do
+ context "when the position pointed at an added line in the old diff" do
+ context "when the file's content was unchanged between the old and the new diff" do
+ let(:old_diff_refs) { diff_refs(initial_commit, create_file_commit) }
+ let(:new_diff_refs) { diff_refs(initial_commit, create_second_file_commit) }
+ let(:old_position) { position(new_path: file_name, new_line: 2) }
+
+ # old diff:
+ # 1 + A
+ # 2 + B
+ # 3 + C
+ #
+ # new diff:
+ # 1 + A
+ # 2 + B
+ # 3 + C
+
+ it "returns the new position" do
+ expect_new_position(
+ new_path: old_position.new_path,
+ new_line: old_position.new_line
+ )
+ end
+ end
+
+ context "when the file's content was changed between the old and the new diff" do
+ context "when that line was unchanged between the old and the new diff" do
+ let(:old_diff_refs) { diff_refs(initial_commit, create_file_commit) }
+ let(:new_diff_refs) { diff_refs(initial_commit, update_line_commit) }
+ let(:old_position) { position(new_path: file_name, new_line: 1) }
+
+ # old diff:
+ # 1 + A
+ # 2 + B
+ # 3 + C
+ #
+ # new diff:
+ # 1 + A
+ # 2 + BB
+ # 3 + C
+
+ it "returns the new position" do
+ expect_new_position(
+ new_path: old_position.new_path,
+ new_line: old_position.new_line
+ )
+ end
+ end
+
+ context "when that line was moved between the old and the new diff" do
+ let(:old_diff_refs) { diff_refs(initial_commit, update_line_commit) }
+ let(:new_diff_refs) { diff_refs(initial_commit, move_line_commit) }
+ let(:old_position) { position(new_path: file_name, new_line: 2) }
+
+ # old diff:
+ # 1 + A
+ # 2 + BB
+ # 3 + C
+ #
+ # new diff:
+ # 1 + BB
+ # 2 + A
+ # 3 + C
+
+ it "returns the new position" do
+ expect_new_position(
+ new_path: old_position.new_path,
+ new_line: 1
+ )
+ end
+ end
+
+ context "when that line was changed between the old and the new diff" do
+ let(:old_diff_refs) { diff_refs(initial_commit, create_file_commit) }
+ let(:new_diff_refs) { diff_refs(initial_commit, update_line_commit) }
+ let(:change_diff_refs) { diff_refs(create_file_commit, update_line_commit) }
+ let(:old_position) { position(new_path: file_name, new_line: 2) }
+
+ # old diff:
+ # 1 + A
+ # 2 + B
+ # 3 + C
+ #
+ # new diff:
+ # 1 + A
+ # 2 + BB
+ # 3 + C
+
+ it "returns the position of the change" do
+ expect_change_position(
+ old_path: file_name,
+ new_path: file_name,
+ old_line: 2,
+ new_line: nil
+ )
+ end
+ end
+
+ context "when that line was deleted between the old and the new diff" do
+ let(:old_diff_refs) { diff_refs(initial_commit, update_line_commit) }
+ let(:new_diff_refs) { diff_refs(initial_commit, delete_line_commit) }
+ let(:change_diff_refs) { diff_refs(update_line_commit, delete_line_commit) }
+ let(:old_position) { position(new_path: file_name, new_line: 3) }
+
+ # old diff:
+ # 1 + A
+ # 2 + BB
+ # 3 + C
+ #
+ # new diff:
+ # 1 + A
+ # 2 + BB
+
+ it "returns the position of the change" do
+ expect_change_position(
+ old_path: file_name,
+ new_path: file_name,
+ old_line: 3,
+ new_line: nil
+ )
+ end
+ end
+ end
+ end
+ end
+
+ context "when the file is changed in the new diff" do
+ context "when the position pointed at an added line in the old diff" do
+ context "when the file's content was unchanged between the old and the new diff" do
+ let(:old_diff_refs) { diff_refs(initial_commit, update_line_commit) }
+ let(:new_diff_refs) { diff_refs(create_file_commit, update_line_commit) }
+ let(:old_position) { position(new_path: file_name, new_line: 1) }
+
+ # old diff:
+ # 1 + A
+ # 2 + BB
+ # 3 + C
+ #
+ # new diff:
+ # 1 1 A
+ # 2 - B
+ # 2 + BB
+ # 3 3 C
+
+ it "returns the new position" do
+ expect_new_position(
+ new_path: old_position.new_path,
+ new_line: old_position.new_line
+ )
+ end
+ end
+
+ context "when the file's content was changed between the old and the new diff" do
+ context "when that line was unchanged between the old and the new diff" do
+ let(:old_diff_refs) { diff_refs(initial_commit, update_line_commit) }
+ let(:new_diff_refs) { diff_refs(update_line_commit, move_line_commit) }
+ let(:old_position) { position(new_path: file_name, new_line: 3) }
+
+ # old diff:
+ # 1 + A
+ # 2 + BB
+ # 3 + C
+ #
+ # new diff:
+ # 1 - A
+ # 2 1 BB
+ # 2 + A
+ # 3 3 C
+
+ it "returns the new position" do
+ expect_new_position(
+ new_path: old_position.new_path,
+ new_line: old_position.new_line
+ )
+ end
+ end
+
+ context "when that line was moved between the old and the new diff" do
+ let(:old_diff_refs) { diff_refs(initial_commit, update_line_commit) }
+ let(:new_diff_refs) { diff_refs(update_line_commit, move_line_commit) }
+ let(:old_position) { position(new_path: file_name, new_line: 2) }
+
+ # old diff:
+ # 1 + A
+ # 2 + BB
+ # 3 + C
+ #
+ # new diff:
+ # 1 - A
+ # 2 1 BB
+ # 2 + A
+ # 3 3 C
+
+ it "returns the new position" do
+ expect_new_position(
+ new_path: old_position.new_path,
+ new_line: 1
+ )
+ end
+ end
+
+ context "when that line was changed between the old and the new diff" do
+ let(:old_diff_refs) { diff_refs(initial_commit, create_file_commit) }
+ let(:new_diff_refs) { diff_refs(create_file_commit, update_line_commit) }
+ let(:change_diff_refs) { diff_refs(create_file_commit, update_line_commit) }
+ let(:old_position) { position(new_path: file_name, new_line: 2) }
+
+ # old diff:
+ # 1 + A
+ # 2 + B
+ # 3 + C
+ #
+ # new diff:
+ # 1 1 A
+ # 2 - B
+ # 2 + BB
+ # 3 3 C
+
+ it "returns the position of the change" do
+ expect_change_position(
+ old_path: file_name,
+ new_path: file_name,
+ old_line: 2,
+ new_line: nil
+ )
+ end
+ end
+
+ context "when that line was deleted between the old and the new diff" do
+ let(:old_diff_refs) { diff_refs(initial_commit, move_line_commit) }
+ let(:new_diff_refs) { diff_refs(move_line_commit, delete_line_commit) }
+ let(:change_diff_refs) { diff_refs(move_line_commit, delete_line_commit) }
+ let(:old_position) { position(new_path: file_name, new_line: 3) }
+
+ # old diff:
+ # 1 + BB
+ # 2 + A
+ # 3 + C
+ #
+ # new diff:
+ # 1 1 BB
+ # 2 2 A
+ # 3 - C
+
+ it "returns the position of the change" do
+ expect_change_position(
+ old_path: file_name,
+ new_path: file_name,
+ old_line: 3,
+ new_line: nil
+ )
+ end
+ end
+ end
+ end
+ end
+
+ context "when the file is renamed in the new diff" do
+ context "when the position pointed at an added line in the old diff" do
+ context "when the file's content was unchanged between the old and the new diff" do
+ let(:old_diff_refs) { diff_refs(initial_commit, delete_line_commit) }
+ let(:new_diff_refs) { diff_refs(delete_line_commit, rename_file_commit) }
+ let(:change_diff_refs) { diff_refs(initial_commit, delete_line_commit) }
+ let(:old_position) { position(new_path: file_name, new_line: 2) }
+
+ # old diff:
+ # 1 + BB
+ # 2 + A
+ #
+ # new diff:
+ # file_name -> new_file_name
+ # 1 1 BB
+ # 2 2 A
+
+ it "returns the position of the change" do
+ expect_change_position(
+ old_path: file_name,
+ new_path: file_name,
+ old_line: nil,
+ new_line: 2
+ )
+ end
+ end
+
+ context "when the file's content was changed between the old and the new diff" do
+ context "when that line was unchanged between the old and the new diff" do
+ let(:old_diff_refs) { diff_refs(initial_commit, delete_line_commit) }
+ let(:new_diff_refs) { diff_refs(delete_line_commit, update_line_again_commit) }
+ let(:old_position) { position(new_path: file_name, new_line: 1) }
+
+ # old diff:
+ # 1 + BB
+ # 2 + A
+ #
+ # new diff:
+ # file_name -> new_file_name
+ # 1 1 BB
+ # 2 - A
+ # 2 + AA
+
+ it "returns the new position" do
+ expect_new_position(
+ old_path: file_name,
+ new_path: new_file_name,
+ old_line: old_position.new_line,
+ new_line: old_position.new_line
+ )
+ end
+ end
+
+ context "when that line was moved between the old and the new diff" do
+ let(:old_diff_refs) { diff_refs(initial_commit, delete_line_commit) }
+ let(:new_diff_refs) { diff_refs(delete_line_commit, move_line_again_commit) }
+ let(:old_position) { position(new_path: file_name, new_line: 1) }
+
+ # old diff:
+ # 1 + BB
+ # 2 + A
+ #
+ # new diff:
+ # file_name -> new_file_name
+ # 1 + AA
+ # 1 2 BB
+ # 2 - A
+
+ it "returns the new position" do
+ expect_new_position(
+ old_path: file_name,
+ new_path: new_file_name,
+ old_line: 1,
+ new_line: 2
+ )
+ end
+ end
+
+ context "when that line was changed between the old and the new diff" do
+ let(:old_diff_refs) { diff_refs(initial_commit, delete_line_commit) }
+ let(:new_diff_refs) { diff_refs(delete_line_commit, update_line_again_commit) }
+ let(:change_diff_refs) { diff_refs(delete_line_commit, update_line_again_commit) }
+ let(:old_position) { position(new_path: file_name, new_line: 2) }
+
+ # old diff:
+ # 1 + BB
+ # 2 + A
+ #
+ # new diff:
+ # file_name -> new_file_name
+ # 1 1 BB
+ # 2 - A
+ # 2 + AA
+
+ it "returns the position of the change" do
+ expect_change_position(
+ old_path: file_name,
+ new_path: new_file_name,
+ old_line: 2,
+ new_line: nil
+ )
+ end
+ end
+ end
+ end
+ end
+
+ context "when the file is deleted in the new diff" do
+ context "when the position pointed at an added line in the old diff" do
+ context "when the file's content was unchanged between the old and the new diff" do
+ let(:old_diff_refs) { diff_refs(initial_commit, delete_line_commit) }
+ let(:new_diff_refs) { diff_refs(delete_line_commit, delete_file_commit) }
+ let(:change_diff_refs) { diff_refs(delete_line_commit, delete_file_commit) }
+ let(:old_position) { position(new_path: file_name, new_line: 2) }
+
+ # old diff:
+ # 1 + BB
+ # 2 + A
+ #
+ # new diff:
+ # 1 - BB
+ # 2 - A
+
+ it "returns the position of the change" do
+ expect_change_position(
+ old_path: file_name,
+ new_path: file_name,
+ old_line: 2,
+ new_line: nil
+ )
+ end
+ end
+
+ context "when the file's content was changed between the old and the new diff" do
+ context "when that line was unchanged between the old and the new diff" do
+ let(:old_diff_refs) { diff_refs(initial_commit, move_line_commit) }
+ let(:new_diff_refs) { diff_refs(delete_line_commit, delete_file_commit) }
+ let(:change_diff_refs) { diff_refs(move_line_commit, delete_file_commit) }
+ let(:old_position) { position(new_path: file_name, new_line: 2) }
+
+ # old diff:
+ # 1 + BB
+ # 2 + A
+ # 3 + C
+ #
+ # new diff:
+ # 1 - BB
+ # 2 - A
+
+ it "returns the position of the change" do
+ expect_change_position(
+ old_path: file_name,
+ new_path: file_name,
+ old_line: 2,
+ new_line: nil
+ )
+ end
+ end
+
+ context "when that line was moved between the old and the new diff" do
+ let(:old_diff_refs) { diff_refs(initial_commit, update_line_commit) }
+ let(:new_diff_refs) { diff_refs(move_line_commit, delete_file_commit) }
+ let(:change_diff_refs) { diff_refs(update_line_commit, delete_file_commit) }
+ let(:old_position) { position(new_path: file_name, new_line: 2) }
+
+ # old diff:
+ # 1 + A
+ # 2 + BB
+ # 3 + C
+ #
+ # new diff:
+ # 1 - BB
+ # 2 - A
+ # 3 - C
+
+ it "returns the position of the change" do
+ expect_change_position(
+ old_path: file_name,
+ new_path: file_name,
+ old_line: 2,
+ new_line: nil
+ )
+ end
+ end
+
+ context "when that line was changed between the old and the new diff" do
+ let(:old_diff_refs) { diff_refs(initial_commit, create_file_commit) }
+ let(:new_diff_refs) { diff_refs(update_line_commit, delete_file_commit) }
+ let(:change_diff_refs) { diff_refs(create_file_commit, delete_file_commit) }
+ let(:old_position) { position(new_path: file_name, new_line: 2) }
+
+ # old diff:
+ # 1 + A
+ # 2 + B
+ # 3 + C
+ #
+ # new diff:
+ # 1 - A
+ # 2 - BB
+ # 3 - C
+
+ it "returns the position of the change" do
+ expect_change_position(
+ old_path: file_name,
+ new_path: file_name,
+ old_line: 2,
+ new_line: nil
+ )
+ end
+ end
+
+ context "when that line was deleted between the old and the new diff" do
+ let(:old_diff_refs) { diff_refs(initial_commit, move_line_commit) }
+ let(:new_diff_refs) { diff_refs(delete_line_commit, delete_file_commit) }
+ let(:change_diff_refs) { diff_refs(move_line_commit, delete_file_commit) }
+ let(:old_position) { position(new_path: file_name, new_line: 3) }
+
+ # old diff:
+ # 1 + BB
+ # 2 + A
+ # 3 + C
+ #
+ # new diff:
+ # 1 - BB
+ # 2 - A
+
+ it "returns the position of the change" do
+ expect_change_position(
+ old_path: file_name,
+ new_path: file_name,
+ old_line: 3,
+ new_line: nil
+ )
+ end
+ end
+ end
+ end
+ end
+
+ context "when the file is unchanged in the new diff" do
+ context "when the position pointed at an added line in the old diff" do
+ context "when the file's content was unchanged between the old and the new diff" do
+ let(:old_diff_refs) { diff_refs(initial_commit, create_file_commit) }
+ let(:new_diff_refs) { diff_refs(create_file_commit, create_second_file_commit) }
+ let(:change_diff_refs) { diff_refs(initial_commit, create_file_commit) }
+ let(:old_position) { position(new_path: file_name, new_line: 2) }
+
+ # old diff:
+ # 1 + A
+ # 2 + B
+ # 3 + C
+ #
+ # new diff:
+ # 1 1 A
+ # 2 2 B
+ # 3 3 C
+
+ it "returns the position of the change" do
+ expect_change_position(
+ old_path: file_name,
+ new_path: file_name,
+ old_line: nil,
+ new_line: 2
+ )
+ end
+ end
+
+ context "when the file's content was changed between the old and the new diff" do
+ context "when that line was unchanged between the old and the new diff" do
+ let(:old_diff_refs) { diff_refs(initial_commit, create_file_commit) }
+ let(:new_diff_refs) { diff_refs(update_line_commit, update_second_file_line_commit) }
+ let(:change_diff_refs) { diff_refs(initial_commit, update_line_commit) }
+ let(:old_position) { position(new_path: file_name, new_line: 1) }
+
+ # old diff:
+ # 1 + A
+ # 2 + B
+ # 3 + C
+ #
+ # new diff:
+ # 1 1 A
+ # 2 2 BB
+ # 3 3 C
+
+ it "returns the position of the change" do
+ expect_change_position(
+ old_path: file_name,
+ new_path: file_name,
+ old_line: nil,
+ new_line: 1
+ )
+ end
+ end
+
+ context "when that line was moved between the old and the new diff" do
+ let(:old_diff_refs) { diff_refs(initial_commit, update_line_commit) }
+ let(:new_diff_refs) { diff_refs(move_line_commit, move_second_file_line_commit) }
+ let(:change_diff_refs) { diff_refs(initial_commit, move_line_commit) }
+ let(:old_position) { position(new_path: file_name, new_line: 2) }
+
+ # old diff:
+ # 1 + A
+ # 2 + BB
+ # 3 + C
+ #
+ # new diff:
+ # 1 1 BB
+ # 2 2 A
+ # 3 3 C
+
+ it "returns the position of the change" do
+ expect_change_position(
+ old_path: file_name,
+ new_path: file_name,
+ old_line: nil,
+ new_line: 1
+ )
+ end
+ end
+
+ context "when that line was changed between the old and the new diff" do
+ let(:old_diff_refs) { diff_refs(initial_commit, create_file_commit) }
+ let(:new_diff_refs) { diff_refs(update_line_commit, update_second_file_line_commit) }
+ let(:change_diff_refs) { diff_refs(create_file_commit, update_second_file_line_commit) }
+ let(:old_position) { position(new_path: file_name, new_line: 2) }
+
+ # old diff:
+ # 1 + A
+ # 2 + B
+ # 3 + C
+ #
+ # new diff:
+ # 1 1 A
+ # 2 2 BB
+ # 3 3 C
+
+ it "returns the position of the change" do
+ expect_change_position(
+ old_path: file_name,
+ new_path: file_name,
+ old_line: 2,
+ new_line: nil
+ )
+ end
+ end
+
+ context "when that line was deleted between the old and the new diff" do
+ let(:old_diff_refs) { diff_refs(initial_commit, move_line_commit) }
+ let(:new_diff_refs) { diff_refs(delete_line_commit, delete_second_file_line_commit) }
+ let(:change_diff_refs) { diff_refs(move_line_commit, delete_second_file_line_commit) }
+ let(:old_position) { position(new_path: file_name, new_line: 3) }
+
+ # old diff:
+ # 1 + BB
+ # 2 + A
+ # 3 + C
+ #
+ # new diff:
+ # 1 1 BB
+ # 2 2 A
+
+ it "returns the position of the change" do
+ expect_change_position(
+ old_path: file_name,
+ new_path: file_name,
+ old_line: 3,
+ new_line: nil
+ )
+ end
+ end
+ end
+ end
+ end
+ end
+
+ context "when the file was changed in the old diff" do
+ context "when the file is created in the new diff" do
+ context "when the position pointed at an added line in the old diff" do
+ context "when the file's content was unchanged between the old and the new diff" do
+ let(:old_diff_refs) { diff_refs(create_file_commit, update_line_commit) }
+ let(:new_diff_refs) { diff_refs(initial_commit, update_line_commit) }
+ let(:old_position) { position(old_path: file_name, new_path: file_name, new_line: 2) }
+
+ # old diff:
+ # 1 1 A
+ # 2 - B
+ # 2 + BB
+ # 3 3 C
+ #
+ # new diff:
+ # 1 + A
+ # 2 + BB
+ # 3 + C
+
+ it "returns the new position" do
+ expect_new_position(
+ new_path: old_position.new_path,
+ old_line: nil,
+ new_line: old_position.new_line
+ )
+ end
+ end
+
+ context "when the file's content was changed between the old and the new diff" do
+ context "when that line was unchanged between the old and the new diff" do
+ let(:old_diff_refs) { diff_refs(create_file_commit, move_line_commit) }
+ let(:new_diff_refs) { diff_refs(initial_commit, move_line_commit) }
+ let(:old_position) { position(old_path: file_name, new_path: file_name, new_line: 1) }
+
+ # old diff:
+ # 1 + BB
+ # 1 2 A
+ # 2 - B
+ # 3 3 C
+ #
+ # new diff:
+ # 1 + BB
+ # 2 + A
+
+ it "returns the new position" do
+ expect_new_position(
+ new_path: old_position.new_path,
+ old_line: nil,
+ new_line: old_position.new_line
+ )
+ end
+ end
+
+ context "when that line was moved between the old and the new diff" do
+ let(:old_diff_refs) { diff_refs(create_file_commit, update_line_commit) }
+ let(:new_diff_refs) { diff_refs(initial_commit, move_line_commit) }
+ let(:old_position) { position(old_path: file_name, new_path: file_name, new_line: 2) }
+
+ # old diff:
+ # 1 1 A
+ # 2 - B
+ # 2 + BB
+ # 3 3 C
+ #
+ # new diff:
+ # 1 + BB
+ # 2 + A
+ # 3 + C
+
+ it "returns the new position" do
+ expect_new_position(
+ new_path: old_position.new_path,
+ old_line: nil,
+ new_line: 1
+ )
+ end
+ end
+
+ context "when that line was changed or deleted between the old and the new diff" do
+ let(:old_diff_refs) { diff_refs(create_file_commit, move_line_commit) }
+ let(:new_diff_refs) { diff_refs(initial_commit, create_file_commit) }
+ let(:change_diff_refs) { diff_refs(move_line_commit, create_file_commit) }
+ let(:old_position) { position(old_path: file_name, new_path: file_name, new_line: 1) }
+
+ # old diff:
+ # 1 + BB
+ # 1 2 A
+ # 2 - B
+ # 3 3 C
+ #
+ # new diff:
+ # 1 + A
+ # 2 + B
+ # 3 + C
+
+ it "returns the position of the change" do
+ expect_change_position(
+ old_path: file_name,
+ new_path: file_name,
+ old_line: 1,
+ new_line: nil
+ )
+ end
+ end
+ end
+ end
+
+ context "when the position pointed at a deleted line in the old diff" do
+ let(:old_diff_refs) { diff_refs(create_file_commit, update_line_commit) }
+ let(:new_diff_refs) { diff_refs(initial_commit, update_line_commit) }
+ let(:change_diff_refs) { diff_refs(create_file_commit, initial_commit) }
+ let(:old_position) { position(old_path: file_name, new_path: file_name, old_line: 2) }
+
+ # old diff:
+ # 1 1 A
+ # 2 - B
+ # 2 + BB
+ # 3 3 C
+ #
+ # new diff:
+ # 1 + A
+ # 2 + BB
+ # 3 + C
+
+ it "returns the position of the change" do
+ expect_change_position(
+ old_path: file_name,
+ new_path: file_name,
+ old_line: 2,
+ new_line: nil
+ )
+ end
+ end
+
+ context "when the position pointed at an unchanged line in the old diff" do
+ context "when the file's content was unchanged between the old and the new diff" do
+ let(:old_diff_refs) { diff_refs(create_file_commit, update_line_commit) }
+ let(:new_diff_refs) { diff_refs(initial_commit, update_line_commit) }
+ let(:old_position) { position(old_path: file_name, new_path: file_name, old_line: 1, new_line: 1) }
+
+ # old diff:
+ # 1 1 A
+ # 2 - B
+ # 2 + BB
+ # 3 3 C
+ #
+ # new diff:
+ # 1 + A
+ # 2 + BB
+ # 3 + C
+
+ it "returns the new position" do
+ expect_new_position(
+ new_path: old_position.new_path,
+ old_line: nil,
+ new_line: old_position.new_line
+ )
+ end
+ end
+
+ context "when the file's content was changed between the old and the new diff" do
+ context "when that line was unchanged between the old and the new diff" do
+ let(:old_diff_refs) { diff_refs(create_file_commit, move_line_commit) }
+ let(:new_diff_refs) { diff_refs(initial_commit, move_line_commit) }
+ let(:old_position) { position(old_path: file_name, new_path: file_name, old_line: 1, new_line: 2) }
+
+ # old diff:
+ # 1 + BB
+ # 1 2 A
+ # 2 - B
+ # 3 3 C
+ #
+ # new diff:
+ # 1 + BB
+ # 2 + A
+
+ it "returns the new position" do
+ expect_new_position(
+ new_path: old_position.new_path,
+ old_line: nil,
+ new_line: old_position.new_line
+ )
+ end
+ end
+
+ context "when that line was moved between the old and the new diff" do
+ let(:old_diff_refs) { diff_refs(move_line_commit, delete_line_commit) }
+ let(:new_diff_refs) { diff_refs(initial_commit, update_line_commit) }
+ let(:old_position) { position(old_path: file_name, new_path: file_name, old_line: 2, new_line: 2) }
+
+ # old diff:
+ # 1 1 BB
+ # 2 2 A
+ # 3 - C
+ #
+ # new diff:
+ # 1 + A
+ # 2 + BB
+ # 3 + C
+
+ it "returns the new position" do
+ expect_new_position(
+ new_path: old_position.new_path,
+ old_line: nil,
+ new_line: 1
+ )
+ end
+ end
+
+ context "when that line was changed or deleted between the old and the new diff" do
+ let(:old_diff_refs) { diff_refs(create_file_commit, move_line_commit) }
+ let(:new_diff_refs) { diff_refs(initial_commit, delete_line_commit) }
+ let(:change_diff_refs) { diff_refs(move_line_commit, delete_line_commit) }
+ let(:old_position) { position(old_path: file_name, new_path: file_name, old_line: 3, new_line: 3) }
+
+ # old diff:
+ # 1 + BB
+ # 1 2 A
+ # 2 - B
+ # 3 3 C
+ #
+ # new diff:
+ # 1 + A
+ # 2 + B
+
+ it "returns the position of the change" do
+ expect_change_position(
+ old_path: file_name,
+ new_path: file_name,
+ old_line: 3,
+ new_line: nil
+ )
+ end
+ end
+ end
+ end
+ end
+
+ context "when the file is changed in the new diff" do
+ context "when the position pointed at an added line in the old diff" do
+ context "when the file's content was unchanged between the old and the new diff" do
+ let(:old_diff_refs) { diff_refs(create_file_commit, update_line_commit) }
+ let(:new_diff_refs) { diff_refs(create_file_commit, update_second_file_line_commit) }
+ let(:old_position) { position(old_path: file_name, new_path: file_name, new_line: 2) }
+
+ # old diff:
+ # 1 1 A
+ # 2 - B
+ # 2 + BB
+ # 3 3 C
+ #
+ # new diff:
+ # 1 1 A
+ # 2 - B
+ # 2 + BB
+ # 3 3 C
+
+ it "returns the new position" do
+ expect_new_position(
+ old_path: old_position.old_path,
+ new_path: old_position.new_path,
+ old_line: nil,
+ new_line: old_position.new_line
+ )
+ end
+ end
+
+ context "when the file's content was changed between the old and the new diff" do
+ context "when that line was unchanged between the old and the new diff" do
+ let(:old_diff_refs) { diff_refs(create_file_commit, move_line_commit) }
+ let(:new_diff_refs) { diff_refs(move_line_commit, delete_line_commit) }
+ let(:old_position) { position(old_path: file_name, new_path: file_name, new_line: 1) }
+
+ # old diff:
+ # 1 + BB
+ # 1 2 A
+ # 2 - B
+ # 3 3 C
+ #
+ # new diff:
+ # 1 1 BB
+ # 2 2 A
+ # 3 - C
+
+ it "returns the new position" do
+ expect_new_position(
+ old_path: old_position.old_path,
+ new_path: old_position.new_path,
+ old_line: 1,
+ new_line: 1
+ )
+ end
+ end
+
+ context "when that line was moved between the old and the new diff" do
+ let(:old_diff_refs) { diff_refs(create_file_commit, update_line_commit) }
+ let(:new_diff_refs) { diff_refs(update_line_commit, move_line_commit) }
+ let(:old_position) { position(old_path: file_name, new_path: file_name, new_line: 2) }
+
+ # old diff:
+ # 1 1 A
+ # 2 - B
+ # 2 + BB
+ # 3 3 C
+ #
+ # new diff:
+ # 1 - A
+ # 2 1 BB
+ # 2 + A
+ # 3 3 C
+
+ it "returns the new position" do
+ expect_new_position(
+ old_path: old_position.old_path,
+ new_path: old_position.new_path,
+ old_line: 2,
+ new_line: 1
+ )
+ end
+ end
+
+ context "when that line was changed or deleted between the old and the new diff" do
+ let(:old_diff_refs) { diff_refs(create_file_commit, move_line_commit) }
+ let(:new_diff_refs) { diff_refs(create_file_commit, update_line_commit) }
+ let(:change_diff_refs) { diff_refs(move_line_commit, update_line_commit) }
+ let(:old_position) { position(old_path: file_name, new_path: file_name, new_line: 1) }
+
+ # old diff:
+ # 1 + BB
+ # 1 2 A
+ # 2 - B
+ # 3 3 C
+ #
+ # new diff:
+ # 1 1 A
+ # 2 - B
+ # 2 + BB
+ # 3 3 C
+
+ it "returns the position of the change" do
+ expect_change_position(
+ old_path: file_name,
+ new_path: file_name,
+ old_line: 1,
+ new_line: nil
+ )
+ end
+ end
+ end
+ end
+
+ context "when the position pointed at a deleted line in the old diff" do
+ context "when the file's content was unchanged between the old and the new diff" do
+ let(:old_diff_refs) { diff_refs(create_file_commit, update_line_commit) }
+ let(:new_diff_refs) { diff_refs(create_file_commit, update_second_file_line_commit) }
+ let(:old_position) { position(old_path: file_name, new_path: file_name, old_line: 2) }
+
+ # old diff:
+ # 1 1 A
+ # 2 - B
+ # 2 + BB
+ # 3 3 C
+ #
+ # new diff:
+ # 1 1 A
+ # 2 - B
+ # 2 + BB
+ # 3 3 C
+
+ it "returns the new position" do
+ expect_new_position(
+ old_path: old_position.old_path,
+ new_path: old_position.new_path,
+ old_line: old_position.old_line,
+ new_line: nil
+ )
+ end
+ end
+ end
+ end
+ end
+ end
+
+ describe "typical use scenarios" do
+ let(:second_branch_name) { "#{branch_name}-2" }
+
+ def expect_new_positions(old_attrs, new_attrs)
+ old_positions = old_attrs.map do |old_attrs|
+ position(old_attrs)
+ end
+
+ new_positions = old_positions.map do |old_position|
+ strategy.trace(old_position)
+ end
+
+ aggregate_failures do
+ new_positions.zip(new_attrs).each do |new_position, new_attrs|
+ if new_attrs&.delete(:change)
+ expect_change_position(new_attrs, new_position)
+ else
+ expect_new_position(new_attrs, new_position)
+ end
+ end
+ end
+ end
+
+ let(:create_file_commit) do
+ initial_commit
+
+ create_file(
+ branch_name,
+ file_name,
+ <<-CONTENT.strip_heredoc
+ A
+ B
+ C
+ D
+ E
+ F
+ CONTENT
+ )
+ end
+
+ let(:second_create_file_commit) do
+ create_file_commit
+
+ create_branch(second_branch_name, branch_name)
+
+ update_file(
+ second_branch_name,
+ file_name,
+ <<-CONTENT.strip_heredoc
+ Z
+ Z
+ Z
+ A
+ B
+ C
+ D
+ E
+ F
+ CONTENT
+ )
+ end
+
+ let(:update_file_commit) do
+ second_create_file_commit
+
+ update_file(
+ branch_name,
+ file_name,
+ <<-CONTENT.strip_heredoc
+ A
+ C
+ DD
+ E
+ F
+ G
+ CONTENT
+ )
+ end
+
+ let(:update_file_again_commit) do
+ update_file_commit
+
+ update_file(
+ branch_name,
+ file_name,
+ <<-CONTENT.strip_heredoc
+ A
+ BB
+ C
+ D
+ E
+ FF
+ G
+ CONTENT
+ )
+ end
+
+ describe "simple push of new commit" do
+ let(:old_diff_refs) { diff_refs(create_file_commit, update_file_commit) }
+ let(:new_diff_refs) { diff_refs(create_file_commit, update_file_again_commit) }
+ let(:change_diff_refs) { diff_refs(update_file_commit, update_file_again_commit) }
+
+ # old diff:
+ # 1 1 A
+ # 2 - B
+ # 3 2 C
+ # 4 - D
+ # 3 + DD
+ # 5 4 E
+ # 6 5 F
+ # 6 + G
+ #
+ # new diff:
+ # 1 1 A
+ # 2 - B
+ # 2 + BB
+ # 3 3 C
+ # 4 4 D
+ # 5 5 E
+ # 6 - F
+ # 6 + FF
+ # 7 + G
+
+ it "returns the new positions" do
+ old_position_attrs = [
+ { old_path: file_name, new_path: file_name, old_line: 1, new_line: 1 }, # A
+ { old_path: file_name, old_line: 2 }, # - B
+ { old_path: file_name, new_path: file_name, old_line: 3, new_line: 2 }, # C
+ { old_path: file_name, old_line: 4 }, # - D
+ { new_path: file_name, new_line: 3 }, # + DD
+ { old_path: file_name, new_path: file_name, old_line: 5, new_line: 4 }, # E
+ { old_path: file_name, new_path: file_name, old_line: 6, new_line: 5 }, # F
+ { new_path: file_name, new_line: 6 } # + G
+ ]
+
+ new_position_attrs = [
+ { old_path: file_name, new_path: file_name, old_line: 1, new_line: 1 },
+ { old_path: file_name, old_line: 2 },
+ { old_path: file_name, new_path: file_name, old_line: 3, new_line: 3 },
+ { new_path: file_name, new_line: 4, change: true },
+ { new_path: file_name, old_line: 3, change: true },
+ { old_path: file_name, new_path: file_name, old_line: 5, new_line: 5 },
+ { new_path: file_name, old_line: 5, change: true },
+ { new_path: file_name, new_line: 7 }
+ ]
+
+ expect_new_positions(old_position_attrs, new_position_attrs)
+ end
+ end
+
+ describe "force push to overwrite last commit" do
+ let(:second_create_file_commit) do
+ create_file_commit
+
+ create_branch(second_branch_name, branch_name)
+
+ update_file(
+ second_branch_name,
+ file_name,
+ <<-CONTENT.strip_heredoc
+ A
+ BB
+ C
+ D
+ E
+ FF
+ G
+ CONTENT
+ )
+ end
+
+ let(:old_diff_refs) { diff_refs(create_file_commit, update_file_commit) }
+ let(:new_diff_refs) { diff_refs(create_file_commit, second_create_file_commit) }
+ let(:change_diff_refs) { diff_refs(update_file_commit, second_create_file_commit) }
+
+ # old diff:
+ # 1 1 A
+ # 2 - B
+ # 3 2 C
+ # 4 - D
+ # 3 + DD
+ # 5 4 E
+ # 6 5 F
+ # 6 + G
+ #
+ # new diff:
+ # 1 1 A
+ # 2 - B
+ # 2 + BB
+ # 3 3 C
+ # 4 4 D
+ # 5 5 E
+ # 6 - F
+ # 6 + FF
+ # 7 + G
+
+ it "returns the new positions" do
+ old_position_attrs = [
+ { old_path: file_name, new_path: file_name, old_line: 1, new_line: 1 }, # A
+ { old_path: file_name, old_line: 2 }, # - B
+ { old_path: file_name, new_path: file_name, old_line: 3, new_line: 2 }, # C
+ { old_path: file_name, old_line: 4 }, # - D
+ { new_path: file_name, new_line: 3 }, # + DD
+ { old_path: file_name, new_path: file_name, old_line: 5, new_line: 4 }, # E
+ { old_path: file_name, new_path: file_name, old_line: 6, new_line: 5 }, # F
+ { new_path: file_name, new_line: 6 } # + G
+ ]
+
+ new_position_attrs = [
+ { old_path: file_name, new_path: file_name, old_line: 1, new_line: 1 },
+ { old_path: file_name, old_line: 2 },
+ { old_path: file_name, new_path: file_name, old_line: 3, new_line: 3 },
+ { new_path: file_name, new_line: 4, change: true },
+ { old_path: file_name, old_line: 3, change: true },
+ { old_path: file_name, new_path: file_name, old_line: 5, new_line: 5 },
+ { old_path: file_name, old_line: 5, change: true },
+ { new_path: file_name, new_line: 7 }
+ ]
+
+ expect_new_positions(old_position_attrs, new_position_attrs)
+ end
+ end
+
+ describe "force push to delete last commit" do
+ let(:old_diff_refs) { diff_refs(create_file_commit, update_file_again_commit) }
+ let(:new_diff_refs) { diff_refs(create_file_commit, update_file_commit) }
+ let(:change_diff_refs) { diff_refs(update_file_again_commit, update_file_commit) }
+
+ # old diff:
+ # 1 1 A
+ # 2 - B
+ # 2 + BB
+ # 3 3 C
+ # 4 4 D
+ # 5 5 E
+ # 6 - F
+ # 6 + FF
+ # 7 + G
+ #
+ # new diff:
+ # 1 1 A
+ # 2 - B
+ # 3 2 C
+ # 4 - D
+ # 3 + DD
+ # 5 4 E
+ # 6 5 F
+ # 6 + G
+
+ it "returns the new positions" do
+ old_position_attrs = [
+ { old_path: file_name, new_path: file_name, old_line: 1, new_line: 1 }, # A
+ { old_path: file_name, old_line: 2 }, # - B
+ { new_path: file_name, new_line: 2 }, # + BB
+ { old_path: file_name, new_path: file_name, old_line: 3, new_line: 3 }, # C
+ { old_path: file_name, new_path: file_name, old_line: 4, new_line: 4 }, # D
+ { old_path: file_name, new_path: file_name, old_line: 5, new_line: 5 }, # E
+ { old_path: file_name, old_line: 6 }, # - F
+ { new_path: file_name, new_line: 6 }, # + FF
+ { new_path: file_name, new_line: 7 } # + G
+ ]
+
+ new_position_attrs = [
+ { old_path: file_name, new_path: file_name, old_line: 1, new_line: 1 },
+ { old_path: file_name, old_line: 2 },
+ { old_path: file_name, old_line: 2, change: true },
+ { old_path: file_name, new_path: file_name, old_line: 3, new_line: 2 },
+ { old_path: file_name, old_line: 4, change: true },
+ { old_path: file_name, new_path: file_name, old_line: 5, new_line: 4 },
+ { new_path: file_name, new_line: 5, change: true },
+ { old_path: file_name, old_line: 6, change: true },
+ { new_path: file_name, new_line: 6 }
+ ]
+
+ expect_new_positions(old_position_attrs, new_position_attrs)
+ end
+ end
+
+ describe "rebase on top of target branch" do
+ let(:second_update_file_commit) do
+ update_file_commit
+
+ update_file(
+ second_branch_name,
+ file_name,
+ <<-CONTENT.strip_heredoc
+ Z
+ Z
+ Z
+ A
+ C
+ DD
+ E
+ F
+ G
+ CONTENT
+ )
+ end
+
+ let(:update_file_again_commit) do
+ second_update_file_commit
+
+ update_file(
+ branch_name,
+ file_name,
+ <<-CONTENT.strip_heredoc
+ A
+ BB
+ C
+ D
+ E
+ FF
+ G
+ CONTENT
+ )
+ end
+
+ let(:overwrite_update_file_again_commit) do
+ update_file_again_commit
+
+ update_file(
+ second_branch_name,
+ file_name,
+ <<-CONTENT.strip_heredoc
+ Z
+ Z
+ Z
+ A
+ BB
+ C
+ D
+ E
+ FF
+ G
+ CONTENT
+ )
+ end
+
+ let(:old_diff_refs) { diff_refs(create_file_commit, update_file_again_commit) }
+ let(:new_diff_refs) { diff_refs(create_file_commit, overwrite_update_file_again_commit) }
+ let(:change_diff_refs) { diff_refs(update_file_again_commit, overwrite_update_file_again_commit) }
+
+ # old diff:
+ # 1 1 A
+ # 2 - B
+ # 2 + BB
+ # 3 3 C
+ # 4 4 D
+ # 5 5 E
+ # 6 - F
+ # 6 + FF
+ # 7 + G
+ #
+ # new diff:
+ # 1 + Z
+ # 2 + Z
+ # 3 + Z
+ # 1 4 A
+ # 2 - B
+ # 5 + BB
+ # 3 6 C
+ # 4 7 D
+ # 5 8 E
+ # 6 - F
+ # 9 + FF
+ # 0 + G
+
+ it "returns the new positions" do
+ old_position_attrs = [
+ { old_path: file_name, new_path: file_name, old_line: 1, new_line: 1 }, # A
+ { old_path: file_name, old_line: 2 }, # - B
+ { new_path: file_name, new_line: 2 }, # + BB
+ { old_path: file_name, new_path: file_name, old_line: 3, new_line: 3 }, # C
+ { old_path: file_name, new_path: file_name, old_line: 4, new_line: 4 }, # D
+ { old_path: file_name, new_path: file_name, old_line: 5, new_line: 5 }, # E
+ { old_path: file_name, old_line: 6 }, # - F
+ { new_path: file_name, new_line: 6 }, # + FF
+ { new_path: file_name, new_line: 7 } # + G
+ ]
+
+ new_position_attrs = [
+ { old_path: file_name, new_path: file_name, old_line: 1, new_line: 4 }, # A
+ { old_path: file_name, old_line: 2 }, # - B
+ { new_path: file_name, new_line: 5 }, # + BB
+ { old_path: file_name, new_path: file_name, old_line: 3, new_line: 6 }, # C
+ { old_path: file_name, new_path: file_name, old_line: 4, new_line: 7 }, # D
+ { old_path: file_name, new_path: file_name, old_line: 5, new_line: 8 }, # E
+ { old_path: file_name, old_line: 6 }, # - F
+ { new_path: file_name, new_line: 9 }, # + FF
+ { new_path: file_name, new_line: 10 } # + G
+ ]
+
+ expect_new_positions(old_position_attrs, new_position_attrs)
+ end
+ end
+
+ describe "merge of target branch" do
+ let(:merge_commit) do
+ second_create_file_commit
+
+ merge_request = create(:merge_request, source_branch: second_branch_name, target_branch: branch_name, source_project: project)
+
+ repository.merge(current_user, merge_request.diff_head_sha, merge_request, "Merge branches")
+
+ project.commit(branch_name)
+ end
+
+ let(:old_diff_refs) { diff_refs(create_file_commit, update_file_again_commit) }
+ let(:new_diff_refs) { diff_refs(create_file_commit, merge_commit) }
+ let(:change_diff_refs) { diff_refs(update_file_again_commit, merge_commit) }
+
+ # old diff:
+ # 1 1 A
+ # 2 - B
+ # 2 + BB
+ # 3 3 C
+ # 4 4 D
+ # 5 5 E
+ # 6 - F
+ # 6 + FF
+ # 7 + G
+ #
+ # new diff:
+ # 1 + Z
+ # 2 + Z
+ # 3 + Z
+ # 1 4 A
+ # 2 - B
+ # 5 + BB
+ # 3 6 C
+ # 4 7 D
+ # 5 8 E
+ # 6 - F
+ # 9 + FF
+ # 0 + G
+
+ it "returns the new positions" do
+ old_position_attrs = [
+ { old_path: file_name, new_path: file_name, old_line: 1, new_line: 1 }, # A
+ { old_path: file_name, old_line: 2 }, # - B
+ { new_path: file_name, new_line: 2 }, # + BB
+ { old_path: file_name, new_path: file_name, old_line: 3, new_line: 3 }, # C
+ { old_path: file_name, new_path: file_name, old_line: 4, new_line: 4 }, # D
+ { old_path: file_name, new_path: file_name, old_line: 5, new_line: 5 }, # E
+ { old_path: file_name, old_line: 6 }, # - F
+ { new_path: file_name, new_line: 6 }, # + FF
+ { new_path: file_name, new_line: 7 } # + G
+ ]
+
+ new_position_attrs = [
+ { old_path: file_name, new_path: file_name, old_line: 1, new_line: 4 }, # A
+ { old_path: file_name, old_line: 2 }, # - B
+ { new_path: file_name, new_line: 5 }, # + BB
+ { old_path: file_name, new_path: file_name, old_line: 3, new_line: 6 }, # C
+ { old_path: file_name, new_path: file_name, old_line: 4, new_line: 7 }, # D
+ { old_path: file_name, new_path: file_name, old_line: 5, new_line: 8 }, # E
+ { old_path: file_name, old_line: 6 }, # - F
+ { new_path: file_name, new_line: 9 }, # + FF
+ { new_path: file_name, new_line: 10 } # + G
+ ]
+
+ expect_new_positions(old_position_attrs, new_position_attrs)
+ end
+ end
+
+ describe "changing target branch" do
+ let(:old_diff_refs) { diff_refs(create_file_commit, update_file_again_commit) }
+ let(:new_diff_refs) { diff_refs(update_file_commit, update_file_again_commit) }
+ let(:change_diff_refs) { diff_refs(create_file_commit, update_file_commit) }
+
+ # old diff:
+ # 1 1 A
+ # 2 - B
+ # 2 + BB
+ # 3 3 C
+ # 4 4 D
+ # 5 5 E
+ # 6 - F
+ # 6 + FF
+ # 7 + G
+ #
+ # new diff:
+ # 1 1 A
+ # 2 + BB
+ # 2 3 C
+ # 3 - DD
+ # 4 + D
+ # 4 5 E
+ # 5 - F
+ # 6 + FF
+ # 7 G
+
+ it "returns the new positions" do
+ old_position_attrs = [
+ { old_path: file_name, new_path: file_name, old_line: 1, new_line: 1 }, # A
+ { old_path: file_name, old_line: 2 }, # - B
+ { new_path: file_name, new_line: 2 }, # + BB
+ { old_path: file_name, new_path: file_name, old_line: 3, new_line: 3 }, # C
+ { old_path: file_name, new_path: file_name, old_line: 4, new_line: 4 }, # D
+ { old_path: file_name, new_path: file_name, old_line: 5, new_line: 5 }, # E
+ { old_path: file_name, old_line: 6 }, # - F
+ { new_path: file_name, new_line: 6 }, # + FF
+ { new_path: file_name, new_line: 7 } # + G
+ ]
+
+ new_position_attrs = [
+ { old_path: file_name, new_path: file_name, old_line: 1, new_line: 1 },
+ { old_path: file_name, old_line: 2, change: true },
+ { new_path: file_name, new_line: 2 },
+ { old_path: file_name, new_path: file_name, old_line: 2, new_line: 3 },
+ { new_path: file_name, new_line: 4 },
+ { old_path: file_name, new_path: file_name, old_line: 4, new_line: 5 },
+ { old_path: file_name, old_line: 5 },
+ { new_path: file_name, new_line: 6 },
+ { new_path: file_name, new_line: 7 }
+ ]
+
+ expect_new_positions(old_position_attrs, new_position_attrs)
+ end
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/diff/position_tracer_spec.rb b/spec/lib/gitlab/diff/position_tracer_spec.rb
index 866550753a8..79b33d4d276 100644
--- a/spec/lib/gitlab/diff/position_tracer_spec.rb
+++ b/spec/lib/gitlab/diff/position_tracer_spec.rb
@@ -1,1896 +1,98 @@
require 'spec_helper'
describe Gitlab::Diff::PositionTracer do
- # Douwe's diary New York City, 2016-06-28
- # --------------------------------------------------------------------------
- #
- # Dear diary,
- #
- # Ideally, we would have a test for every single diff scenario that can
- # occur and that the PositionTracer should correctly trace a position
- # through, across the following variables:
- #
- # - Old diff file type: created, changed, renamed, deleted, unchanged (5)
- # - Old diff line type: added, removed, unchanged (3)
- # - New diff file type: created, changed, renamed, deleted, unchanged (5)
- # - New diff line type: added, removed, unchanged (3)
- # - Old-to-new diff line change: kept, moved, undone (3)
- #
- # This adds up to 5 * 3 * 5 * 3 * 3 = 675 different potential scenarios,
- # and 675 different tests to cover them all. In reality, it would be fewer,
- # since one cannot have a removed line in a created file diff, for example,
- # but for the sake of this diary entry, let's be pessimistic.
- #
- # Writing these tests is a manual and time consuming process, as every test
- # requires the manual construction or finding of a combination of diffs that
- # create the exact diff scenario we are looking for, and can take between
- # 1 and 10 minutes, depending on the farfetchedness of the scenario and
- # complexity of creating it.
- #
- # This means that writing tests to cover all of these scenarios would end up
- # taking between 11 and 112 hours in total, which I do not believe is the
- # best use of my time.
- #
- # A better course of action would be to think of scenarios that are likely
- # to occur, but also potentially tricky to trace correctly, and only cover
- # those, with a few more obvious scenarios thrown in to cover our bases.
- #
- # Unfortunately, I only came to the above realization once I was about
- # 1/5th of the way through the process of writing ALL THE SPECS, having
- # already wasted about 3 hours trying to be thorough.
- #
- # I did find 2 bugs while writing those though, so that's good.
- #
- # In any case, all of this means that the tests below will be extremely
- # (excessively, unjustifiably) thorough for scenarios where "the file was
- # created in the old diff" and then drop off to comparatively lackluster
- # testing of other scenarios.
- #
- # I did still try to cover most of the obvious and potentially tricky
- # scenarios, though.
+ include PositionTracerHelpers
- include RepoHelpers
-
- let(:project) { create(:project, :repository) }
- let(:current_user) { project.owner }
- let(:repository) { project.repository }
- let(:file_name) { "test-file" }
- let(:new_file_name) { "#{file_name}-new" }
- let(:second_file_name) { "#{file_name}-2" }
- let(:branch_name) { "position-tracer-test" }
-
- let(:old_diff_refs) { raise NotImplementedError }
- let(:new_diff_refs) { raise NotImplementedError }
- let(:change_diff_refs) { raise NotImplementedError }
- let(:old_position) { raise NotImplementedError }
-
- let(:position_tracer) { described_class.new(project: project, old_diff_refs: old_diff_refs, new_diff_refs: new_diff_refs) }
- subject { position_tracer.trace(old_position) }
-
- def diff_refs(base_commit, head_commit)
- Gitlab::Diff::DiffRefs.new(base_sha: base_commit.id, head_sha: head_commit.id)
- end
-
- def text_position_attrs
- [:old_line, :new_line]
- end
-
- def position(attrs = {})
- attrs.reverse_merge!(
- diff_refs: old_diff_refs
+ subject do
+ described_class.new(
+ project: project,
+ old_diff_refs: old_diff_refs,
+ new_diff_refs: new_diff_refs
)
- Gitlab::Diff::Position.new(attrs)
end
- def expect_new_position(attrs, result = subject)
- aggregate_failures("expect new position #{attrs.inspect}") do
- if attrs.nil?
- expect(result[:outdated]).to be_truthy
- else
- expect(result[:outdated]).to be_falsey
+ describe '#trace' do
+ let(:diff_refs) { double(complete?: true) }
+ let(:project) { double }
+ let(:old_diff_refs) { diff_refs }
+ let(:new_diff_refs) { diff_refs }
+ let(:position) { double(on_text?: on_text?, diff_refs: diff_refs) }
+ let(:tracer) { double }
- new_position = result[:position]
- expect(new_position).not_to be_nil
+ context 'position is on text' do
+ let(:on_text?) { true }
- expect(new_position.diff_refs).to eq(new_diff_refs)
+ it 'calls LineStrategy#trace' do
+ expect(Gitlab::Diff::PositionTracer::LineStrategy)
+ .to receive(:new)
+ .with(subject)
+ .and_return(tracer)
+ expect(tracer).to receive(:trace).with(position)
- attrs.each do |attr, value|
- if text_position_attrs.include?(attr)
- expect(new_position.formatter.send(attr)).to eq(value)
- else
- expect(new_position.send(attr)).to eq(value)
- end
- end
+ subject.trace(position)
end
end
- end
-
- def expect_change_position(attrs, result = subject)
- aggregate_failures("expect change position #{attrs.inspect}") do
- expect(result[:outdated]).to be_truthy
-
- change_position = result[:position]
- if attrs.nil? || attrs.empty?
- expect(change_position).to be_nil
- else
- expect(change_position).not_to be_nil
-
- expect(change_position.diff_refs).to eq(change_diff_refs)
-
- attrs.each do |attr, value|
- if text_position_attrs.include?(attr)
- expect(change_position.formatter.send(attr)).to eq(value)
- else
- expect(change_position.send(attr)).to eq(value)
- end
- end
- end
- end
- end
-
- def create_branch(new_name, branch_name)
- CreateBranchService.new(project, current_user).execute(new_name, branch_name)
- end
-
- def create_file(branch_name, file_name, content)
- Files::CreateService.new(
- project,
- current_user,
- start_branch: branch_name,
- branch_name: branch_name,
- commit_message: "Create file",
- file_path: file_name,
- file_content: content
- ).execute
- project.commit(branch_name)
- end
-
- def update_file(branch_name, file_name, content)
- Files::UpdateService.new(
- project,
- current_user,
- start_branch: branch_name,
- branch_name: branch_name,
- commit_message: "Update file",
- file_path: file_name,
- file_content: content
- ).execute
- project.commit(branch_name)
- end
-
- def delete_file(branch_name, file_name)
- Files::DeleteService.new(
- project,
- current_user,
- start_branch: branch_name,
- branch_name: branch_name,
- commit_message: "Delete file",
- file_path: file_name
- ).execute
- project.commit(branch_name)
- end
-
- let(:initial_commit) do
- create_branch(branch_name, "master")[:branch].name
- project.commit(branch_name)
- end
-
- describe "#trace" do
- describe "diff scenarios" do
- let(:create_file_commit) do
- initial_commit
-
- create_file(
- branch_name,
- file_name,
- <<-CONTENT.strip_heredoc
- A
- B
- C
- CONTENT
- )
- end
-
- let(:create_second_file_commit) do
- create_file_commit
-
- create_file(
- branch_name,
- second_file_name,
- <<-CONTENT.strip_heredoc
- D
- E
- CONTENT
- )
- end
-
- let(:update_line_commit) do
- create_second_file_commit
-
- update_file(
- branch_name,
- file_name,
- <<-CONTENT.strip_heredoc
- A
- BB
- C
- CONTENT
- )
- end
-
- let(:update_second_file_line_commit) do
- update_line_commit
-
- update_file(
- branch_name,
- second_file_name,
- <<-CONTENT.strip_heredoc
- D
- EE
- CONTENT
- )
- end
-
- let(:move_line_commit) do
- update_second_file_line_commit
-
- update_file(
- branch_name,
- file_name,
- <<-CONTENT.strip_heredoc
- BB
- A
- C
- CONTENT
- )
- end
-
- let(:add_second_file_line_commit) do
- move_line_commit
-
- update_file(
- branch_name,
- second_file_name,
- <<-CONTENT.strip_heredoc
- D
- EE
- F
- CONTENT
- )
- end
-
- let(:move_second_file_line_commit) do
- add_second_file_line_commit
-
- update_file(
- branch_name,
- second_file_name,
- <<-CONTENT.strip_heredoc
- D
- F
- EE
- CONTENT
- )
- end
-
- let(:delete_line_commit) do
- move_second_file_line_commit
-
- update_file(
- branch_name,
- file_name,
- <<-CONTENT.strip_heredoc
- BB
- A
- CONTENT
- )
- end
-
- let(:delete_second_file_line_commit) do
- delete_line_commit
-
- update_file(
- branch_name,
- second_file_name,
- <<-CONTENT.strip_heredoc
- D
- F
- CONTENT
- )
- end
-
- let(:delete_file_commit) do
- delete_second_file_line_commit
-
- delete_file(branch_name, file_name)
- end
-
- let(:rename_file_commit) do
- delete_file_commit
-
- create_file(
- branch_name,
- new_file_name,
- <<-CONTENT.strip_heredoc
- BB
- A
- CONTENT
- )
- end
-
- let(:update_line_again_commit) do
- rename_file_commit
-
- update_file(
- branch_name,
- new_file_name,
- <<-CONTENT.strip_heredoc
- BB
- AA
- CONTENT
- )
- end
-
- let(:move_line_again_commit) do
- update_line_again_commit
-
- update_file(
- branch_name,
- new_file_name,
- <<-CONTENT.strip_heredoc
- AA
- BB
- CONTENT
- )
- end
-
- let(:delete_line_again_commit) do
- move_line_again_commit
-
- update_file(
- branch_name,
- new_file_name,
- <<-CONTENT.strip_heredoc
- AA
- CONTENT
- )
- end
-
- context "when the file was created in the old diff" do
- context "when the file is created in the new diff" do
- context "when the position pointed at an added line in the old diff" do
- context "when the file's content was unchanged between the old and the new diff" do
- let(:old_diff_refs) { diff_refs(initial_commit, create_file_commit) }
- let(:new_diff_refs) { diff_refs(initial_commit, create_second_file_commit) }
- let(:old_position) { position(new_path: file_name, new_line: 2) }
-
- # old diff:
- # 1 + A
- # 2 + B
- # 3 + C
- #
- # new diff:
- # 1 + A
- # 2 + B
- # 3 + C
-
- it "returns the new position" do
- expect_new_position(
- new_path: old_position.new_path,
- new_line: old_position.new_line
- )
- end
- end
-
- context "when the file's content was changed between the old and the new diff" do
- context "when that line was unchanged between the old and the new diff" do
- let(:old_diff_refs) { diff_refs(initial_commit, create_file_commit) }
- let(:new_diff_refs) { diff_refs(initial_commit, update_line_commit) }
- let(:old_position) { position(new_path: file_name, new_line: 1) }
-
- # old diff:
- # 1 + A
- # 2 + B
- # 3 + C
- #
- # new diff:
- # 1 + A
- # 2 + BB
- # 3 + C
-
- it "returns the new position" do
- expect_new_position(
- new_path: old_position.new_path,
- new_line: old_position.new_line
- )
- end
- end
-
- context "when that line was moved between the old and the new diff" do
- let(:old_diff_refs) { diff_refs(initial_commit, update_line_commit) }
- let(:new_diff_refs) { diff_refs(initial_commit, move_line_commit) }
- let(:old_position) { position(new_path: file_name, new_line: 2) }
-
- # old diff:
- # 1 + A
- # 2 + BB
- # 3 + C
- #
- # new diff:
- # 1 + BB
- # 2 + A
- # 3 + C
-
- it "returns the new position" do
- expect_new_position(
- new_path: old_position.new_path,
- new_line: 1
- )
- end
- end
-
- context "when that line was changed between the old and the new diff" do
- let(:old_diff_refs) { diff_refs(initial_commit, create_file_commit) }
- let(:new_diff_refs) { diff_refs(initial_commit, update_line_commit) }
- let(:change_diff_refs) { diff_refs(create_file_commit, update_line_commit) }
- let(:old_position) { position(new_path: file_name, new_line: 2) }
-
- # old diff:
- # 1 + A
- # 2 + B
- # 3 + C
- #
- # new diff:
- # 1 + A
- # 2 + BB
- # 3 + C
-
- it "returns the position of the change" do
- expect_change_position(
- old_path: file_name,
- new_path: file_name,
- old_line: 2,
- new_line: nil
- )
- end
- end
-
- context "when that line was deleted between the old and the new diff" do
- let(:old_diff_refs) { diff_refs(initial_commit, update_line_commit) }
- let(:new_diff_refs) { diff_refs(initial_commit, delete_line_commit) }
- let(:change_diff_refs) { diff_refs(update_line_commit, delete_line_commit) }
- let(:old_position) { position(new_path: file_name, new_line: 3) }
-
- # old diff:
- # 1 + A
- # 2 + BB
- # 3 + C
- #
- # new diff:
- # 1 + A
- # 2 + BB
-
- it "returns the position of the change" do
- expect_change_position(
- old_path: file_name,
- new_path: file_name,
- old_line: 3,
- new_line: nil
- )
- end
- end
- end
- end
- end
-
- context "when the file is changed in the new diff" do
- context "when the position pointed at an added line in the old diff" do
- context "when the file's content was unchanged between the old and the new diff" do
- let(:old_diff_refs) { diff_refs(initial_commit, update_line_commit) }
- let(:new_diff_refs) { diff_refs(create_file_commit, update_line_commit) }
- let(:old_position) { position(new_path: file_name, new_line: 1) }
-
- # old diff:
- # 1 + A
- # 2 + BB
- # 3 + C
- #
- # new diff:
- # 1 1 A
- # 2 - B
- # 2 + BB
- # 3 3 C
-
- it "returns the new position" do
- expect_new_position(
- new_path: old_position.new_path,
- new_line: old_position.new_line
- )
- end
- end
-
- context "when the file's content was changed between the old and the new diff" do
- context "when that line was unchanged between the old and the new diff" do
- let(:old_diff_refs) { diff_refs(initial_commit, update_line_commit) }
- let(:new_diff_refs) { diff_refs(update_line_commit, move_line_commit) }
- let(:old_position) { position(new_path: file_name, new_line: 3) }
-
- # old diff:
- # 1 + A
- # 2 + BB
- # 3 + C
- #
- # new diff:
- # 1 - A
- # 2 1 BB
- # 2 + A
- # 3 3 C
-
- it "returns the new position" do
- expect_new_position(
- new_path: old_position.new_path,
- new_line: old_position.new_line
- )
- end
- end
-
- context "when that line was moved between the old and the new diff" do
- let(:old_diff_refs) { diff_refs(initial_commit, update_line_commit) }
- let(:new_diff_refs) { diff_refs(update_line_commit, move_line_commit) }
- let(:old_position) { position(new_path: file_name, new_line: 2) }
-
- # old diff:
- # 1 + A
- # 2 + BB
- # 3 + C
- #
- # new diff:
- # 1 - A
- # 2 1 BB
- # 2 + A
- # 3 3 C
-
- it "returns the new position" do
- expect_new_position(
- new_path: old_position.new_path,
- new_line: 1
- )
- end
- end
-
- context "when that line was changed between the old and the new diff" do
- let(:old_diff_refs) { diff_refs(initial_commit, create_file_commit) }
- let(:new_diff_refs) { diff_refs(create_file_commit, update_line_commit) }
- let(:change_diff_refs) { diff_refs(create_file_commit, update_line_commit) }
- let(:old_position) { position(new_path: file_name, new_line: 2) }
-
- # old diff:
- # 1 + A
- # 2 + B
- # 3 + C
- #
- # new diff:
- # 1 1 A
- # 2 - B
- # 2 + BB
- # 3 3 C
-
- it "returns the position of the change" do
- expect_change_position(
- old_path: file_name,
- new_path: file_name,
- old_line: 2,
- new_line: nil
- )
- end
- end
-
- context "when that line was deleted between the old and the new diff" do
- let(:old_diff_refs) { diff_refs(initial_commit, move_line_commit) }
- let(:new_diff_refs) { diff_refs(move_line_commit, delete_line_commit) }
- let(:change_diff_refs) { diff_refs(move_line_commit, delete_line_commit) }
- let(:old_position) { position(new_path: file_name, new_line: 3) }
-
- # old diff:
- # 1 + BB
- # 2 + A
- # 3 + C
- #
- # new diff:
- # 1 1 BB
- # 2 2 A
- # 3 - C
-
- it "returns the position of the change" do
- expect_change_position(
- old_path: file_name,
- new_path: file_name,
- old_line: 3,
- new_line: nil
- )
- end
- end
- end
- end
- end
-
- context "when the file is renamed in the new diff" do
- context "when the position pointed at an added line in the old diff" do
- context "when the file's content was unchanged between the old and the new diff" do
- let(:old_diff_refs) { diff_refs(initial_commit, delete_line_commit) }
- let(:new_diff_refs) { diff_refs(delete_line_commit, rename_file_commit) }
- let(:change_diff_refs) { diff_refs(initial_commit, delete_line_commit) }
- let(:old_position) { position(new_path: file_name, new_line: 2) }
-
- # old diff:
- # 1 + BB
- # 2 + A
- #
- # new diff:
- # file_name -> new_file_name
- # 1 1 BB
- # 2 2 A
-
- it "returns the position of the change" do
- expect_change_position(
- old_path: file_name,
- new_path: file_name,
- old_line: nil,
- new_line: 2
- )
- end
- end
-
- context "when the file's content was changed between the old and the new diff" do
- context "when that line was unchanged between the old and the new diff" do
- let(:old_diff_refs) { diff_refs(initial_commit, delete_line_commit) }
- let(:new_diff_refs) { diff_refs(delete_line_commit, update_line_again_commit) }
- let(:old_position) { position(new_path: file_name, new_line: 1) }
-
- # old diff:
- # 1 + BB
- # 2 + A
- #
- # new diff:
- # file_name -> new_file_name
- # 1 1 BB
- # 2 - A
- # 2 + AA
-
- it "returns the new position" do
- expect_new_position(
- old_path: file_name,
- new_path: new_file_name,
- old_line: old_position.new_line,
- new_line: old_position.new_line
- )
- end
- end
-
- context "when that line was moved between the old and the new diff" do
- let(:old_diff_refs) { diff_refs(initial_commit, delete_line_commit) }
- let(:new_diff_refs) { diff_refs(delete_line_commit, move_line_again_commit) }
- let(:old_position) { position(new_path: file_name, new_line: 1) }
-
- # old diff:
- # 1 + BB
- # 2 + A
- #
- # new diff:
- # file_name -> new_file_name
- # 1 + AA
- # 1 2 BB
- # 2 - A
-
- it "returns the new position" do
- expect_new_position(
- old_path: file_name,
- new_path: new_file_name,
- old_line: 1,
- new_line: 2
- )
- end
- end
-
- context "when that line was changed between the old and the new diff" do
- let(:old_diff_refs) { diff_refs(initial_commit, delete_line_commit) }
- let(:new_diff_refs) { diff_refs(delete_line_commit, update_line_again_commit) }
- let(:change_diff_refs) { diff_refs(delete_line_commit, update_line_again_commit) }
- let(:old_position) { position(new_path: file_name, new_line: 2) }
-
- # old diff:
- # 1 + BB
- # 2 + A
- #
- # new diff:
- # file_name -> new_file_name
- # 1 1 BB
- # 2 - A
- # 2 + AA
-
- it "returns the position of the change" do
- expect_change_position(
- old_path: file_name,
- new_path: new_file_name,
- old_line: 2,
- new_line: nil
- )
- end
- end
- end
- end
- end
-
- context "when the file is deleted in the new diff" do
- context "when the position pointed at an added line in the old diff" do
- context "when the file's content was unchanged between the old and the new diff" do
- let(:old_diff_refs) { diff_refs(initial_commit, delete_line_commit) }
- let(:new_diff_refs) { diff_refs(delete_line_commit, delete_file_commit) }
- let(:change_diff_refs) { diff_refs(delete_line_commit, delete_file_commit) }
- let(:old_position) { position(new_path: file_name, new_line: 2) }
-
- # old diff:
- # 1 + BB
- # 2 + A
- #
- # new diff:
- # 1 - BB
- # 2 - A
-
- it "returns the position of the change" do
- expect_change_position(
- old_path: file_name,
- new_path: file_name,
- old_line: 2,
- new_line: nil
- )
- end
- end
-
- context "when the file's content was changed between the old and the new diff" do
- context "when that line was unchanged between the old and the new diff" do
- let(:old_diff_refs) { diff_refs(initial_commit, move_line_commit) }
- let(:new_diff_refs) { diff_refs(delete_line_commit, delete_file_commit) }
- let(:change_diff_refs) { diff_refs(move_line_commit, delete_file_commit) }
- let(:old_position) { position(new_path: file_name, new_line: 2) }
-
- # old diff:
- # 1 + BB
- # 2 + A
- # 3 + C
- #
- # new diff:
- # 1 - BB
- # 2 - A
-
- it "returns the position of the change" do
- expect_change_position(
- old_path: file_name,
- new_path: file_name,
- old_line: 2,
- new_line: nil
- )
- end
- end
-
- context "when that line was moved between the old and the new diff" do
- let(:old_diff_refs) { diff_refs(initial_commit, update_line_commit) }
- let(:new_diff_refs) { diff_refs(move_line_commit, delete_file_commit) }
- let(:change_diff_refs) { diff_refs(update_line_commit, delete_file_commit) }
- let(:old_position) { position(new_path: file_name, new_line: 2) }
-
- # old diff:
- # 1 + A
- # 2 + BB
- # 3 + C
- #
- # new diff:
- # 1 - BB
- # 2 - A
- # 3 - C
-
- it "returns the position of the change" do
- expect_change_position(
- old_path: file_name,
- new_path: file_name,
- old_line: 2,
- new_line: nil
- )
- end
- end
-
- context "when that line was changed between the old and the new diff" do
- let(:old_diff_refs) { diff_refs(initial_commit, create_file_commit) }
- let(:new_diff_refs) { diff_refs(update_line_commit, delete_file_commit) }
- let(:change_diff_refs) { diff_refs(create_file_commit, delete_file_commit) }
- let(:old_position) { position(new_path: file_name, new_line: 2) }
-
- # old diff:
- # 1 + A
- # 2 + B
- # 3 + C
- #
- # new diff:
- # 1 - A
- # 2 - BB
- # 3 - C
-
- it "returns the position of the change" do
- expect_change_position(
- old_path: file_name,
- new_path: file_name,
- old_line: 2,
- new_line: nil
- )
- end
- end
-
- context "when that line was deleted between the old and the new diff" do
- let(:old_diff_refs) { diff_refs(initial_commit, move_line_commit) }
- let(:new_diff_refs) { diff_refs(delete_line_commit, delete_file_commit) }
- let(:change_diff_refs) { diff_refs(move_line_commit, delete_file_commit) }
- let(:old_position) { position(new_path: file_name, new_line: 3) }
- # old diff:
- # 1 + BB
- # 2 + A
- # 3 + C
- #
- # new diff:
- # 1 - BB
- # 2 - A
+ context 'position is not on text' do
+ let(:on_text?) { false }
- it "returns the position of the change" do
- expect_change_position(
- old_path: file_name,
- new_path: file_name,
- old_line: 3,
- new_line: nil
- )
- end
- end
- end
- end
- end
+ it 'calls ImageStrategy#trace' do
+ expect(Gitlab::Diff::PositionTracer::ImageStrategy)
+ .to receive(:new)
+ .with(subject)
+ .and_return(tracer)
+ expect(tracer).to receive(:trace).with(position)
- context "when the file is unchanged in the new diff" do
- context "when the position pointed at an added line in the old diff" do
- context "when the file's content was unchanged between the old and the new diff" do
- let(:old_diff_refs) { diff_refs(initial_commit, create_file_commit) }
- let(:new_diff_refs) { diff_refs(create_file_commit, create_second_file_commit) }
- let(:change_diff_refs) { diff_refs(initial_commit, create_file_commit) }
- let(:old_position) { position(new_path: file_name, new_line: 2) }
-
- # old diff:
- # 1 + A
- # 2 + B
- # 3 + C
- #
- # new diff:
- # 1 1 A
- # 2 2 B
- # 3 3 C
-
- it "returns the position of the change" do
- expect_change_position(
- old_path: file_name,
- new_path: file_name,
- old_line: nil,
- new_line: 2
- )
- end
- end
-
- context "when the file's content was changed between the old and the new diff" do
- context "when that line was unchanged between the old and the new diff" do
- let(:old_diff_refs) { diff_refs(initial_commit, create_file_commit) }
- let(:new_diff_refs) { diff_refs(update_line_commit, update_second_file_line_commit) }
- let(:change_diff_refs) { diff_refs(initial_commit, update_line_commit) }
- let(:old_position) { position(new_path: file_name, new_line: 1) }
-
- # old diff:
- # 1 + A
- # 2 + B
- # 3 + C
- #
- # new diff:
- # 1 1 A
- # 2 2 BB
- # 3 3 C
-
- it "returns the position of the change" do
- expect_change_position(
- old_path: file_name,
- new_path: file_name,
- old_line: nil,
- new_line: 1
- )
- end
- end
-
- context "when that line was moved between the old and the new diff" do
- let(:old_diff_refs) { diff_refs(initial_commit, update_line_commit) }
- let(:new_diff_refs) { diff_refs(move_line_commit, move_second_file_line_commit) }
- let(:change_diff_refs) { diff_refs(initial_commit, move_line_commit) }
- let(:old_position) { position(new_path: file_name, new_line: 2) }
-
- # old diff:
- # 1 + A
- # 2 + BB
- # 3 + C
- #
- # new diff:
- # 1 1 BB
- # 2 2 A
- # 3 3 C
-
- it "returns the position of the change" do
- expect_change_position(
- old_path: file_name,
- new_path: file_name,
- old_line: nil,
- new_line: 1
- )
- end
- end
-
- context "when that line was changed between the old and the new diff" do
- let(:old_diff_refs) { diff_refs(initial_commit, create_file_commit) }
- let(:new_diff_refs) { diff_refs(update_line_commit, update_second_file_line_commit) }
- let(:change_diff_refs) { diff_refs(create_file_commit, update_second_file_line_commit) }
- let(:old_position) { position(new_path: file_name, new_line: 2) }
-
- # old diff:
- # 1 + A
- # 2 + B
- # 3 + C
- #
- # new diff:
- # 1 1 A
- # 2 2 BB
- # 3 3 C
-
- it "returns the position of the change" do
- expect_change_position(
- old_path: file_name,
- new_path: file_name,
- old_line: 2,
- new_line: nil
- )
- end
- end
-
- context "when that line was deleted between the old and the new diff" do
- let(:old_diff_refs) { diff_refs(initial_commit, move_line_commit) }
- let(:new_diff_refs) { diff_refs(delete_line_commit, delete_second_file_line_commit) }
- let(:change_diff_refs) { diff_refs(move_line_commit, delete_second_file_line_commit) }
- let(:old_position) { position(new_path: file_name, new_line: 3) }
-
- # old diff:
- # 1 + BB
- # 2 + A
- # 3 + C
- #
- # new diff:
- # 1 1 BB
- # 2 2 A
-
- it "returns the position of the change" do
- expect_change_position(
- old_path: file_name,
- new_path: file_name,
- old_line: 3,
- new_line: nil
- )
- end
- end
- end
- end
- end
- end
-
- context "when the file was changed in the old diff" do
- context "when the file is created in the new diff" do
- context "when the position pointed at an added line in the old diff" do
- context "when the file's content was unchanged between the old and the new diff" do
- let(:old_diff_refs) { diff_refs(create_file_commit, update_line_commit) }
- let(:new_diff_refs) { diff_refs(initial_commit, update_line_commit) }
- let(:old_position) { position(old_path: file_name, new_path: file_name, new_line: 2) }
-
- # old diff:
- # 1 1 A
- # 2 - B
- # 2 + BB
- # 3 3 C
- #
- # new diff:
- # 1 + A
- # 2 + BB
- # 3 + C
-
- it "returns the new position" do
- expect_new_position(
- new_path: old_position.new_path,
- old_line: nil,
- new_line: old_position.new_line
- )
- end
- end
-
- context "when the file's content was changed between the old and the new diff" do
- context "when that line was unchanged between the old and the new diff" do
- let(:old_diff_refs) { diff_refs(create_file_commit, move_line_commit) }
- let(:new_diff_refs) { diff_refs(initial_commit, move_line_commit) }
- let(:old_position) { position(old_path: file_name, new_path: file_name, new_line: 1) }
-
- # old diff:
- # 1 + BB
- # 1 2 A
- # 2 - B
- # 3 3 C
- #
- # new diff:
- # 1 + BB
- # 2 + A
-
- it "returns the new position" do
- expect_new_position(
- new_path: old_position.new_path,
- old_line: nil,
- new_line: old_position.new_line
- )
- end
- end
-
- context "when that line was moved between the old and the new diff" do
- let(:old_diff_refs) { diff_refs(create_file_commit, update_line_commit) }
- let(:new_diff_refs) { diff_refs(initial_commit, move_line_commit) }
- let(:old_position) { position(old_path: file_name, new_path: file_name, new_line: 2) }
-
- # old diff:
- # 1 1 A
- # 2 - B
- # 2 + BB
- # 3 3 C
- #
- # new diff:
- # 1 + BB
- # 2 + A
- # 3 + C
-
- it "returns the new position" do
- expect_new_position(
- new_path: old_position.new_path,
- old_line: nil,
- new_line: 1
- )
- end
- end
-
- context "when that line was changed or deleted between the old and the new diff" do
- let(:old_diff_refs) { diff_refs(create_file_commit, move_line_commit) }
- let(:new_diff_refs) { diff_refs(initial_commit, create_file_commit) }
- let(:change_diff_refs) { diff_refs(move_line_commit, create_file_commit) }
- let(:old_position) { position(old_path: file_name, new_path: file_name, new_line: 1) }
-
- # old diff:
- # 1 + BB
- # 1 2 A
- # 2 - B
- # 3 3 C
- #
- # new diff:
- # 1 + A
- # 2 + B
- # 3 + C
-
- it "returns the position of the change" do
- expect_change_position(
- old_path: file_name,
- new_path: file_name,
- old_line: 1,
- new_line: nil
- )
- end
- end
- end
- end
-
- context "when the position pointed at a deleted line in the old diff" do
- let(:old_diff_refs) { diff_refs(create_file_commit, update_line_commit) }
- let(:new_diff_refs) { diff_refs(initial_commit, update_line_commit) }
- let(:change_diff_refs) { diff_refs(create_file_commit, initial_commit) }
- let(:old_position) { position(old_path: file_name, new_path: file_name, old_line: 2) }
-
- # old diff:
- # 1 1 A
- # 2 - B
- # 2 + BB
- # 3 3 C
- #
- # new diff:
- # 1 + A
- # 2 + BB
- # 3 + C
-
- it "returns the position of the change" do
- expect_change_position(
- old_path: file_name,
- new_path: file_name,
- old_line: 2,
- new_line: nil
- )
- end
- end
-
- context "when the position pointed at an unchanged line in the old diff" do
- context "when the file's content was unchanged between the old and the new diff" do
- let(:old_diff_refs) { diff_refs(create_file_commit, update_line_commit) }
- let(:new_diff_refs) { diff_refs(initial_commit, update_line_commit) }
- let(:old_position) { position(old_path: file_name, new_path: file_name, old_line: 1, new_line: 1) }
-
- # old diff:
- # 1 1 A
- # 2 - B
- # 2 + BB
- # 3 3 C
- #
- # new diff:
- # 1 + A
- # 2 + BB
- # 3 + C
-
- it "returns the new position" do
- expect_new_position(
- new_path: old_position.new_path,
- old_line: nil,
- new_line: old_position.new_line
- )
- end
- end
-
- context "when the file's content was changed between the old and the new diff" do
- context "when that line was unchanged between the old and the new diff" do
- let(:old_diff_refs) { diff_refs(create_file_commit, move_line_commit) }
- let(:new_diff_refs) { diff_refs(initial_commit, move_line_commit) }
- let(:old_position) { position(old_path: file_name, new_path: file_name, old_line: 1, new_line: 2) }
-
- # old diff:
- # 1 + BB
- # 1 2 A
- # 2 - B
- # 3 3 C
- #
- # new diff:
- # 1 + BB
- # 2 + A
-
- it "returns the new position" do
- expect_new_position(
- new_path: old_position.new_path,
- old_line: nil,
- new_line: old_position.new_line
- )
- end
- end
-
- context "when that line was moved between the old and the new diff" do
- let(:old_diff_refs) { diff_refs(move_line_commit, delete_line_commit) }
- let(:new_diff_refs) { diff_refs(initial_commit, update_line_commit) }
- let(:old_position) { position(old_path: file_name, new_path: file_name, old_line: 2, new_line: 2) }
-
- # old diff:
- # 1 1 BB
- # 2 2 A
- # 3 - C
- #
- # new diff:
- # 1 + A
- # 2 + BB
- # 3 + C
-
- it "returns the new position" do
- expect_new_position(
- new_path: old_position.new_path,
- old_line: nil,
- new_line: 1
- )
- end
- end
-
- context "when that line was changed or deleted between the old and the new diff" do
- let(:old_diff_refs) { diff_refs(create_file_commit, move_line_commit) }
- let(:new_diff_refs) { diff_refs(initial_commit, delete_line_commit) }
- let(:change_diff_refs) { diff_refs(move_line_commit, delete_line_commit) }
- let(:old_position) { position(old_path: file_name, new_path: file_name, old_line: 3, new_line: 3) }
-
- # old diff:
- # 1 + BB
- # 1 2 A
- # 2 - B
- # 3 3 C
- #
- # new diff:
- # 1 + A
- # 2 + B
-
- it "returns the position of the change" do
- expect_change_position(
- old_path: file_name,
- new_path: file_name,
- old_line: 3,
- new_line: nil
- )
- end
- end
- end
- end
- end
-
- context "when the file is changed in the new diff" do
- context "when the position pointed at an added line in the old diff" do
- context "when the file's content was unchanged between the old and the new diff" do
- let(:old_diff_refs) { diff_refs(create_file_commit, update_line_commit) }
- let(:new_diff_refs) { diff_refs(create_file_commit, update_second_file_line_commit) }
- let(:old_position) { position(old_path: file_name, new_path: file_name, new_line: 2) }
-
- # old diff:
- # 1 1 A
- # 2 - B
- # 2 + BB
- # 3 3 C
- #
- # new diff:
- # 1 1 A
- # 2 - B
- # 2 + BB
- # 3 3 C
-
- it "returns the new position" do
- expect_new_position(
- old_path: old_position.old_path,
- new_path: old_position.new_path,
- old_line: nil,
- new_line: old_position.new_line
- )
- end
- end
-
- context "when the file's content was changed between the old and the new diff" do
- context "when that line was unchanged between the old and the new diff" do
- let(:old_diff_refs) { diff_refs(create_file_commit, move_line_commit) }
- let(:new_diff_refs) { diff_refs(move_line_commit, delete_line_commit) }
- let(:old_position) { position(old_path: file_name, new_path: file_name, new_line: 1) }
-
- # old diff:
- # 1 + BB
- # 1 2 A
- # 2 - B
- # 3 3 C
- #
- # new diff:
- # 1 1 BB
- # 2 2 A
- # 3 - C
-
- it "returns the new position" do
- expect_new_position(
- old_path: old_position.old_path,
- new_path: old_position.new_path,
- old_line: 1,
- new_line: 1
- )
- end
- end
-
- context "when that line was moved between the old and the new diff" do
- let(:old_diff_refs) { diff_refs(create_file_commit, update_line_commit) }
- let(:new_diff_refs) { diff_refs(update_line_commit, move_line_commit) }
- let(:old_position) { position(old_path: file_name, new_path: file_name, new_line: 2) }
-
- # old diff:
- # 1 1 A
- # 2 - B
- # 2 + BB
- # 3 3 C
- #
- # new diff:
- # 1 - A
- # 2 1 BB
- # 2 + A
- # 3 3 C
-
- it "returns the new position" do
- expect_new_position(
- old_path: old_position.old_path,
- new_path: old_position.new_path,
- old_line: 2,
- new_line: 1
- )
- end
- end
-
- context "when that line was changed or deleted between the old and the new diff" do
- let(:old_diff_refs) { diff_refs(create_file_commit, move_line_commit) }
- let(:new_diff_refs) { diff_refs(create_file_commit, update_line_commit) }
- let(:change_diff_refs) { diff_refs(move_line_commit, update_line_commit) }
- let(:old_position) { position(old_path: file_name, new_path: file_name, new_line: 1) }
-
- # old diff:
- # 1 + BB
- # 1 2 A
- # 2 - B
- # 3 3 C
- #
- # new diff:
- # 1 1 A
- # 2 - B
- # 2 + BB
- # 3 3 C
-
- it "returns the position of the change" do
- expect_change_position(
- old_path: file_name,
- new_path: file_name,
- old_line: 1,
- new_line: nil
- )
- end
- end
- end
- end
-
- context "when the position pointed at a deleted line in the old diff" do
- context "when the file's content was unchanged between the old and the new diff" do
- let(:old_diff_refs) { diff_refs(create_file_commit, update_line_commit) }
- let(:new_diff_refs) { diff_refs(create_file_commit, update_second_file_line_commit) }
- let(:old_position) { position(old_path: file_name, new_path: file_name, old_line: 2) }
-
- # old diff:
- # 1 1 A
- # 2 - B
- # 2 + BB
- # 3 3 C
- #
- # new diff:
- # 1 1 A
- # 2 - B
- # 2 + BB
- # 3 3 C
-
- it "returns the new position" do
- expect_new_position(
- old_path: old_position.old_path,
- new_path: old_position.new_path,
- old_line: old_position.old_line,
- new_line: nil
- )
- end
- end
- end
- end
+ subject.trace(position)
end
end
end
- describe "typical use scenarios" do
- let(:second_branch_name) { "#{branch_name}-2" }
-
- def expect_new_positions(old_attrs, new_attrs)
- old_positions = old_attrs.map do |old_attrs|
- position(old_attrs)
- end
+ describe 'diffs methods' do
+ let(:project) { create(:project, :repository) }
+ let(:current_user) { project.owner }
- new_positions = old_positions.map do |old_position|
- position_tracer.trace(old_position)
- end
-
- aggregate_failures do
- new_positions.zip(new_attrs).each do |new_position, new_attrs|
- if new_attrs&.delete(:change)
- expect_change_position(new_attrs, new_position)
- else
- expect_new_position(new_attrs, new_position)
- end
- end
- end
- end
-
- let(:create_file_commit) do
- initial_commit
-
- create_file(
- branch_name,
- file_name,
- <<-CONTENT.strip_heredoc
- A
- B
- C
- D
- E
- F
- CONTENT
- )
- end
-
- let(:second_create_file_commit) do
- create_file_commit
-
- create_branch(second_branch_name, branch_name)
-
- update_file(
- second_branch_name,
- file_name,
- <<-CONTENT.strip_heredoc
- Z
- Z
- Z
- A
- B
- C
- D
- E
- F
- CONTENT
+ let(:old_diff_refs) do
+ diff_refs(
+ project.commit(create_branch('new-branch', 'master')[:branch].name),
+ create_file('new-branch', 'file.md', 'content')
)
end
- let(:update_file_commit) do
- second_create_file_commit
-
- update_file(
- branch_name,
- file_name,
- <<-CONTENT.strip_heredoc
- A
- C
- DD
- E
- F
- G
- CONTENT
- )
- end
-
- let(:update_file_again_commit) do
- update_file_commit
-
- update_file(
- branch_name,
- file_name,
- <<-CONTENT.strip_heredoc
- A
- BB
- C
- D
- E
- FF
- G
- CONTENT
+ let(:new_diff_refs) do
+ diff_refs(
+ create_file('new-branch', 'file.md', 'content'),
+ update_file('new-branch', 'file.md', 'updatedcontent')
)
end
- describe "simple push of new commit" do
- let(:old_diff_refs) { diff_refs(create_file_commit, update_file_commit) }
- let(:new_diff_refs) { diff_refs(create_file_commit, update_file_again_commit) }
- let(:change_diff_refs) { diff_refs(update_file_commit, update_file_again_commit) }
-
- # old diff:
- # 1 1 A
- # 2 - B
- # 3 2 C
- # 4 - D
- # 3 + DD
- # 5 4 E
- # 6 5 F
- # 6 + G
- #
- # new diff:
- # 1 1 A
- # 2 - B
- # 2 + BB
- # 3 3 C
- # 4 4 D
- # 5 5 E
- # 6 - F
- # 6 + FF
- # 7 + G
-
- it "returns the new positions" do
- old_position_attrs = [
- { old_path: file_name, new_path: file_name, old_line: 1, new_line: 1 }, # A
- { old_path: file_name, old_line: 2 }, # - B
- { old_path: file_name, new_path: file_name, old_line: 3, new_line: 2 }, # C
- { old_path: file_name, old_line: 4 }, # - D
- { new_path: file_name, new_line: 3 }, # + DD
- { old_path: file_name, new_path: file_name, old_line: 5, new_line: 4 }, # E
- { old_path: file_name, new_path: file_name, old_line: 6, new_line: 5 }, # F
- { new_path: file_name, new_line: 6 }, # + G
- ]
-
- new_position_attrs = [
- { old_path: file_name, new_path: file_name, old_line: 1, new_line: 1 },
- { old_path: file_name, old_line: 2 },
- { old_path: file_name, new_path: file_name, old_line: 3, new_line: 3 },
- { new_path: file_name, new_line: 4, change: true },
- { new_path: file_name, old_line: 3, change: true },
- { old_path: file_name, new_path: file_name, old_line: 5, new_line: 5 },
- { new_path: file_name, old_line: 5, change: true },
- { new_path: file_name, new_line: 7 }
- ]
+ describe '#ac_diffs' do
+ it 'returns the diffs between the base of old and new diff' do
+ diff_refs = subject.ac_diffs.diff_refs
- expect_new_positions(old_position_attrs, new_position_attrs)
+ expect(diff_refs.base_sha).to eq(old_diff_refs.base_sha)
+ expect(diff_refs.start_sha).to eq(old_diff_refs.base_sha)
+ expect(diff_refs.head_sha).to eq(new_diff_refs.base_sha)
end
end
- describe "force push to overwrite last commit" do
- let(:second_create_file_commit) do
- create_file_commit
+ describe '#bd_diffs' do
+ it 'returns the diffs between the HEAD of old and new diff' do
+ diff_refs = subject.bd_diffs.diff_refs
- create_branch(second_branch_name, branch_name)
-
- update_file(
- second_branch_name,
- file_name,
- <<-CONTENT.strip_heredoc
- A
- BB
- C
- D
- E
- FF
- G
- CONTENT
- )
- end
-
- let(:old_diff_refs) { diff_refs(create_file_commit, update_file_commit) }
- let(:new_diff_refs) { diff_refs(create_file_commit, second_create_file_commit) }
- let(:change_diff_refs) { diff_refs(update_file_commit, second_create_file_commit) }
-
- # old diff:
- # 1 1 A
- # 2 - B
- # 3 2 C
- # 4 - D
- # 3 + DD
- # 5 4 E
- # 6 5 F
- # 6 + G
- #
- # new diff:
- # 1 1 A
- # 2 - B
- # 2 + BB
- # 3 3 C
- # 4 4 D
- # 5 5 E
- # 6 - F
- # 6 + FF
- # 7 + G
-
- it "returns the new positions" do
- old_position_attrs = [
- { old_path: file_name, new_path: file_name, old_line: 1, new_line: 1 }, # A
- { old_path: file_name, old_line: 2 }, # - B
- { old_path: file_name, new_path: file_name, old_line: 3, new_line: 2 }, # C
- { old_path: file_name, old_line: 4 }, # - D
- { new_path: file_name, new_line: 3 }, # + DD
- { old_path: file_name, new_path: file_name, old_line: 5, new_line: 4 }, # E
- { old_path: file_name, new_path: file_name, old_line: 6, new_line: 5 }, # F
- { new_path: file_name, new_line: 6 }, # + G
- ]
-
- new_position_attrs = [
- { old_path: file_name, new_path: file_name, old_line: 1, new_line: 1 },
- { old_path: file_name, old_line: 2 },
- { old_path: file_name, new_path: file_name, old_line: 3, new_line: 3 },
- { new_path: file_name, new_line: 4, change: true },
- { old_path: file_name, old_line: 3, change: true },
- { old_path: file_name, new_path: file_name, old_line: 5, new_line: 5 },
- { old_path: file_name, old_line: 5, change: true },
- { new_path: file_name, new_line: 7 }
- ]
-
- expect_new_positions(old_position_attrs, new_position_attrs)
+ expect(diff_refs.base_sha).to eq(old_diff_refs.head_sha)
+ expect(diff_refs.start_sha).to eq(old_diff_refs.head_sha)
+ expect(diff_refs.head_sha).to eq(new_diff_refs.head_sha)
end
end
- describe "force push to delete last commit" do
- let(:old_diff_refs) { diff_refs(create_file_commit, update_file_again_commit) }
- let(:new_diff_refs) { diff_refs(create_file_commit, update_file_commit) }
- let(:change_diff_refs) { diff_refs(update_file_again_commit, update_file_commit) }
-
- # old diff:
- # 1 1 A
- # 2 - B
- # 2 + BB
- # 3 3 C
- # 4 4 D
- # 5 5 E
- # 6 - F
- # 6 + FF
- # 7 + G
- #
- # new diff:
- # 1 1 A
- # 2 - B
- # 3 2 C
- # 4 - D
- # 3 + DD
- # 5 4 E
- # 6 5 F
- # 6 + G
-
- it "returns the new positions" do
- old_position_attrs = [
- { old_path: file_name, new_path: file_name, old_line: 1, new_line: 1 }, # A
- { old_path: file_name, old_line: 2 }, # - B
- { new_path: file_name, new_line: 2 }, # + BB
- { old_path: file_name, new_path: file_name, old_line: 3, new_line: 3 }, # C
- { old_path: file_name, new_path: file_name, old_line: 4, new_line: 4 }, # D
- { old_path: file_name, new_path: file_name, old_line: 5, new_line: 5 }, # E
- { old_path: file_name, old_line: 6 }, # - F
- { new_path: file_name, new_line: 6 }, # + FF
- { new_path: file_name, new_line: 7 }, # + G
- ]
-
- new_position_attrs = [
- { old_path: file_name, new_path: file_name, old_line: 1, new_line: 1 },
- { old_path: file_name, old_line: 2 },
- { old_path: file_name, old_line: 2, change: true },
- { old_path: file_name, new_path: file_name, old_line: 3, new_line: 2 },
- { old_path: file_name, old_line: 4, change: true },
- { old_path: file_name, new_path: file_name, old_line: 5, new_line: 4 },
- { new_path: file_name, new_line: 5, change: true },
- { old_path: file_name, old_line: 6, change: true },
- { new_path: file_name, new_line: 6 }
- ]
-
- expect_new_positions(old_position_attrs, new_position_attrs)
- end
- end
-
- describe "rebase on top of target branch" do
- let(:second_update_file_commit) do
- update_file_commit
-
- update_file(
- second_branch_name,
- file_name,
- <<-CONTENT.strip_heredoc
- Z
- Z
- Z
- A
- C
- DD
- E
- F
- G
- CONTENT
- )
- end
-
- let(:update_file_again_commit) do
- second_update_file_commit
-
- update_file(
- branch_name,
- file_name,
- <<-CONTENT.strip_heredoc
- A
- BB
- C
- D
- E
- FF
- G
- CONTENT
- )
- end
-
- let(:overwrite_update_file_again_commit) do
- update_file_again_commit
-
- update_file(
- second_branch_name,
- file_name,
- <<-CONTENT.strip_heredoc
- Z
- Z
- Z
- A
- BB
- C
- D
- E
- FF
- G
- CONTENT
- )
- end
-
- let(:old_diff_refs) { diff_refs(create_file_commit, update_file_again_commit) }
- let(:new_diff_refs) { diff_refs(create_file_commit, overwrite_update_file_again_commit) }
- let(:change_diff_refs) { diff_refs(update_file_again_commit, overwrite_update_file_again_commit) }
-
- # old diff:
- # 1 1 A
- # 2 - B
- # 2 + BB
- # 3 3 C
- # 4 4 D
- # 5 5 E
- # 6 - F
- # 6 + FF
- # 7 + G
- #
- # new diff:
- # 1 + Z
- # 2 + Z
- # 3 + Z
- # 1 4 A
- # 2 - B
- # 5 + BB
- # 3 6 C
- # 4 7 D
- # 5 8 E
- # 6 - F
- # 9 + FF
- # 0 + G
-
- it "returns the new positions" do
- old_position_attrs = [
- { old_path: file_name, new_path: file_name, old_line: 1, new_line: 1 }, # A
- { old_path: file_name, old_line: 2 }, # - B
- { new_path: file_name, new_line: 2 }, # + BB
- { old_path: file_name, new_path: file_name, old_line: 3, new_line: 3 }, # C
- { old_path: file_name, new_path: file_name, old_line: 4, new_line: 4 }, # D
- { old_path: file_name, new_path: file_name, old_line: 5, new_line: 5 }, # E
- { old_path: file_name, old_line: 6 }, # - F
- { new_path: file_name, new_line: 6 }, # + FF
- { new_path: file_name, new_line: 7 }, # + G
- ]
-
- new_position_attrs = [
- { old_path: file_name, new_path: file_name, old_line: 1, new_line: 4 }, # A
- { old_path: file_name, old_line: 2 }, # - B
- { new_path: file_name, new_line: 5 }, # + BB
- { old_path: file_name, new_path: file_name, old_line: 3, new_line: 6 }, # C
- { old_path: file_name, new_path: file_name, old_line: 4, new_line: 7 }, # D
- { old_path: file_name, new_path: file_name, old_line: 5, new_line: 8 }, # E
- { old_path: file_name, old_line: 6 }, # - F
- { new_path: file_name, new_line: 9 }, # + FF
- { new_path: file_name, new_line: 10 }, # + G
- ]
-
- expect_new_positions(old_position_attrs, new_position_attrs)
- end
- end
-
- describe "merge of target branch" do
- let(:merge_commit) do
- second_create_file_commit
-
- merge_request = create(:merge_request, source_branch: second_branch_name, target_branch: branch_name, source_project: project)
-
- repository.merge(current_user, merge_request.diff_head_sha, merge_request, "Merge branches")
-
- project.commit(branch_name)
- end
-
- let(:old_diff_refs) { diff_refs(create_file_commit, update_file_again_commit) }
- let(:new_diff_refs) { diff_refs(create_file_commit, merge_commit) }
- let(:change_diff_refs) { diff_refs(update_file_again_commit, merge_commit) }
-
- # old diff:
- # 1 1 A
- # 2 - B
- # 2 + BB
- # 3 3 C
- # 4 4 D
- # 5 5 E
- # 6 - F
- # 6 + FF
- # 7 + G
- #
- # new diff:
- # 1 + Z
- # 2 + Z
- # 3 + Z
- # 1 4 A
- # 2 - B
- # 5 + BB
- # 3 6 C
- # 4 7 D
- # 5 8 E
- # 6 - F
- # 9 + FF
- # 0 + G
-
- it "returns the new positions" do
- old_position_attrs = [
- { old_path: file_name, new_path: file_name, old_line: 1, new_line: 1 }, # A
- { old_path: file_name, old_line: 2 }, # - B
- { new_path: file_name, new_line: 2 }, # + BB
- { old_path: file_name, new_path: file_name, old_line: 3, new_line: 3 }, # C
- { old_path: file_name, new_path: file_name, old_line: 4, new_line: 4 }, # D
- { old_path: file_name, new_path: file_name, old_line: 5, new_line: 5 }, # E
- { old_path: file_name, old_line: 6 }, # - F
- { new_path: file_name, new_line: 6 }, # + FF
- { new_path: file_name, new_line: 7 }, # + G
- ]
-
- new_position_attrs = [
- { old_path: file_name, new_path: file_name, old_line: 1, new_line: 4 }, # A
- { old_path: file_name, old_line: 2 }, # - B
- { new_path: file_name, new_line: 5 }, # + BB
- { old_path: file_name, new_path: file_name, old_line: 3, new_line: 6 }, # C
- { old_path: file_name, new_path: file_name, old_line: 4, new_line: 7 }, # D
- { old_path: file_name, new_path: file_name, old_line: 5, new_line: 8 }, # E
- { old_path: file_name, old_line: 6 }, # - F
- { new_path: file_name, new_line: 9 }, # + FF
- { new_path: file_name, new_line: 10 }, # + G
- ]
-
- expect_new_positions(old_position_attrs, new_position_attrs)
- end
- end
-
- describe "changing target branch" do
- let(:old_diff_refs) { diff_refs(create_file_commit, update_file_again_commit) }
- let(:new_diff_refs) { diff_refs(update_file_commit, update_file_again_commit) }
- let(:change_diff_refs) { diff_refs(create_file_commit, update_file_commit) }
-
- # old diff:
- # 1 1 A
- # 2 - B
- # 2 + BB
- # 3 3 C
- # 4 4 D
- # 5 5 E
- # 6 - F
- # 6 + FF
- # 7 + G
- #
- # new diff:
- # 1 1 A
- # 2 + BB
- # 2 3 C
- # 3 - DD
- # 4 + D
- # 4 5 E
- # 5 - F
- # 6 + FF
- # 7 G
-
- it "returns the new positions" do
- old_position_attrs = [
- { old_path: file_name, new_path: file_name, old_line: 1, new_line: 1 }, # A
- { old_path: file_name, old_line: 2 }, # - B
- { new_path: file_name, new_line: 2 }, # + BB
- { old_path: file_name, new_path: file_name, old_line: 3, new_line: 3 }, # C
- { old_path: file_name, new_path: file_name, old_line: 4, new_line: 4 }, # D
- { old_path: file_name, new_path: file_name, old_line: 5, new_line: 5 }, # E
- { old_path: file_name, old_line: 6 }, # - F
- { new_path: file_name, new_line: 6 }, # + FF
- { new_path: file_name, new_line: 7 }, # + G
- ]
-
- new_position_attrs = [
- { old_path: file_name, new_path: file_name, old_line: 1, new_line: 1 },
- { old_path: file_name, old_line: 2, change: true },
- { new_path: file_name, new_line: 2 },
- { old_path: file_name, new_path: file_name, old_line: 2, new_line: 3 },
- { new_path: file_name, new_line: 4 },
- { old_path: file_name, new_path: file_name, old_line: 4, new_line: 5 },
- { old_path: file_name, old_line: 5 },
- { new_path: file_name, new_line: 6 },
- { new_path: file_name, new_line: 7 }
- ]
+ describe '#cd_diffs' do
+ it 'returns the diffs in the new diff' do
+ diff_refs = subject.cd_diffs.diff_refs
- expect_new_positions(old_position_attrs, new_position_attrs)
+ expect(diff_refs.base_sha).to eq(new_diff_refs.base_sha)
+ expect(diff_refs.start_sha).to eq(new_diff_refs.base_sha)
+ expect(diff_refs.head_sha).to eq(new_diff_refs.head_sha)
end
end
end
diff --git a/spec/lib/gitlab/git/commit_spec.rb b/spec/lib/gitlab/git/commit_spec.rb
index 25052a79916..3f0e6b34291 100644
--- a/spec/lib/gitlab/git/commit_spec.rb
+++ b/spec/lib/gitlab/git/commit_spec.rb
@@ -408,7 +408,7 @@ describe Gitlab::Git::Commit, :seed_helper do
context 'when oids is empty' do
it 'makes no Gitaly request' do
- expect(Gitlab::GitalyClient).not_to receive(:call)
+ expect(Gitlab::GitalyClient).not_to receive(:call).with(repository.storage, :commit_service, :list_commits_by_oid)
described_class.batch_by_oid(repository, [])
end
diff --git a/spec/lib/gitlab/git/repository_spec.rb b/spec/lib/gitlab/git/repository_spec.rb
index cceeae8afe6..a28b95e5bff 100644
--- a/spec/lib/gitlab/git/repository_spec.rb
+++ b/spec/lib/gitlab/git/repository_spec.rb
@@ -1694,14 +1694,15 @@ describe Gitlab::Git::Repository, :seed_helper do
let(:branch_head) { '6d394385cf567f80a8fd85055db1ab4c5295806f' }
let(:left_sha) { 'cfe32cf61b73a0d5e9f13e774abde7ff789b1660' }
let(:right_branch) { 'test-master' }
+ let(:first_parent_ref) { 'refs/heads/test-master' }
let(:target_ref) { 'refs/merge-requests/999/merge' }
before do
- repository.create_branch(right_branch, branch_head) unless repository.branch_exists?(right_branch)
+ repository.create_branch(right_branch, branch_head) unless repository.ref_exists?(first_parent_ref)
end
def merge_to_ref
- repository.merge_to_ref(user, left_sha, right_branch, target_ref, 'Merge message')
+ repository.merge_to_ref(user, left_sha, right_branch, target_ref, 'Merge message', first_parent_ref)
end
it 'generates a commit in the target_ref' do
@@ -1716,7 +1717,7 @@ describe Gitlab::Git::Repository, :seed_helper do
end
it 'does not change the right branch HEAD' do
- expect { merge_to_ref }.not_to change { repository.find_branch(right_branch).target }
+ expect { merge_to_ref }.not_to change { repository.commit(first_parent_ref).sha }
end
end
diff --git a/spec/lib/gitlab/git/rugged_impl/use_rugged_spec.rb b/spec/lib/gitlab/git/rugged_impl/use_rugged_spec.rb
new file mode 100644
index 00000000000..f957ed00945
--- /dev/null
+++ b/spec/lib/gitlab/git/rugged_impl/use_rugged_spec.rb
@@ -0,0 +1,97 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require 'json'
+require 'tempfile'
+
+describe Gitlab::Git::RuggedImpl::UseRugged, :seed_helper do
+ let(:project) { create(:project, :repository) }
+ let(:repository) { project.repository }
+ let(:feature_flag_name) { 'feature-flag-name' }
+ let(:feature_flag) { Feature.get(feature_flag_name) }
+ let(:temp_gitaly_metadata_file) { create_temporary_gitaly_metadata_file }
+
+ before(:all) do
+ create_gitaly_metadata_file
+ end
+
+ subject(:wrapper) do
+ klazz = Class.new { include Gitlab::Git::RuggedImpl::UseRugged }
+ klazz.new
+ end
+
+ before do
+ Gitlab::GitalyClient.instance_variable_set(:@can_use_disk, {})
+ end
+
+ context 'when feature flag is not persisted' do
+ before do
+ allow(Feature).to receive(:persisted?).with(feature_flag).and_return(false)
+ end
+
+ it 'returns true when gitaly matches disk' do
+ expect(subject.use_rugged?(repository, feature_flag_name)).to be true
+ end
+
+ it 'returns false when disk access fails' do
+ allow(Gitlab::GitalyClient).to receive(:storage_metadata_file_path).and_return("/fake/path/doesnt/exist")
+
+ expect(subject.use_rugged?(repository, feature_flag_name)).to be false
+ end
+
+ it "returns false when gitaly doesn't match disk" do
+ allow(Gitlab::GitalyClient).to receive(:storage_metadata_file_path).and_return(temp_gitaly_metadata_file)
+
+ expect(subject.use_rugged?(repository, feature_flag_name)).to be_falsey
+
+ File.delete(temp_gitaly_metadata_file)
+ end
+
+ it "doesn't lead to a second rpc call because gitaly client should use the cached value" do
+ expect(subject.use_rugged?(repository, feature_flag_name)).to be true
+
+ expect(Gitlab::GitalyClient).not_to receive(:filesystem_id)
+
+ subject.use_rugged?(repository, feature_flag_name)
+ end
+ end
+
+ context 'when feature flag is persisted' do
+ before do
+ allow(Feature).to receive(:persisted?).with(feature_flag).and_return(true)
+ end
+
+ it 'returns false when the feature flag is off' do
+ allow(feature_flag).to receive(:enabled?).and_return(false)
+
+ expect(subject.use_rugged?(repository, feature_flag_name)).to be_falsey
+ end
+
+ it "returns true when feature flag is on" do
+ allow(feature_flag).to receive(:enabled?).and_return(true)
+ allow(Gitlab::GitalyClient).to receive(:can_use_disk?).and_return(false)
+
+ expect(subject.use_rugged?(repository, feature_flag_name)).to be true
+ end
+ end
+
+ def create_temporary_gitaly_metadata_file
+ tmp = Tempfile.new('.gitaly-metadata')
+ gitaly_metadata = {
+ "gitaly_filesystem_id" => "some-value"
+ }
+ tmp.write(gitaly_metadata.to_json)
+ tmp.flush
+ tmp.close
+ tmp.path
+ end
+
+ def create_gitaly_metadata_file
+ File.open(File.join(SEED_STORAGE_PATH, '.gitaly-metadata'), 'w+') do |f|
+ gitaly_metadata = {
+ "gitaly_filesystem_id" => SecureRandom.uuid
+ }
+ f.write(gitaly_metadata.to_json)
+ end
+ end
+end
diff --git a/spec/lib/gitlab/gitaly_client/operation_service_spec.rb b/spec/lib/gitlab/gitaly_client/operation_service_spec.rb
index 18663a72fcd..f38b8d31237 100644
--- a/spec/lib/gitlab/gitaly_client/operation_service_spec.rb
+++ b/spec/lib/gitlab/gitaly_client/operation_service_spec.rb
@@ -79,13 +79,13 @@ describe Gitlab::GitalyClient::OperationService do
end
describe '#user_merge_to_ref' do
- let(:branch) { 'my-branch' }
+ let(:first_parent_ref) { 'refs/heads/my-branch' }
let(:source_sha) { 'cfe32cf61b73a0d5e9f13e774abde7ff789b1660' }
let(:ref) { 'refs/merge-requests/x/merge' }
let(:message) { 'validación' }
let(:response) { Gitaly::UserMergeToRefResponse.new(commit_id: 'new-commit-id') }
- subject { client.user_merge_to_ref(user, source_sha, branch, ref, message) }
+ subject { client.user_merge_to_ref(user, source_sha, nil, ref, message, first_parent_ref) }
it 'sends a user_merge_to_ref message' do
expect_any_instance_of(Gitaly::OperationService::Stub)
diff --git a/spec/lib/gitlab/graphql/authorize/authorize_field_service_spec.rb b/spec/lib/gitlab/graphql/authorize/authorize_field_service_spec.rb
index aec9c4baf0a..d60d1b7559a 100644
--- a/spec/lib/gitlab/graphql/authorize/authorize_field_service_spec.rb
+++ b/spec/lib/gitlab/graphql/authorize/authorize_field_service_spec.rb
@@ -7,35 +7,39 @@ require 'spec_helper'
describe Gitlab::Graphql::Authorize::AuthorizeFieldService do
def type(type_authorizations = [])
Class.new(Types::BaseObject) do
- graphql_name "TestType"
+ graphql_name 'TestType'
authorize type_authorizations
end
end
- def type_with_field(field_type, field_authorizations = [], resolved_value = "Resolved value")
+ def type_with_field(field_type, field_authorizations = [], resolved_value = 'Resolved value', **options)
Class.new(Types::BaseObject) do
- graphql_name "TestTypeWithField"
- field :test_field, field_type, null: true, authorize: field_authorizations, resolve: -> (_, _, _) { resolved_value}
+ graphql_name 'TestTypeWithField'
+ options.reverse_merge!(null: true)
+ field :test_field, field_type,
+ authorize: field_authorizations,
+ resolve: -> (_, _, _) { resolved_value },
+ **options
end
end
let(:current_user) { double(:current_user) }
subject(:service) { described_class.new(field) }
- describe "#authorized_resolve" do
- let(:presented_object) { double("presented object") }
- let(:presented_type) { double("parent type", object: presented_object) }
+ describe '#authorized_resolve' do
+ let(:presented_object) { double('presented object') }
+ let(:presented_type) { double('parent type', object: presented_object) }
subject(:resolved) { service.authorized_resolve.call(presented_type, {}, { current_user: current_user }) }
- context "scalar types" do
- shared_examples "checking permissions on the presented object" do
- it "checks the abilities on the object being presented and returns the value" do
+ context 'scalar types' do
+ shared_examples 'checking permissions on the presented object' do
+ it 'checks the abilities on the object being presented and returns the value' do
expected_permissions.each do |permission|
spy_ability_check_for(permission, presented_object, passed: true)
end
- expect(resolved).to eq("Resolved value")
+ expect(resolved).to eq('Resolved value')
end
it "returns nil if the value wasn't authorized" do
@@ -45,61 +49,71 @@ describe Gitlab::Graphql::Authorize::AuthorizeFieldService do
end
end
- context "when the field is a built-in scalar type" do
- let(:field) { type_with_field(GraphQL::STRING_TYPE, :read_field).fields["testField"].to_graphql }
+ context 'when the field is a built-in scalar type' do
+ let(:field) { type_with_field(GraphQL::STRING_TYPE, :read_field).fields['testField'].to_graphql }
let(:expected_permissions) { [:read_field] }
- it_behaves_like "checking permissions on the presented object"
+ it_behaves_like 'checking permissions on the presented object'
end
- context "when the field is a list of scalar types" do
- let(:field) { type_with_field([GraphQL::STRING_TYPE], :read_field).fields["testField"].to_graphql }
+ context 'when the field is a list of scalar types' do
+ let(:field) { type_with_field([GraphQL::STRING_TYPE], :read_field).fields['testField'].to_graphql }
let(:expected_permissions) { [:read_field] }
- it_behaves_like "checking permissions on the presented object"
+ it_behaves_like 'checking permissions on the presented object'
end
- context "when the field is sub-classed scalar type" do
- let(:field) { type_with_field(Types::TimeType, :read_field).fields["testField"].to_graphql }
+ context 'when the field is sub-classed scalar type' do
+ let(:field) { type_with_field(Types::TimeType, :read_field).fields['testField'].to_graphql }
let(:expected_permissions) { [:read_field] }
- it_behaves_like "checking permissions on the presented object"
+ it_behaves_like 'checking permissions on the presented object'
end
- context "when the field is a list of sub-classed scalar types" do
- let(:field) { type_with_field([Types::TimeType], :read_field).fields["testField"].to_graphql }
+ context 'when the field is a list of sub-classed scalar types' do
+ let(:field) { type_with_field([Types::TimeType], :read_field).fields['testField'].to_graphql }
let(:expected_permissions) { [:read_field] }
- it_behaves_like "checking permissions on the presented object"
+ it_behaves_like 'checking permissions on the presented object'
end
end
- context "when the field is a specific type" do
+ context 'when the field is a specific type' do
let(:custom_type) { type(:read_type) }
- let(:object_in_field) { double("presented in field") }
- let(:field) { type_with_field(custom_type, :read_field, object_in_field).fields["testField"].to_graphql }
+ let(:object_in_field) { double('presented in field') }
+ let(:field) { type_with_field(custom_type, :read_field, object_in_field).fields['testField'].to_graphql }
- it "checks both field & type permissions" do
+ it 'checks both field & type permissions' do
spy_ability_check_for(:read_field, object_in_field, passed: true)
spy_ability_check_for(:read_type, object_in_field, passed: true)
expect(resolved).to eq(object_in_field)
end
- it "returns nil if viewing was not allowed" do
+ it 'returns nil if viewing was not allowed' do
spy_ability_check_for(:read_field, object_in_field, passed: false)
spy_ability_check_for(:read_type, object_in_field, passed: true)
expect(resolved).to be_nil
end
- context "when the field is a list" do
- let(:object_1) { double("presented in field 1") }
- let(:object_2) { double("presented in field 2") }
+ context 'when the field is not nullable' do
+ let(:field) { type_with_field(custom_type, [], object_in_field, null: false).fields['testField'].to_graphql }
+
+ it 'returns nil when viewing is not allowed' do
+ spy_ability_check_for(:read_type, object_in_field, passed: false)
+
+ expect(resolved).to be_nil
+ end
+ end
+
+ context 'when the field is a list' do
+ let(:object_1) { double('presented in field 1') }
+ let(:object_2) { double('presented in field 2') }
let(:presented_types) { [double(object: object_1), double(object: object_2)] }
- let(:field) { type_with_field([custom_type], :read_field, presented_types).fields["testField"].to_graphql }
+ let(:field) { type_with_field([custom_type], :read_field, presented_types).fields['testField'].to_graphql }
- it "checks all permissions" do
+ it 'checks all permissions' do
allow(Ability).to receive(:allowed?) { true }
spy_ability_check_for(:read_field, object_1, passed: true)
@@ -110,7 +124,7 @@ describe Gitlab::Graphql::Authorize::AuthorizeFieldService do
expect(resolved).to eq(presented_types)
end
- it "filters out objects that the user cannot see" do
+ it 'filters out objects that the user cannot see' do
allow(Ability).to receive(:allowed?) { true }
spy_ability_check_for(:read_type, object_1, passed: false)
diff --git a/spec/lib/gitlab/graphql/calls_gitaly/instrumentation_spec.rb b/spec/lib/gitlab/graphql/calls_gitaly/instrumentation_spec.rb
new file mode 100644
index 00000000000..d93ce464a92
--- /dev/null
+++ b/spec/lib/gitlab/graphql/calls_gitaly/instrumentation_spec.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+require 'spec_helper'
+
+describe Gitlab::Graphql::CallsGitaly::Instrumentation do
+ subject { described_class.new }
+
+ describe '#calls_gitaly_check' do
+ let(:gitaly_field) { Types::BaseField.new(name: 'test', type: GraphQL::STRING_TYPE, null: true, calls_gitaly: true) }
+ let(:no_gitaly_field) { Types::BaseField.new(name: 'test', type: GraphQL::STRING_TYPE, null: true, calls_gitaly: false) }
+
+ context 'if there are no Gitaly calls' do
+ it 'does not raise an error if calls_gitaly is false' do
+ expect { subject.send(:calls_gitaly_check, no_gitaly_field, 0) }.not_to raise_error
+ end
+ end
+
+ context 'if there is at least 1 Gitaly call' do
+ it 'raises an error if calls_gitaly: is false or not defined' do
+ expect { subject.send(:calls_gitaly_check, no_gitaly_field, 1) }.to raise_error(/specify a constant complexity or add `calls_gitaly: true`/)
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/graphql/find_argument_in_parent_spec.rb b/spec/lib/gitlab/graphql/find_argument_in_parent_spec.rb
new file mode 100644
index 00000000000..91e90315b3e
--- /dev/null
+++ b/spec/lib/gitlab/graphql/find_argument_in_parent_spec.rb
@@ -0,0 +1,44 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Gitlab::Graphql::FindArgumentInParent do
+ describe '#find' do
+ def build_node(parent = nil, args: {})
+ props = { irep_node: double(arguments: args) }
+ props[:parent] = parent if parent # The root node shouldn't respond to parent
+
+ double(props)
+ end
+
+ let(:parent) do
+ build_node(
+ build_node(
+ build_node(
+ build_node,
+ args: { myArg: 1 }
+ )
+ )
+ )
+ end
+ let(:arg_name) { :my_arg }
+
+ it 'searches parents and returns the argument' do
+ expect(described_class.find(parent, :my_arg)).to eq(1)
+ end
+
+ it 'can find argument when passed in as both Ruby and GraphQL-formatted symbols and strings' do
+ [:my_arg, :myArg, 'my_arg', 'myArg'].each do |arg|
+ expect(described_class.find(parent, arg)).to eq(1)
+ end
+ end
+
+ it 'returns nil if no arguments found in parents' do
+ expect(described_class.find(parent, :bar)).to eq(nil)
+ end
+
+ it 'can limit the depth it searches to' do
+ expect(described_class.find(parent, :my_arg, limit_depth: 1)).to eq(nil)
+ end
+ end
+end
diff --git a/spec/lib/gitlab/import_export/safe_model_attributes.yml b/spec/lib/gitlab/import_export/safe_model_attributes.yml
index a406c25b1d8..28b187c3676 100644
--- a/spec/lib/gitlab/import_export/safe_model_attributes.yml
+++ b/spec/lib/gitlab/import_export/safe_model_attributes.yml
@@ -123,6 +123,7 @@ Release:
- project_id
- created_at
- updated_at
+- released_at
Releases::Link:
- id
- release_id
@@ -429,6 +430,7 @@ Service:
- confidential_issues_events
- confidential_note_events
- deployment_events
+- description
ProjectHook:
- id
- url
diff --git a/spec/lib/gitlab/issuable_metadata_spec.rb b/spec/lib/gitlab/issuable_metadata_spec.rb
index 916f3876a8e..032467b8b4e 100644
--- a/spec/lib/gitlab/issuable_metadata_spec.rb
+++ b/spec/lib/gitlab/issuable_metadata_spec.rb
@@ -7,11 +7,11 @@ describe Gitlab::IssuableMetadata do
subject { Class.new { include Gitlab::IssuableMetadata }.new }
it 'returns an empty Hash if an empty collection is provided' do
- expect(subject.issuable_meta_data(Issue.none, 'Issue')).to eq({})
+ expect(subject.issuable_meta_data(Issue.none, 'Issue', user)).to eq({})
end
it 'raises an error when given a collection with no limit' do
- expect { subject.issuable_meta_data(Issue.all, 'Issue') }.to raise_error(/must have a limit/)
+ expect { subject.issuable_meta_data(Issue.all, 'Issue', user) }.to raise_error(/must have a limit/)
end
context 'issues' do
@@ -23,7 +23,7 @@ describe Gitlab::IssuableMetadata do
let!(:closing_issues) { create(:merge_requests_closing_issues, issue: issue, merge_request: merge_request) }
it 'aggregates stats on issues' do
- data = subject.issuable_meta_data(Issue.all.limit(10), 'Issue')
+ data = subject.issuable_meta_data(Issue.all.limit(10), 'Issue', user)
expect(data.count).to eq(2)
expect(data[issue.id].upvotes).to eq(1)
@@ -46,7 +46,7 @@ describe Gitlab::IssuableMetadata do
let!(:note) { create(:note_on_merge_request, author: user, project: project, noteable: merge_request, note: "a comment on a MR") }
it 'aggregates stats on merge requests' do
- data = subject.issuable_meta_data(MergeRequest.all.limit(10), 'MergeRequest')
+ data = subject.issuable_meta_data(MergeRequest.all.limit(10), 'MergeRequest', user)
expect(data.count).to eq(2)
expect(data[merge_request.id].upvotes).to eq(1)
diff --git a/spec/lib/gitlab/legacy_github_import/importer_spec.rb b/spec/lib/gitlab/legacy_github_import/importer_spec.rb
index a0c664da185..9163019514b 100644
--- a/spec/lib/gitlab/legacy_github_import/importer_spec.rb
+++ b/spec/lib/gitlab/legacy_github_import/importer_spec.rb
@@ -132,6 +132,7 @@ describe Gitlab::LegacyGithubImport::Importer do
body: 'Release v1.0.0',
draft: false,
created_at: created_at,
+ published_at: created_at,
updated_at: updated_at,
url: "#{api_root}/repos/octocat/Hello-World/releases/1"
)
@@ -144,6 +145,7 @@ describe Gitlab::LegacyGithubImport::Importer do
body: nil,
draft: false,
created_at: created_at,
+ published_at: created_at,
updated_at: updated_at,
url: "#{api_root}/repos/octocat/Hello-World/releases/2"
)
diff --git a/spec/lib/gitlab/legacy_github_import/release_formatter_spec.rb b/spec/lib/gitlab/legacy_github_import/release_formatter_spec.rb
index c57b96fb00d..534cf219520 100644
--- a/spec/lib/gitlab/legacy_github_import/release_formatter_spec.rb
+++ b/spec/lib/gitlab/legacy_github_import/release_formatter_spec.rb
@@ -4,6 +4,7 @@ describe Gitlab::LegacyGithubImport::ReleaseFormatter do
let!(:project) { create(:project, namespace: create(:namespace, path: 'octocat')) }
let(:octocat) { double(id: 123456, login: 'octocat') }
let(:created_at) { DateTime.strptime('2011-01-26T19:01:12Z') }
+ let(:published_at) { DateTime.strptime('2011-01-26T20:00:00Z') }
let(:base_data) do
{
@@ -11,7 +12,7 @@ describe Gitlab::LegacyGithubImport::ReleaseFormatter do
name: 'First release',
draft: false,
created_at: created_at,
- published_at: created_at,
+ published_at: published_at,
body: 'Release v1.0.0'
}
end
@@ -28,6 +29,7 @@ describe Gitlab::LegacyGithubImport::ReleaseFormatter do
name: 'First release',
description: 'Release v1.0.0',
created_at: created_at,
+ released_at: published_at,
updated_at: created_at
}
diff --git a/spec/lib/gitlab/metrics/samplers/ruby_sampler_spec.rb b/spec/lib/gitlab/metrics/samplers/ruby_sampler_spec.rb
index aaf8c9fa2a0..4d93b70e6e3 100644
--- a/spec/lib/gitlab/metrics/samplers/ruby_sampler_spec.rb
+++ b/spec/lib/gitlab/metrics/samplers/ruby_sampler_spec.rb
@@ -8,12 +8,19 @@ describe Gitlab::Metrics::Samplers::RubySampler do
allow(Gitlab::Metrics::NullMetric).to receive(:instance).and_return(null_metric)
end
+ describe '#initialize' do
+ it 'sets process_start_time_seconds' do
+ Timecop.freeze do
+ expect(sampler.metrics[:process_start_time_seconds].get).to eq(Time.now.to_i)
+ end
+ end
+ end
+
describe '#sample' do
it 'samples various statistics' do
expect(Gitlab::Metrics::System).to receive(:cpu_time)
expect(Gitlab::Metrics::System).to receive(:file_descriptor_count)
expect(Gitlab::Metrics::System).to receive(:memory_usage)
- expect(Gitlab::Metrics::System).to receive(:process_start_time)
expect(Gitlab::Metrics::System).to receive(:max_open_file_descriptors)
expect(sampler).to receive(:sample_gc)
@@ -44,13 +51,6 @@ describe Gitlab::Metrics::Samplers::RubySampler do
sampler.sample
end
- it 'adds a metric containing the process start time' do
- expect(Gitlab::Metrics::System).to receive(:process_start_time).and_return(12345)
- expect(sampler.metrics[:process_start_time_seconds]).to receive(:set).with({}, 12345)
-
- sampler.sample
- end
-
it 'adds a metric containing the process max file descriptors' do
expect(Gitlab::Metrics::System).to receive(:max_open_file_descriptors).and_return(1024)
expect(sampler.metrics[:process_max_fds]).to receive(:set).with({}, 1024)
diff --git a/spec/lib/gitlab/metrics/system_spec.rb b/spec/lib/gitlab/metrics/system_spec.rb
index da87df15746..3b434a02f63 100644
--- a/spec/lib/gitlab/metrics/system_spec.rb
+++ b/spec/lib/gitlab/metrics/system_spec.rb
@@ -19,12 +19,6 @@ describe Gitlab::Metrics::System do
expect(described_class.max_open_file_descriptors).to be > 0
end
end
-
- describe '.process_start_time' do
- it 'returns the process start time' do
- expect(described_class.process_start_time).to be > 0
- end
- end
else
describe '.memory_usage' do
it 'returns 0.0' do
@@ -43,12 +37,6 @@ describe Gitlab::Metrics::System do
expect(described_class.max_open_file_descriptors).to eq(0)
end
end
-
- describe 'process_start_time' do
- it 'returns 0' do
- expect(described_class.process_start_time).to eq(0)
- end
- end
end
describe '.cpu_time' do
diff --git a/spec/lib/gitlab/namespaced_session_store_spec.rb b/spec/lib/gitlab/namespaced_session_store_spec.rb
index c0af2ede32a..e177c44ad67 100644
--- a/spec/lib/gitlab/namespaced_session_store_spec.rb
+++ b/spec/lib/gitlab/namespaced_session_store_spec.rb
@@ -4,19 +4,33 @@ require 'spec_helper'
describe Gitlab::NamespacedSessionStore do
let(:key) { :some_key }
- subject { described_class.new(key) }
- it 'stores data under the specified key' do
- Gitlab::Session.with_session({}) do
- subject[:new_data] = 123
+ context 'current session' do
+ subject { described_class.new(key) }
- expect(Thread.current[:session_storage][key]).to eq(new_data: 123)
+ it 'stores data under the specified key' do
+ Gitlab::Session.with_session({}) do
+ subject[:new_data] = 123
+
+ expect(Thread.current[:session_storage][key]).to eq(new_data: 123)
+ end
+ end
+
+ it 'retrieves data from the given key' do
+ Thread.current[:session_storage] = { key => { existing_data: 123 } }
+
+ expect(subject[:existing_data]).to eq 123
end
end
- it 'retrieves data from the given key' do
- Thread.current[:session_storage] = { key => { existing_data: 123 } }
+ context 'passed in session' do
+ let(:data) { { 'data' => 42 } }
+ let(:session) { { 'some_key' => data } }
+
+ subject { described_class.new(key, session.with_indifferent_access) }
- expect(subject[:existing_data]).to eq 123
+ it 'retrieves data from the given key' do
+ expect(subject['data']).to eq 42
+ end
end
end
diff --git a/spec/lib/gitlab/performance_bar_spec.rb b/spec/lib/gitlab/performance_bar_spec.rb
index f480376acb4..ee3c571c9c0 100644
--- a/spec/lib/gitlab/performance_bar_spec.rb
+++ b/spec/lib/gitlab/performance_bar_spec.rb
@@ -3,17 +3,42 @@ require 'spec_helper'
describe Gitlab::PerformanceBar do
shared_examples 'allowed user IDs are cached' do
before do
- # Warm the Redis cache
+ # Warm the caches
described_class.enabled?(user)
end
it 'caches the allowed user IDs in cache', :use_clean_rails_memory_store_caching do
expect do
+ expect(described_class.l1_cache_backend).to receive(:fetch).and_call_original
+ expect(described_class.l2_cache_backend).not_to receive(:fetch)
expect(described_class.enabled?(user)).to be_truthy
end.not_to exceed_query_limit(0)
end
+
+ it 'caches the allowed user IDs in L1 cache for 1 minute', :use_clean_rails_memory_store_caching do
+ Timecop.travel 2.minutes do
+ expect do
+ expect(described_class.l1_cache_backend).to receive(:fetch).and_call_original
+ expect(described_class.l2_cache_backend).to receive(:fetch).and_call_original
+ expect(described_class.enabled?(user)).to be_truthy
+ end.not_to exceed_query_limit(0)
+ end
+ end
+
+ it 'caches the allowed user IDs in L2 cache for 5 minutes', :use_clean_rails_memory_store_caching do
+ Timecop.travel 6.minutes do
+ expect do
+ expect(described_class.l1_cache_backend).to receive(:fetch).and_call_original
+ expect(described_class.l2_cache_backend).to receive(:fetch).and_call_original
+ expect(described_class.enabled?(user)).to be_truthy
+ end.not_to exceed_query_limit(2)
+ end
+ end
end
+ it { expect(described_class.l1_cache_backend).to eq(Gitlab::ThreadMemoryCache.cache_backend) }
+ it { expect(described_class.l2_cache_backend).to eq(Rails.cache) }
+
describe '.enabled?' do
let(:user) { create(:user) }
diff --git a/spec/lib/gitlab/sql/pattern_spec.rb b/spec/lib/gitlab/sql/pattern_spec.rb
index 5b5052de372..98838712eae 100644
--- a/spec/lib/gitlab/sql/pattern_spec.rb
+++ b/spec/lib/gitlab/sql/pattern_spec.rb
@@ -10,6 +10,12 @@ describe Gitlab::SQL::Pattern do
it 'returns exact matching pattern' do
expect(to_pattern).to eq('12')
end
+
+ context 'and ignore_minimum_char_limit is true' do
+ it 'returns partial matching pattern' do
+ expect(User.to_pattern(query, use_minimum_char_limit: false)).to eq('%12%')
+ end
+ end
end
context 'when a query with a escape character is shorter than 3 chars' do
@@ -18,6 +24,12 @@ describe Gitlab::SQL::Pattern do
it 'returns sanitized exact matching pattern' do
expect(to_pattern).to eq('\_2')
end
+
+ context 'and ignore_minimum_char_limit is true' do
+ it 'returns sanitized partial matching pattern' do
+ expect(User.to_pattern(query, use_minimum_char_limit: false)).to eq('%\_2%')
+ end
+ end
end
context 'when a query is equal to 3 chars' do
diff --git a/spec/lib/gitlab/user_extractor_spec.rb b/spec/lib/gitlab/user_extractor_spec.rb
deleted file mode 100644
index b86ec5445b8..00000000000
--- a/spec/lib/gitlab/user_extractor_spec.rb
+++ /dev/null
@@ -1,78 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-describe Gitlab::UserExtractor do
- let(:text) do
- <<~TXT
- This is a long texth that mentions some users.
- @user-1, @user-2 and user@gitlab.org take a walk in the park.
- There they meet @user-4 that was out with other-user@gitlab.org.
- @user-1 thought it was late, so went home straight away
- TXT
- end
- subject(:extractor) { described_class.new(text) }
-
- describe '#users' do
- it 'returns an empty relation when nil was passed' do
- extractor = described_class.new(nil)
-
- expect(extractor.users).to be_empty
- expect(extractor.users).to be_a(ActiveRecord::Relation)
- end
-
- it 'returns the user case insensitive for usernames' do
- user = create(:user, username: "USER-4")
-
- expect(extractor.users).to include(user)
- end
-
- it 'returns users by primary email' do
- user = create(:user, email: 'user@gitlab.org')
-
- expect(extractor.users).to include(user)
- end
-
- it 'returns users by secondary email' do
- user = create(:email, email: 'other-user@gitlab.org').user
-
- expect(extractor.users).to include(user)
- end
-
- context 'input as array of strings' do
- it 'is treated as one string' do
- extractor = described_class.new(text.lines)
-
- user_1 = create(:user, username: "USER-1")
- user_4 = create(:user, username: "USER-4")
- user_email = create(:user, email: 'user@gitlab.org')
-
- expect(extractor.users).to contain_exactly(user_1, user_4, user_email)
- end
- end
- end
-
- describe '#matches' do
- it 'includes all mentioned email adresses' do
- expect(extractor.matches[:emails]).to contain_exactly('user@gitlab.org', 'other-user@gitlab.org')
- end
-
- it 'includes all mentioned usernames' do
- expect(extractor.matches[:usernames]).to contain_exactly('user-1', 'user-2', 'user-4')
- end
-
- context 'input has no matching e-mail or usernames' do
- it 'returns an empty list of users' do
- extractor = described_class.new('My test')
-
- expect(extractor.users).to be_empty
- end
- end
- end
-
- describe '#references' do
- it 'includes all user-references once' do
- expect(extractor.references).to contain_exactly('user-1', 'user-2', 'user@gitlab.org', 'user-4', 'other-user@gitlab.org')
- end
- end
-end
diff --git a/spec/lib/gitlab/utils/deep_size_spec.rb b/spec/lib/gitlab/utils/deep_size_spec.rb
new file mode 100644
index 00000000000..1e619a15980
--- /dev/null
+++ b/spec/lib/gitlab/utils/deep_size_spec.rb
@@ -0,0 +1,43 @@
+require 'spec_helper'
+
+describe Gitlab::Utils::DeepSize do
+ let(:data) do
+ {
+ a: [1, 2, 3],
+ b: {
+ c: [4, 5],
+ d: [
+ { e: [[6], [7]] }
+ ]
+ }
+ }
+ end
+
+ let(:max_size) { 1.kilobyte }
+ let(:max_depth) { 10 }
+ let(:deep_size) { described_class.new(data, max_size: max_size, max_depth: max_depth) }
+
+ describe '#evaluate' do
+ context 'when data within size and depth limits' do
+ it 'returns true' do
+ expect(deep_size).to be_valid
+ end
+ end
+
+ context 'when data not within size limit' do
+ let(:max_size) { 200.bytes }
+
+ it 'returns false' do
+ expect(deep_size).not_to be_valid
+ end
+ end
+
+ context 'when data not within depth limit' do
+ let(:max_depth) { 2 }
+
+ it 'returns false' do
+ expect(deep_size).not_to be_valid
+ end
+ end
+ end
+end
diff --git a/spec/lib/peek/views/redis_detailed_spec.rb b/spec/lib/peek/views/redis_detailed_spec.rb
new file mode 100644
index 00000000000..da13b6df53b
--- /dev/null
+++ b/spec/lib/peek/views/redis_detailed_spec.rb
@@ -0,0 +1,36 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Peek::Views::RedisDetailed do
+ let(:redis_detailed_class) do
+ Class.new do
+ include Peek::Views::RedisDetailed
+ end
+ end
+
+ subject { redis_detailed_class.new }
+
+ using RSpec::Parameterized::TableSyntax
+
+ where(:cmd, :expected) do
+ [:auth, 'test'] | 'auth <redacted>'
+ [:set, 'key', 'value'] | 'set key <redacted>'
+ [:set, 'bad'] | 'set bad'
+ [:hmset, 'key1', 'value1', 'key2', 'value2'] | 'hmset key1 <redacted>'
+ [:get, 'key'] | 'get key'
+ end
+
+ with_them do
+ it 'scrubs Redis commands', :request_store do
+ subject.detail_store << { cmd: cmd, duration: 1.second }
+
+ expect(subject.details.count).to eq(1)
+ expect(subject.details.first)
+ .to eq({
+ cmd: expected,
+ duration: 1000
+ })
+ end
+ end
+end
diff --git a/spec/mailers/notify_spec.rb b/spec/mailers/notify_spec.rb
index fa1343fe759..56bbcc4c306 100644
--- a/spec/mailers/notify_spec.rb
+++ b/spec/mailers/notify_spec.rb
@@ -606,7 +606,7 @@ describe Notify do
it_behaves_like 'a user cannot unsubscribe through footer link'
it 'has the correct subject and body' do
- is_expected.to have_referable_subject(project_snippet, include_group: true, reply: true)
+ is_expected.to have_referable_subject(project_snippet, reply: true)
is_expected.to have_body_text project_snippet_note.note
end
end
@@ -813,7 +813,7 @@ describe Notify do
it 'has the correct subject and body' do
aggregate_failures do
- is_expected.to have_subject("Re: #{project.name} | #{project.group.name} | #{commit.title} (#{commit.short_id})")
+ is_expected.to have_subject("Re: #{project.name} | #{commit.title} (#{commit.short_id})")
is_expected.to have_body_text(commit.short_id)
end
end
@@ -839,7 +839,7 @@ describe Notify do
it 'has the correct subject and body' do
aggregate_failures do
- is_expected.to have_referable_subject(merge_request, include_group: true, reply: true)
+ is_expected.to have_referable_subject(merge_request, reply: true)
is_expected.to have_body_text note_on_merge_request_path
end
end
@@ -865,7 +865,7 @@ describe Notify do
it 'has the correct subject and body' do
aggregate_failures do
- is_expected.to have_referable_subject(issue, include_group: true, reply: true)
+ is_expected.to have_referable_subject(issue, reply: true)
is_expected.to have_body_text(note_on_issue_path)
end
end
@@ -931,7 +931,7 @@ describe Notify do
it_behaves_like 'appearance header and footer not enabled'
it 'has the correct subject' do
- is_expected.to have_subject "Re: #{project.name} | #{project.group.name} | #{commit.title} (#{commit.short_id})"
+ is_expected.to have_subject "Re: #{project.name} | #{commit.title} (#{commit.short_id})"
end
it 'contains a link to the commit' do
@@ -959,7 +959,7 @@ describe Notify do
it_behaves_like 'appearance header and footer not enabled'
it 'has the correct subject' do
- is_expected.to have_referable_subject(merge_request, include_group: true, reply: true)
+ is_expected.to have_referable_subject(merge_request, reply: true)
end
it 'contains a link to the merge request note' do
@@ -987,7 +987,7 @@ describe Notify do
it_behaves_like 'appearance header and footer not enabled'
it 'has the correct subject' do
- is_expected.to have_referable_subject(issue, include_group: true, reply: true)
+ is_expected.to have_referable_subject(issue, reply: true)
end
it 'contains a link to the issue note' do
diff --git a/spec/migrations/add_foreign_key_to_merge_requests_spec.rb b/spec/migrations/add_foreign_key_to_merge_requests_spec.rb
deleted file mode 100644
index d9ad9a585f0..00000000000
--- a/spec/migrations/add_foreign_key_to_merge_requests_spec.rb
+++ /dev/null
@@ -1,39 +0,0 @@
-require 'spec_helper'
-require Rails.root.join('db', 'migrate', '20170713104829_add_foreign_key_to_merge_requests.rb')
-
-describe AddForeignKeyToMergeRequests, :migration do
- let(:projects) { table(:projects) }
- let(:merge_requests) { table(:merge_requests) }
- let(:pipelines) { table(:ci_pipelines) }
-
- before do
- projects.create!(name: 'gitlab', path: 'gitlab-org/gitlab-ce')
- pipelines.create!(project_id: projects.first.id,
- ref: 'some-branch',
- sha: 'abc12345')
-
- # merge request without a pipeline
- create_merge_request(head_pipeline_id: nil)
-
- # merge request with non-existent pipeline
- create_merge_request(head_pipeline_id: 1234)
-
- # merge reqeust with existing pipeline assigned
- create_merge_request(head_pipeline_id: pipelines.first.id)
- end
-
- it 'correctly adds a foreign key to head_pipeline_id' do
- migrate!
-
- expect(merge_requests.first.head_pipeline_id).to be_nil
- expect(merge_requests.second.head_pipeline_id).to be_nil
- expect(merge_requests.third.head_pipeline_id).to eq pipelines.first.id
- end
-
- def create_merge_request(**opts)
- merge_requests.create!(source_project_id: projects.first.id,
- target_project_id: projects.first.id,
- source_branch: 'some-branch',
- target_branch: 'master', **opts)
- end
-end
diff --git a/spec/migrations/add_head_pipeline_for_each_merge_request_spec.rb b/spec/migrations/add_head_pipeline_for_each_merge_request_spec.rb
deleted file mode 100644
index 13dc62595b5..00000000000
--- a/spec/migrations/add_head_pipeline_for_each_merge_request_spec.rb
+++ /dev/null
@@ -1,32 +0,0 @@
-require 'spec_helper'
-require Rails.root.join('db', 'post_migrate', '20170508170547_add_head_pipeline_for_each_merge_request.rb')
-
-describe AddHeadPipelineForEachMergeRequest, :migration do
- let(:migration) { described_class.new }
-
- let!(:project) { table(:projects).create! }
- let!(:other_project) { table(:projects).create! }
-
- let!(:pipeline_1) { table(:ci_pipelines).create!(project_id: project.id, ref: "branch_1") }
- let!(:pipeline_2) { table(:ci_pipelines).create!(project_id: other_project.id, ref: "branch_1") }
- let!(:pipeline_3) { table(:ci_pipelines).create!(project_id: other_project.id, ref: "branch_1") }
- let!(:pipeline_4) { table(:ci_pipelines).create!(project_id: project.id, ref: "branch_2") }
-
- let!(:mr_1) { table(:merge_requests).create!(source_project_id: project.id, target_project_id: project.id, source_branch: "branch_1", target_branch: "target_1") }
- let!(:mr_2) { table(:merge_requests).create!(source_project_id: other_project.id, target_project_id: project.id, source_branch: "branch_1", target_branch: "target_2") }
- let!(:mr_3) { table(:merge_requests).create!(source_project_id: project.id, target_project_id: project.id, source_branch: "branch_2", target_branch: "master") }
- let!(:mr_4) { table(:merge_requests).create!(source_project_id: project.id, target_project_id: project.id, source_branch: "branch_3", target_branch: "master") }
-
- context "#up" do
- context "when source_project and source_branch of pipeline are the same of merge request" do
- it "sets head_pipeline_id of given merge requests" do
- migration.up
-
- expect(mr_1.reload.head_pipeline_id).to eq(pipeline_1.id)
- expect(mr_2.reload.head_pipeline_id).to eq(pipeline_3.id)
- expect(mr_3.reload.head_pipeline_id).to eq(pipeline_4.id)
- expect(mr_4.reload.head_pipeline_id).to be_nil
- end
- end
- end
-end
diff --git a/spec/migrations/backfill_and_add_not_null_constraint_to_released_at_column_on_releases_table_spec.rb b/spec/migrations/backfill_and_add_not_null_constraint_to_released_at_column_on_releases_table_spec.rb
new file mode 100644
index 00000000000..9cae1daacea
--- /dev/null
+++ b/spec/migrations/backfill_and_add_not_null_constraint_to_released_at_column_on_releases_table_spec.rb
@@ -0,0 +1,28 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require Rails.root.join('db', 'migrate', '20190628185004_backfill_and_add_not_null_constraint_to_released_at_column_on_releases_table.rb')
+
+describe BackfillAndAddNotNullConstraintToReleasedAtColumnOnReleasesTable, :migration do
+ let(:releases) { table(:releases) }
+ let(:namespaces) { table(:namespaces) }
+ let(:projects) { table(:projects) }
+
+ subject(:migration) { described_class.new }
+
+ it 'fills released_at with the value of created_at' do
+ created_at_a = Time.zone.parse('2019-02-10T08:00:00Z')
+ created_at_b = Time.zone.parse('2019-03-10T18:00:00Z')
+ namespace = namespaces.create(name: 'foo', path: 'foo')
+ project = projects.create!(namespace_id: namespace.id)
+ release_a = releases.create!(project_id: project.id, created_at: created_at_a)
+ release_b = releases.create!(project_id: project.id, created_at: created_at_b)
+
+ disable_migrations_output { migration.up }
+
+ release_a.reload
+ release_b.reload
+ expect(release_a.released_at).to eq(created_at_a)
+ expect(release_b.released_at).to eq(created_at_b)
+ end
+end
diff --git a/spec/migrations/backfill_store_project_full_path_in_repo_spec.rb b/spec/migrations/backfill_store_project_full_path_in_repo_spec.rb
index 34f4a36d63d..65a918d5440 100644
--- a/spec/migrations/backfill_store_project_full_path_in_repo_spec.rb
+++ b/spec/migrations/backfill_store_project_full_path_in_repo_spec.rb
@@ -13,7 +13,7 @@ describe BackfillStoreProjectFullPathInRepo, :migration do
subject(:migration) { described_class.new }
around do |example|
- Sidekiq::Testing.inline! do
+ perform_enqueued_jobs do
example.run
end
end
diff --git a/spec/migrations/calculate_conv_dev_index_percentages_spec.rb b/spec/migrations/calculate_conv_dev_index_percentages_spec.rb
deleted file mode 100644
index 09c78d02890..00000000000
--- a/spec/migrations/calculate_conv_dev_index_percentages_spec.rb
+++ /dev/null
@@ -1,59 +0,0 @@
-# encoding: utf-8
-
-require 'spec_helper'
-require Rails.root.join('db', 'post_migrate', '20170803090603_calculate_conv_dev_index_percentages.rb')
-
-describe CalculateConvDevIndexPercentages, :migration do
- let(:migration) { described_class.new }
- let!(:conv_dev_index) do
- table(:conversational_development_index_metrics).create!(
- leader_issues: 9.256,
- leader_notes: 0,
- leader_milestones: 16.2456,
- leader_boards: 5.2123,
- leader_merge_requests: 1.2,
- leader_ci_pipelines: 12.1234,
- leader_environments: 3.3333,
- leader_deployments: 1.200,
- leader_projects_prometheus_active: 0.111,
- leader_service_desk_issues: 15.891,
- instance_issues: 1.234,
- instance_notes: 28.123,
- instance_milestones: 0,
- instance_boards: 3.254,
- instance_merge_requests: 0.6,
- instance_ci_pipelines: 2.344,
- instance_environments: 2.2222,
- instance_deployments: 0.771,
- instance_projects_prometheus_active: 0.109,
- instance_service_desk_issues: 13.345,
- percentage_issues: 0,
- percentage_notes: 0,
- percentage_milestones: 0,
- percentage_boards: 0,
- percentage_merge_requests: 0,
- percentage_ci_pipelines: 0,
- percentage_environments: 0,
- percentage_deployments: 0,
- percentage_projects_prometheus_active: 0,
- percentage_service_desk_issues: 0)
- end
-
- describe '#up' do
- it 'calculates percentages correctly' do
- migration.up
- conv_dev_index.reload
-
- expect(conv_dev_index.percentage_issues).to be_within(0.1).of(13.3)
- expect(conv_dev_index.percentage_notes).to be_zero # leader 0
- expect(conv_dev_index.percentage_milestones).to be_zero # instance 0
- expect(conv_dev_index.percentage_boards).to be_within(0.1).of(62.4)
- expect(conv_dev_index.percentage_merge_requests).to eq(50.0)
- expect(conv_dev_index.percentage_ci_pipelines).to be_within(0.1).of(19.3)
- expect(conv_dev_index.percentage_environments).to be_within(0.1).of(66.7)
- expect(conv_dev_index.percentage_deployments).to be_within(0.1).of(64.2)
- expect(conv_dev_index.percentage_projects_prometheus_active).to be_within(0.1).of(98.2)
- expect(conv_dev_index.percentage_service_desk_issues).to be_within(0.1).of(84.0)
- end
- end
-end
diff --git a/spec/migrations/clean_appearance_symlinks_spec.rb b/spec/migrations/clean_appearance_symlinks_spec.rb
deleted file mode 100644
index 9225dc0d894..00000000000
--- a/spec/migrations/clean_appearance_symlinks_spec.rb
+++ /dev/null
@@ -1,46 +0,0 @@
-require 'spec_helper'
-require Rails.root.join('db', 'post_migrate', '20170613111224_clean_appearance_symlinks.rb')
-
-describe CleanAppearanceSymlinks do
- let(:migration) { described_class.new }
- let(:test_dir) { File.join(Rails.root, "tmp", "tests", "clean_appearance_test") }
- let(:uploads_dir) { File.join(test_dir, "public", "uploads") }
- let(:new_uploads_dir) { File.join(uploads_dir, "system") }
- let(:original_path) { File.join(new_uploads_dir, 'appearance') }
- let(:symlink_path) { File.join(uploads_dir, 'appearance') }
-
- before do
- FileUtils.remove_dir(test_dir) if File.directory?(test_dir)
- FileUtils.mkdir_p(uploads_dir)
- allow(migration).to receive(:base_directory).and_return(test_dir)
- allow(migration).to receive(:say)
- end
-
- describe "#up" do
- before do
- FileUtils.mkdir_p(original_path)
- FileUtils.ln_s(original_path, symlink_path)
- end
-
- it 'removes the symlink' do
- migration.up
-
- expect(File.symlink?(symlink_path)).to be(false)
- end
- end
-
- describe '#down' do
- before do
- FileUtils.mkdir_p(File.join(original_path))
- FileUtils.touch(File.join(original_path, 'dummy.file'))
- end
-
- it 'creates a symlink' do
- expected_path = File.join(symlink_path, "dummy.file")
- migration.down
-
- expect(File.exist?(expected_path)).to be(true)
- expect(File.symlink?(symlink_path)).to be(true)
- end
- end
-end
diff --git a/spec/migrations/clean_stage_id_reference_migration_spec.rb b/spec/migrations/clean_stage_id_reference_migration_spec.rb
deleted file mode 100644
index 9a581df28a2..00000000000
--- a/spec/migrations/clean_stage_id_reference_migration_spec.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-require 'spec_helper'
-require Rails.root.join('db', 'migrate', '20170710083355_clean_stage_id_reference_migration.rb')
-
-describe CleanStageIdReferenceMigration, :migration, :sidekiq, :redis do
- let(:migration_class) { 'MigrateBuildStageIdReference' }
- let(:migration) { spy('migration') }
-
- before do
- allow(Gitlab::BackgroundMigration.const_get(migration_class))
- .to receive(:new).and_return(migration)
- end
-
- context 'when there are pending background migrations' do
- it 'processes pending jobs synchronously' do
- Sidekiq::Testing.disable! do
- BackgroundMigrationWorker.perform_in(2.minutes, migration_class, [1, 1])
- BackgroundMigrationWorker.perform_async(migration_class, [1, 1])
-
- migrate!
-
- expect(migration).to have_received(:perform).with(1, 1).twice
- end
- end
- end
- context 'when there are no background migrations pending' do
- it 'does nothing' do
- Sidekiq::Testing.disable! do
- migrate!
-
- expect(migration).not_to have_received(:perform)
- end
- end
- end
-end
diff --git a/spec/migrations/clean_stages_statuses_migration_spec.rb b/spec/migrations/clean_stages_statuses_migration_spec.rb
deleted file mode 100644
index 38705f8eaae..00000000000
--- a/spec/migrations/clean_stages_statuses_migration_spec.rb
+++ /dev/null
@@ -1,51 +0,0 @@
-require 'spec_helper'
-require Rails.root.join('db', 'migrate', '20170912113435_clean_stages_statuses_migration.rb')
-
-describe CleanStagesStatusesMigration, :migration, :sidekiq, :redis do
- let(:migration) { spy('migration') }
-
- before do
- allow(Gitlab::BackgroundMigration::MigrateStageStatus)
- .to receive(:new).and_return(migration)
- end
-
- context 'when there are pending background migrations' do
- it 'processes pending jobs synchronously' do
- Sidekiq::Testing.disable! do
- BackgroundMigrationWorker
- .perform_in(2.minutes, 'MigrateStageStatus', [1, 1])
- BackgroundMigrationWorker
- .perform_async('MigrateStageStatus', [1, 1])
-
- migrate!
-
- expect(migration).to have_received(:perform).with(1, 1).twice
- end
- end
- end
-
- context 'when there are no background migrations pending' do
- it 'does nothing' do
- Sidekiq::Testing.disable! do
- migrate!
-
- expect(migration).not_to have_received(:perform)
- end
- end
- end
-
- context 'when there are still unmigrated stages afterwards' do
- let(:stages) { table('ci_stages') }
-
- before do
- stages.create!(status: nil, name: 'build')
- stages.create!(status: nil, name: 'test')
- end
-
- it 'migrates statuses sequentially in batches' do
- migrate!
-
- expect(migration).to have_received(:perform).once
- end
- end
-end
diff --git a/spec/migrations/clean_upload_symlinks_spec.rb b/spec/migrations/clean_upload_symlinks_spec.rb
deleted file mode 100644
index 26653b9c008..00000000000
--- a/spec/migrations/clean_upload_symlinks_spec.rb
+++ /dev/null
@@ -1,46 +0,0 @@
-require 'spec_helper'
-require Rails.root.join('db', 'post_migrate', '20170406111121_clean_upload_symlinks.rb')
-
-describe CleanUploadSymlinks do
- let(:migration) { described_class.new }
- let(:test_dir) { File.join(Rails.root, "tmp", "tests", "move_uploads_test") }
- let(:uploads_dir) { File.join(test_dir, "public", "uploads") }
- let(:new_uploads_dir) { File.join(uploads_dir, "-", "system") }
- let(:original_path) { File.join(new_uploads_dir, 'user') }
- let(:symlink_path) { File.join(uploads_dir, 'user') }
-
- before do
- FileUtils.remove_dir(test_dir) if File.directory?(test_dir)
- FileUtils.mkdir_p(uploads_dir)
- allow(migration).to receive(:base_directory).and_return(test_dir)
- allow(migration).to receive(:say)
- end
-
- describe "#up" do
- before do
- FileUtils.mkdir_p(original_path)
- FileUtils.ln_s(original_path, symlink_path)
- end
-
- it 'removes the symlink' do
- migration.up
-
- expect(File.symlink?(symlink_path)).to be(false)
- end
- end
-
- describe '#down' do
- before do
- FileUtils.mkdir_p(File.join(original_path))
- FileUtils.touch(File.join(original_path, 'dummy.file'))
- end
-
- it 'creates a symlink' do
- expected_path = File.join(symlink_path, "dummy.file")
- migration.down
-
- expect(File.exist?(expected_path)).to be(true)
- expect(File.symlink?(symlink_path)).to be(true)
- end
- end
-end
diff --git a/spec/migrations/cleanup_move_system_upload_folder_symlink_spec.rb b/spec/migrations/cleanup_move_system_upload_folder_symlink_spec.rb
deleted file mode 100644
index 3a9fa8c7113..00000000000
--- a/spec/migrations/cleanup_move_system_upload_folder_symlink_spec.rb
+++ /dev/null
@@ -1,35 +0,0 @@
-require 'spec_helper'
-require Rails.root.join("db", "post_migrate", "20170717111152_cleanup_move_system_upload_folder_symlink.rb")
-
-describe CleanupMoveSystemUploadFolderSymlink do
- let(:migration) { described_class.new }
- let(:test_base) { File.join(Rails.root, 'tmp', 'tests', 'move-system-upload-folder') }
- let(:test_folder) { File.join(test_base, '-', 'system') }
-
- before do
- allow(migration).to receive(:base_directory).and_return(test_base)
- FileUtils.rm_rf(test_base)
- FileUtils.mkdir_p(test_folder)
- allow(migration).to receive(:say)
- end
-
- describe '#up' do
- before do
- FileUtils.ln_s(test_folder, File.join(test_base, 'system'))
- end
-
- it 'removes the symlink' do
- migration.up
-
- expect(File.exist?(File.join(test_base, 'system'))).to be_falsey
- end
- end
-
- describe '#down' do
- it 'creates the symlink' do
- migration.down
-
- expect(File.symlink?(File.join(test_base, 'system'))).to be_truthy
- end
- end
-end
diff --git a/spec/migrations/cleanup_nonexisting_namespace_pending_delete_projects_spec.rb b/spec/migrations/cleanup_nonexisting_namespace_pending_delete_projects_spec.rb
deleted file mode 100644
index 0e6bded29b4..00000000000
--- a/spec/migrations/cleanup_nonexisting_namespace_pending_delete_projects_spec.rb
+++ /dev/null
@@ -1,29 +0,0 @@
-require 'spec_helper'
-require Rails.root.join('db', 'post_migrate', '20170816102555_cleanup_nonexisting_namespace_pending_delete_projects.rb')
-
-describe CleanupNonexistingNamespacePendingDeleteProjects, :migration do
- let(:projects) { table(:projects) }
- let(:namespaces) { table(:namespaces) }
-
- describe '#up' do
- let!(:some_project) { projects.create! }
- let(:namespace) { namespaces.create!(name: 'test', path: 'test') }
-
- it 'only cleans up when namespace does not exist' do
- projects.create!(pending_delete: true, namespace_id: namespace.id)
- project = projects.create!(pending_delete: true, namespace_id: 0)
-
- expect(NamespacelessProjectDestroyWorker).to receive(:bulk_perform_async).with([[project.id]])
-
- described_class.new.up
- end
-
- it 'does nothing when no pending delete projects without namespace found' do
- projects.create!(pending_delete: true, namespace_id: namespace.id)
-
- expect(NamespacelessProjectDestroyWorker).not_to receive(:bulk_perform_async)
-
- described_class.new.up
- end
- end
-end
diff --git a/spec/migrations/convert_custom_notification_settings_to_columns_spec.rb b/spec/migrations/convert_custom_notification_settings_to_columns_spec.rb
deleted file mode 100644
index d1bf6bdf9d6..00000000000
--- a/spec/migrations/convert_custom_notification_settings_to_columns_spec.rb
+++ /dev/null
@@ -1,120 +0,0 @@
-require 'spec_helper'
-require Rails.root.join('db', 'post_migrate', '20170607121233_convert_custom_notification_settings_to_columns')
-
-describe ConvertCustomNotificationSettingsToColumns, :migration do
- let(:user_class) { table(:users) }
-
- let(:settings_params) do
- [
- { level: 0, events: [:new_note] }, # disabled, single event
- { level: 3, events: [:new_issue, :reopen_issue, :close_issue, :reassign_issue] }, # global, multiple events
- { level: 5, events: described_class::EMAIL_EVENTS }, # custom, all events
- { level: 5, events: [] } # custom, no events
- ]
- end
-
- let(:notification_settings_before) do
- settings_params.map do |params|
- events = {}
-
- params[:events].each do |event|
- events[event] = true
- end
-
- user = user_class.create!(email: "user-#{SecureRandom.hex}@example.org", username: "user-#{SecureRandom.hex}", encrypted_password: '12345678')
- create_params = { user_id: user.id, level: params[:level], events: events }
- notification_setting = described_class::NotificationSetting.create(create_params)
-
- [notification_setting, params]
- end
- end
-
- let(:notification_settings_after) do
- settings_params.map do |params|
- events = {}
-
- params[:events].each do |event|
- events[event] = true
- end
-
- user = user_class.create!(email: "user-#{SecureRandom.hex}@example.org", username: "user-#{SecureRandom.hex}", encrypted_password: '12345678')
- create_params = events.merge(user_id: user.id, level: params[:level])
- notification_setting = described_class::NotificationSetting.create(create_params)
-
- [notification_setting, params]
- end
- end
-
- describe '#up' do
- it 'migrates all settings where a custom event is enabled, even if they are not currently using the custom level' do
- notification_settings_before
-
- described_class.new.up
-
- notification_settings_before.each do |(notification_setting, params)|
- notification_setting.reload
-
- expect(notification_setting.read_attribute_before_type_cast(:events)).to be_nil
- expect(notification_setting.level).to eq(params[:level])
-
- described_class::EMAIL_EVENTS.each do |event|
- # We don't set the others to false, just let them default to nil
- expected = params[:events].include?(event) || nil
-
- expect(notification_setting.read_attribute(event)).to eq(expected)
- end
- end
- end
- end
-
- describe '#down' do
- it 'creates a custom events hash for all settings where at least one event is enabled' do
- notification_settings_after
-
- described_class.new.down
-
- notification_settings_after.each do |(notification_setting, params)|
- notification_setting.reload
-
- expect(notification_setting.level).to eq(params[:level])
-
- if params[:events].empty?
- # We don't migrate empty settings
- expect(notification_setting.events).to eq({})
- else
- described_class::EMAIL_EVENTS.each do |event|
- expected = params[:events].include?(event)
-
- expect(notification_setting.events[event]).to eq(expected)
- expect(notification_setting.read_attribute(event)).to be_nil
- end
- end
- end
- end
-
- it 'reverts the database to the state it was in before' do
- notification_settings_before
-
- described_class.new.up
- described_class.new.down
-
- notification_settings_before.each do |(notification_setting, params)|
- notification_setting.reload
-
- expect(notification_setting.level).to eq(params[:level])
-
- if params[:events].empty?
- # We don't migrate empty settings
- expect(notification_setting.events).to eq({})
- else
- described_class::EMAIL_EVENTS.each do |event|
- expected = params[:events].include?(event)
-
- expect(notification_setting.events[event]).to eq(expected)
- expect(notification_setting.read_attribute(event)).to be_nil
- end
- end
- end
- end
- end
-end
diff --git a/spec/migrations/delete_conflicting_redirect_routes_spec.rb b/spec/migrations/delete_conflicting_redirect_routes_spec.rb
deleted file mode 100644
index 8a191bd7139..00000000000
--- a/spec/migrations/delete_conflicting_redirect_routes_spec.rb
+++ /dev/null
@@ -1,42 +0,0 @@
-require 'spec_helper'
-require Rails.root.join('db', 'post_migrate', '20170907170235_delete_conflicting_redirect_routes')
-
-describe DeleteConflictingRedirectRoutes, :migration, :sidekiq do
- let!(:redirect_routes) { table(:redirect_routes) }
- let!(:routes) { table(:routes) }
-
- around do |example|
- Timecop.freeze { example.run }
- end
-
- before do
- routes.create!(id: 1, source_id: 1, source_type: 'Namespace', path: 'foo1')
- routes.create!(id: 2, source_id: 2, source_type: 'Namespace', path: 'foo2')
- routes.create!(id: 3, source_id: 3, source_type: 'Namespace', path: 'foo3')
- routes.create!(id: 4, source_id: 4, source_type: 'Namespace', path: 'foo4')
- routes.create!(id: 5, source_id: 5, source_type: 'Namespace', path: 'foo5')
-
- # Valid redirects
- redirect_routes.create!(source_id: 1, source_type: 'Namespace', path: 'bar')
- redirect_routes.create!(source_id: 1, source_type: 'Namespace', path: 'bar2')
- redirect_routes.create!(source_id: 2, source_type: 'Namespace', path: 'bar3')
-
- # Conflicting redirects
- redirect_routes.create!(source_id: 2, source_type: 'Namespace', path: 'foo1')
- redirect_routes.create!(source_id: 1, source_type: 'Namespace', path: 'foo2')
- redirect_routes.create!(source_id: 1, source_type: 'Namespace', path: 'foo3')
- redirect_routes.create!(source_id: 1, source_type: 'Namespace', path: 'foo4')
- redirect_routes.create!(source_id: 1, source_type: 'Namespace', path: 'foo5')
- end
-
- # No-op. See https://gitlab.com/gitlab-com/infrastructure/issues/3460#note_53223252
- it 'NO-OP: does not schedule any background migrations' do
- Sidekiq::Testing.fake! do
- Timecop.freeze do
- migrate!
-
- expect(BackgroundMigrationWorker.jobs.size).to eq 0
- end
- end
- end
-end
diff --git a/spec/migrations/fix_wrongly_renamed_routes_spec.rb b/spec/migrations/fix_wrongly_renamed_routes_spec.rb
deleted file mode 100644
index 543cf55f076..00000000000
--- a/spec/migrations/fix_wrongly_renamed_routes_spec.rb
+++ /dev/null
@@ -1,86 +0,0 @@
-require 'spec_helper'
-require Rails.root.join('db', 'post_migrate', '20170518231126_fix_wrongly_renamed_routes.rb')
-
-describe FixWronglyRenamedRoutes, :migration do
- let(:subject) { described_class.new }
- let(:namespaces_table) { table(:namespaces) }
- let(:projects_table) { table(:projects) }
- let(:routes_table) { table(:routes) }
- let(:broken_namespace) do
- namespaces_table.create!(name: 'apiis', path: 'apiis').tap do |namespace|
- routes_table.create!(source_type: 'Namespace', source_id: namespace.id, name: 'api0is', path: 'api0is')
- end
- end
- let(:broken_namespace_route) { routes_table.where(source_type: 'Namespace', source_id: broken_namespace.id).first }
-
- describe '#wrongly_renamed' do
- it "includes routes that have names that don't match their namespace" do
- broken_namespace
- other_namespace = namespaces_table.create!(name: 'api0', path: 'api0')
- routes_table.create!(source_type: 'Namespace', source_id: other_namespace.id, name: 'api0', path: 'api0')
-
- expect(subject.wrongly_renamed.map(&:id))
- .to contain_exactly(broken_namespace_route.id)
- end
- end
-
- describe "#paths_and_corrections" do
- it 'finds the wrong path and gets the correction from the namespace' do
- broken_namespace
- namespaces_table.create!(name: 'uploads-test', path: 'uploads-test').tap do |namespace|
- routes_table.create!(source_type: 'Namespace', source_id: namespace.id, name: 'uploads-test', path: 'uploads0-test')
- end
-
- expected_result = [
- { 'namespace_path' => 'apiis', 'path' => 'api0is' },
- { 'namespace_path' => 'uploads-test', 'path' => 'uploads0-test' }
- ]
-
- expect(subject.paths_and_corrections).to include(*expected_result)
- end
- end
-
- describe '#routes_in_namespace_query' do
- it 'includes only the required routes' do
- namespace = namespaces_table.create!(name: 'hello', path: 'hello')
- namespace_route = routes_table.create!(source_type: 'Namespace', source_id: namespace.id, name: 'hello', path: 'hello')
- project = projects_table.new(name: 'my-project', path: 'my-project', namespace_id: namespace.id).tap do |project|
- project.save!(validate: false)
- end
- routes_table.create!(source_type: 'Project', source_id: project.id, name: 'my-project', path: 'hello/my-project')
- _other_namespace = namespaces_table.create!(name: 'hello0', path: 'hello0')
-
- result = routes_table.where(subject.routes_in_namespace_query('hello'))
- project_route = routes_table.where(source_type: 'Project', source_id: project.id).first
-
- expect(result).to contain_exactly(namespace_route, project_route)
- end
- end
-
- describe '#up' do
- it 'renames incorrectly named routes' do
- broken_project =
- projects_table.new(name: 'broken-project', path: 'broken-project', namespace_id: broken_namespace.id).tap do |project|
- project.save!(validate: false)
- routes_table.create!(source_type: 'Project', source_id: project.id, name: 'broken-project', path: 'api0is/broken-project')
- end
-
- subject.up
-
- broken_project_route = routes_table.where(source_type: 'Project', source_id: broken_project.id).first
-
- expect(broken_project_route.path).to eq('apiis/broken-project')
- expect(broken_namespace_route.reload.path).to eq('apiis')
- end
-
- it "doesn't touch namespaces that look like something that should be renamed" do
- namespaces_table.create!(name: 'apiis', path: 'apiis')
- namespace = namespaces_table.create!(name: 'hello', path: 'api0')
- namespace_route = routes_table.create!(source_type: 'Namespace', source_id: namespace.id, name: 'hello', path: 'api0')
-
- subject.up
-
- expect(namespace_route.reload.path).to eq('api0')
- end
- end
-end
diff --git a/spec/migrations/issues_moved_to_id_foreign_key_spec.rb b/spec/migrations/issues_moved_to_id_foreign_key_spec.rb
deleted file mode 100644
index 71a4e71ac8a..00000000000
--- a/spec/migrations/issues_moved_to_id_foreign_key_spec.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-require 'spec_helper'
-require Rails.root.join('db', 'migrate', '20171106151218_issues_moved_to_id_foreign_key.rb')
-
-describe IssuesMovedToIdForeignKey, :migration do
- let(:issues) { table(:issues) }
-
- let!(:issue_third) { issues.create! }
- let!(:issue_second) { issues.create!(moved_to_id: issue_third.id) }
- let!(:issue_first) { issues.create!(moved_to_id: issue_second.id) }
-
- subject { described_class.new }
-
- it 'removes the orphaned moved_to_id' do
- subject.down
-
- issue_third.update!(moved_to_id: 0)
-
- subject.up
-
- expect(issue_first.reload.moved_to_id).to eq(issue_second.id)
- expect(issue_second.reload.moved_to_id).to eq(issue_third.id)
- expect(issue_third.reload.moved_to_id).to be_nil
- end
-end
diff --git a/spec/migrations/migrate_build_stage_reference_again_spec.rb b/spec/migrations/migrate_build_stage_reference_again_spec.rb
deleted file mode 100644
index 6be480ce58e..00000000000
--- a/spec/migrations/migrate_build_stage_reference_again_spec.rb
+++ /dev/null
@@ -1,62 +0,0 @@
-require 'spec_helper'
-require Rails.root.join('db', 'post_migrate', '20170526190000_migrate_build_stage_reference_again.rb')
-
-describe MigrateBuildStageReferenceAgain, :migration do
- ##
- # Create test data - pipeline and CI/CD jobs.
- #
-
- let(:jobs) { table(:ci_builds) }
- let(:stages) { table(:ci_stages) }
- let(:pipelines) { table(:ci_pipelines) }
- let(:projects) { table(:projects) }
-
- before do
- # Create projects
- #
- projects.create!(id: 123, name: 'gitlab1', path: 'gitlab1')
- projects.create!(id: 456, name: 'gitlab2', path: 'gitlab2')
-
- # Create CI/CD pipelines
- #
- pipelines.create!(id: 1, project_id: 123, ref: 'master', sha: 'adf43c3a')
- pipelines.create!(id: 2, project_id: 456, ref: 'feature', sha: '21a3deb')
-
- # Create CI/CD jobs
- #
- jobs.create!(id: 1, commit_id: 1, project_id: 123, stage_idx: 2, stage: 'build')
- jobs.create!(id: 2, commit_id: 1, project_id: 123, stage_idx: 2, stage: 'build')
- jobs.create!(id: 3, commit_id: 1, project_id: 123, stage_idx: 1, stage: 'test')
- jobs.create!(id: 4, commit_id: 1, project_id: 123, stage_idx: 3, stage: 'deploy')
- jobs.create!(id: 5, commit_id: 2, project_id: 456, stage_idx: 2, stage: 'test:2')
- jobs.create!(id: 6, commit_id: 2, project_id: 456, stage_idx: 1, stage: 'test:1')
- jobs.create!(id: 7, commit_id: 2, project_id: 456, stage_idx: 1, stage: 'test:1')
- jobs.create!(id: 8, commit_id: 3, project_id: 789, stage_idx: 3, stage: 'deploy')
-
- # Create CI/CD stages
- #
- stages.create(id: 101, pipeline_id: 1, project_id: 123, name: 'test')
- stages.create(id: 102, pipeline_id: 1, project_id: 123, name: 'build')
- stages.create(id: 103, pipeline_id: 1, project_id: 123, name: 'deploy')
- stages.create(id: 104, pipeline_id: 2, project_id: 456, name: 'test:1')
- stages.create(id: 105, pipeline_id: 2, project_id: 456, name: 'test:2')
- stages.create(id: 106, pipeline_id: 2, project_id: 456, name: 'deploy')
- end
-
- it 'correctly migrate build stage references' do
- expect(jobs.where(stage_id: nil).count).to eq 8
-
- migrate!
-
- expect(jobs.where(stage_id: nil).count).to eq 1
-
- expect(jobs.find(1).stage_id).to eq 102
- expect(jobs.find(2).stage_id).to eq 102
- expect(jobs.find(3).stage_id).to eq 101
- expect(jobs.find(4).stage_id).to eq 103
- expect(jobs.find(5).stage_id).to eq 105
- expect(jobs.find(6).stage_id).to eq 104
- expect(jobs.find(7).stage_id).to eq 104
- expect(jobs.find(8).stage_id).to eq nil
- end
-end
diff --git a/spec/migrations/migrate_gcp_clusters_to_new_clusters_architectures_spec.rb b/spec/migrations/migrate_gcp_clusters_to_new_clusters_architectures_spec.rb
deleted file mode 100644
index ba4c66057d4..00000000000
--- a/spec/migrations/migrate_gcp_clusters_to_new_clusters_architectures_spec.rb
+++ /dev/null
@@ -1,181 +0,0 @@
-require 'spec_helper'
-require Rails.root.join('db', 'post_migrate', '20171013104327_migrate_gcp_clusters_to_new_clusters_architectures.rb')
-
-describe MigrateGcpClustersToNewClustersArchitectures, :migration do
- let(:projects) { table(:projects) }
- let(:project) { projects.create }
- let(:users) { table(:users) }
- let(:user) { users.create! }
- let(:service) { GcpMigrationSpec::KubernetesService.create!(project_id: project.id) }
-
- module GcpMigrationSpec
- class KubernetesService < ActiveRecord::Base
- self.table_name = 'services'
-
- serialize :properties, JSON
-
- default_value_for :active, true
- default_value_for :type, 'KubernetesService'
- default_value_for :properties, {
- api_url: 'https://kubernetes.example.com',
- token: 'a' * 40
- }
- end
- end
-
- context 'when cluster is being created' do
- let(:project_id) { project.id }
- let(:user_id) { user.id }
- let(:service_id) { service.id }
- let(:status) { 2 } # creating
- let(:gcp_cluster_size) { 1 }
- let(:created_at) { "'2017-10-17 20:24:02'" }
- let(:updated_at) { "'2017-10-17 20:28:44'" }
- let(:enabled) { true }
- let(:status_reason) { "''" }
- let(:project_namespace) { "'sample-app'" }
- let(:endpoint) { 'NULL' }
- let(:ca_cert) { 'NULL' }
- let(:encrypted_kubernetes_token) { 'NULL' }
- let(:encrypted_kubernetes_token_iv) { 'NULL' }
- let(:username) { 'NULL' }
- let(:encrypted_password) { 'NULL' }
- let(:encrypted_password_iv) { 'NULL' }
- let(:gcp_project_id) { "'gcp_project_id'" }
- let(:gcp_cluster_zone) { "'gcp_cluster_zone'" }
- let(:gcp_cluster_name) { "'gcp_cluster_name'" }
- let(:gcp_machine_type) { "'gcp_machine_type'" }
- let(:gcp_operation_id) { 'NULL' }
- let(:encrypted_gcp_token) { "'encrypted_gcp_token'" }
- let(:encrypted_gcp_token_iv) { "'encrypted_gcp_token_iv'" }
-
- let(:cluster) { described_class::Cluster.last }
- let(:cluster_id) { cluster.id }
-
- before do
- ActiveRecord::Base.connection.execute <<-SQL
- INSERT INTO gcp_clusters (project_id, user_id, service_id, status, gcp_cluster_size, created_at, updated_at, enabled, status_reason, project_namespace, endpoint, ca_cert, encrypted_kubernetes_token, encrypted_kubernetes_token_iv, username, encrypted_password, encrypted_password_iv, gcp_project_id, gcp_cluster_zone, gcp_cluster_name, gcp_machine_type, gcp_operation_id, encrypted_gcp_token, encrypted_gcp_token_iv)
- VALUES (#{project_id}, #{user_id}, #{service_id}, #{status}, #{gcp_cluster_size}, #{created_at}, #{updated_at}, #{enabled}, #{status_reason}, #{project_namespace}, #{endpoint}, #{ca_cert}, #{encrypted_kubernetes_token}, #{encrypted_kubernetes_token_iv}, #{username}, #{encrypted_password}, #{encrypted_password_iv}, #{gcp_project_id}, #{gcp_cluster_zone}, #{gcp_cluster_name}, #{gcp_machine_type}, #{gcp_operation_id}, #{encrypted_gcp_token}, #{encrypted_gcp_token_iv});
- SQL
- end
-
- it 'correctly migrate to new clusters architectures' do
- migrate!
-
- expect(described_class::Cluster.count).to eq(1)
- expect(described_class::ClustersProject.count).to eq(1)
- expect(described_class::ProvidersGcp.count).to eq(1)
- expect(described_class::PlatformsKubernetes.count).to eq(1)
-
- expect(cluster.user_id).to eq(user.id)
- expect(cluster.enabled).to be_truthy
- expect(cluster.name).to eq(gcp_cluster_name.delete!("'"))
- expect(cluster.provider_type).to eq('gcp')
- expect(cluster.platform_type).to eq('kubernetes')
-
- expect(cluster.project_ids).to include(project.id)
-
- expect(cluster.provider_gcp.cluster_id).to eq(cluster.id)
- expect(cluster.provider_gcp.status).to eq(status)
- expect(cluster.provider_gcp.status_reason).to eq(tr(status_reason))
- expect(cluster.provider_gcp.gcp_project_id).to eq(tr(gcp_project_id))
- expect(cluster.provider_gcp.zone).to eq(tr(gcp_cluster_zone))
- expect(cluster.provider_gcp.num_nodes).to eq(gcp_cluster_size)
- expect(cluster.provider_gcp.machine_type).to eq(tr(gcp_machine_type))
- expect(cluster.provider_gcp.operation_id).to be_nil
- expect(cluster.provider_gcp.endpoint).to be_nil
- expect(cluster.provider_gcp.encrypted_access_token).to eq(tr(encrypted_gcp_token))
- expect(cluster.provider_gcp.encrypted_access_token_iv).to eq(tr(encrypted_gcp_token_iv))
-
- expect(cluster.platform_kubernetes.cluster_id).to eq(cluster.id)
- expect(cluster.platform_kubernetes.api_url).to be_nil
- expect(cluster.platform_kubernetes.ca_cert).to be_nil
- expect(cluster.platform_kubernetes.namespace).to eq(tr(project_namespace))
- expect(cluster.platform_kubernetes.username).to be_nil
- expect(cluster.platform_kubernetes.encrypted_password).to be_nil
- expect(cluster.platform_kubernetes.encrypted_password_iv).to be_nil
- expect(cluster.platform_kubernetes.encrypted_token).to be_nil
- expect(cluster.platform_kubernetes.encrypted_token_iv).to be_nil
- end
- end
-
- context 'when cluster has been created' do
- let(:project_id) { project.id }
- let(:user_id) { user.id }
- let(:service_id) { service.id }
- let(:status) { 3 } # created
- let(:gcp_cluster_size) { 1 }
- let(:created_at) { "'2017-10-17 20:24:02'" }
- let(:updated_at) { "'2017-10-17 20:28:44'" }
- let(:enabled) { true }
- let(:status_reason) { "'general error'" }
- let(:project_namespace) { "'sample-app'" }
- let(:endpoint) { "'111.111.111.111'" }
- let(:ca_cert) { "'ca_cert'" }
- let(:encrypted_kubernetes_token) { "'encrypted_kubernetes_token'" }
- let(:encrypted_kubernetes_token_iv) { "'encrypted_kubernetes_token_iv'" }
- let(:username) { "'username'" }
- let(:encrypted_password) { "'encrypted_password'" }
- let(:encrypted_password_iv) { "'encrypted_password_iv'" }
- let(:gcp_project_id) { "'gcp_project_id'" }
- let(:gcp_cluster_zone) { "'gcp_cluster_zone'" }
- let(:gcp_cluster_name) { "'gcp_cluster_name'" }
- let(:gcp_machine_type) { "'gcp_machine_type'" }
- let(:gcp_operation_id) { "'gcp_operation_id'" }
- let(:encrypted_gcp_token) { "'encrypted_gcp_token'" }
- let(:encrypted_gcp_token_iv) { "'encrypted_gcp_token_iv'" }
-
- let(:cluster) { described_class::Cluster.last }
- let(:cluster_id) { cluster.id }
-
- before do
- ActiveRecord::Base.connection.execute <<-SQL
- INSERT INTO gcp_clusters (project_id, user_id, service_id, status, gcp_cluster_size, created_at, updated_at, enabled, status_reason, project_namespace, endpoint, ca_cert, encrypted_kubernetes_token, encrypted_kubernetes_token_iv, username, encrypted_password, encrypted_password_iv, gcp_project_id, gcp_cluster_zone, gcp_cluster_name, gcp_machine_type, gcp_operation_id, encrypted_gcp_token, encrypted_gcp_token_iv)
- VALUES (#{project_id}, #{user_id}, #{service_id}, #{status}, #{gcp_cluster_size}, #{created_at}, #{updated_at}, #{enabled}, #{status_reason}, #{project_namespace}, #{endpoint}, #{ca_cert}, #{encrypted_kubernetes_token}, #{encrypted_kubernetes_token_iv}, #{username}, #{encrypted_password}, #{encrypted_password_iv}, #{gcp_project_id}, #{gcp_cluster_zone}, #{gcp_cluster_name}, #{gcp_machine_type}, #{gcp_operation_id}, #{encrypted_gcp_token}, #{encrypted_gcp_token_iv});
- SQL
- end
-
- it 'correctly migrate to new clusters architectures' do
- migrate!
-
- expect(described_class::Cluster.count).to eq(1)
- expect(described_class::ClustersProject.count).to eq(1)
- expect(described_class::ProvidersGcp.count).to eq(1)
- expect(described_class::PlatformsKubernetes.count).to eq(1)
-
- expect(cluster.user_id).to eq(user.id)
- expect(cluster.enabled).to be_truthy
- expect(cluster.name).to eq(tr(gcp_cluster_name))
- expect(cluster.provider_type).to eq('gcp')
- expect(cluster.platform_type).to eq('kubernetes')
-
- expect(cluster.project_ids).to include(project.id)
-
- expect(cluster.provider_gcp.cluster_id).to eq(cluster.id)
- expect(cluster.provider_gcp.status).to eq(status)
- expect(cluster.provider_gcp.status_reason).to eq(tr(status_reason))
- expect(cluster.provider_gcp.gcp_project_id).to eq(tr(gcp_project_id))
- expect(cluster.provider_gcp.zone).to eq(tr(gcp_cluster_zone))
- expect(cluster.provider_gcp.num_nodes).to eq(gcp_cluster_size)
- expect(cluster.provider_gcp.machine_type).to eq(tr(gcp_machine_type))
- expect(cluster.provider_gcp.operation_id).to eq(tr(gcp_operation_id))
- expect(cluster.provider_gcp.endpoint).to eq(tr(endpoint))
- expect(cluster.provider_gcp.encrypted_access_token).to eq(tr(encrypted_gcp_token))
- expect(cluster.provider_gcp.encrypted_access_token_iv).to eq(tr(encrypted_gcp_token_iv))
-
- expect(cluster.platform_kubernetes.cluster_id).to eq(cluster.id)
- expect(cluster.platform_kubernetes.api_url).to eq('https://' + tr(endpoint))
- expect(cluster.platform_kubernetes.ca_cert).to eq(tr(ca_cert))
- expect(cluster.platform_kubernetes.namespace).to eq(tr(project_namespace))
- expect(cluster.platform_kubernetes.username).to eq(tr(username))
- expect(cluster.platform_kubernetes.encrypted_password).to eq(tr(encrypted_password))
- expect(cluster.platform_kubernetes.encrypted_password_iv).to eq(tr(encrypted_password_iv))
- expect(cluster.platform_kubernetes.encrypted_token).to eq(tr(encrypted_kubernetes_token))
- expect(cluster.platform_kubernetes.encrypted_token_iv).to eq(tr(encrypted_kubernetes_token_iv))
- end
- end
-
- def tr(str)
- str.delete("'")
- end
-end
diff --git a/spec/migrations/migrate_issues_to_ghost_user_spec.rb b/spec/migrations/migrate_issues_to_ghost_user_spec.rb
deleted file mode 100644
index 0016f058a17..00000000000
--- a/spec/migrations/migrate_issues_to_ghost_user_spec.rb
+++ /dev/null
@@ -1,51 +0,0 @@
-require 'spec_helper'
-require Rails.root.join('db', 'migrate', '20170825104051_migrate_issues_to_ghost_user.rb')
-
-describe MigrateIssuesToGhostUser, :migration do
- describe '#up' do
- let(:projects) { table(:projects) }
- let(:issues) { table(:issues) }
- let(:users) { table(:users) }
-
- before do
- project = projects.create!(name: 'gitlab', namespace_id: 1)
- user = users.create(email: 'test@example.com')
- issues.create(title: 'Issue 1', author_id: nil, project_id: project.id)
- issues.create(title: 'Issue 2', author_id: user.id, project_id: project.id)
- end
-
- context 'when ghost user exists' do
- let!(:ghost) { users.create(ghost: true, email: 'ghost@example.com') }
-
- it 'does not create a new user' do
- expect { migrate! }.not_to change { User.count }
- end
-
- it 'migrates issues where author = nil to the ghost user' do
- migrate!
-
- expect(issues.first.reload.author_id).to eq(ghost.id)
- end
-
- it 'does not change issues authored by an existing user' do
- expect { migrate! }.not_to change { issues.second.reload.author_id}
- end
- end
-
- context 'when ghost user does not exist' do
- it 'creates a new user' do
- expect { migrate! }.to change { User.count }.by(1)
- end
-
- it 'migrates issues where author = nil to the ghost user' do
- migrate!
-
- expect(issues.first.reload.author_id).to eq(User.ghost.id)
- end
-
- it 'does not change issues authored by an existing user' do
- expect { migrate! }.not_to change { issues.second.reload.author_id}
- end
- end
- end
-end
diff --git a/spec/migrations/migrate_kubernetes_service_to_new_clusters_architectures_spec.rb b/spec/migrations/migrate_kubernetes_service_to_new_clusters_architectures_spec.rb
deleted file mode 100644
index df0015b6dd3..00000000000
--- a/spec/migrations/migrate_kubernetes_service_to_new_clusters_architectures_spec.rb
+++ /dev/null
@@ -1,312 +0,0 @@
-require 'spec_helper'
-require Rails.root.join('db', 'post_migrate', '20171124104327_migrate_kubernetes_service_to_new_clusters_architectures.rb')
-
-describe MigrateKubernetesServiceToNewClustersArchitectures, :migration do
- context 'when unique KubernetesService exists' do
- shared_examples 'KubernetesService migration' do
- let(:sample_num) { 2 }
-
- let(:projects) do
- (1..sample_num).each_with_object([]) do |n, array|
- array << MigrateKubernetesServiceToNewClustersArchitectures::Project.create!
- end
- end
-
- let!(:kubernetes_services) do
- projects.map do |project|
- MigrateKubernetesServiceToNewClustersArchitectures::Service.create!(
- project: project,
- active: active,
- category: 'deployment',
- type: 'KubernetesService',
- properties: "{\"namespace\":\"prod\",\"api_url\":\"https://kubernetes#{project.id}.com\",\"ca_pem\":\"ca_pem#{project.id}\",\"token\":\"token#{project.id}\"}")
- end
- end
-
- it 'migrates the KubernetesService to Platform::Kubernetes' do
- expect { migrate! }.to change { MigrateKubernetesServiceToNewClustersArchitectures::Cluster.count }.by(sample_num)
-
- projects.each do |project|
- project.clusters.last.tap do |cluster|
- expect(cluster.enabled).to eq(active)
- expect(cluster.platform_kubernetes.api_url).to eq(project.kubernetes_service.api_url)
- expect(cluster.platform_kubernetes.ca_cert).to eq(project.kubernetes_service.ca_pem)
- expect(cluster.platform_kubernetes.token).to eq(project.kubernetes_service.token)
- expect(project.kubernetes_service).not_to be_active
- end
- end
- end
- end
-
- context 'when KubernetesService is active' do
- let(:active) { true }
-
- it_behaves_like 'KubernetesService migration'
- end
- end
-
- context 'when unique KubernetesService spawned from Service Template' do
- let(:sample_num) { 2 }
-
- let(:projects) do
- (1..sample_num).each_with_object([]) do |n, array|
- array << MigrateKubernetesServiceToNewClustersArchitectures::Project.create!
- end
- end
-
- let!(:kubernetes_service_template) do
- MigrateKubernetesServiceToNewClustersArchitectures::Service.create!(
- template: true,
- category: 'deployment',
- type: 'KubernetesService',
- properties: "{\"namespace\":\"prod\",\"api_url\":\"https://sample.kubernetes.com\",\"ca_pem\":\"ca_pem-sample\",\"token\":\"token-sample\"}")
- end
-
- let!(:kubernetes_services) do
- projects.map do |project|
- MigrateKubernetesServiceToNewClustersArchitectures::Service.create!(
- project: project,
- category: 'deployment',
- type: 'KubernetesService',
- properties: "{\"namespace\":\"prod\",\"api_url\":\"#{kubernetes_service_template.api_url}\",\"ca_pem\":\"#{kubernetes_service_template.ca_pem}\",\"token\":\"#{kubernetes_service_template.token}\"}")
- end
- end
-
- it 'migrates the KubernetesService to Platform::Kubernetes without template' do
- expect { migrate! }.to change { MigrateKubernetesServiceToNewClustersArchitectures::Cluster.count }.by(sample_num)
-
- projects.each do |project|
- project.clusters.last.tap do |cluster|
- expect(cluster.platform_kubernetes.api_url).to eq(project.kubernetes_service.api_url)
- expect(cluster.platform_kubernetes.ca_cert).to eq(project.kubernetes_service.ca_pem)
- expect(cluster.platform_kubernetes.token).to eq(project.kubernetes_service.token)
- expect(project.kubernetes_service).not_to be_active
- end
- end
- end
- end
-
- context 'when managed KubernetesService exists' do
- let(:project) { MigrateKubernetesServiceToNewClustersArchitectures::Project.create! }
-
- let(:cluster) do
- MigrateKubernetesServiceToNewClustersArchitectures::Cluster.create!(
- projects: [project],
- name: 'sample-cluster',
- platform_type: :kubernetes,
- provider_type: :user,
- platform_kubernetes_attributes: {
- api_url: 'https://sample.kubernetes.com',
- ca_cert: 'ca_pem-sample',
- token: 'token-sample'
- } )
- end
-
- let!(:kubernetes_service) do
- MigrateKubernetesServiceToNewClustersArchitectures::Service.create!(
- project: project,
- active: cluster.enabled,
- category: 'deployment',
- type: 'KubernetesService',
- properties: "{\"api_url\":\"#{cluster.platform_kubernetes.api_url}\"}")
- end
-
- it 'does not migrate the KubernetesService and disables the kubernetes_service' do # Because the corresponding Platform::Kubernetes already exists
- expect { migrate! }.not_to change { MigrateKubernetesServiceToNewClustersArchitectures::Cluster.count }
-
- kubernetes_service.reload
- expect(kubernetes_service).not_to be_active
- end
- end
-
- context 'when production cluster has already been existed' do # i.e. There are no environment_scope conflicts
- let(:project) { MigrateKubernetesServiceToNewClustersArchitectures::Project.create! }
-
- let(:cluster) do
- MigrateKubernetesServiceToNewClustersArchitectures::Cluster.create!(
- projects: [project],
- name: 'sample-cluster',
- platform_type: :kubernetes,
- provider_type: :user,
- environment_scope: 'production/*',
- platform_kubernetes_attributes: {
- api_url: 'https://sample.kubernetes.com',
- ca_cert: 'ca_pem-sample',
- token: 'token-sample'
- } )
- end
-
- let!(:kubernetes_service) do
- MigrateKubernetesServiceToNewClustersArchitectures::Service.create!(
- project: project,
- active: true,
- category: 'deployment',
- type: 'KubernetesService',
- properties: "{\"api_url\":\"https://debug.kube.com\"}")
- end
-
- it 'migrates the KubernetesService to Platform::Kubernetes' do
- expect { migrate! }.to change { MigrateKubernetesServiceToNewClustersArchitectures::Cluster.count }.by(1)
-
- kubernetes_service.reload
- project.clusters.last.tap do |cluster|
- expect(cluster.environment_scope).to eq('*')
- expect(cluster.platform_kubernetes.api_url).to eq(kubernetes_service.api_url)
- expect(cluster.platform_kubernetes.ca_cert).to eq(kubernetes_service.ca_pem)
- expect(cluster.platform_kubernetes.token).to eq(kubernetes_service.token)
- expect(kubernetes_service).not_to be_active
- end
- end
- end
-
- context 'when default cluster has already been existed' do
- let(:project) { MigrateKubernetesServiceToNewClustersArchitectures::Project.create! }
-
- let!(:cluster) do
- MigrateKubernetesServiceToNewClustersArchitectures::Cluster.create!(
- projects: [project],
- name: 'sample-cluster',
- platform_type: :kubernetes,
- provider_type: :user,
- environment_scope: '*',
- platform_kubernetes_attributes: {
- api_url: 'https://sample.kubernetes.com',
- ca_cert: 'ca_pem-sample',
- token: 'token-sample'
- } )
- end
-
- let!(:kubernetes_service) do
- MigrateKubernetesServiceToNewClustersArchitectures::Service.create!(
- project: project,
- active: true,
- category: 'deployment',
- type: 'KubernetesService',
- properties: "{\"api_url\":\"https://debug.kube.com\"}")
- end
-
- it 'migrates the KubernetesService to Platform::Kubernetes with dedicated environment_scope' do # Because environment_scope is duplicated
- expect { migrate! }.to change { MigrateKubernetesServiceToNewClustersArchitectures::Cluster.count }.by(1)
-
- kubernetes_service.reload
- project.clusters.last.tap do |cluster|
- expect(cluster.environment_scope).to eq('migrated/*')
- expect(cluster.platform_kubernetes.api_url).to eq(kubernetes_service.api_url)
- expect(cluster.platform_kubernetes.ca_cert).to eq(kubernetes_service.ca_pem)
- expect(cluster.platform_kubernetes.token).to eq(kubernetes_service.token)
- expect(kubernetes_service).not_to be_active
- end
- end
- end
-
- context 'when default cluster and migrated cluster has already been existed' do
- let(:project) { MigrateKubernetesServiceToNewClustersArchitectures::Project.create! }
-
- let!(:cluster) do
- MigrateKubernetesServiceToNewClustersArchitectures::Cluster.create!(
- projects: [project],
- name: 'sample-cluster',
- platform_type: :kubernetes,
- provider_type: :user,
- environment_scope: '*',
- platform_kubernetes_attributes: {
- api_url: 'https://sample.kubernetes.com',
- ca_cert: 'ca_pem-sample',
- token: 'token-sample'
- } )
- end
-
- let!(:migrated_cluster) do
- MigrateKubernetesServiceToNewClustersArchitectures::Cluster.create!(
- projects: [project],
- name: 'sample-cluster',
- platform_type: :kubernetes,
- provider_type: :user,
- environment_scope: 'migrated/*',
- platform_kubernetes_attributes: {
- api_url: 'https://sample.kubernetes.com',
- ca_cert: 'ca_pem-sample',
- token: 'token-sample'
- } )
- end
-
- let!(:kubernetes_service) do
- MigrateKubernetesServiceToNewClustersArchitectures::Service.create!(
- project: project,
- active: true,
- category: 'deployment',
- type: 'KubernetesService',
- properties: "{\"api_url\":\"https://debug.kube.com\"}")
- end
-
- it 'migrates the KubernetesService to Platform::Kubernetes with dedicated environment_scope' do # Because environment_scope is duplicated
- expect { migrate! }.to change { MigrateKubernetesServiceToNewClustersArchitectures::Cluster.count }.by(1)
-
- kubernetes_service.reload
- project.clusters.last.tap do |cluster|
- expect(cluster.environment_scope).to eq('migrated0/*')
- expect(cluster.platform_kubernetes.api_url).to eq(kubernetes_service.api_url)
- expect(cluster.platform_kubernetes.ca_cert).to eq(kubernetes_service.ca_pem)
- expect(cluster.platform_kubernetes.token).to eq(kubernetes_service.token)
- expect(kubernetes_service).not_to be_active
- end
- end
- end
-
- context 'when KubernetesService has nullified parameters' do
- let(:project) { MigrateKubernetesServiceToNewClustersArchitectures::Project.create! }
-
- before do
- MigrateKubernetesServiceToNewClustersArchitectures::Service.create!(
- project: project,
- active: false,
- category: 'deployment',
- type: 'KubernetesService',
- properties: "{}")
- end
-
- it 'does not migrate the KubernetesService and disables the kubernetes_service' do
- expect { migrate! }.not_to change { MigrateKubernetesServiceToNewClustersArchitectures::Cluster.count }
-
- expect(project.kubernetes_service).not_to be_active
- end
- end
-
- # Platforms::Kubernetes validates `token` reagdless of the activeness,
- # whereas KubernetesService validates `token` if only it's activated
- # However, in this migration file, there are no validations because of the re-defined model class
- # therefore, we should safely add this raw to Platform::Kubernetes
- context 'when KubernetesService has empty token' do
- let(:project) { MigrateKubernetesServiceToNewClustersArchitectures::Project.create! }
-
- before do
- MigrateKubernetesServiceToNewClustersArchitectures::Service.create!(
- project: project,
- active: false,
- category: 'deployment',
- type: 'KubernetesService',
- properties: "{\"namespace\":\"prod\",\"api_url\":\"http://111.111.111.111\",\"ca_pem\":\"a\",\"token\":\"\"}")
- end
-
- it 'does not migrate the KubernetesService and disables the kubernetes_service' do
- expect { migrate! }.to change { MigrateKubernetesServiceToNewClustersArchitectures::Cluster.count }.by(1)
-
- project.clusters.last.tap do |cluster|
- expect(cluster.environment_scope).to eq('*')
- expect(cluster.platform_kubernetes.namespace).to eq('prod')
- expect(cluster.platform_kubernetes.api_url).to eq('http://111.111.111.111')
- expect(cluster.platform_kubernetes.ca_cert).to eq('a')
- expect(cluster.platform_kubernetes.token).to be_empty
- expect(project.kubernetes_service).not_to be_active
- end
- end
- end
-
- context 'when KubernetesService does not exist' do
- let!(:project) { MigrateKubernetesServiceToNewClustersArchitectures::Project.create! }
-
- it 'does not migrate the KubernetesService' do
- expect { migrate! }.not_to change { MigrateKubernetesServiceToNewClustersArchitectures::Cluster.count }
- end
- end
-end
diff --git a/spec/migrations/migrate_old_artifacts_spec.rb b/spec/migrations/migrate_old_artifacts_spec.rb
deleted file mode 100644
index bc826d91471..00000000000
--- a/spec/migrations/migrate_old_artifacts_spec.rb
+++ /dev/null
@@ -1,140 +0,0 @@
-# encoding: utf-8
-
-require 'spec_helper'
-require Rails.root.join('db', 'post_migrate', '20170523083112_migrate_old_artifacts.rb')
-
-# Adding the ci_job_artifacts table (from the 20170918072948 schema)
-# makes the use of model code below easier.
-describe MigrateOldArtifacts, :migration, schema: 20170918072948 do
- let(:migration) { described_class.new }
- let!(:directory) { Dir.mktmpdir }
-
- before do
- allow(Gitlab.config.artifacts).to receive(:path).and_return(directory)
- end
-
- after do
- FileUtils.remove_entry_secure(directory)
- end
-
- context 'with migratable data' do
- let(:projects) { table(:projects) }
- let(:ci_pipelines) { table(:ci_pipelines) }
- let(:ci_builds) { table(:ci_builds) }
-
- let!(:project1) { projects.create!(ci_id: 2) }
- let!(:project2) { projects.create!(ci_id: 3) }
- let!(:project3) { projects.create! }
-
- let!(:pipeline1) { ci_pipelines.create!(project_id: project1.id) }
- let!(:pipeline2) { ci_pipelines.create!(project_id: project2.id) }
- let!(:pipeline3) { ci_pipelines.create!(project_id: project3.id) }
-
- let!(:build_with_legacy_artifacts) { ci_builds.create!(commit_id: pipeline1.id, project_id: project1.id, type: 'Ci::Build').becomes(Ci::Build) }
- let!(:build_without_artifacts) { ci_builds.create!(commit_id: pipeline1.id, project_id: project1.id, type: 'Ci::Build').becomes(Ci::Build) }
- let!(:build2) { ci_builds.create!(commit_id: pipeline2.id, project_id: project2.id, type: 'Ci::Build').becomes(Ci::Build) }
- let!(:build3) { ci_builds.create!(commit_id: pipeline3.id, project_id: project3.id, type: 'Ci::Build').becomes(Ci::Build) }
-
- before do
- setup_builds(build2, build3)
-
- store_artifacts_in_legacy_path(build_with_legacy_artifacts)
- end
-
- it "legacy artifacts are not accessible" do
- expect(build_with_legacy_artifacts.artifacts?).to be_falsey
- end
-
- describe '#min_id' do
- subject { migration.send(:min_id) }
-
- it 'returns the newest build for which ci_id is not defined' do
- is_expected.to eq(build3.id)
- end
- end
-
- describe '#builds_with_artifacts' do
- subject { migration.send(:builds_with_artifacts).map(&:id) }
-
- it 'returns a list of builds that has artifacts and could be migrated' do
- is_expected.to contain_exactly(build_with_legacy_artifacts.id, build2.id)
- end
- end
-
- describe '#up' do
- context 'when migrating artifacts' do
- before do
- migration.up
- end
-
- it 'all files do have artifacts' do
- Ci::Build.with_artifacts_archive do |build|
- expect(build).to have_artifacts
- end
- end
-
- it 'artifacts are no longer present on legacy path' do
- expect(File.exist?(legacy_path(build_with_legacy_artifacts))).to eq(false)
- end
- end
-
- context 'when there are artifacts in old and new directory' do
- before do
- store_artifacts_in_legacy_path(build2)
-
- migration.up
- end
-
- it 'does not move old files' do
- expect(File.exist?(legacy_path(build2))).to eq(true)
- end
- end
- end
-
- private
-
- def store_artifacts_in_legacy_path(build)
- FileUtils.mkdir_p(legacy_path(build))
-
- FileUtils.copy(
- Rails.root.join('spec/fixtures/ci_build_artifacts.zip'),
- File.join(legacy_path(build), "ci_build_artifacts.zip"))
-
- FileUtils.copy(
- Rails.root.join('spec/fixtures/ci_build_artifacts_metadata.gz'),
- File.join(legacy_path(build), "ci_build_artifacts_metadata.gz"))
-
- build.update_columns(
- artifacts_file: 'ci_build_artifacts.zip',
- artifacts_metadata: 'ci_build_artifacts_metadata.gz')
-
- build.reload
- end
-
- def legacy_path(build)
- File.join(directory,
- build.created_at.utc.strftime('%Y_%m'),
- build.project.ci_id.to_s,
- build.id.to_s)
- end
-
- def new_legacy_path(build)
- File.join(directory,
- build.created_at.utc.strftime('%Y_%m'),
- build.project_id.to_s,
- build.id.to_s)
- end
-
- def setup_builds(*builds)
- builds.each do |build|
- FileUtils.mkdir_p(new_legacy_path(build))
-
- build.update_columns(
- artifacts_file: 'ci_build_artifacts.zip',
- artifacts_metadata: 'ci_build_artifacts_metadata.gz')
-
- build.reload
- end
- end
- end
-end
diff --git a/spec/migrations/migrate_pipeline_sidekiq_queues_spec.rb b/spec/migrations/migrate_pipeline_sidekiq_queues_spec.rb
deleted file mode 100644
index e38044ccceb..00000000000
--- a/spec/migrations/migrate_pipeline_sidekiq_queues_spec.rb
+++ /dev/null
@@ -1,49 +0,0 @@
-require 'spec_helper'
-require Rails.root.join('db', 'post_migrate', '20170822101017_migrate_pipeline_sidekiq_queues.rb')
-
-describe MigratePipelineSidekiqQueues, :sidekiq, :redis do
- include Gitlab::Database::MigrationHelpers
- include StubWorker
-
- context 'when there are jobs in the queues' do
- it 'correctly migrates queue when migrating up' do
- Sidekiq::Testing.disable! do
- stub_worker(queue: :pipeline).perform_async('Something', [1])
- stub_worker(queue: :build).perform_async('Something', [1])
-
- described_class.new.up
-
- expect(sidekiq_queue_length('pipeline')).to eq 0
- expect(sidekiq_queue_length('build')).to eq 0
- expect(sidekiq_queue_length('pipeline_default')).to eq 2
- end
- end
-
- it 'correctly migrates queue when migrating down' do
- Sidekiq::Testing.disable! do
- stub_worker(queue: :pipeline_default).perform_async('Class', [1])
- stub_worker(queue: :pipeline_processing).perform_async('Class', [2])
- stub_worker(queue: :pipeline_hooks).perform_async('Class', [3])
- stub_worker(queue: :pipeline_cache).perform_async('Class', [4])
-
- described_class.new.down
-
- expect(sidekiq_queue_length('pipeline')).to eq 4
- expect(sidekiq_queue_length('pipeline_default')).to eq 0
- expect(sidekiq_queue_length('pipeline_processing')).to eq 0
- expect(sidekiq_queue_length('pipeline_hooks')).to eq 0
- expect(sidekiq_queue_length('pipeline_cache')).to eq 0
- end
- end
- end
-
- context 'when there are no jobs in the queues' do
- it 'does not raise error when migrating up' do
- expect { described_class.new.up }.not_to raise_error
- end
-
- it 'does not raise error when migrating down' do
- expect { described_class.new.down }.not_to raise_error
- end
- end
-end
diff --git a/spec/migrations/migrate_pipeline_stages_spec.rb b/spec/migrations/migrate_pipeline_stages_spec.rb
deleted file mode 100644
index c47f2bb8ff9..00000000000
--- a/spec/migrations/migrate_pipeline_stages_spec.rb
+++ /dev/null
@@ -1,56 +0,0 @@
-require 'spec_helper'
-require Rails.root.join('db', 'post_migrate', '20170526185842_migrate_pipeline_stages.rb')
-
-describe MigratePipelineStages, :migration do
- ##
- # Create test data - pipeline and CI/CD jobs.
- #
-
- let(:jobs) { table(:ci_builds) }
- let(:stages) { table(:ci_stages) }
- let(:pipelines) { table(:ci_pipelines) }
- let(:projects) { table(:projects) }
-
- before do
- # Create projects
- #
- projects.create!(id: 123, name: 'gitlab1', path: 'gitlab1')
- projects.create!(id: 456, name: 'gitlab2', path: 'gitlab2')
-
- # Create CI/CD pipelines
- #
- pipelines.create!(id: 1, project_id: 123, ref: 'master', sha: 'adf43c3a')
- pipelines.create!(id: 2, project_id: 456, ref: 'feature', sha: '21a3deb')
-
- # Create CI/CD jobs
- #
- jobs.create!(id: 1, commit_id: 1, project_id: 123, stage_idx: 2, stage: 'build')
- jobs.create!(id: 2, commit_id: 1, project_id: 123, stage_idx: 2, stage: 'build')
- jobs.create!(id: 3, commit_id: 1, project_id: 123, stage_idx: 1, stage: 'test')
- jobs.create!(id: 4, commit_id: 1, project_id: 123, stage_idx: 1, stage: 'test')
- jobs.create!(id: 5, commit_id: 1, project_id: 123, stage_idx: 3, stage: 'deploy')
- jobs.create!(id: 6, commit_id: 2, project_id: 456, stage_idx: 3, stage: 'deploy')
- jobs.create!(id: 7, commit_id: 2, project_id: 456, stage_idx: 2, stage: 'test:2')
- jobs.create!(id: 8, commit_id: 2, project_id: 456, stage_idx: 1, stage: 'test:1')
- jobs.create!(id: 9, commit_id: 2, project_id: 456, stage_idx: 1, stage: 'test:1')
- jobs.create!(id: 10, commit_id: 2, project_id: 456, stage_idx: 2, stage: 'test:2')
- jobs.create!(id: 11, commit_id: 3, project_id: 456, stage_idx: 3, stage: 'deploy')
- jobs.create!(id: 12, commit_id: 2, project_id: 789, stage_idx: 3, stage: 'deploy')
- end
-
- it 'correctly migrates pipeline stages' do
- expect(stages.count).to be_zero
-
- migrate!
-
- expect(stages.count).to eq 6
- expect(stages.all.pluck(:name))
- .to match_array %w[test build deploy test:1 test:2 deploy]
- expect(stages.where(pipeline_id: 1).order(:id).pluck(:name))
- .to eq %w[test build deploy]
- expect(stages.where(pipeline_id: 2).order(:id).pluck(:name))
- .to eq %w[test:1 test:2 deploy]
- expect(stages.where(pipeline_id: 3).count).to be_zero
- expect(stages.where(project_id: 789).count).to be_zero
- end
-end
diff --git a/spec/migrations/migrate_process_commit_worker_jobs_spec.rb b/spec/migrations/migrate_process_commit_worker_jobs_spec.rb
deleted file mode 100644
index 6219a67c900..00000000000
--- a/spec/migrations/migrate_process_commit_worker_jobs_spec.rb
+++ /dev/null
@@ -1,197 +0,0 @@
-# encoding: utf-8
-
-require 'spec_helper'
-require Rails.root.join('db', 'migrate', '20161124141322_migrate_process_commit_worker_jobs.rb')
-
-describe MigrateProcessCommitWorkerJobs do
- set(:project) { create(:project, :legacy_storage, :repository) } # rubocop:disable RSpec/FactoriesInMigrationSpecs
- set(:user) { create(:user) } # rubocop:disable RSpec/FactoriesInMigrationSpecs
- let(:commit) do
- Gitlab::Git::Commit.last(project.repository.raw)
- end
-
- describe 'Project' do
- describe 'find_including_path' do
- it 'returns Project instances' do
- expect(described_class::Project.find_including_path(project.id))
- .to be_an_instance_of(described_class::Project)
- end
-
- it 'selects the full path for every Project' do
- migration_project = described_class::Project
- .find_including_path(project.id)
-
- expect(migration_project[:path_with_namespace])
- .to eq(project.full_path)
- end
- end
-
- describe '#repository' do
- it 'returns a mock implemention of ::Repository' do
- migration_project = described_class::Project
- .find_including_path(project.id)
-
- expect(migration_project.repository).to respond_to(:storage)
- expect(migration_project.repository).to respond_to(:gitaly_repository)
- end
- end
- end
-
- describe '#up', :clean_gitlab_redis_shared_state do
- let(:migration) { described_class.new }
-
- def job_count
- Sidekiq.redis { |r| r.llen('queue:process_commit') }
- end
-
- def pop_job
- JSON.parse(Sidekiq.redis { |r| r.lpop('queue:process_commit') })
- end
-
- before do
- Sidekiq.redis do |redis|
- job = JSON.dump(args: [project.id, user.id, commit.id])
- redis.lpush('queue:process_commit', job)
- end
- end
-
- it 'skips jobs using a project that no longer exists' do
- allow(described_class::Project).to receive(:find_including_path)
- .with(project.id)
- .and_return(nil)
-
- migration.up
-
- expect(job_count).to eq(0)
- end
-
- it 'skips jobs using commits that no longer exist' do
- allow_any_instance_of(Gitlab::GitalyClient::CommitService)
- .to receive(:find_commit)
- .with(commit.id)
- .and_return(nil)
-
- migration.up
-
- expect(job_count).to eq(0)
- end
-
- it 'inserts migrated jobs back into the queue' do
- migration.up
-
- expect(job_count).to eq(1)
- end
-
- it 'encodes data to UTF-8' do
- allow(commit).to receive(:body)
- .and_return('김치'.force_encoding('BINARY'))
-
- migration.up
-
- job = pop_job
-
- # We don't care so much about what is being stored, instead we just want
- # to make sure the encoding is right so that JSON encoding the data
- # doesn't produce any errors.
- expect(job['args'][2]['message'].encoding).to eq(Encoding::UTF_8)
- end
-
- context 'a migrated job' do
- let(:job) do
- migration.up
- pop_job
- end
-
- let(:commit_hash) do
- job['args'][2]
- end
-
- it 'includes the project ID' do
- expect(job['args'][0]).to eq(project.id)
- end
-
- it 'includes the user ID' do
- expect(job['args'][1]).to eq(user.id)
- end
-
- it 'includes the commit ID' do
- expect(commit_hash['id']).to eq(commit.id)
- end
-
- it 'includes the commit message' do
- expect(commit_hash['message']).to eq(commit.message)
- end
-
- it 'includes the parent IDs' do
- expect(commit_hash['parent_ids']).to eq(commit.parent_ids)
- end
-
- it 'includes the author date' do
- expect(commit_hash['authored_date']).to eq(commit.authored_date.to_s)
- end
-
- it 'includes the author name' do
- expect(commit_hash['author_name']).to eq(commit.author_name)
- end
-
- it 'includes the author Email' do
- expect(commit_hash['author_email']).to eq(commit.author_email)
- end
-
- it 'includes the commit date' do
- expect(commit_hash['committed_date']).to eq(commit.committed_date.to_s)
- end
-
- it 'includes the committer name' do
- expect(commit_hash['committer_name']).to eq(commit.committer_name)
- end
-
- it 'includes the committer Email' do
- expect(commit_hash['committer_email']).to eq(commit.committer_email)
- end
- end
- end
-
- describe '#down', :clean_gitlab_redis_shared_state do
- let(:migration) { described_class.new }
-
- def job_count
- Sidekiq.redis { |r| r.llen('queue:process_commit') }
- end
-
- before do
- Sidekiq.redis do |redis|
- job = JSON.dump(args: [project.id, user.id, commit.id])
- redis.lpush('queue:process_commit', job)
-
- migration.up
- end
- end
-
- it 'pushes migrated jobs back into the queue' do
- migration.down
-
- expect(job_count).to eq(1)
- end
-
- context 'a migrated job' do
- let(:job) do
- migration.down
-
- JSON.parse(Sidekiq.redis { |r| r.lpop('queue:process_commit') })
- end
-
- it 'includes the project ID' do
- expect(job['args'][0]).to eq(project.id)
- end
-
- it 'includes the user ID' do
- expect(job['args'][1]).to eq(user.id)
- end
-
- it 'includes the commit SHA' do
- expect(job['args'][2]).to eq(commit.id)
- end
- end
- end
-end
diff --git a/spec/migrations/migrate_stage_id_reference_in_background_spec.rb b/spec/migrations/migrate_stage_id_reference_in_background_spec.rb
deleted file mode 100644
index dd6f5325750..00000000000
--- a/spec/migrations/migrate_stage_id_reference_in_background_spec.rb
+++ /dev/null
@@ -1,55 +0,0 @@
-require 'spec_helper'
-require Rails.root.join('db', 'post_migrate', '20170628080858_migrate_stage_id_reference_in_background')
-
-describe MigrateStageIdReferenceInBackground, :migration, :sidekiq do
- let(:jobs) { table(:ci_builds) }
- let(:stages) { table(:ci_stages) }
- let(:pipelines) { table(:ci_pipelines) }
- let(:projects) { table(:projects) }
-
- before do
- stub_const("#{described_class.name}::BATCH_SIZE", 3)
- stub_const("#{described_class.name}::RANGE_SIZE", 2)
-
- projects.create!(id: 123, name: 'gitlab1', path: 'gitlab1')
- projects.create!(id: 345, name: 'gitlab2', path: 'gitlab2')
-
- pipelines.create!(id: 1, project_id: 123, ref: 'master', sha: 'adf43c3a')
- pipelines.create!(id: 2, project_id: 345, ref: 'feature', sha: 'cdf43c3c')
-
- jobs.create!(id: 1, commit_id: 1, project_id: 123, stage_idx: 2, stage: 'build')
- jobs.create!(id: 2, commit_id: 1, project_id: 123, stage_idx: 2, stage: 'build')
- jobs.create!(id: 3, commit_id: 1, project_id: 123, stage_idx: 1, stage: 'test')
- jobs.create!(id: 4, commit_id: 1, project_id: 123, stage_idx: 3, stage: 'deploy')
- jobs.create!(id: 5, commit_id: 2, project_id: 345, stage_idx: 1, stage: 'test')
-
- stages.create(id: 101, pipeline_id: 1, project_id: 123, name: 'test')
- stages.create(id: 102, pipeline_id: 1, project_id: 123, name: 'build')
- stages.create(id: 103, pipeline_id: 1, project_id: 123, name: 'deploy')
-
- jobs.create!(id: 6, commit_id: 2, project_id: 345, stage_id: 101, stage_idx: 1, stage: 'test')
- end
-
- it 'correctly schedules background migrations' do
- Sidekiq::Testing.fake! do
- Timecop.freeze do
- migrate!
-
- expect(described_class::MIGRATION).to be_scheduled_delayed_migration(2.minutes, 1, 2)
- expect(described_class::MIGRATION).to be_scheduled_delayed_migration(2.minutes, 3, 3)
- expect(described_class::MIGRATION).to be_scheduled_delayed_migration(4.minutes, 4, 5)
- expect(BackgroundMigrationWorker.jobs.size).to eq 3
- end
- end
- end
-
- it 'schedules background migrations' do
- perform_enqueued_jobs do
- expect(jobs.where(stage_id: nil).count).to eq 5
-
- migrate!
-
- expect(jobs.where(stage_id: nil).count).to eq 1
- end
- end
-end
diff --git a/spec/migrations/migrate_stages_statuses_spec.rb b/spec/migrations/migrate_stages_statuses_spec.rb
deleted file mode 100644
index 5483e24fce7..00000000000
--- a/spec/migrations/migrate_stages_statuses_spec.rb
+++ /dev/null
@@ -1,68 +0,0 @@
-require 'spec_helper'
-require Rails.root.join('db', 'post_migrate', '20170711145558_migrate_stages_statuses.rb')
-
-describe MigrateStagesStatuses, :sidekiq, :migration do
- let(:jobs) { table(:ci_builds) }
- let(:stages) { table(:ci_stages) }
- let(:pipelines) { table(:ci_pipelines) }
- let(:projects) { table(:projects) }
-
- STATUSES = { created: 0, pending: 1, running: 2, success: 3,
- failed: 4, canceled: 5, skipped: 6, manual: 7 }.freeze
-
- before do
- stub_const("#{described_class.name}::BATCH_SIZE", 2)
- stub_const("#{described_class.name}::RANGE_SIZE", 1)
-
- projects.create!(id: 1, name: 'gitlab1', path: 'gitlab1')
- projects.create!(id: 2, name: 'gitlab2', path: 'gitlab2')
-
- pipelines.create!(id: 1, project_id: 1, ref: 'master', sha: 'adf43c3a')
- pipelines.create!(id: 2, project_id: 2, ref: 'feature', sha: '21a3deb')
-
- create_job(project: 1, pipeline: 1, stage: 'test', status: 'success')
- create_job(project: 1, pipeline: 1, stage: 'test', status: 'running')
- create_job(project: 1, pipeline: 1, stage: 'build', status: 'success')
- create_job(project: 1, pipeline: 1, stage: 'build', status: 'failed')
- create_job(project: 2, pipeline: 2, stage: 'test', status: 'success')
- create_job(project: 2, pipeline: 2, stage: 'test', status: 'success')
- create_job(project: 2, pipeline: 2, stage: 'test', status: 'failed', retried: true)
-
- stages.create!(id: 1, pipeline_id: 1, project_id: 1, name: 'test', status: nil)
- stages.create!(id: 2, pipeline_id: 1, project_id: 1, name: 'build', status: nil)
- stages.create!(id: 3, pipeline_id: 2, project_id: 2, name: 'test', status: nil)
- end
-
- it 'correctly migrates stages statuses' do
- perform_enqueued_jobs do
- expect(stages.where(status: nil).count).to eq 3
-
- migrate!
-
- expect(stages.where(status: nil)).to be_empty
- expect(stages.all.order('id ASC').pluck(:status))
- .to eq [STATUSES[:running], STATUSES[:failed], STATUSES[:success]]
- end
- end
-
- it 'correctly schedules background migrations' do
- Sidekiq::Testing.fake! do
- Timecop.freeze do
- migrate!
-
- expect(described_class::MIGRATION).to be_scheduled_delayed_migration(5.minutes, 1, 1)
- expect(described_class::MIGRATION).to be_scheduled_delayed_migration(5.minutes, 2, 2)
- expect(described_class::MIGRATION).to be_scheduled_delayed_migration(10.minutes, 3, 3)
- expect(BackgroundMigrationWorker.jobs.size).to eq 3
- end
- end
- end
-
- def create_job(project:, pipeline:, stage:, status:, **opts)
- stages = { test: 1, build: 2, deploy: 3 }
-
- jobs.create!(project_id: project, commit_id: pipeline,
- stage_idx: stages[stage.to_sym], stage: stage,
- status: status, **opts)
- end
-end
diff --git a/spec/migrations/migrate_user_activities_to_users_last_activity_on_spec.rb b/spec/migrations/migrate_user_activities_to_users_last_activity_on_spec.rb
deleted file mode 100644
index 88aef3b70b4..00000000000
--- a/spec/migrations/migrate_user_activities_to_users_last_activity_on_spec.rb
+++ /dev/null
@@ -1,49 +0,0 @@
-# encoding: utf-8
-
-require 'spec_helper'
-require Rails.root.join('db', 'post_migrate', '20170324160416_migrate_user_activities_to_users_last_activity_on.rb')
-
-describe MigrateUserActivitiesToUsersLastActivityOn, :clean_gitlab_redis_shared_state, :migration do
- let(:migration) { described_class.new }
- let!(:user_active_1) { table(:users).create!(email: 'test1', username: 'test1') }
- let!(:user_active_2) { table(:users).create!(email: 'test2', username: 'test2') }
-
- def record_activity(user, time)
- Gitlab::Redis::SharedState.with do |redis|
- redis.zadd(described_class::USER_ACTIVITY_SET_KEY, time.to_i, user.username)
- end
- end
-
- around do |example|
- Timecop.freeze { example.run }
- end
-
- before do
- record_activity(user_active_1, described_class::TIME_WHEN_ACTIVITY_SET_WAS_INTRODUCED + 2.months)
- record_activity(user_active_2, described_class::TIME_WHEN_ACTIVITY_SET_WAS_INTRODUCED + 3.months)
- mute_stdout { migration.up }
- end
-
- describe '#up' do
- it 'fills last_activity_on from the legacy Redis Sorted Set' do
- expect(user_active_1.reload.last_activity_on).to eq((described_class::TIME_WHEN_ACTIVITY_SET_WAS_INTRODUCED + 2.months).to_date)
- expect(user_active_2.reload.last_activity_on).to eq((described_class::TIME_WHEN_ACTIVITY_SET_WAS_INTRODUCED + 3.months).to_date)
- end
- end
-
- describe '#down' do
- it 'sets last_activity_on to NULL for all users' do
- mute_stdout { migration.down }
-
- expect(user_active_1.reload.last_activity_on).to be_nil
- expect(user_active_2.reload.last_activity_on).to be_nil
- end
- end
-
- def mute_stdout
- orig_stdout = $stdout
- $stdout = StringIO.new
- yield
- $stdout = orig_stdout
- end
-end
diff --git a/spec/migrations/migrate_user_authentication_token_to_personal_access_token_spec.rb b/spec/migrations/migrate_user_authentication_token_to_personal_access_token_spec.rb
deleted file mode 100644
index b4834705011..00000000000
--- a/spec/migrations/migrate_user_authentication_token_to_personal_access_token_spec.rb
+++ /dev/null
@@ -1,25 +0,0 @@
-require 'spec_helper'
-require Rails.root.join('db', 'migrate', '20171012125712_migrate_user_authentication_token_to_personal_access_token.rb')
-
-describe MigrateUserAuthenticationTokenToPersonalAccessToken, :migration do
- let(:users) { table(:users) }
- let(:personal_access_tokens) { table(:personal_access_tokens) }
-
- let!(:user) { users.create!(id: 1, email: 'user@example.com', authentication_token: 'user-token', admin: false) }
- let!(:admin) { users.create!(id: 2, email: 'admin@example.com', authentication_token: 'admin-token', admin: true) }
-
- it 'migrates private tokens to Personal Access Tokens' do
- migrate!
-
- expect(personal_access_tokens.count).to eq(2)
-
- user_token = personal_access_tokens.find_by(user_id: user.id)
- admin_token = personal_access_tokens.find_by(user_id: admin.id)
-
- expect(user_token.token).to eq('user-token')
- expect(admin_token.token).to eq('admin-token')
-
- expect(user_token.scopes).to eq(%w[api].to_yaml)
- expect(admin_token.scopes).to eq(%w[api sudo].to_yaml)
- end
-end
diff --git a/spec/migrations/migrate_user_project_view_spec.rb b/spec/migrations/migrate_user_project_view_spec.rb
deleted file mode 100644
index a0179ab3ceb..00000000000
--- a/spec/migrations/migrate_user_project_view_spec.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-# encoding: utf-8
-
-require 'spec_helper'
-require Rails.root.join('db', 'post_migrate', '20170406142253_migrate_user_project_view.rb')
-
-describe MigrateUserProjectView, :migration do
- let(:migration) { described_class.new }
- let!(:user) { table(:users).create!(project_view: User.project_views['readme']) }
-
- describe '#up' do
- it 'updates project view setting with new value' do
- migration.up
-
- expect(user.reload.project_view).to eq(User.project_views['files'])
- end
- end
-end
diff --git a/spec/migrations/move_personal_snippets_files_spec.rb b/spec/migrations/move_personal_snippets_files_spec.rb
deleted file mode 100644
index d94ae1e52f5..00000000000
--- a/spec/migrations/move_personal_snippets_files_spec.rb
+++ /dev/null
@@ -1,197 +0,0 @@
-require 'spec_helper'
-require Rails.root.join('db', 'post_migrate', '20170612071012_move_personal_snippets_files.rb')
-
-describe MovePersonalSnippetsFiles, :migration do
- let(:migration) { described_class.new }
- let(:test_dir) { File.join(Rails.root, "tmp", "tests", "move_snippet_files_test") }
- let(:uploads_dir) { File.join(test_dir, 'uploads') }
- let(:new_uploads_dir) { File.join(uploads_dir, '-', 'system') }
-
- let(:notes) { table(:notes) }
- let(:snippets) { table(:snippets) }
- let(:uploads) { table(:uploads) }
-
- let(:user) { table(:users).create!(email: 'user@example.com', projects_limit: 10) }
- let(:project) { table(:projects).create!(name: 'gitlab', namespace_id: 1) }
-
- before do
- allow(CarrierWave).to receive(:root).and_return(test_dir)
- allow(migration).to receive(:base_directory).and_return(test_dir)
- FileUtils.remove_dir(test_dir) if File.directory?(test_dir)
- allow(migration).to receive(:say)
- end
-
- describe "#up" do
- let(:snippet) do
- snippet = snippets.create!(author_id: user.id)
- create_upload('picture.jpg', snippet)
- snippet.update(description: markdown_linking_file('picture.jpg', snippet))
- snippet
- end
-
- let(:snippet_with_missing_file) do
- snippet = snippets.create!(author_id: user.id, project_id: project.id)
- create_upload('picture.jpg', snippet, create_file: false)
- snippet.update(description: markdown_linking_file('picture.jpg', snippet))
- snippet
- end
-
- it 'moves the files' do
- source_path = File.join(uploads_dir, model_file_path('picture.jpg', snippet))
- destination_path = File.join(new_uploads_dir, model_file_path('picture.jpg', snippet))
-
- migration.up
-
- expect(File.exist?(source_path)).to be_falsy
- expect(File.exist?(destination_path)).to be_truthy
- end
-
- describe 'updating the markdown' do
- it 'includes the new path when the file exists' do
- secret = "secret#{snippet.id}"
- file_location = "/uploads/-/system/personal_snippet/#{snippet.id}/#{secret}/picture.jpg"
-
- migration.up
-
- expect(snippet.reload.description).to include(file_location)
- end
-
- it 'does not update the markdown when the file is missing' do
- secret = "secret#{snippet_with_missing_file.id}"
- file_location = "/uploads/personal_snippet/#{snippet_with_missing_file.id}/#{secret}/picture.jpg"
-
- migration.up
-
- expect(snippet_with_missing_file.reload.description).to include(file_location)
- end
-
- it 'updates the note markdown' do
- secret = "secret#{snippet.id}"
- file_location = "/uploads/-/system/personal_snippet/#{snippet.id}/#{secret}/picture.jpg"
- markdown = markdown_linking_file('picture.jpg', snippet)
- note = notes.create!(noteable_id: snippet.id,
- noteable_type: Snippet,
- note: "with #{markdown}",
- author_id: user.id)
-
- migration.up
-
- expect(note.reload.note).to include(file_location)
- end
- end
- end
-
- describe "#down" do
- let(:snippet) do
- snippet = snippets.create!(author_id: user.id)
- create_upload('picture.jpg', snippet, in_new_path: true)
- snippet.update(description: markdown_linking_file('picture.jpg', snippet, in_new_path: true))
- snippet
- end
-
- let(:snippet_with_missing_file) do
- snippet = snippets.create!(author_id: user.id)
- create_upload('picture.jpg', snippet, create_file: false, in_new_path: true)
- snippet.update(description: markdown_linking_file('picture.jpg', snippet, in_new_path: true))
- snippet
- end
-
- it 'moves the files' do
- source_path = File.join(new_uploads_dir, model_file_path('picture.jpg', snippet))
- destination_path = File.join(uploads_dir, model_file_path('picture.jpg', snippet))
-
- migration.down
-
- expect(File.exist?(source_path)).to be_falsey
- expect(File.exist?(destination_path)).to be_truthy
- end
-
- describe 'updating the markdown' do
- it 'includes the new path when the file exists' do
- secret = "secret#{snippet.id}"
- file_location = "/uploads/personal_snippet/#{snippet.id}/#{secret}/picture.jpg"
-
- migration.down
-
- expect(snippet.reload.description).to include(file_location)
- end
-
- it 'keeps the markdown as is when the file is missing' do
- secret = "secret#{snippet_with_missing_file.id}"
- file_location = "/uploads/-/system/personal_snippet/#{snippet_with_missing_file.id}/#{secret}/picture.jpg"
-
- migration.down
-
- expect(snippet_with_missing_file.reload.description).to include(file_location)
- end
-
- it 'updates the note markdown' do
- markdown = markdown_linking_file('picture.jpg', snippet, in_new_path: true)
- secret = "secret#{snippet.id}"
- file_location = "/uploads/personal_snippet/#{snippet.id}/#{secret}/picture.jpg"
- note = notes.create!(noteable_id: snippet.id,
- noteable_type: Snippet,
- note: "with #{markdown}",
- author_id: user.id)
-
- migration.down
-
- expect(note.reload.note).to include(file_location)
- end
- end
- end
-
- describe '#update_markdown' do
- it 'escapes sql in the snippet description' do
- migration.instance_variable_set('@source_relative_location', '/uploads/personal_snippet')
- migration.instance_variable_set('@destination_relative_location', '/uploads/system/personal_snippet')
-
- secret = '123456789'
- filename = 'hello.jpg'
- snippet = snippets.create!(author_id: user.id)
-
- path_before = "/uploads/personal_snippet/#{snippet.id}/#{secret}/#{filename}"
- path_after = "/uploads/system/personal_snippet/#{snippet.id}/#{secret}/#{filename}"
- description_before = "Hello world; ![image](#{path_before})'; select * from users;"
- description_after = "Hello world; ![image](#{path_after})'; select * from users;"
-
- migration.update_markdown(snippet.id, secret, filename, description_before)
-
- expect(snippet.reload.description).to eq(description_after)
- end
- end
-
- def create_upload(filename, snippet, create_file: true, in_new_path: false)
- secret = "secret#{snippet.id}"
- absolute_path = if in_new_path
- File.join(new_uploads_dir, model_file_path(filename, snippet))
- else
- File.join(uploads_dir, model_file_path(filename, snippet))
- end
-
- if create_file
- FileUtils.mkdir_p(File.dirname(absolute_path))
- FileUtils.touch(absolute_path)
- end
-
- uploads.create!(model_id: snippet.id,
- model_type: snippet.class,
- path: "#{secret}/#{filename}",
- uploader: PersonalFileUploader,
- size: 100.kilobytes)
- end
-
- def markdown_linking_file(filename, snippet, in_new_path: false)
- markdown = "![#{filename.split('.')[0]}]"
- markdown += '(/uploads'
- markdown += '/-/system' if in_new_path
- markdown += "/#{model_file_path(filename, snippet)})"
- markdown
- end
-
- def model_file_path(filename, snippet)
- secret = "secret#{snippet.id}"
-
- File.join('personal_snippet', snippet.id.to_s, secret, filename)
- end
-end
diff --git a/spec/migrations/move_system_upload_folder_spec.rb b/spec/migrations/move_system_upload_folder_spec.rb
deleted file mode 100644
index d3180477db3..00000000000
--- a/spec/migrations/move_system_upload_folder_spec.rb
+++ /dev/null
@@ -1,80 +0,0 @@
-require 'spec_helper'
-require Rails.root.join("db", "migrate", "20170717074009_move_system_upload_folder.rb")
-
-describe MoveSystemUploadFolder do
- let(:migration) { described_class.new }
- let(:test_base) { File.join(Rails.root, 'tmp', 'tests', 'move-system-upload-folder') }
-
- before do
- allow(migration).to receive(:base_directory).and_return(test_base)
- FileUtils.rm_rf(test_base)
- FileUtils.mkdir_p(test_base)
- allow(migration).to receive(:say)
- end
-
- describe '#up' do
- let(:test_folder) { File.join(test_base, 'system') }
- let(:test_file) { File.join(test_folder, 'file') }
-
- before do
- FileUtils.mkdir_p(test_folder)
- FileUtils.touch(test_file)
- end
-
- it 'moves the related folder' do
- migration.up
-
- expect(File.exist?(File.join(test_base, '-', 'system', 'file'))).to be_truthy
- end
-
- it 'creates a symlink linking making the new folder available on the old path' do
- migration.up
-
- expect(File.symlink?(File.join(test_base, 'system'))).to be_truthy
- expect(File.exist?(File.join(test_base, 'system', 'file'))).to be_truthy
- end
-
- it 'does not move if the target directory already exists' do
- FileUtils.mkdir_p(File.join(test_base, '-', 'system'))
-
- expect(FileUtils).not_to receive(:mv)
- expect(migration).to receive(:say).with(/already exists. No need to redo the move/)
-
- migration.up
- end
- end
-
- describe '#down' do
- let(:test_folder) { File.join(test_base, '-', 'system') }
- let(:test_file) { File.join(test_folder, 'file') }
-
- before do
- FileUtils.mkdir_p(test_folder)
- FileUtils.touch(test_file)
- end
-
- it 'moves the system folder back to the old location' do
- migration.down
-
- expect(File.exist?(File.join(test_base, 'system', 'file'))).to be_truthy
- end
-
- it 'removes the symlink if it existed' do
- FileUtils.ln_s(test_folder, File.join(test_base, 'system'))
-
- migration.down
-
- expect(File.directory?(File.join(test_base, 'system'))).to be_truthy
- expect(File.symlink?(File.join(test_base, 'system'))).to be_falsey
- end
-
- it 'does not move if the old directory already exists' do
- FileUtils.mkdir_p(File.join(test_base, 'system'))
-
- expect(FileUtils).not_to receive(:mv)
- expect(migration).to receive(:say).with(/already exists and is not a symlink, no need to revert/)
-
- migration.down
- end
- end
-end
diff --git a/spec/migrations/move_uploads_to_system_dir_spec.rb b/spec/migrations/move_uploads_to_system_dir_spec.rb
deleted file mode 100644
index ca11a2004c5..00000000000
--- a/spec/migrations/move_uploads_to_system_dir_spec.rb
+++ /dev/null
@@ -1,68 +0,0 @@
-require "spec_helper"
-require Rails.root.join("db", "migrate", "20170316163845_move_uploads_to_system_dir.rb")
-
-describe MoveUploadsToSystemDir do
- let(:migration) { described_class.new }
- let(:test_dir) { File.join(Rails.root, "tmp", "move_uploads_test") }
- let(:uploads_dir) { File.join(test_dir, "public", "uploads") }
- let(:new_uploads_dir) { File.join(uploads_dir, "-", "system") }
-
- before do
- FileUtils.remove_dir(test_dir) if File.directory?(test_dir)
- FileUtils.mkdir_p(uploads_dir)
- allow(migration).to receive(:base_directory).and_return(test_dir)
- allow(migration).to receive(:say)
- end
-
- describe "#up" do
- before do
- FileUtils.mkdir_p(File.join(uploads_dir, 'user'))
- FileUtils.touch(File.join(uploads_dir, 'user', 'dummy.file'))
- end
-
- it 'moves the directory to the new path' do
- expected_path = File.join(new_uploads_dir, 'user', 'dummy.file')
-
- migration.up
-
- expect(File.exist?(expected_path)).to be(true)
- end
-
- it 'creates a symlink in the old location' do
- symlink_path = File.join(uploads_dir, 'user')
- expected_path = File.join(symlink_path, 'dummy.file')
-
- migration.up
-
- expect(File.exist?(expected_path)).to be(true)
- expect(File.symlink?(symlink_path)).to be(true)
- end
- end
-
- describe "#down" do
- before do
- FileUtils.mkdir_p(File.join(new_uploads_dir, 'user'))
- FileUtils.touch(File.join(new_uploads_dir, 'user', 'dummy.file'))
- end
-
- it 'moves the directory to the old path' do
- expected_path = File.join(uploads_dir, 'user', 'dummy.file')
-
- migration.down
-
- expect(File.exist?(expected_path)).to be(true)
- end
-
- it 'removes the symlink if it existed' do
- FileUtils.ln_s(File.join(new_uploads_dir, 'user'), File.join(uploads_dir, 'user'))
-
- directory = File.join(uploads_dir, 'user')
- expected_path = File.join(directory, 'dummy.file')
-
- migration.down
-
- expect(File.exist?(expected_path)).to be(true)
- expect(File.symlink?(directory)).to be(false)
- end
- end
-end
diff --git a/spec/migrations/normalize_ldap_extern_uids_spec.rb b/spec/migrations/normalize_ldap_extern_uids_spec.rb
deleted file mode 100644
index a23a5d54e0a..00000000000
--- a/spec/migrations/normalize_ldap_extern_uids_spec.rb
+++ /dev/null
@@ -1,56 +0,0 @@
-require 'spec_helper'
-require Rails.root.join('db', 'post_migrate', '20170921101004_normalize_ldap_extern_uids')
-
-describe NormalizeLdapExternUids, :migration, :sidekiq do
- let!(:identities) { table(:identities) }
-
- around do |example|
- Timecop.freeze { example.run }
- end
-
- before do
- stub_const("Gitlab::Database::MigrationHelpers::BACKGROUND_MIGRATION_BATCH_SIZE", 2)
- stub_const("Gitlab::Database::MigrationHelpers::BACKGROUND_MIGRATION_JOB_BUFFER_SIZE", 2)
-
- # LDAP identities
- (1..4).each do |i|
- identities.create!(id: i, provider: 'ldapmain', extern_uid: " uid = foo #{i}, ou = People, dc = example, dc = com ", user_id: i)
- end
-
- # Non-LDAP identity
- identities.create!(id: 5, provider: 'foo', extern_uid: " uid = foo 5, ou = People, dc = example, dc = com ", user_id: 5)
- end
-
- it 'correctly schedules background migrations' do
- Sidekiq::Testing.fake! do
- Timecop.freeze do
- migrate!
-
- expect(BackgroundMigrationWorker.jobs[0]['args']).to eq([described_class::MIGRATION, [1, 2]])
- expect(BackgroundMigrationWorker.jobs[0]['at']).to eq(2.minutes.from_now.to_f)
- expect(BackgroundMigrationWorker.jobs[1]['args']).to eq([described_class::MIGRATION, [3, 4]])
- expect(BackgroundMigrationWorker.jobs[1]['at']).to eq(4.minutes.from_now.to_f)
- expect(BackgroundMigrationWorker.jobs[2]['args']).to eq([described_class::MIGRATION, [5, 5]])
- expect(BackgroundMigrationWorker.jobs[2]['at']).to eq(6.minutes.from_now.to_f)
- expect(BackgroundMigrationWorker.jobs.size).to eq 3
- end
- end
- end
-
- it 'migrates the LDAP identities' do
- perform_enqueued_jobs do
- migrate!
- identities.where(id: 1..4).each do |identity|
- expect(identity.extern_uid).to eq("uid=foo #{identity.id},ou=people,dc=example,dc=com")
- end
- end
- end
-
- it 'does not modify non-LDAP identities' do
- perform_enqueued_jobs do
- migrate!
- identity = identities.last
- expect(identity.extern_uid).to eq(" uid = foo 5, ou = People, dc = example, dc = com ")
- end
- end
-end
diff --git a/spec/migrations/populate_can_push_from_deploy_keys_projects_spec.rb b/spec/migrations/populate_can_push_from_deploy_keys_projects_spec.rb
deleted file mode 100644
index 0ff98933d5c..00000000000
--- a/spec/migrations/populate_can_push_from_deploy_keys_projects_spec.rb
+++ /dev/null
@@ -1,43 +0,0 @@
-require 'spec_helper'
-require Rails.root.join('db', 'migrate', '20171215113714_populate_can_push_from_deploy_keys_projects.rb')
-
-describe PopulateCanPushFromDeployKeysProjects, :migration do
- let(:migration) { described_class.new }
- let(:deploy_keys) { table(:keys) }
- let(:deploy_keys_projects) { table(:deploy_keys_projects) }
- let(:projects) { table(:projects) }
-
- before do
- deploy_keys.inheritance_column = nil
-
- projects.create!(id: 1, name: 'gitlab1', path: 'gitlab1')
- (1..10).each do |index|
- deploy_keys.create!(id: index, title: 'dummy', type: 'DeployKey', key: Spec::Support::Helpers::KeyGeneratorHelper.new(1024).generate + ' dummy@gitlab.com')
- deploy_keys_projects.create!(id: index, deploy_key_id: index, project_id: 1)
- end
- end
-
- describe '#up' do
- it 'migrates can_push from deploy_keys to deploy_keys_projects' do
- deploy_keys.limit(5).update_all(can_push: true)
-
- expected = deploy_keys.order(:id).pluck(:id, :can_push)
-
- migration.up
-
- expect(deploy_keys_projects.order(:id).pluck(:deploy_key_id, :can_push)).to eq expected
- end
- end
-
- describe '#down' do
- it 'migrates can_push from deploy_keys_projects to deploy_keys' do
- deploy_keys_projects.limit(5).update_all(can_push: true)
-
- expected = deploy_keys_projects.order(:id).pluck(:deploy_key_id, :can_push)
-
- migration.down
-
- expect(deploy_keys.order(:id).pluck(:id, :can_push)).to eq expected
- end
- end
-end
diff --git a/spec/migrations/remove_assignee_id_from_issue_spec.rb b/spec/migrations/remove_assignee_id_from_issue_spec.rb
deleted file mode 100644
index 2c6f992d3ae..00000000000
--- a/spec/migrations/remove_assignee_id_from_issue_spec.rb
+++ /dev/null
@@ -1,37 +0,0 @@
-require 'spec_helper'
-require Rails.root.join('db', 'post_migrate', '20170523073948_remove_assignee_id_from_issue.rb')
-
-describe RemoveAssigneeIdFromIssue, :migration do
- let(:issues) { table(:issues) }
- let(:issue_assignees) { table(:issue_assignees) }
- let(:users) { table(:users) }
-
- let!(:user_1) { users.create(email: 'email1@example.com') }
- let!(:user_2) { users.create(email: 'email2@example.com') }
- let!(:user_3) { users.create(email: 'email3@example.com') }
-
- def create_issue(assignees:)
- issues.create.tap do |issue|
- assignees.each do |assignee|
- issue_assignees.create(issue_id: issue.id, user_id: assignee.id)
- end
- end
- end
-
- let!(:issue_single_assignee) { create_issue(assignees: [user_1]) }
- let!(:issue_no_assignee) { create_issue(assignees: []) }
- let!(:issue_multiple_assignees) { create_issue(assignees: [user_2, user_3]) }
-
- describe '#down' do
- it 'sets the assignee_id to a random matching assignee from the assignees table' do
- migrate!
- disable_migrations_output { described_class.new.down }
-
- expect(issue_single_assignee.reload.assignee_id).to eq(user_1.id)
- expect(issue_no_assignee.reload.assignee_id).to be_nil
- expect(issue_multiple_assignees.reload.assignee_id).to eq(user_2.id).or(user_3.id)
-
- disable_migrations_output { described_class.new.up }
- end
- end
-end
diff --git a/spec/migrations/remove_dot_git_from_usernames_spec.rb b/spec/migrations/remove_dot_git_from_usernames_spec.rb
deleted file mode 100644
index f11880a83e9..00000000000
--- a/spec/migrations/remove_dot_git_from_usernames_spec.rb
+++ /dev/null
@@ -1,58 +0,0 @@
-# encoding: utf-8
-
-require 'spec_helper'
-require Rails.root.join('db', 'migrate', '20161226122833_remove_dot_git_from_usernames.rb')
-
-describe RemoveDotGitFromUsernames do
- let(:user) { create(:user) } # rubocop:disable RSpec/FactoriesInMigrationSpecs
- let(:migration) { described_class.new }
-
- describe '#up' do
- before do
- update_namespace(user, 'test.git')
- end
-
- it 'renames user with .git in username' do
- migration.up
-
- expect(user.reload.username).to eq('test_git')
- expect(user.namespace.reload.path).to eq('test_git')
- expect(user.namespace.route.path).to eq('test_git')
- end
- end
-
- context 'when new path exists already' do
- describe '#up' do
- let(:user2) { create(:user) } # rubocop:disable RSpec/FactoriesInMigrationSpecs
-
- before do
- update_namespace(user, 'test.git')
- update_namespace(user2, 'test_git')
-
- default_hash = Gitlab.config.repositories.storages.default.to_h
- default_hash['path'] = 'tmp/tests/custom_repositories'
- storages = { 'default' => Gitlab::GitalyClient::StorageSettings.new(default_hash) }
-
- allow(Gitlab.config.repositories).to receive(:storages).and_return(storages)
- allow(migration).to receive(:route_exists?).with('test_git').and_return(true)
- allow(migration).to receive(:route_exists?).with('test_git1').and_return(false)
- end
-
- it 'renames user with .git in username' do
- migration.up
-
- expect(user.reload.username).to eq('test_git1')
- expect(user.namespace.reload.path).to eq('test_git1')
- expect(user.namespace.route.path).to eq('test_git1')
- end
- end
- end
-
- def update_namespace(user, path)
- namespace = user.namespace
- namespace.path = path
- namespace.save!(validate: false)
-
- user.update_column(:username, path)
- end
-end
diff --git a/spec/migrations/remove_duplicate_mr_events_spec.rb b/spec/migrations/remove_duplicate_mr_events_spec.rb
deleted file mode 100644
index 2509ac6afd6..00000000000
--- a/spec/migrations/remove_duplicate_mr_events_spec.rb
+++ /dev/null
@@ -1,26 +0,0 @@
-require 'spec_helper'
-require Rails.root.join('db', 'post_migrate', '20170815060945_remove_duplicate_mr_events.rb')
-
-describe RemoveDuplicateMrEvents, :delete do
- let(:migration) { described_class.new }
-
- describe '#up' do
- let(:user) { create(:user) } # rubocop:disable RSpec/FactoriesInMigrationSpecs
- let(:merge_requests) { create_list(:merge_request, 2) } # rubocop:disable RSpec/FactoriesInMigrationSpecs
- let(:issue) { create(:issue) } # rubocop:disable RSpec/FactoriesInMigrationSpecs
- let!(:events) do
- [
- create(:event, :created, author: user, target: merge_requests.first), # rubocop:disable RSpec/FactoriesInMigrationSpecs
- create(:event, :created, author: user, target: merge_requests.first), # rubocop:disable RSpec/FactoriesInMigrationSpecs
- create(:event, :updated, author: user, target: merge_requests.first), # rubocop:disable RSpec/FactoriesInMigrationSpecs
- create(:event, :created, author: user, target: merge_requests.second), # rubocop:disable RSpec/FactoriesInMigrationSpecs
- create(:event, :created, author: user, target: issue), # rubocop:disable RSpec/FactoriesInMigrationSpecs
- create(:event, :created, author: user, target: issue) # rubocop:disable RSpec/FactoriesInMigrationSpecs
- ]
- end
-
- it 'removes duplicated merge request create records' do
- expect { migration.up }.to change { Event.count }.from(6).to(5)
- end
- end
-end
diff --git a/spec/migrations/remove_empty_fork_networks_spec.rb b/spec/migrations/remove_empty_fork_networks_spec.rb
deleted file mode 100644
index f6d030ab25c..00000000000
--- a/spec/migrations/remove_empty_fork_networks_spec.rb
+++ /dev/null
@@ -1,35 +0,0 @@
-require 'spec_helper'
-require Rails.root.join('db', 'post_migrate', '20171114104051_remove_empty_fork_networks.rb')
-
-describe RemoveEmptyForkNetworks, :migration do
- let!(:fork_networks) { table(:fork_networks) }
- let!(:projects) { table(:projects) }
- let!(:fork_network_members) { table(:fork_network_members) }
-
- let(:deleted_project) { projects.create! }
- let!(:empty_network) { fork_networks.create!(id: 1, root_project_id: deleted_project.id) }
- let!(:other_network) { fork_networks.create!(id: 2, root_project_id: projects.create.id) }
-
- before do
- fork_network_members.create(fork_network_id: empty_network.id,
- project_id: empty_network.root_project_id)
- fork_network_members.create(fork_network_id: other_network.id,
- project_id: other_network.root_project_id)
-
- deleted_project.destroy!
- end
-
- after do
- Upload.reset_column_information
- end
-
- it 'deletes only the fork network without members' do
- expect(fork_networks.count).to eq(2)
-
- migrate!
-
- expect(fork_networks.find_by(id: empty_network.id)).to be_nil
- expect(fork_networks.find_by(id: other_network.id)).not_to be_nil
- expect(fork_networks.count).to eq(1)
- end
-end
diff --git a/spec/migrations/remove_project_labels_group_id_spec.rb b/spec/migrations/remove_project_labels_group_id_spec.rb
deleted file mode 100644
index 01b09e71d83..00000000000
--- a/spec/migrations/remove_project_labels_group_id_spec.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-# encoding: utf-8
-
-require 'spec_helper'
-require Rails.root.join('db', 'post_migrate', '20180202111106_remove_project_labels_group_id.rb')
-
-describe RemoveProjectLabelsGroupId, :delete do
- let(:migration) { described_class.new }
- let(:group) { create(:group) } # rubocop:disable RSpec/FactoriesInMigrationSpecs
- let!(:project_label) { create(:label, group_id: group.id) } # rubocop:disable RSpec/FactoriesInMigrationSpecs
- let!(:group_label) { create(:group_label) } # rubocop:disable RSpec/FactoriesInMigrationSpecs
-
- describe '#up' do
- it 'updates the project labels group ID' do
- expect { migration.up }.to change { project_label.reload.group_id }.to(nil)
- end
-
- it 'keeps the group labels group ID' do
- expect { migration.up }.not_to change { group_label.reload.group_id }
- end
- end
-end
diff --git a/spec/migrations/rename_duplicated_variable_key_spec.rb b/spec/migrations/rename_duplicated_variable_key_spec.rb
deleted file mode 100644
index 11096564dfa..00000000000
--- a/spec/migrations/rename_duplicated_variable_key_spec.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-require 'spec_helper'
-require Rails.root.join('db', 'migrate', '20170622135451_rename_duplicated_variable_key.rb')
-
-describe RenameDuplicatedVariableKey, :migration do
- let(:variables) { table(:ci_variables) }
- let(:projects) { table(:projects) }
-
- before do
- projects.create!(id: 1)
- variables.create!(id: 1, key: 'key1', project_id: 1)
- variables.create!(id: 2, key: 'key2', project_id: 1)
- variables.create!(id: 3, key: 'keyX', project_id: 1)
- variables.create!(id: 4, key: 'keyX', project_id: 1)
- variables.create!(id: 5, key: 'keyY', project_id: 1)
- variables.create!(id: 6, key: 'keyX', project_id: 1)
- variables.create!(id: 7, key: 'key7', project_id: 1)
- variables.create!(id: 8, key: 'keyY', project_id: 1)
- end
-
- it 'correctly remove duplicated records with smaller id' do
- migrate!
-
- expect(variables.pluck(:id, :key)).to contain_exactly(
- [1, 'key1'],
- [2, 'key2'],
- [3, 'keyX_3'],
- [4, 'keyX_4'],
- [5, 'keyY_5'],
- [6, 'keyX'],
- [7, 'key7'],
- [8, 'keyY']
- )
- end
-end
diff --git a/spec/migrations/rename_more_reserved_project_names_spec.rb b/spec/migrations/rename_more_reserved_project_names_spec.rb
deleted file mode 100644
index 80ae209e9d1..00000000000
--- a/spec/migrations/rename_more_reserved_project_names_spec.rb
+++ /dev/null
@@ -1,57 +0,0 @@
-# encoding: utf-8
-
-require 'spec_helper'
-require Rails.root.join('db', 'post_migrate', '20170313133418_rename_more_reserved_project_names.rb')
-
-# This migration uses multiple threads, and thus different transactions. This
-# means data created in this spec may not be visible to some threads. To work
-# around this we use the DELETE cleaning strategy.
-describe RenameMoreReservedProjectNames, :delete do
- let(:migration) { described_class.new }
- let!(:project) { create(:project) } # rubocop:disable RSpec/FactoriesInMigrationSpecs
-
- before do
- project.path = 'artifacts'
- project.save!(validate: false)
- end
-
- describe '#up' do
- context 'when project repository exists' do
- before do
- project.create_repository
- end
-
- context 'when no exception is raised' do
- it 'renames project with reserved names' do
- migration.up
-
- expect(project.reload.path).to eq('artifacts0')
- end
- end
-
- context 'when exception is raised during rename' do
- before do
- service = instance_double('service')
-
- allow(service)
- .to receive(:execute)
- .and_raise(Projects::AfterRenameService::RenameFailedError)
-
- expect(migration)
- .to receive(:after_rename_service)
- .and_return(service)
- end
-
- it 'captures exception from project rename' do
- expect { migration.up }.not_to raise_error
- end
- end
- end
-
- context 'when project repository does not exist' do
- it 'does not raise error' do
- expect { migration.up }.not_to raise_error
- end
- end
- end
-end
diff --git a/spec/migrations/rename_reserved_project_names_spec.rb b/spec/migrations/rename_reserved_project_names_spec.rb
deleted file mode 100644
index 93e5c032287..00000000000
--- a/spec/migrations/rename_reserved_project_names_spec.rb
+++ /dev/null
@@ -1,61 +0,0 @@
-# encoding: utf-8
-
-require 'spec_helper'
-require Rails.root.join('db', 'post_migrate', '20161221153951_rename_reserved_project_names.rb')
-
-# This migration is using factories, which set fields that don't actually
-# exist in the DB schema previous to 20161221153951. Thus we just use the
-# latest schema when testing this migration.
-# This is ok-ish because:
-# 1. This migration is a data migration
-# 2. It only relies on very stable DB fields: routes.id, routes.path, namespaces.id, projects.namespace_id
-# Ideally, the test should not use factories and rely on the `table` helper instead.
-describe RenameReservedProjectNames, :migration, schema: :latest do
- let(:migration) { described_class.new }
- let!(:project) { create(:project) } # rubocop:disable RSpec/FactoriesInMigrationSpecs
-
- before do
- project.path = 'projects'
- project.save!(validate: false)
- end
-
- describe '#up' do
- context 'when project repository exists' do
- before do
- project.create_repository
- end
-
- context 'when no exception is raised' do
- it 'renames project with reserved names' do
- migration.up
-
- expect(project.reload.path).to eq('projects0')
- end
- end
-
- context 'when exception is raised during rename' do
- before do
- service = instance_double('service')
-
- allow(service)
- .to receive(:execute)
- .and_raise(Projects::AfterRenameService::RenameFailedError)
-
- expect(migration)
- .to receive(:after_rename_service)
- .and_return(service)
- end
-
- it 'captures exception from project rename' do
- expect { migration.up }.not_to raise_error
- end
- end
- end
-
- context 'when project repository does not exist' do
- it 'does not raise error' do
- expect { migration.up }.not_to raise_error
- end
- end
- end
-end
diff --git a/spec/migrations/rename_users_with_renamed_namespace_spec.rb b/spec/migrations/rename_users_with_renamed_namespace_spec.rb
deleted file mode 100644
index b8a4dc2b2c0..00000000000
--- a/spec/migrations/rename_users_with_renamed_namespace_spec.rb
+++ /dev/null
@@ -1,22 +0,0 @@
-require 'spec_helper'
-require Rails.root.join('db', 'post_migrate', '20170518200835_rename_users_with_renamed_namespace.rb')
-
-describe RenameUsersWithRenamedNamespace, :delete do
- it 'renames a user that had their namespace renamed to the namespace path' do
- other_user = create(:user, username: 'kodingu') # rubocop:disable RSpec/FactoriesInMigrationSpecs
- other_user1 = create(:user, username: 'api0') # rubocop:disable RSpec/FactoriesInMigrationSpecs
-
- user = create(:user, username: "Users0") # rubocop:disable RSpec/FactoriesInMigrationSpecs
- user.update_column(:username, 'Users')
- user1 = create(:user, username: "import0") # rubocop:disable RSpec/FactoriesInMigrationSpecs
- user1.update_column(:username, 'import')
-
- described_class.new.up
-
- expect(user.reload.username).to eq('Users0')
- expect(user1.reload.username).to eq('import0')
-
- expect(other_user.reload.username).to eq('kodingu')
- expect(other_user1.reload.username).to eq('api0')
- end
-end
diff --git a/spec/migrations/schedule_merge_request_latest_merge_request_diff_id_migrations_spec.rb b/spec/migrations/schedule_merge_request_latest_merge_request_diff_id_migrations_spec.rb
deleted file mode 100644
index 76fe16581ac..00000000000
--- a/spec/migrations/schedule_merge_request_latest_merge_request_diff_id_migrations_spec.rb
+++ /dev/null
@@ -1,64 +0,0 @@
-require 'spec_helper'
-require Rails.root.join('db', 'post_migrate', '20171026082505_schedule_merge_request_latest_merge_request_diff_id_migrations')
-
-describe ScheduleMergeRequestLatestMergeRequestDiffIdMigrations, :migration, :sidekiq do
- let(:projects_table) { table(:projects) }
- let(:merge_requests_table) { table(:merge_requests) }
- let(:merge_request_diffs_table) { table(:merge_request_diffs) }
-
- let(:project) { projects_table.create!(name: 'gitlab', path: 'gitlab-org/gitlab-ce') }
-
- let!(:merge_request_1) { create_mr!('mr_1', diffs: 1) }
- let!(:merge_request_2) { create_mr!('mr_2', diffs: 2) }
- let!(:merge_request_migrated) { create_mr!('merge_request_migrated', diffs: 3) }
- let!(:merge_request_4) { create_mr!('mr_4', diffs: 3) }
-
- def create_mr!(name, diffs: 0)
- merge_request =
- merge_requests_table.create!(target_project_id: project.id,
- target_branch: 'master',
- source_project_id: project.id,
- source_branch: name,
- title: name)
-
- diffs.times do
- merge_request_diffs_table.create!(merge_request_id: merge_request.id)
- end
-
- merge_request
- end
-
- def diffs_for(merge_request)
- merge_request_diffs_table.where(merge_request_id: merge_request.id)
- end
-
- before do
- stub_const("#{described_class.name}::BATCH_SIZE", 1)
-
- diff_id = diffs_for(merge_request_migrated).minimum(:id)
- merge_request_migrated.update!(latest_merge_request_diff_id: diff_id)
- end
-
- it 'correctly schedules background migrations' do
- Sidekiq::Testing.fake! do
- Timecop.freeze do
- migrate!
-
- expect(described_class::MIGRATION).to be_scheduled_delayed_migration(5.minutes, merge_request_1.id, merge_request_1.id)
- expect(described_class::MIGRATION).to be_scheduled_delayed_migration(10.minutes, merge_request_2.id, merge_request_2.id)
- expect(described_class::MIGRATION).to be_scheduled_delayed_migration(15.minutes, merge_request_4.id, merge_request_4.id)
- expect(BackgroundMigrationWorker.jobs.size).to eq 3
- end
- end
- end
-
- it 'schedules background migrations' do
- perform_enqueued_jobs do
- expect(merge_requests_table.where(latest_merge_request_diff_id: nil).count).to eq 3
-
- migrate!
-
- expect(merge_requests_table.where(latest_merge_request_diff_id: nil).count).to eq 0
- end
- end
-end
diff --git a/spec/migrations/track_untracked_uploads_spec.rb b/spec/migrations/track_untracked_uploads_spec.rb
deleted file mode 100644
index 2fccfb3f12c..00000000000
--- a/spec/migrations/track_untracked_uploads_spec.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-require 'spec_helper'
-require Rails.root.join('db', 'post_migrate', '20171103140253_track_untracked_uploads')
-
-describe TrackUntrackedUploads, :migration, :sidekiq do
- include MigrationsHelpers::TrackUntrackedUploadsHelpers
-
- it 'correctly schedules the follow-up background migration' do
- Sidekiq::Testing.fake! do
- migrate!
-
- expect(described_class::MIGRATION).to be_scheduled_migration
- expect(BackgroundMigrationWorker.jobs.size).to eq(1)
- end
- end
-end
diff --git a/spec/migrations/turn_nested_groups_into_regular_groups_for_mysql_spec.rb b/spec/migrations/turn_nested_groups_into_regular_groups_for_mysql_spec.rb
deleted file mode 100644
index 5f5ba426d69..00000000000
--- a/spec/migrations/turn_nested_groups_into_regular_groups_for_mysql_spec.rb
+++ /dev/null
@@ -1,70 +0,0 @@
-require 'spec_helper'
-require Rails.root.join('db', 'migrate', '20170503140202_turn_nested_groups_into_regular_groups_for_mysql.rb')
-
-describe TurnNestedGroupsIntoRegularGroupsForMysql do
- let!(:parent_group) { create(:group) } # rubocop:disable RSpec/FactoriesInMigrationSpecs
- let!(:child_group) { create(:group, parent: parent_group) } # rubocop:disable RSpec/FactoriesInMigrationSpecs
- let!(:project) { create(:project, :legacy_storage, :empty_repo, namespace: child_group) } # rubocop:disable RSpec/FactoriesInMigrationSpecs
- let!(:member) { create(:user) } # rubocop:disable RSpec/FactoriesInMigrationSpecs
- let(:migration) { described_class.new }
-
- before do
- parent_group.add_developer(member)
-
- allow(migration).to receive(:run_migration?).and_return(true)
- allow(migration).to receive(:verbose).and_return(false)
- end
-
- describe '#up' do
- let(:updated_project) do
- # path_with_namespace is memoized in an instance variable so we retrieve a
- # new row here to work around that.
- Project.find(project.id)
- end
-
- before do
- migration.up
- end
-
- it 'unsets the parent_id column' do
- expect(Namespace.where('parent_id IS NOT NULL').any?).to eq(false)
- end
-
- it 'adds members of parent groups as members to the migrated group' do
- is_member = child_group.members
- .where(user_id: member, access_level: Gitlab::Access::DEVELOPER).any?
-
- expect(is_member).to eq(true)
- end
-
- it 'update the path of the nested group' do
- child_group.reload
-
- expect(child_group.path).to eq("#{parent_group.name}-#{child_group.name}")
- end
-
- it 'renames projects of the nested group' do
- expect(updated_project.full_path)
- .to eq("#{parent_group.name}-#{child_group.name}/#{updated_project.path}")
- end
-
- it 'renames the repository of any projects' do
- repo_path = Gitlab::GitalyClient::StorageSettings.allow_disk_access do
- updated_project.repository.path
- end
-
- expect(repo_path)
- .to end_with("#{parent_group.name}-#{child_group.name}/#{updated_project.path}.git")
-
- expect(File.directory?(repo_path)).to eq(true)
- end
-
- it 'creates a redirect route for renamed projects' do
- exists = RedirectRoute
- .where(source_type: 'Project', source_id: project.id)
- .any?
-
- expect(exists).to eq(true)
- end
- end
-end
diff --git a/spec/migrations/update_legacy_diff_notes_type_for_import_spec.rb b/spec/migrations/update_legacy_diff_notes_type_for_import_spec.rb
deleted file mode 100644
index d625b60ff50..00000000000
--- a/spec/migrations/update_legacy_diff_notes_type_for_import_spec.rb
+++ /dev/null
@@ -1,22 +0,0 @@
-require 'spec_helper'
-require Rails.root.join('db', 'post_migrate', '20170927112318_update_legacy_diff_notes_type_for_import.rb')
-
-describe UpdateLegacyDiffNotesTypeForImport, :migration do
- let(:notes) { table(:notes) }
-
- before do
- notes.inheritance_column = nil
-
- notes.create(type: 'Note')
- notes.create(type: 'LegacyDiffNote')
- notes.create(type: 'Github::Import::Note')
- notes.create(type: 'Github::Import::LegacyDiffNote')
- end
-
- it 'updates the notes type' do
- migrate!
-
- expect(notes.pluck(:type))
- .to contain_exactly('Note', 'Github::Import::Note', 'LegacyDiffNote', 'LegacyDiffNote')
- end
-end
diff --git a/spec/migrations/update_notes_type_for_import_spec.rb b/spec/migrations/update_notes_type_for_import_spec.rb
deleted file mode 100644
index 06195d970d8..00000000000
--- a/spec/migrations/update_notes_type_for_import_spec.rb
+++ /dev/null
@@ -1,22 +0,0 @@
-require 'spec_helper'
-require Rails.root.join('db', 'post_migrate', '20170927112319_update_notes_type_for_import.rb')
-
-describe UpdateNotesTypeForImport, :migration do
- let(:notes) { table(:notes) }
-
- before do
- notes.inheritance_column = nil
-
- notes.create(type: 'Note')
- notes.create(type: 'LegacyDiffNote')
- notes.create(type: 'Github::Import::Note')
- notes.create(type: 'Github::Import::LegacyDiffNote')
- end
-
- it 'updates the notes type' do
- migrate!
-
- expect(notes.pluck(:type))
- .to contain_exactly('Note', 'Note', 'LegacyDiffNote', 'Github::Import::LegacyDiffNote')
- end
-end
diff --git a/spec/migrations/update_retried_for_ci_build_spec.rb b/spec/migrations/update_retried_for_ci_build_spec.rb
deleted file mode 100644
index 637dcbb8e01..00000000000
--- a/spec/migrations/update_retried_for_ci_build_spec.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-require 'spec_helper'
-require Rails.root.join('db', 'post_migrate', '20170503004427_update_retried_for_ci_build.rb')
-
-describe UpdateRetriedForCiBuild, :delete do
- let(:pipeline) { create(:ci_pipeline) } # rubocop:disable RSpec/FactoriesInMigrationSpecs
- let!(:build_old) { create(:ci_build, pipeline: pipeline, name: 'test') } # rubocop:disable RSpec/FactoriesInMigrationSpecs
- let!(:build_new) { create(:ci_build, pipeline: pipeline, name: 'test') } # rubocop:disable RSpec/FactoriesInMigrationSpecs
-
- before do
- described_class.new.up
- end
-
- it 'updates ci_builds.is_retried' do
- expect(build_old.reload).to be_retried
- expect(build_new.reload).not_to be_retried
- end
-end
diff --git a/spec/migrations/update_upload_paths_to_system_spec.rb b/spec/migrations/update_upload_paths_to_system_spec.rb
deleted file mode 100644
index 984b428a020..00000000000
--- a/spec/migrations/update_upload_paths_to_system_spec.rb
+++ /dev/null
@@ -1,59 +0,0 @@
-require 'spec_helper'
-require Rails.root.join('db', 'post_migrate', '20170317162059_update_upload_paths_to_system.rb')
-
-describe UpdateUploadPathsToSystem, :migration do
- let(:migration) { described_class.new }
- let(:uploads_table) { table(:uploads) }
- let(:base_upload_attributes) { { size: 42, uploader: 'John Doe' } }
-
- before do
- allow(migration).to receive(:say)
- end
-
- describe '#uploads_to_switch_to_new_path' do
- it 'contains only uploads with the old path for the correct models' do
- _upload_for_other_type = create_upload('Pipeline', 'uploads/ci_pipeline/avatar.jpg')
- _upload_with_system_path = create_upload('Project', 'uploads/-/system/project/avatar.jpg')
- _upload_with_other_path = create_upload('Project', 'thelongsecretforafileupload/avatar.jpg')
- old_upload = create_upload('Project', 'uploads/project/avatar.jpg')
- group_upload = create_upload('Namespace', 'uploads/group/avatar.jpg')
-
- expect(uploads_table.where(migration.uploads_to_switch_to_new_path)).to contain_exactly(old_upload, group_upload)
- end
- end
-
- describe '#uploads_to_switch_to_old_path' do
- it 'contains only uploads with the new path for the correct models' do
- _upload_for_other_type = create_upload('Pipeline', 'uploads/ci_pipeline/avatar.jpg')
- upload_with_system_path = create_upload('Project', 'uploads/-/system/project/avatar.jpg')
- _upload_with_other_path = create_upload('Project', 'thelongsecretforafileupload/avatar.jpg')
- _old_upload = create_upload('Project', 'uploads/project/avatar.jpg')
-
- expect(uploads_table.where(migration.uploads_to_switch_to_old_path)).to contain_exactly(upload_with_system_path)
- end
- end
-
- describe '#up' do
- it 'updates old upload records to the new path' do
- old_upload = create_upload('Project', 'uploads/project/avatar.jpg')
-
- migration.up
-
- expect(old_upload.reload.path).to eq('uploads/-/system/project/avatar.jpg')
- end
- end
-
- describe '#down' do
- it 'updates the new system patsh to the old paths' do
- new_upload = create_upload('Project', 'uploads/-/system/project/avatar.jpg')
-
- migration.down
-
- expect(new_upload.reload.path).to eq('uploads/project/avatar.jpg')
- end
- end
-
- def create_upload(type, path)
- uploads_table.create(base_upload_attributes.merge(model_type: type, path: path))
- end
-end
diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb
index 55cea48b641..e24bbc39761 100644
--- a/spec/models/ci/pipeline_spec.rb
+++ b/spec/models/ci/pipeline_spec.rb
@@ -2998,4 +2998,28 @@ describe Ci::Pipeline, :mailer do
end
end
end
+
+ describe '#error_messages' do
+ subject { pipeline.error_messages }
+
+ before do
+ pipeline.valid?
+ end
+
+ context 'when pipeline has errors' do
+ let(:pipeline) { build(:ci_pipeline, sha: nil, ref: nil) }
+
+ it 'returns the full error messages' do
+ is_expected.to eq("Sha can't be blank and Ref can't be blank")
+ end
+ end
+
+ context 'when pipeline does not have errors' do
+ let(:pipeline) { build(:ci_pipeline) }
+
+ it 'returns empty string' do
+ is_expected.to be_empty
+ end
+ end
+ end
end
diff --git a/spec/models/clusters/applications/ingress_spec.rb b/spec/models/clusters/applications/ingress_spec.rb
index 292ddabd2d8..057517d3820 100644
--- a/spec/models/clusters/applications/ingress_spec.rb
+++ b/spec/models/clusters/applications/ingress_spec.rb
@@ -21,7 +21,21 @@ describe Clusters::Applications::Ingress do
describe '#can_uninstall?' do
subject { ingress.can_uninstall? }
- it { is_expected.to be_falsey }
+ it 'returns true if application_jupyter_nil_or_installable? AND external_ip_or_hostname? are true' do
+ ingress.external_ip = 'IP'
+
+ is_expected.to be_truthy
+ end
+
+ it 'returns false if application_jupyter_nil_or_installable? is false' do
+ create(:clusters_applications_jupyter, :installed, cluster: ingress.cluster)
+
+ is_expected.to be_falsey
+ end
+
+ it 'returns false if external_ip_or_hostname? is false' do
+ is_expected.to be_falsey
+ end
end
describe '#make_installed!' do
diff --git a/spec/models/clusters/applications/jupyter_spec.rb b/spec/models/clusters/applications/jupyter_spec.rb
index 43fa1010b2b..3ff66a074e4 100644
--- a/spec/models/clusters/applications/jupyter_spec.rb
+++ b/spec/models/clusters/applications/jupyter_spec.rb
@@ -16,7 +16,7 @@ describe Clusters::Applications::Jupyter do
subject { jupyter.can_uninstall? }
- it { is_expected.to be_falsey }
+ it { is_expected.to be_truthy }
end
describe '#set_initial_status' do
diff --git a/spec/models/clusters/clusters_hierarchy_spec.rb b/spec/models/clusters/clusters_hierarchy_spec.rb
new file mode 100644
index 00000000000..0470ebe17ea
--- /dev/null
+++ b/spec/models/clusters/clusters_hierarchy_spec.rb
@@ -0,0 +1,73 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Clusters::ClustersHierarchy do
+ describe '#base_and_ancestors' do
+ def base_and_ancestors(clusterable)
+ described_class.new(clusterable).base_and_ancestors
+ end
+
+ context 'project in nested group with clusters at every level' do
+ let!(:cluster) { create(:cluster, :project, projects: [project]) }
+ let!(:child) { create(:cluster, :group, groups: [child_group]) }
+ let!(:parent) { create(:cluster, :group, groups: [parent_group]) }
+ let!(:ancestor) { create(:cluster, :group, groups: [ancestor_group]) }
+
+ let(:ancestor_group) { create(:group) }
+ let(:parent_group) { create(:group, parent: ancestor_group) }
+ let(:child_group) { create(:group, parent: parent_group) }
+ let(:project) { create(:project, group: child_group) }
+
+ it 'returns clusters for project' do
+ expect(base_and_ancestors(project)).to eq([cluster, child, parent, ancestor])
+ end
+
+ it 'returns clusters for child_group' do
+ expect(base_and_ancestors(child_group)).to eq([child, parent, ancestor])
+ end
+
+ it 'returns clusters for parent_group' do
+ expect(base_and_ancestors(parent_group)).to eq([parent, ancestor])
+ end
+
+ it 'returns clusters for ancestor_group' do
+ expect(base_and_ancestors(ancestor_group)).to eq([ancestor])
+ end
+ end
+
+ context 'project in a namespace' do
+ let!(:cluster) { create(:cluster, :project) }
+
+ it 'returns clusters for project' do
+ expect(base_and_ancestors(cluster.project)).to eq([cluster])
+ end
+ end
+
+ context 'project in nested group with clusters at some levels' do
+ let!(:child) { create(:cluster, :group, groups: [child_group]) }
+ let!(:ancestor) { create(:cluster, :group, groups: [ancestor_group]) }
+
+ let(:ancestor_group) { create(:group) }
+ let(:parent_group) { create(:group, parent: ancestor_group) }
+ let(:child_group) { create(:group, parent: parent_group) }
+ let(:project) { create(:project, group: child_group) }
+
+ it 'returns clusters for project' do
+ expect(base_and_ancestors(project)).to eq([child, ancestor])
+ end
+
+ it 'returns clusters for child_group' do
+ expect(base_and_ancestors(child_group)).to eq([child, ancestor])
+ end
+
+ it 'returns clusters for parent_group' do
+ expect(base_and_ancestors(parent_group)).to eq([ancestor])
+ end
+
+ it 'returns clusters for ancestor_group' do
+ expect(base_and_ancestors(ancestor_group)).to eq([ancestor])
+ end
+ end
+ end
+end
diff --git a/spec/models/concerns/cacheable_attributes_spec.rb b/spec/models/concerns/cacheable_attributes_spec.rb
index 394fac52aa7..eeacdadab9c 100644
--- a/spec/models/concerns/cacheable_attributes_spec.rb
+++ b/spec/models/concerns/cacheable_attributes_spec.rb
@@ -143,14 +143,14 @@ describe CacheableAttributes do
allow(ApplicationSetting).to receive(:current_without_cache).twice.and_return(nil)
expect(ApplicationSetting.current).to be_nil
- expect(Rails.cache.exist?(ApplicationSetting.cache_key)).to be(false)
+ expect(ApplicationSetting.cache_backend.exist?(ApplicationSetting.cache_key)).to be(false)
end
it 'caches non-nil object' do
create(:application_setting)
expect(ApplicationSetting.current).to eq(ApplicationSetting.last)
- expect(Rails.cache.exist?(ApplicationSetting.cache_key)).to be(true)
+ expect(ApplicationSetting.cache_backend.exist?(ApplicationSetting.cache_key)).to be(true)
# subsequent calls retrieve the record from the cache
last_record = ApplicationSetting.last
@@ -188,11 +188,12 @@ describe CacheableAttributes do
end
end
- it 'uses RequestStore in addition to Rails.cache', :request_store do
+ it 'uses RequestStore in addition to Thread memory cache', :request_store do
# Warm up the cache
create(:application_setting).cache!
- expect(Rails.cache).to receive(:read).with(ApplicationSetting.cache_key).once.and_call_original
+ expect(ApplicationSetting.cache_backend).to eq(Gitlab::ThreadMemoryCache.cache_backend)
+ expect(ApplicationSetting.cache_backend).to receive(:read).with(ApplicationSetting.cache_key).once.and_call_original
2.times { ApplicationSetting.current }
end
diff --git a/spec/models/concerns/deployment_platform_spec.rb b/spec/models/concerns/deployment_platform_spec.rb
index 2378f400540..e2fc8a5d127 100644
--- a/spec/models/concerns/deployment_platform_spec.rb
+++ b/spec/models/concerns/deployment_platform_spec.rb
@@ -5,7 +5,7 @@ require 'rails_helper'
describe DeploymentPlatform do
let(:project) { create(:project) }
- describe '#deployment_platform' do
+ shared_examples '#deployment_platform' do
subject { project.deployment_platform }
context 'with no Kubernetes configuration on CI/CD, no Kubernetes Service' do
@@ -84,4 +84,20 @@ describe DeploymentPlatform do
end
end
end
+
+ context 'legacy implementation' do
+ before do
+ stub_feature_flags(clusters_cte: false)
+ end
+
+ include_examples '#deployment_platform'
+ end
+
+ context 'CTE implementation' do
+ before do
+ stub_feature_flags(clusters_cte: true)
+ end
+
+ include_examples '#deployment_platform'
+ end
end
diff --git a/spec/models/concerns/issuable_spec.rb b/spec/models/concerns/issuable_spec.rb
index 64f02978d79..68224a56515 100644
--- a/spec/models/concerns/issuable_spec.rb
+++ b/spec/models/concerns/issuable_spec.rb
@@ -223,6 +223,16 @@ describe Issuable do
expect(issuable_class.full_search(searchable_issue2.description.downcase)).to eq([searchable_issue2])
end
+ it 'returns issues with a fuzzy matching description for a query shorter than 3 chars if told to do so' do
+ search = searchable_issue2.description.downcase.scan(/\w+/).sample[-1]
+
+ expect(issuable_class.full_search(search, use_minimum_char_limit: false)).to include(searchable_issue2)
+ end
+
+ it 'returns issues with a fuzzy matching title for a query shorter than 3 chars if told to do so' do
+ expect(issuable_class.full_search('i', use_minimum_char_limit: false)).to include(searchable_issue)
+ end
+
context 'when matching columns is "title"' do
it 'returns issues with a matching title' do
expect(issuable_class.full_search(searchable_issue.title, matched_columns: 'title'))
diff --git a/spec/models/concerns/reactive_caching_spec.rb b/spec/models/concerns/reactive_caching_spec.rb
index 7faa196623f..3d026932f59 100644
--- a/spec/models/concerns/reactive_caching_spec.rb
+++ b/spec/models/concerns/reactive_caching_spec.rb
@@ -47,30 +47,12 @@ describe ReactiveCaching, :use_clean_rails_memory_store_caching do
subject(:go!) { instance.result }
- context 'when cache is empty' do
- it { is_expected.to be_nil }
-
- it 'enqueues a background worker to bootstrap the cache' do
- expect(ReactiveCachingWorker).to receive(:perform_async).with(CacheTest, 666)
-
- go!
- end
-
- it 'updates the cache lifespan' do
- expect(reactive_cache_alive?(instance)).to be_falsy
-
- go!
-
- expect(reactive_cache_alive?(instance)).to be_truthy
- end
- end
-
- context 'when the cache is full' do
+ shared_examples 'a cacheable value' do |cached_value|
before do
- stub_reactive_cache(instance, 4)
+ stub_reactive_cache(instance, cached_value)
end
- it { is_expected.to eq(4) }
+ it { is_expected.to eq(cached_value) }
it 'does not enqueue a background worker' do
expect(ReactiveCachingWorker).not_to receive(:perform_async)
@@ -90,9 +72,7 @@ describe ReactiveCaching, :use_clean_rails_memory_store_caching do
end
it { is_expected.to be_nil }
- end
- context 'when cache was invalidated' do
it 'refreshes cache' do
expect(ReactiveCachingWorker).to receive(:perform_async).with(CacheTest, 666)
@@ -101,12 +81,34 @@ describe ReactiveCaching, :use_clean_rails_memory_store_caching do
end
end
- context 'when cache contains non-nil but blank value' do
- before do
- stub_reactive_cache(instance, false)
+ context 'when cache is empty' do
+ it { is_expected.to be_nil }
+
+ it 'enqueues a background worker to bootstrap the cache' do
+ expect(ReactiveCachingWorker).to receive(:perform_async).with(CacheTest, 666)
+
+ go!
end
- it { is_expected.to eq(false) }
+ it 'updates the cache lifespan' do
+ expect(reactive_cache_alive?(instance)).to be_falsy
+
+ go!
+
+ expect(reactive_cache_alive?(instance)).to be_truthy
+ end
+ end
+
+ context 'when the cache is full' do
+ it_behaves_like 'a cacheable value', 4
+ end
+
+ context 'when the cache contains non-nil but blank value' do
+ it_behaves_like 'a cacheable value', false
+ end
+
+ context 'when the cache contains nil value' do
+ it_behaves_like 'a cacheable value', nil
end
end
@@ -206,8 +208,9 @@ describe ReactiveCaching, :use_clean_rails_memory_store_caching do
expect(read_reactive_cache(instance)).to eq("preexisting")
end
- it 'enqueues a repeat worker' do
- expect_reactive_cache_update_queued(instance)
+ it 'does not enqueue a repeat worker' do
+ expect(ReactiveCachingWorker)
+ .not_to receive(:perform_in)
expect { go! }.to raise_error("foo")
end
diff --git a/spec/models/deploy_token_spec.rb b/spec/models/deploy_token_spec.rb
index 2fe82eaa778..8d951ab6f0f 100644
--- a/spec/models/deploy_token_spec.rb
+++ b/spec/models/deploy_token_spec.rb
@@ -8,6 +8,15 @@ describe DeployToken do
it { is_expected.to have_many :project_deploy_tokens }
it { is_expected.to have_many(:projects).through(:project_deploy_tokens) }
+ describe 'validations' do
+ let(:username_format_message) { "can contain only letters, digits, '_', '-', '+', and '.'" }
+
+ it { is_expected.to validate_length_of(:username).is_at_most(255) }
+ it { is_expected.to allow_value('GitLab+deploy_token-3.14').for(:username) }
+ it { is_expected.not_to allow_value('<script>').for(:username).with_message(username_format_message) }
+ it { is_expected.not_to allow_value('').for(:username).with_message(username_format_message) }
+ end
+
describe '#ensure_token' do
it 'ensures a token' do
deploy_token.token = nil
@@ -87,8 +96,30 @@ describe DeployToken do
end
describe '#username' do
- it 'returns a harcoded username' do
- expect(deploy_token.username).to eq("gitlab+deploy-token-#{deploy_token.id}")
+ context 'persisted records' do
+ it 'returns a default username if none is set' do
+ expect(deploy_token.username).to eq("gitlab+deploy-token-#{deploy_token.id}")
+ end
+
+ it 'returns the username provided if one is set' do
+ deploy_token = create(:deploy_token, username: 'deployer')
+
+ expect(deploy_token.username).to eq('deployer')
+ end
+ end
+
+ context 'new records' do
+ it 'returns nil if no username is set' do
+ deploy_token = build(:deploy_token)
+
+ expect(deploy_token.username).to be_nil
+ end
+
+ it 'returns the username provided if one is set' do
+ deploy_token = build(:deploy_token, username: 'deployer')
+
+ expect(deploy_token.username).to eq('deployer')
+ end
end
end
diff --git a/spec/models/deployment_metrics_spec.rb b/spec/models/deployment_metrics_spec.rb
new file mode 100644
index 00000000000..0aadb1f3a5e
--- /dev/null
+++ b/spec/models/deployment_metrics_spec.rb
@@ -0,0 +1,126 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe DeploymentMetrics do
+ describe '#has_metrics?' do
+ subject { described_class.new(deployment.project, deployment).has_metrics? }
+
+ context 'when deployment is failed' do
+ let(:deployment) { create(:deployment, :failed) }
+
+ it { is_expected.to be_falsy }
+ end
+
+ context 'when deployment is success' do
+ let(:deployment) { create(:deployment, :success) }
+
+ context 'without a monitoring service' do
+ it { is_expected.to be_falsy }
+ end
+
+ context 'with a Prometheus Service' do
+ let(:prometheus_service) { instance_double(PrometheusService, can_query?: true) }
+
+ before do
+ allow(deployment.project).to receive(:find_or_initialize_service).with('prometheus').and_return prometheus_service
+ end
+
+ it { is_expected.to be_truthy }
+ end
+
+ context 'with a Prometheus Service that cannot query' do
+ let(:prometheus_service) { instance_double(PrometheusService, can_query?: false) }
+
+ before do
+ allow(deployment.project).to receive(:find_or_initialize_service).with('prometheus').and_return prometheus_service
+ end
+
+ it { is_expected.to be_falsy }
+ end
+
+ context 'with a cluster Prometheus' do
+ let(:deployment) { create(:deployment, :success, :on_cluster) }
+ let!(:prometheus) { create(:clusters_applications_prometheus, :installed, cluster: deployment.cluster) }
+
+ before do
+ expect(deployment.cluster.application_prometheus).to receive(:can_query?).and_return(true)
+ end
+
+ it { is_expected.to be_truthy }
+ end
+
+ context 'fallback deployment platform' do
+ let(:cluster) { create(:cluster, :provided_by_user, environment_scope: '*', projects: [deployment.project]) }
+ let!(:prometheus) { create(:clusters_applications_prometheus, :installed, cluster: cluster) }
+
+ before do
+ expect(deployment.project).to receive(:deployment_platform).and_return(cluster.platform)
+ expect(cluster.application_prometheus).to receive(:can_query?).and_return(true)
+ end
+
+ it { is_expected.to be_truthy }
+ end
+ end
+ end
+
+ describe '#metrics' do
+ let(:deployment) { create(:deployment, :success) }
+ let(:prometheus_adapter) { instance_double(PrometheusService, can_query?: true) }
+ let(:deployment_metrics) { described_class.new(deployment.project, deployment) }
+
+ subject { deployment_metrics.metrics }
+
+ context 'metrics are disabled' do
+ it { is_expected.to eq({}) }
+ end
+
+ context 'metrics are enabled' do
+ let(:simple_metrics) do
+ {
+ success: true,
+ metrics: {},
+ last_update: 42
+ }
+ end
+
+ before do
+ allow(deployment_metrics).to receive(:prometheus_adapter).and_return(prometheus_adapter)
+ expect(prometheus_adapter).to receive(:query).with(:deployment, deployment).and_return(simple_metrics)
+ end
+
+ it { is_expected.to eq(simple_metrics.merge({ deployment_time: deployment.created_at.to_i })) }
+ end
+ end
+
+ describe '#additional_metrics' do
+ let(:project) { create(:project, :repository) }
+ let(:deployment) { create(:deployment, :succeed, project: project) }
+ let(:deployment_metrics) { described_class.new(deployment.project, deployment) }
+
+ subject { deployment_metrics.additional_metrics }
+
+ context 'metrics are disabled' do
+ it { is_expected.to eq({}) }
+ end
+
+ context 'metrics are enabled' do
+ let(:simple_metrics) do
+ {
+ success: true,
+ metrics: {},
+ last_update: 42
+ }
+ end
+
+ let(:prometheus_adapter) { instance_double('prometheus_adapter', can_query?: true) }
+
+ before do
+ allow(deployment_metrics).to receive(:prometheus_adapter).and_return(prometheus_adapter)
+ expect(prometheus_adapter).to receive(:query).with(:additional_metrics_deployment, deployment).and_return(simple_metrics)
+ end
+
+ it { is_expected.to eq(simple_metrics.merge({ deployment_time: deployment.created_at.to_i })) }
+ end
+ end
+end
diff --git a/spec/models/deployment_spec.rb b/spec/models/deployment_spec.rb
index 8d0eb0f4a06..d4e631f109b 100644
--- a/spec/models/deployment_spec.rb
+++ b/spec/models/deployment_spec.rb
@@ -295,125 +295,6 @@ describe Deployment do
end
end
- describe '#has_metrics?' do
- subject { deployment.has_metrics? }
-
- context 'when deployment is failed' do
- let(:deployment) { create(:deployment, :failed) }
-
- it { is_expected.to be_falsy }
- end
-
- context 'when deployment is success' do
- let(:deployment) { create(:deployment, :success) }
-
- context 'without a monitoring service' do
- it { is_expected.to be_falsy }
- end
-
- context 'with a Prometheus Service' do
- let(:prometheus_service) { double(:prometheus_service, can_query?: true) }
-
- before do
- allow(deployment.project).to receive(:find_or_initialize_service).with('prometheus').and_return prometheus_service
- end
-
- it { is_expected.to be_truthy }
- end
-
- context 'with a Prometheus Service that cannot query' do
- let(:prometheus_service) { double(:prometheus_service, can_query?: false) }
-
- before do
- allow(deployment.project).to receive(:find_or_initialize_service).with('prometheus').and_return prometheus_service
- end
-
- it { is_expected.to be_falsy }
- end
-
- context 'with a cluster Prometheus' do
- let(:deployment) { create(:deployment, :success, :on_cluster) }
- let!(:prometheus) { create(:clusters_applications_prometheus, :installed, cluster: deployment.cluster) }
-
- before do
- expect(deployment.cluster.application_prometheus).to receive(:can_query?).and_return(true)
- end
-
- it { is_expected.to be_truthy }
- end
-
- context 'fallback deployment platform' do
- let(:cluster) { create(:cluster, :provided_by_user, environment_scope: '*', projects: [deployment.project]) }
- let!(:prometheus) { create(:clusters_applications_prometheus, :installed, cluster: cluster) }
-
- before do
- expect(deployment.project).to receive(:deployment_platform).and_return(cluster.platform)
- expect(cluster.application_prometheus).to receive(:can_query?).and_return(true)
- end
-
- it { is_expected.to be_truthy }
- end
- end
- end
-
- describe '#metrics' do
- let(:deployment) { create(:deployment, :success) }
- let(:prometheus_adapter) { double('prometheus_adapter', can_query?: true) }
-
- subject { deployment.metrics }
-
- context 'metrics are disabled' do
- it { is_expected.to eq({}) }
- end
-
- context 'metrics are enabled' do
- let(:simple_metrics) do
- {
- success: true,
- metrics: {},
- last_update: 42
- }
- end
-
- before do
- allow(deployment).to receive(:prometheus_adapter).and_return(prometheus_adapter)
- allow(prometheus_adapter).to receive(:query).with(:deployment, deployment).and_return(simple_metrics)
- end
-
- it { is_expected.to eq(simple_metrics.merge({ deployment_time: deployment.created_at.to_i })) }
- end
- end
-
- describe '#additional_metrics' do
- let(:project) { create(:project, :repository) }
- let(:deployment) { create(:deployment, :succeed, project: project) }
-
- subject { deployment.additional_metrics }
-
- context 'metrics are disabled' do
- it { is_expected.to eq({}) }
- end
-
- context 'metrics are enabled' do
- let(:simple_metrics) do
- {
- success: true,
- metrics: {},
- last_update: 42
- }
- end
-
- let(:prometheus_adapter) { double('prometheus_adapter', can_query?: true) }
-
- before do
- allow(deployment).to receive(:prometheus_adapter).and_return(prometheus_adapter)
- allow(prometheus_adapter).to receive(:query).with(:additional_metrics_deployment, deployment).and_return(simple_metrics)
- end
-
- it { is_expected.to eq(simple_metrics.merge({ deployment_time: deployment.created_at.to_i })) }
- end
- end
-
describe '#stop_action' do
let(:build) { create(:ci_build) }
@@ -441,38 +322,4 @@ describe Deployment do
end
end
end
-
- describe '#deployment_platform_cluster' do
- let(:deployment) { create(:deployment) }
- let(:project) { deployment.project }
- let(:environment) { deployment.environment }
-
- subject { deployment.deployment_platform_cluster }
-
- before do
- expect(project).to receive(:deployment_platform)
- .with(environment: environment.name).and_call_original
- end
-
- context 'project has no deployment platform' do
- before do
- expect(project.clusters).to be_empty
- end
-
- it { is_expected.to be_nil }
- end
-
- context 'project uses the kubernetes service for deployments' do
- let!(:service) { create(:kubernetes_service, project: project) }
-
- it { is_expected.to be_nil }
- end
-
- context 'project has a deployment platform' do
- let!(:cluster) { create(:cluster, projects: [project]) }
- let!(:platform) { create(:cluster_platform_kubernetes, cluster: cluster) }
-
- it { is_expected.to eq cluster }
- end
- end
end
diff --git a/spec/models/environment_status_spec.rb b/spec/models/environment_status_spec.rb
index c503c35305f..e2836420df9 100644
--- a/spec/models/environment_status_spec.rb
+++ b/spec/models/environment_status_spec.rb
@@ -11,11 +11,10 @@ describe EnvironmentStatus do
let(:merge_request) { create(:merge_request, :deployed_review_app, deployment: deployment) }
let(:sha) { deployment.sha }
- subject(:environment_status) { described_class.new(environment, merge_request, sha) }
+ subject(:environment_status) { described_class.new(project, environment, merge_request, sha) }
it { is_expected.to delegate_method(:id).to(:environment) }
it { is_expected.to delegate_method(:name).to(:environment) }
- it { is_expected.to delegate_method(:project).to(:environment) }
it { is_expected.to delegate_method(:deployed_at).to(:deployment) }
it { is_expected.to delegate_method(:status).to(:deployment) }
diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb
index a2547755510..9b0c232f370 100644
--- a/spec/models/merge_request_spec.rb
+++ b/spec/models/merge_request_spec.rb
@@ -7,6 +7,8 @@ describe MergeRequest do
include ProjectForksHelper
include ReactiveCachingHelpers
+ using RSpec::Parameterized::TableSyntax
+
subject { create(:merge_request) }
describe 'associations' do
@@ -1996,6 +1998,47 @@ describe MergeRequest do
end
end
+ describe '#rebase_async' do
+ let(:merge_request) { create(:merge_request) }
+ let(:user_id) { double(:user_id) }
+ let(:rebase_jid) { 'rebase-jid' }
+
+ subject(:execute) { merge_request.rebase_async(user_id) }
+
+ it 'atomically enqueues a RebaseWorker job and updates rebase_jid' do
+ expect(RebaseWorker)
+ .to receive(:perform_async)
+ .with(merge_request.id, user_id)
+ .and_return(rebase_jid)
+
+ expect(merge_request).to receive(:lock!).and_call_original
+
+ execute
+
+ expect(merge_request.rebase_jid).to eq(rebase_jid)
+ end
+
+ it 'refuses to enqueue a job if a rebase is in progress' do
+ merge_request.update_column(:rebase_jid, rebase_jid)
+
+ expect(RebaseWorker).not_to receive(:perform_async)
+ expect(Gitlab::SidekiqStatus)
+ .to receive(:running?)
+ .with(rebase_jid)
+ .and_return(true)
+
+ expect { execute }.to raise_error(ActiveRecord::StaleObjectError)
+ end
+
+ it 'refuses to enqueue a job if the MR is not open' do
+ merge_request.update_column(:state, 'foo')
+
+ expect(RebaseWorker).not_to receive(:perform_async)
+
+ expect { execute }.to raise_error(ActiveRecord::StaleObjectError)
+ end
+ end
+
describe '#mergeable?' do
let(:project) { create(:project) }
@@ -2946,40 +2989,64 @@ describe MergeRequest do
end
describe '#rebase_in_progress?' do
- shared_examples 'checking whether a rebase is in progress' do
- let(:repo_path) do
- Gitlab::GitalyClient::StorageSettings.allow_disk_access do
- subject.source_project.repository.path
- end
- end
- let(:rebase_path) { File.join(repo_path, "gitlab-worktree", "rebase-#{subject.id}") }
+ where(:rebase_jid, :jid_valid, :result) do
+ 'foo' | true | true
+ 'foo' | false | false
+ '' | true | false
+ nil | true | false
+ end
- before do
- system(*%W(#{Gitlab.config.git.bin_path} -C #{repo_path} worktree add --detach #{rebase_path} master))
+ with_them do
+ let(:merge_request) { create(:merge_request) }
+
+ subject { merge_request.rebase_in_progress? }
+
+ it do
+ # Stub out the legacy gitaly implementation
+ allow(merge_request).to receive(:gitaly_rebase_in_progress?) { false }
+
+ allow(Gitlab::SidekiqStatus).to receive(:running?).with(rebase_jid) { jid_valid }
+
+ merge_request.rebase_jid = rebase_jid
+
+ is_expected.to eq(result)
end
+ end
+ end
- it 'returns true when there is a current rebase directory' do
- expect(subject.rebase_in_progress?).to be_truthy
+ describe '#gitaly_rebase_in_progress?' do
+ let(:repo_path) do
+ Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+ subject.source_project.repository.path
end
+ end
+ let(:rebase_path) { File.join(repo_path, "gitlab-worktree", "rebase-#{subject.id}") }
- it 'returns false when there is no rebase directory' do
- FileUtils.rm_rf(rebase_path)
+ before do
+ system(*%W(#{Gitlab.config.git.bin_path} -C #{repo_path} worktree add --detach #{rebase_path} master))
+ end
- expect(subject.rebase_in_progress?).to be_falsey
- end
+ it 'returns true when there is a current rebase directory' do
+ expect(subject.rebase_in_progress?).to be_truthy
+ end
- it 'returns false when the rebase directory has expired' do
- time = 20.minutes.ago.to_time
- File.utime(time, time, rebase_path)
+ it 'returns false when there is no rebase directory' do
+ FileUtils.rm_rf(rebase_path)
- expect(subject.rebase_in_progress?).to be_falsey
- end
+ expect(subject.rebase_in_progress?).to be_falsey
+ end
- it 'returns false when the source project has been removed' do
- allow(subject).to receive(:source_project).and_return(nil)
+ it 'returns false when the rebase directory has expired' do
+ time = 20.minutes.ago.to_time
+ File.utime(time, time, rebase_path)
- expect(subject.rebase_in_progress?).to be_falsey
- end
+ expect(subject.rebase_in_progress?).to be_falsey
+ end
+
+ it 'returns false when the source project has been removed' do
+ allow(subject).to receive(:source_project).and_return(nil)
+
+ expect(subject.rebase_in_progress?).to be_falsey
end
end
@@ -3153,4 +3220,34 @@ describe MergeRequest do
it { is_expected.to be_truthy }
end
end
+
+ describe '#cleanup_refs' do
+ subject { merge_request.cleanup_refs(only: only) }
+
+ let(:merge_request) { build(:merge_request) }
+
+ context 'when removing all refs' do
+ let(:only) { :all }
+
+ it 'deletes all refs from the target project' do
+ expect(merge_request.target_project.repository)
+ .to receive(:delete_refs)
+ .with(merge_request.ref_path, merge_request.merge_ref_path, merge_request.train_ref_path)
+
+ subject
+ end
+ end
+
+ context 'when removing only train ref' do
+ let(:only) { :train }
+
+ it 'deletes train ref from the target project' do
+ expect(merge_request.target_project.repository)
+ .to receive(:delete_refs)
+ .with(merge_request.train_ref_path)
+
+ subject
+ end
+ end
+ end
end
diff --git a/spec/models/namespace/aggregation_schedule_spec.rb b/spec/models/namespace/aggregation_schedule_spec.rb
index 5ba7547ff4d..0f1283717e0 100644
--- a/spec/models/namespace/aggregation_schedule_spec.rb
+++ b/spec/models/namespace/aggregation_schedule_spec.rb
@@ -2,6 +2,106 @@
require 'spec_helper'
-RSpec.describe Namespace::AggregationSchedule, type: :model do
+RSpec.describe Namespace::AggregationSchedule, :clean_gitlab_redis_shared_state, type: :model do
+ include ExclusiveLeaseHelpers
+
it { is_expected.to belong_to :namespace }
+
+ describe '.delay_timeout' do
+ context 'when timeout is set on redis' do
+ it 'uses personalized timeout' do
+ Gitlab::Redis::SharedState.with do |redis|
+ redis.set(described_class::REDIS_SHARED_KEY, 1.hour)
+ end
+
+ expect(described_class.delay_timeout).to eq(1.hour)
+ end
+ end
+
+ context 'when timeout is not set on redis' do
+ it 'uses default timeout' do
+ expect(described_class.delay_timeout).to eq(3.hours)
+ end
+ end
+ end
+
+ describe '#schedule_root_storage_statistics' do
+ let(:namespace) { create(:namespace) }
+ let(:aggregation_schedule) { namespace.build_aggregation_schedule }
+ let(:lease_key) { "namespace:namespaces_root_statistics:#{namespace.id}" }
+
+ context "when we can't obtain the lease" do
+ it 'does not schedule the workers' do
+ stub_exclusive_lease_taken(lease_key, timeout: described_class::DEFAULT_LEASE_TIMEOUT)
+
+ expect(Namespaces::RootStatisticsWorker)
+ .not_to receive(:perform_async)
+
+ expect(Namespaces::RootStatisticsWorker)
+ .not_to receive(:perform_in)
+
+ aggregation_schedule.save!
+ end
+ end
+
+ context 'when we can obtain the lease' do
+ it 'schedules a root storage statistics after create' do
+ stub_exclusive_lease(lease_key, timeout: described_class::DEFAULT_LEASE_TIMEOUT)
+
+ expect(Namespaces::RootStatisticsWorker)
+ .to receive(:perform_async).once
+
+ expect(Namespaces::RootStatisticsWorker)
+ .to receive(:perform_in).once
+ .with(described_class::DEFAULT_LEASE_TIMEOUT, aggregation_schedule.namespace_id)
+
+ aggregation_schedule.save!
+ end
+
+ it 'does not release the lease' do
+ stub_exclusive_lease(lease_key, timeout: described_class::DEFAULT_LEASE_TIMEOUT)
+
+ aggregation_schedule.save!
+
+ exclusive_lease = aggregation_schedule.exclusive_lease
+ expect(exclusive_lease.exists?).to be_truthy
+ end
+
+ it 'only executes the workers once' do
+ # Avoid automatic deletion of Namespace::AggregationSchedule
+ # for testing purposes.
+ expect(Namespaces::RootStatisticsWorker)
+ .to receive(:perform_async).once
+ .and_return(nil)
+
+ expect(Namespaces::RootStatisticsWorker)
+ .to receive(:perform_in).once
+ .with(described_class::DEFAULT_LEASE_TIMEOUT, aggregation_schedule.namespace_id)
+ .and_return(nil)
+
+ # Scheduling workers for the first time
+ aggregation_schedule.schedule_root_storage_statistics
+
+ # Executing again, this time workers should not be scheduled
+ # due to the lease not been released.
+ aggregation_schedule.schedule_root_storage_statistics
+ end
+ end
+
+ context 'with a personalized lease timeout' do
+ before do
+ Gitlab::Redis::SharedState.with do |redis|
+ redis.set(described_class::REDIS_SHARED_KEY, 1.hour)
+ end
+ end
+
+ it 'uses a personalized time' do
+ expect(Namespaces::RootStatisticsWorker)
+ .to receive(:perform_in)
+ .with(1.hour, aggregation_schedule.namespace_id)
+
+ aggregation_schedule.save!
+ end
+ end
+ end
end
diff --git a/spec/models/namespace/root_storage_statistics_spec.rb b/spec/models/namespace/root_storage_statistics_spec.rb
index f6fb5af5aae..3229a32234e 100644
--- a/spec/models/namespace/root_storage_statistics_spec.rb
+++ b/spec/models/namespace/root_storage_statistics_spec.rb
@@ -7,4 +7,69 @@ RSpec.describe Namespace::RootStorageStatistics, type: :model do
it { is_expected.to have_one(:route).through(:namespace) }
it { is_expected.to delegate_method(:all_projects).to(:namespace) }
+
+ describe '#recalculate!' do
+ let(:namespace) { create(:group) }
+ let(:root_storage_statistics) { create(:namespace_root_storage_statistics, namespace: namespace) }
+
+ let(:project1) { create(:project, namespace: namespace) }
+ let(:project2) { create(:project, namespace: namespace) }
+
+ let!(:stat1) { create(:project_statistics, project: project1, with_data: true, size_multiplier: 100) }
+ let!(:stat2) { create(:project_statistics, project: project2, with_data: true, size_multiplier: 200) }
+
+ shared_examples 'data refresh' do
+ it 'aggregates project statistics' do
+ root_storage_statistics.recalculate!
+
+ root_storage_statistics.reload
+
+ total_repository_size = stat1.repository_size + stat2.repository_size
+ total_wiki_size = stat1.wiki_size + stat2.wiki_size
+ total_lfs_objects_size = stat1.lfs_objects_size + stat2.lfs_objects_size
+ total_build_artifacts_size = stat1.build_artifacts_size + stat2.build_artifacts_size
+ total_packages_size = stat1.packages_size + stat2.packages_size
+ total_storage_size = stat1.storage_size + stat2.storage_size
+
+ expect(root_storage_statistics.repository_size).to eq(total_repository_size)
+ expect(root_storage_statistics.wiki_size).to eq(total_wiki_size)
+ expect(root_storage_statistics.lfs_objects_size).to eq(total_lfs_objects_size)
+ expect(root_storage_statistics.build_artifacts_size).to eq(total_build_artifacts_size)
+ expect(root_storage_statistics.packages_size).to eq(total_packages_size)
+ expect(root_storage_statistics.storage_size).to eq(total_storage_size)
+ end
+
+ it 'works when there are no projects' do
+ Project.delete_all
+
+ root_storage_statistics.recalculate!
+
+ root_storage_statistics.reload
+ expect(root_storage_statistics.repository_size).to eq(0)
+ expect(root_storage_statistics.wiki_size).to eq(0)
+ expect(root_storage_statistics.lfs_objects_size).to eq(0)
+ expect(root_storage_statistics.build_artifacts_size).to eq(0)
+ expect(root_storage_statistics.packages_size).to eq(0)
+ expect(root_storage_statistics.storage_size).to eq(0)
+ end
+ end
+
+ it_behaves_like 'data refresh'
+
+ context 'with subgroups', :nested_groups do
+ let(:subgroup1) { create(:group, parent: namespace)}
+ let(:subgroup2) { create(:group, parent: subgroup1)}
+
+ let(:project1) { create(:project, namespace: subgroup1) }
+ let(:project2) { create(:project, namespace: subgroup2) }
+
+ it_behaves_like 'data refresh'
+ end
+
+ context 'with a personal namespace' do
+ let(:namespace) { create(:user).namespace }
+
+ it_behaves_like 'data refresh'
+ end
+ end
end
diff --git a/spec/models/namespace_spec.rb b/spec/models/namespace_spec.rb
index 30e49cf204f..f908f3504e0 100644
--- a/spec/models/namespace_spec.rb
+++ b/spec/models/namespace_spec.rb
@@ -837,4 +837,20 @@ describe Namespace do
it { is_expected.to be_falsy }
end
end
+
+ describe '#aggregation_scheduled?' do
+ let(:namespace) { create(:namespace) }
+
+ subject { namespace.aggregation_scheduled? }
+
+ context 'with an aggregation scheduled association' do
+ let(:namespace) { create(:namespace, :with_aggregation_schedule) }
+
+ it { is_expected.to be_truthy }
+ end
+
+ context 'without an aggregation scheduled association' do
+ it { is_expected.to be_falsy }
+ end
+ end
end
diff --git a/spec/models/project_services/bugzilla_service_spec.rb b/spec/models/project_services/bugzilla_service_spec.rb
index 6818db48fee..d5b0f94f461 100644
--- a/spec/models/project_services/bugzilla_service_spec.rb
+++ b/spec/models/project_services/bugzilla_service_spec.rb
@@ -32,4 +32,49 @@ describe BugzillaService do
it { is_expected.not_to validate_presence_of(:new_issue_url) }
end
end
+
+ context 'overriding properties' do
+ let(:default_title) { 'JIRA' }
+ let(:default_description) { 'JiraService|Jira issue tracker' }
+ let(:url) { 'http://bugzilla.example.com' }
+ let(:access_params) do
+ { project_url: url, issues_url: url, new_issue_url: url }
+ end
+
+ # this will be removed as part of https://gitlab.com/gitlab-org/gitlab-ce/issues/63084
+ context 'when data are stored in properties' do
+ let(:properties) { access_params.merge(title: title, description: description) }
+ let(:service) { create(:bugzilla_service, properties: properties) }
+
+ include_examples 'issue tracker fields'
+ end
+
+ context 'when data are stored in separated fields' do
+ let(:service) do
+ create(:bugzilla_service, title: title, description: description, properties: access_params)
+ end
+
+ include_examples 'issue tracker fields'
+ end
+
+ context 'when data are stored in both properties and separated fields' do
+ let(:properties) { access_params.merge(title: 'wrong title', description: 'wrong description') }
+ let(:service) do
+ create(:bugzilla_service, title: title, description: description, properties: properties)
+ end
+
+ include_examples 'issue tracker fields'
+ end
+
+ context 'when no title & description are set' do
+ let(:service) do
+ create(:bugzilla_service, properties: access_params)
+ end
+
+ it 'returns default values' do
+ expect(service.title).to eq('Bugzilla')
+ expect(service.description).to eq('Bugzilla issue tracker')
+ end
+ end
+ end
end
diff --git a/spec/models/project_services/custom_issue_tracker_service_spec.rb b/spec/models/project_services/custom_issue_tracker_service_spec.rb
index f0e7551693d..56b0bda6626 100644
--- a/spec/models/project_services/custom_issue_tracker_service_spec.rb
+++ b/spec/models/project_services/custom_issue_tracker_service_spec.rb
@@ -48,4 +48,47 @@ describe CustomIssueTrackerService do
end
end
end
+
+ context 'overriding properties' do
+ let(:url) { 'http://custom.example.com' }
+ let(:access_params) do
+ { project_url: url, issues_url: url, new_issue_url: url }
+ end
+
+ # this will be removed as part of https://gitlab.com/gitlab-org/gitlab-ce/issues/63084
+ context 'when data are stored in properties' do
+ let(:properties) { access_params.merge(title: title, description: description) }
+ let(:service) { create(:custom_issue_tracker_service, properties: properties) }
+
+ include_examples 'issue tracker fields'
+ end
+
+ context 'when data are stored in separated fields' do
+ let(:service) do
+ create(:custom_issue_tracker_service, title: title, description: description, properties: access_params)
+ end
+
+ include_examples 'issue tracker fields'
+ end
+
+ context 'when data are stored in both properties and separated fields' do
+ let(:properties) { access_params.merge(title: 'wrong title', description: 'wrong description') }
+ let(:service) do
+ create(:custom_issue_tracker_service, title: title, description: description, properties: properties)
+ end
+
+ include_examples 'issue tracker fields'
+ end
+
+ context 'when no title & description are set' do
+ let(:service) do
+ create(:custom_issue_tracker_service, properties: access_params)
+ end
+
+ it 'returns default values' do
+ expect(service.title).to eq('Custom Issue Tracker')
+ expect(service.description).to eq('Custom issue tracker')
+ end
+ end
+ end
end
diff --git a/spec/models/project_services/drone_ci_service_spec.rb b/spec/models/project_services/drone_ci_service_spec.rb
index 22df19d943f..a771d1bf27f 100644
--- a/spec/models/project_services/drone_ci_service_spec.rb
+++ b/spec/models/project_services/drone_ci_service_spec.rb
@@ -101,6 +101,15 @@ describe DroneCiService, :use_clean_rails_memory_store_caching do
is_expected.to eq(:error)
end
+ Gitlab::HTTP::HTTP_ERRORS.each do |http_error|
+ it "sets commit status to :error with a #{http_error.name} error" do
+ WebMock.stub_request(:get, commit_status_path)
+ .to_raise(http_error)
+
+ is_expected.to eq(:error)
+ end
+ end
+
{
"killed" => :canceled,
"failure" => :failed,
diff --git a/spec/models/project_services/gitlab_issue_tracker_service_spec.rb b/spec/models/project_services/gitlab_issue_tracker_service_spec.rb
index 11f96c03d46..a3726f09dc5 100644
--- a/spec/models/project_services/gitlab_issue_tracker_service_spec.rb
+++ b/spec/models/project_services/gitlab_issue_tracker_service_spec.rb
@@ -51,4 +51,47 @@ describe GitlabIssueTrackerService do
end
end
end
+
+ context 'overriding properties' do
+ let(:url) { 'http://gitlab.example.com' }
+ let(:access_params) do
+ { project_url: url, issues_url: url, new_issue_url: url }
+ end
+
+ # this will be removed as part of https://gitlab.com/gitlab-org/gitlab-ce/issues/63084
+ context 'when data are stored in properties' do
+ let(:properties) { access_params.merge(title: title, description: description) }
+ let(:service) { create(:gitlab_issue_tracker_service, properties: properties) }
+
+ include_examples 'issue tracker fields'
+ end
+
+ context 'when data are stored in separated fields' do
+ let(:service) do
+ create(:gitlab_issue_tracker_service, title: title, description: description, properties: access_params)
+ end
+
+ include_examples 'issue tracker fields'
+ end
+
+ context 'when data are stored in both properties and separated fields' do
+ let(:properties) { access_params.merge(title: 'wrong title', description: 'wrong description') }
+ let(:service) do
+ create(:gitlab_issue_tracker_service, title: title, description: description, properties: properties)
+ end
+
+ include_examples 'issue tracker fields'
+ end
+
+ context 'when no title & description are set' do
+ let(:service) do
+ create(:gitlab_issue_tracker_service, properties: access_params)
+ end
+
+ it 'returns default values' do
+ expect(service.title).to eq('GitLab')
+ expect(service.description).to eq('GitLab issue tracker')
+ end
+ end
+ end
end
diff --git a/spec/models/project_services/jira_service_spec.rb b/spec/models/project_services/jira_service_spec.rb
index fc08457a3c5..9b122d85293 100644
--- a/spec/models/project_services/jira_service_spec.rb
+++ b/spec/models/project_services/jira_service_spec.rb
@@ -115,6 +115,70 @@ describe JiraService do
end
end
+ describe '#create' do
+ let(:params) do
+ {
+ project: create(:project), title: 'custom title', description: 'custom description'
+ }
+ end
+
+ subject { described_class.create(params) }
+
+ it 'does not store title & description into properties' do
+ expect(subject.properties.keys).not_to include('title', 'description')
+ end
+
+ it 'sets title & description correctly' do
+ service = subject
+
+ expect(service.title).to eq('custom title')
+ expect(service.description).to eq('custom description')
+ end
+ end
+
+ context 'overriding properties' do
+ let(:url) { 'http://issue_tracker.example.com' }
+ let(:access_params) do
+ { url: url, username: 'username', password: 'password' }
+ end
+
+ # this will be removed as part of https://gitlab.com/gitlab-org/gitlab-ce/issues/63084
+ context 'when data are stored in properties' do
+ let(:properties) { access_params.merge(title: title, description: description) }
+ let(:service) { create(:jira_service, properties: properties) }
+
+ include_examples 'issue tracker fields'
+ end
+
+ context 'when data are stored in separated fields' do
+ let(:service) do
+ create(:jira_service, title: title, description: description, properties: access_params)
+ end
+
+ include_examples 'issue tracker fields'
+ end
+
+ context 'when data are stored in both properties and separated fields' do
+ let(:properties) { access_params.merge(title: 'wrong title', description: 'wrong description') }
+ let(:service) do
+ create(:jira_service, title: title, description: description, properties: properties)
+ end
+
+ include_examples 'issue tracker fields'
+ end
+
+ context 'when no title & description are set' do
+ let(:service) do
+ create(:jira_service, properties: access_params)
+ end
+
+ it 'returns default values' do
+ expect(service.title).to eq('Jira')
+ expect(service.description).to eq('Jira issue tracker')
+ end
+ end
+ end
+
describe '#close_issue' do
let(:custom_base_url) { 'http://custom_url' }
let(:user) { create(:user) }
@@ -450,36 +514,54 @@ describe JiraService do
end
describe 'description and title' do
- let(:project) { create(:project) }
+ let(:title) { 'Jira One' }
+ let(:description) { 'Jira One issue tracker' }
+ let(:properties) do
+ {
+ url: 'http://jira.example.com/web',
+ username: 'mic',
+ password: 'password',
+ title: title,
+ description: description
+ }
+ end
context 'when it is not set' do
- before do
- @service = project.create_jira_service(active: true)
- end
+ it 'default values are returned' do
+ service = create(:jira_service)
- after do
- @service.destroy!
+ expect(service.title).to eq('Jira')
+ expect(service.description).to eq('Jira issue tracker')
end
+ end
- it 'is initialized' do
- expect(@service.title).to eq('Jira')
- expect(@service.description).to eq('Jira issue tracker')
+ context 'when it is set in properties' do
+ it 'values from properties are returned' do
+ service = create(:jira_service, properties: properties)
+
+ expect(service.title).to eq(title)
+ expect(service.description).to eq(description)
end
end
- context 'when it is set' do
- before do
- properties = { 'title' => 'Jira One', 'description' => 'Jira One issue tracker' }
- @service = project.create_jira_service(active: true, properties: properties)
- end
+ context 'when it is in title & description fields' do
+ it 'values from title and description fields are returned' do
+ service = create(:jira_service, title: title, description: description)
- after do
- @service.destroy!
+ expect(service.title).to eq(title)
+ expect(service.description).to eq(description)
end
+ end
+
+ context 'when it is in both properites & title & description fields' do
+ it 'values from title and description fields are returned' do
+ title2 = 'Jira 2'
+ description2 = 'Jira description 2'
- it 'is correct' do
- expect(@service.title).to eq('Jira One')
- expect(@service.description).to eq('Jira One issue tracker')
+ service = create(:jira_service, title: title2, description: description2, properties: properties)
+
+ expect(service.title).to eq(title2)
+ expect(service.description).to eq(description2)
end
end
end
@@ -505,29 +587,21 @@ describe JiraService do
end
describe 'project and issue urls' do
- let(:project) { create(:project) }
-
context 'when gitlab.yml was initialized' do
- before do
+ it 'is prepopulated with the settings' do
settings = {
'jira' => {
- 'title' => 'Jira',
'url' => 'http://jira.sample/projects/project_a',
'api_url' => 'http://jira.sample/api'
}
}
allow(Gitlab.config).to receive(:issues_tracker).and_return(settings)
- @service = project.create_jira_service(active: true)
- end
- after do
- @service.destroy!
- end
+ project = create(:project)
+ service = project.create_jira_service(active: true)
- it 'is prepopulated with the settings' do
- expect(@service.properties['title']).to eq('Jira')
- expect(@service.properties['url']).to eq('http://jira.sample/projects/project_a')
- expect(@service.properties['api_url']).to eq('http://jira.sample/api')
+ expect(service.properties['url']).to eq('http://jira.sample/projects/project_a')
+ expect(service.properties['api_url']).to eq('http://jira.sample/api')
end
end
end
diff --git a/spec/models/project_services/kubernetes_service_spec.rb b/spec/models/project_services/kubernetes_service_spec.rb
index 5d7d6c34e67..d33bbb0470f 100644
--- a/spec/models/project_services/kubernetes_service_spec.rb
+++ b/spec/models/project_services/kubernetes_service_spec.rb
@@ -142,235 +142,6 @@ describe KubernetesService, :use_clean_rails_memory_store_caching do
end
end
- describe '#kubernetes_namespace_for' do
- subject { service.kubernetes_namespace_for(project) }
-
- shared_examples 'a correctly formatted namespace' do
- it 'returns a valid Kubernetes namespace name' do
- expect(subject).to match(Gitlab::Regex.kubernetes_namespace_regex)
- expect(subject).to eq(expected_namespace)
- end
- end
-
- it_behaves_like 'a correctly formatted namespace' do
- let(:expected_namespace) { service.send(:default_namespace) }
- end
-
- context 'when the project path contains forbidden characters' do
- before do
- project.path = '-a_Strange.Path--forSure'
- end
-
- it_behaves_like 'a correctly formatted namespace' do
- let(:expected_namespace) { "a-strange-path--forsure-#{project.id}" }
- end
- end
-
- context 'when namespace is specified' do
- before do
- service.namespace = 'my-namespace'
- end
-
- it_behaves_like 'a correctly formatted namespace' do
- let(:expected_namespace) { 'my-namespace' }
- end
- end
-
- context 'when service is not assigned to project' do
- before do
- service.project = nil
- end
-
- it 'does not return namespace' do
- is_expected.to be_nil
- end
- end
- end
-
- describe '#test' do
- let(:discovery_url) { 'https://kubernetes.example.com/api/v1' }
-
- before do
- stub_kubeclient_discover(service.api_url)
- end
-
- context 'with path prefix in api_url' do
- let(:discovery_url) { 'https://kubernetes.example.com/prefix/api/v1' }
-
- it 'tests with the prefix' do
- service.api_url = 'https://kubernetes.example.com/prefix'
- stub_kubeclient_discover(service.api_url)
-
- expect(service.test[:success]).to be_truthy
- expect(WebMock).to have_requested(:get, discovery_url).once
- end
- end
-
- context 'with custom CA certificate' do
- it 'is added to the certificate store' do
- service.ca_pem = "CA PEM DATA"
-
- cert = double("certificate")
- expect(OpenSSL::X509::Certificate).to receive(:new).with(service.ca_pem).and_return(cert)
- expect_any_instance_of(OpenSSL::X509::Store).to receive(:add_cert).with(cert)
-
- expect(service.test[:success]).to be_truthy
- expect(WebMock).to have_requested(:get, discovery_url).once
- end
- end
-
- context 'success' do
- it 'reads the discovery endpoint' do
- expect(service.test[:success]).to be_truthy
- expect(WebMock).to have_requested(:get, discovery_url).once
- end
- end
-
- context 'failure' do
- it 'fails to read the discovery endpoint' do
- WebMock.stub_request(:get, service.api_url + '/api/v1').to_return(status: 404)
-
- expect(service.test[:success]).to be_falsy
- expect(WebMock).to have_requested(:get, discovery_url).once
- end
- end
- end
-
- describe '#predefined_variable' do
- let(:kubeconfig) do
- config_file = expand_fixture_path('config/kubeconfig.yml')
- config = YAML.load(File.read(config_file))
- config.dig('users', 0, 'user')['token'] = 'token'
- config.dig('contexts', 0, 'context')['namespace'] = namespace
- config.dig('clusters', 0, 'cluster')['certificate-authority-data'] =
- Base64.strict_encode64('CA PEM DATA')
-
- YAML.dump(config)
- end
-
- before do
- subject.api_url = 'https://kube.domain.com'
- subject.token = 'token'
- subject.ca_pem = 'CA PEM DATA'
- subject.project = project
- end
-
- shared_examples 'setting variables' do
- it 'sets the variables' do
- expect(subject.predefined_variables(project: project)).to include(
- { key: 'KUBE_URL', value: 'https://kube.domain.com', public: true },
- { key: 'KUBE_TOKEN', value: 'token', public: false, masked: true },
- { key: 'KUBE_NAMESPACE', value: namespace, public: true },
- { key: 'KUBECONFIG', value: kubeconfig, public: false, file: true },
- { key: 'KUBE_CA_PEM', value: 'CA PEM DATA', public: true },
- { key: 'KUBE_CA_PEM_FILE', value: 'CA PEM DATA', public: true, file: true }
- )
- end
- end
-
- context 'namespace is provided' do
- let(:namespace) { 'my-project' }
-
- before do
- subject.namespace = namespace
- end
-
- it_behaves_like 'setting variables'
- end
-
- context 'no namespace provided' do
- let(:namespace) { subject.kubernetes_namespace_for(project) }
-
- it_behaves_like 'setting variables'
-
- it 'sets the KUBE_NAMESPACE' do
- kube_namespace = subject.predefined_variables(project: project).find { |h| h[:key] == 'KUBE_NAMESPACE' }
-
- expect(kube_namespace).not_to be_nil
- expect(kube_namespace[:value]).to match(/\A#{Gitlab::PathRegex::PATH_REGEX_STR}-\d+\z/)
- end
- end
- end
-
- describe '#terminals' do
- let(:environment) { build(:environment, project: project, name: "env", slug: "env-000000") }
-
- subject { service.terminals(environment) }
-
- context 'with invalid pods' do
- it 'returns no terminals' do
- stub_reactive_cache(service, pods: [{ "bad" => "pod" }])
-
- is_expected.to be_empty
- end
- end
-
- context 'with valid pods' do
- let(:pod) { kube_pod(environment_slug: environment.slug, namespace: service.kubernetes_namespace_for(project), project_slug: project.full_path_slug) }
- let(:pod_with_no_terminal) { kube_pod(environment_slug: environment.slug, project_slug: project.full_path_slug, status: "Pending") }
- let(:terminals) { kube_terminals(service, pod) }
-
- before do
- stub_reactive_cache(
- service,
- pods: [pod, pod, pod_with_no_terminal, kube_pod(environment_slug: "should-be-filtered-out")]
- )
- end
-
- it 'returns terminals' do
- is_expected.to eq(terminals + terminals)
- end
-
- it 'uses max session time from settings' do
- stub_application_setting(terminal_max_session_time: 600)
-
- times = subject.map { |terminal| terminal[:max_session_time] }
- expect(times).to eq [600, 600, 600, 600]
- end
- end
- end
-
- describe '#calculate_reactive_cache' do
- subject { service.calculate_reactive_cache }
-
- let(:namespace) { service.kubernetes_namespace_for(project) }
-
- context 'when service is inactive' do
- before do
- service.active = false
- end
-
- it { is_expected.to be_nil }
- end
-
- context 'when kubernetes responds with valid pods' do
- before do
- stub_kubeclient_pods(namespace)
- stub_kubeclient_deployments(namespace) # Used by EE
- end
-
- it { is_expected.to include(pods: [kube_pod]) }
- end
-
- context 'when kubernetes responds with 500s' do
- before do
- stub_kubeclient_pods(namespace, status: 500)
- stub_kubeclient_deployments(namespace, status: 500) # Used by EE
- end
-
- it { expect { subject }.to raise_error(Kubeclient::HttpError) }
- end
-
- context 'when kubernetes responds with 404s' do
- before do
- stub_kubeclient_pods(namespace, status: 404)
- stub_kubeclient_deployments(namespace, status: 404) # Used by EE
- end
-
- it { is_expected.to include(pods: []) }
- end
- end
-
describe "#deprecated?" do
let(:kubernetes_service) { create(:kubernetes_service) }
diff --git a/spec/models/project_services/redmine_service_spec.rb b/spec/models/project_services/redmine_service_spec.rb
index ac570ac27e1..806e3695962 100644
--- a/spec/models/project_services/redmine_service_spec.rb
+++ b/spec/models/project_services/redmine_service_spec.rb
@@ -40,4 +40,47 @@ describe RedmineService do
expect(described_class.reference_pattern.match('#123')[:issue]).to eq('123')
end
end
+
+ context 'overriding properties' do
+ let(:url) { 'http://redmine.example.com' }
+ let(:access_params) do
+ { project_url: url, issues_url: url, new_issue_url: url }
+ end
+
+ # this will be removed as part of https://gitlab.com/gitlab-org/gitlab-ce/issues/63084
+ context 'when data are stored in properties' do
+ let(:properties) { access_params.merge(title: title, description: description) }
+ let(:service) { create(:redmine_service, properties: properties) }
+
+ include_examples 'issue tracker fields'
+ end
+
+ context 'when data are stored in separated fields' do
+ let(:service) do
+ create(:redmine_service, title: title, description: description, properties: access_params)
+ end
+
+ include_examples 'issue tracker fields'
+ end
+
+ context 'when data are stored in both properties and separated fields' do
+ let(:properties) { access_params.merge(title: 'wrong title', description: 'wrong description') }
+ let(:service) do
+ create(:redmine_service, title: title, description: description, properties: properties)
+ end
+
+ include_examples 'issue tracker fields'
+ end
+
+ context 'when no title & description are set' do
+ let(:service) do
+ create(:redmine_service, properties: access_params)
+ end
+
+ it 'returns default values' do
+ expect(service.title).to eq('Redmine')
+ expect(service.description).to eq('Redmine issue tracker')
+ end
+ end
+ end
end
diff --git a/spec/models/project_services/youtrack_service_spec.rb b/spec/models/project_services/youtrack_service_spec.rb
index bf9d892f66c..b47ef6702b4 100644
--- a/spec/models/project_services/youtrack_service_spec.rb
+++ b/spec/models/project_services/youtrack_service_spec.rb
@@ -37,4 +37,47 @@ describe YoutrackService do
expect(described_class.reference_pattern.match('YT-123')[:issue]).to eq('YT-123')
end
end
+
+ context 'overriding properties' do
+ let(:url) { 'http://youtrack.example.com' }
+ let(:access_params) do
+ { project_url: url, issues_url: url, new_issue_url: url }
+ end
+
+ # this will be removed as part of https://gitlab.com/gitlab-org/gitlab-ce/issues/63084
+ context 'when data are stored in properties' do
+ let(:properties) { access_params.merge(title: title, description: description) }
+ let(:service) { create(:youtrack_service, properties: properties) }
+
+ include_examples 'issue tracker fields'
+ end
+
+ context 'when data are stored in separated fields' do
+ let(:service) do
+ create(:youtrack_service, title: title, description: description, properties: access_params)
+ end
+
+ include_examples 'issue tracker fields'
+ end
+
+ context 'when data are stored in both properties and separated fields' do
+ let(:properties) { access_params.merge(title: 'wrong title', description: 'wrong description') }
+ let(:service) do
+ create(:youtrack_service, title: title, description: description, properties: properties)
+ end
+
+ include_examples 'issue tracker fields'
+ end
+
+ context 'when no title & description are set' do
+ let(:service) do
+ create(:youtrack_service, properties: access_params)
+ end
+
+ it 'returns default values' do
+ expect(service.title).to eq('YouTrack')
+ expect(service.description).to eq('YouTrack issue tracker')
+ end
+ end
+ end
end
diff --git a/spec/models/project_statistics_spec.rb b/spec/models/project_statistics_spec.rb
index 1cb49d83ffa..db3e4902c64 100644
--- a/spec/models/project_statistics_spec.rb
+++ b/spec/models/project_statistics_spec.rb
@@ -135,6 +135,49 @@ describe ProjectStatistics do
expect(statistics.wiki_size).to eq(0)
end
end
+
+ context 'when the column is namespace relatable' do
+ let(:namespace) { create(:group) }
+ let(:project) { create(:project, namespace: namespace) }
+
+ context 'when the feature flag is off' do
+ it 'does not schedule the aggregation worker' do
+ stub_feature_flags(update_statistics_namespace: false, namespace: namespace)
+
+ expect(Namespaces::ScheduleAggregationWorker)
+ .not_to receive(:perform_async)
+
+ statistics.refresh!(only: [:lfs_objects_size])
+ end
+ end
+
+ context 'when the feature flag is on' do
+ it 'schedules the aggregation worker' do
+ expect(Namespaces::ScheduleAggregationWorker)
+ .to receive(:perform_async)
+
+ statistics.refresh!(only: [:lfs_objects_size])
+ end
+ end
+
+ context 'when no argument is passed' do
+ it 'schedules the aggregation worker' do
+ expect(Namespaces::ScheduleAggregationWorker)
+ .to receive(:perform_async)
+
+ statistics.refresh!
+ end
+ end
+ end
+
+ context 'when the column is not namespace relatable' do
+ it 'does not schedules an aggregation worker' do
+ expect(Namespaces::ScheduleAggregationWorker)
+ .not_to receive(:perform_async)
+
+ statistics.refresh!(only: [:commit_count])
+ end
+ end
end
describe '#update_commit_count' do
diff --git a/spec/models/release_spec.rb b/spec/models/release_spec.rb
index 7c106ce6b85..e9d846e7291 100644
--- a/spec/models/release_spec.rb
+++ b/spec/models/release_spec.rb
@@ -64,4 +64,14 @@ RSpec.describe Release do
is_expected.to all(be_a(Releases::Source))
end
end
+
+ describe '#upcoming_release?' do
+ context 'during the backfill migration when released_at could be nil' do
+ it 'handles a nil released_at value and returns false' do
+ allow(release).to receive(:released_at).and_return nil
+
+ expect(release.upcoming_release?).to eq(false)
+ end
+ end
+ end
end
diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb
index 13da7bd7407..3d967aa4ab8 100644
--- a/spec/models/repository_spec.rb
+++ b/spec/models/repository_spec.rb
@@ -1420,12 +1420,13 @@ describe Repository do
source_project: project)
end
- it 'writes merge of source and target to MR merge_ref_path' do
+ it 'writes merge of source SHA and first parent ref to MR merge_ref_path' do
merge_commit_id = repository.merge_to_ref(user,
merge_request.diff_head_sha,
merge_request,
merge_request.merge_ref_path,
- 'Custom message')
+ 'Custom message',
+ merge_request.target_branch_ref)
merge_commit = repository.commit(merge_commit_id)
diff --git a/spec/models/service_spec.rb b/spec/models/service_spec.rb
index d442c73c118..0797b9a9d83 100644
--- a/spec/models/service_spec.rb
+++ b/spec/models/service_spec.rb
@@ -244,7 +244,8 @@ describe Service do
let(:service) do
GitlabIssueTrackerService.create(
project: create(:project),
- title: 'random title'
+ title: 'random title',
+ project_url: 'http://gitlab.example.com'
)
end
@@ -252,8 +253,12 @@ describe Service do
expect { service }.not_to raise_error
end
+ it 'sets title correctly' do
+ expect(service.title).to eq('random title')
+ end
+
it 'creates the properties' do
- expect(service.properties).to eq({ "title" => "random title" })
+ expect(service.properties).to eq({ "project_url" => "http://gitlab.example.com" })
end
end
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index b098fe3c9f4..a4d177da0be 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -3354,7 +3354,7 @@ describe User do
end
describe '#requires_usage_stats_consent?' do
- let(:user) { create(:user, created_at: 8.days.ago) }
+ let(:user) { create(:user, :admin, created_at: 8.days.ago) }
before do
allow(user).to receive(:has_current_license?).and_return false
@@ -3378,7 +3378,7 @@ describe User do
end
it 'does not require consent if usage stats were set by this user' do
- allow(Gitlab::CurrentSettings).to receive(:usage_stats_set_by_user_id).and_return(user.id)
+ create(:application_setting, usage_stats_set_by_user_id: user.id)
expect(user.requires_usage_stats_consent?).to be false
end
diff --git a/spec/requests/api/graphql/namespace/projects_spec.rb b/spec/requests/api/graphql/namespace/projects_spec.rb
index de1cd9586b6..63fa16c79ca 100644
--- a/spec/requests/api/graphql/namespace/projects_spec.rb
+++ b/spec/requests/api/graphql/namespace/projects_spec.rb
@@ -58,9 +58,7 @@ describe 'getting projects', :nested_groups do
it 'finds only public projects' do
post_graphql(query, current_user: nil)
- expect(graphql_data['namespace']['projects']['edges'].size).to eq(1)
- project = graphql_data['namespace']['projects']['edges'][0]['node']
- expect(project['id']).to eq(public_project.to_global_id.to_s)
+ expect(graphql_data['namespace']).to be_nil
end
end
end
diff --git a/spec/requests/api/graphql/project/repository_spec.rb b/spec/requests/api/graphql/project/repository_spec.rb
index 67af612a4a0..261433a3d6a 100644
--- a/spec/requests/api/graphql/project/repository_spec.rb
+++ b/spec/requests/api/graphql/project/repository_spec.rb
@@ -34,4 +34,28 @@ describe 'getting a repository in a project' do
expect(graphql_data['project']).to be(nil)
end
end
+
+ context 'when the repository is only accessible to members' do
+ let(:project) do
+ create(:project, :public, :repository, repository_access_level: ProjectFeature::PRIVATE)
+ end
+
+ it 'returns a repository for the owner' do
+ post_graphql(query, current_user: current_user)
+
+ expect(graphql_data['project']['repository']).not_to be_nil
+ end
+
+ it 'returns nil for the repository for other users' do
+ post_graphql(query, current_user: create(:user))
+
+ expect(graphql_data['project']['repository']).to be_nil
+ end
+
+ it 'returns nil for the repository for other users' do
+ post_graphql(query, current_user: nil)
+
+ expect(graphql_data['project']['repository']).to be_nil
+ end
+ end
end
diff --git a/spec/requests/api/graphql_spec.rb b/spec/requests/api/graphql_spec.rb
index 656d6f8b50b..54401ec4085 100644
--- a/spec/requests/api/graphql_spec.rb
+++ b/spec/requests/api/graphql_spec.rb
@@ -6,16 +6,6 @@ describe 'GraphQL' do
let(:query) { graphql_query_for('echo', 'text' => 'Hello world' ) }
- context 'graphql is disabled by feature flag' do
- before do
- stub_feature_flags(graphql: false)
- end
-
- it 'does not generate a route for GraphQL' do
- expect { post_graphql(query) }.to raise_error(ActionController::RoutingError)
- end
- end
-
context 'logging' do
shared_examples 'logging a graphql query' do
let(:expected_params) do
@@ -131,4 +121,35 @@ describe 'GraphQL' do
end
end
end
+
+ describe 'testing for Gitaly calls' do
+ let(:project) { create(:project, :repository) }
+ let(:user) { create(:user) }
+
+ let(:query) do
+ graphql_query_for('project', { 'fullPath' => project.full_path }, %w(id))
+ end
+
+ before do
+ project.add_developer(user)
+ end
+
+ it_behaves_like 'a working graphql query' do
+ before do
+ post_graphql(query, current_user: user)
+ end
+ end
+
+ context 'when Gitaly is called' do
+ before do
+ allow(Gitlab::GitalyClient).to receive(:get_request_count).and_return(1, 2)
+ end
+
+ it "logs a warning that the 'calls_gitaly' field declaration is missing" do
+ expect(Gitlab::Sentry).to receive(:track_exception).once
+
+ post_graphql(query, current_user: user)
+ end
+ end
+ end
end
diff --git a/spec/requests/api/issues/get_group_issues_spec.rb b/spec/requests/api/issues/get_group_issues_spec.rb
index 8b02cf56e9f..9a41d790945 100644
--- a/spec/requests/api/issues/get_group_issues_spec.rb
+++ b/spec/requests/api/issues/get_group_issues_spec.rb
@@ -23,7 +23,11 @@ describe API::Issues do
describe 'GET /groups/:id/issues' do
let!(:group) { create(:group) }
- let!(:group_project) { create(:project, :public, creator_id: user.id, namespace: group) }
+ let!(:group_project) { create(:project, :public, :repository, creator_id: user.id, namespace: group) }
+ let!(:private_mrs_project) do
+ create(:project, :public, :repository, creator_id: user.id, namespace: group, merge_requests_access_level: ProjectFeature::PRIVATE)
+ end
+
let!(:group_closed_issue) do
create :closed_issue,
author: user,
@@ -234,6 +238,30 @@ describe API::Issues do
it_behaves_like 'group issues statistics'
end
end
+
+ context "when returns issue merge_requests_count for different access levels" do
+ let!(:merge_request1) do
+ create(:merge_request,
+ :simple,
+ author: user,
+ source_project: private_mrs_project,
+ target_project: private_mrs_project,
+ description: "closes #{group_issue.to_reference(private_mrs_project)}")
+ end
+ let!(:merge_request2) do
+ create(:merge_request,
+ :simple,
+ author: user,
+ source_project: group_project,
+ target_project: group_project,
+ description: "closes #{group_issue.to_reference}")
+ end
+
+ it_behaves_like 'accessible merge requests count' do
+ let(:api_url) { base_url }
+ let(:target_issue) { group_issue }
+ end
+ end
end
end
diff --git a/spec/requests/api/issues/get_project_issues_spec.rb b/spec/requests/api/issues/get_project_issues_spec.rb
index 0b0f754ab57..f7ca6fd1e0a 100644
--- a/spec/requests/api/issues/get_project_issues_spec.rb
+++ b/spec/requests/api/issues/get_project_issues_spec.rb
@@ -4,8 +4,9 @@ require 'spec_helper'
describe API::Issues do
set(:user) { create(:user) }
- set(:project) do
- create(:project, :public, creator_id: user.id, namespace: user.namespace)
+ set(:project) { create(:project, :public, :repository, creator_id: user.id, namespace: user.namespace) }
+ set(:private_mrs_project) do
+ create(:project, :public, :repository, creator_id: user.id, namespace: user.namespace, merge_requests_access_level: ProjectFeature::PRIVATE)
end
let(:user2) { create(:user) }
@@ -60,9 +61,28 @@ describe API::Issues do
let(:no_milestone_title) { 'None' }
let(:any_milestone_title) { 'Any' }
+ let!(:merge_request1) do
+ create(:merge_request,
+ :simple,
+ author: user,
+ source_project: project,
+ target_project: project,
+ description: "closes #{issue.to_reference}")
+ end
+ let!(:merge_request2) do
+ create(:merge_request,
+ :simple,
+ author: user,
+ source_project: private_mrs_project,
+ target_project: private_mrs_project,
+ description: "closes #{issue.to_reference(private_mrs_project)}")
+ end
+
before(:all) do
project.add_reporter(user)
project.add_guest(guest)
+ private_mrs_project.add_reporter(user)
+ private_mrs_project.add_guest(guest)
end
before do
@@ -257,6 +277,11 @@ describe API::Issues do
expect_paginated_array_response(issue.id)
end
+ it_behaves_like 'accessible merge requests count' do
+ let(:api_url) { "/projects/#{project.id}/issues" }
+ let(:target_issue) { issue }
+ end
+
context 'with labeled issues' do
let(:label_b) { create(:label, title: 'foo', project: project) }
let(:label_c) { create(:label, title: 'bar', project: project) }
@@ -636,34 +661,26 @@ describe API::Issues do
expect(json_response['iid']).to eq(confidential_issue.iid)
end
end
- end
-
- describe 'GET :id/issues/:issue_iid/closed_by' do
- let(:merge_request) do
- create(:merge_request,
- :simple,
- author: user,
- source_project: project,
- target_project: project,
- description: "closes #{issue.to_reference}")
- end
- before do
- create(:merge_requests_closing_issues, issue: issue, merge_request: merge_request)
+ it_behaves_like 'accessible merge requests count' do
+ let(:api_url) { "/projects/#{project.id}/issues/#{issue.iid}" }
+ let(:target_issue) { issue }
end
+ end
+ describe 'GET :id/issues/:issue_iid/closed_by' do
context 'when unauthenticated' do
it 'return public project issues' do
get api("/projects/#{project.id}/issues/#{issue.iid}/closed_by")
- expect_paginated_array_response(merge_request.id)
+ expect_paginated_array_response(merge_request1.id)
end
end
it 'returns merge requests that will close issue on merge' do
get api("/projects/#{project.id}/issues/#{issue.iid}/closed_by", user)
- expect_paginated_array_response(merge_request.id)
+ expect_paginated_array_response(merge_request1.id)
end
context 'when no merge requests will close issue' do
@@ -721,13 +738,6 @@ describe API::Issues do
end
it 'returns merge requests that mentioned a issue' do
- create(:merge_request,
- :simple,
- author: user,
- source_project: project,
- target_project: project,
- description: 'Some description')
-
get_related_merge_requests(project.id, issue.iid, user)
expect_paginated_array_response(related_mr.id)
diff --git a/spec/requests/api/issues/issues_spec.rb b/spec/requests/api/issues/issues_spec.rb
index f32ffd1c77b..d195f54be11 100644
--- a/spec/requests/api/issues/issues_spec.rb
+++ b/spec/requests/api/issues/issues_spec.rb
@@ -4,8 +4,9 @@ require 'spec_helper'
describe API::Issues do
set(:user) { create(:user) }
- set(:project) do
- create(:project, :public, creator_id: user.id, namespace: user.namespace)
+ set(:project) { create(:project, :public, :repository, creator_id: user.id, namespace: user.namespace) }
+ set(:private_mrs_project) do
+ create(:project, :public, :repository, creator_id: user.id, namespace: user.namespace, merge_requests_access_level: ProjectFeature::PRIVATE)
end
let(:user2) { create(:user) }
@@ -63,6 +64,8 @@ describe API::Issues do
before(:all) do
project.add_reporter(user)
project.add_guest(guest)
+ private_mrs_project.add_reporter(user)
+ private_mrs_project.add_guest(guest)
end
before do
@@ -725,6 +728,30 @@ describe API::Issues do
end
end
end
+
+ context "when returns issue merge_requests_count for different access levels" do
+ let!(:merge_request1) do
+ create(:merge_request,
+ :simple,
+ author: user,
+ source_project: private_mrs_project,
+ target_project: private_mrs_project,
+ description: "closes #{issue.to_reference(private_mrs_project)}")
+ end
+ let!(:merge_request2) do
+ create(:merge_request,
+ :simple,
+ author: user,
+ source_project: project,
+ target_project: project,
+ description: "closes #{issue.to_reference}")
+ end
+
+ it_behaves_like 'accessible merge requests count' do
+ let(:api_url) { "/issues" }
+ let(:target_issue) { issue }
+ end
+ end
end
describe 'DELETE /projects/:id/issues/:issue_iid' do
diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb
index 76d093e0774..ced853caab4 100644
--- a/spec/requests/api/merge_requests_spec.rb
+++ b/spec/requests/api/merge_requests_spec.rb
@@ -834,6 +834,31 @@ describe API::MergeRequests do
end
end
+ context 'head_pipeline' do
+ before do
+ merge_request.update(head_pipeline: create(:ci_pipeline))
+ merge_request.project.project_feature.update(builds_access_level: 10)
+ end
+
+ context 'when user can read the pipeline' do
+ it 'exposes pipeline information' do
+ get api("/projects/#{project.id}/merge_requests/#{merge_request.iid}", user)
+
+ expect(json_response).to include('head_pipeline')
+ end
+ end
+
+ context 'when user can not read the pipeline' do
+ let(:guest) { create(:user) }
+
+ it 'does not expose pipeline information' do
+ get api("/projects/#{project.id}/merge_requests/#{merge_request.iid}", guest)
+
+ expect(json_response).not_to include('head_pipeline')
+ end
+ end
+ end
+
it 'returns the commits behind the target branch when include_diverged_commits_count is present' do
allow_any_instance_of(merge_request.class).to receive(:diverged_commits_count).and_return(1)
@@ -2008,6 +2033,9 @@ describe API::MergeRequests do
expect(response).to have_gitlab_http_status(202)
expect(RebaseWorker.jobs.size).to eq(1)
+
+ expect(merge_request.reload).to be_rebase_in_progress
+ expect(json_response['rebase_in_progress']).to be(true)
end
it 'returns 403 if the user cannot push to the branch' do
@@ -2018,6 +2046,16 @@ describe API::MergeRequests do
expect(response).to have_gitlab_http_status(403)
end
+
+ it 'returns 409 if a rebase is already in progress' do
+ Sidekiq::Testing.fake! do
+ merge_request.rebase_async(user.id)
+
+ put api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/rebase", user)
+ end
+
+ expect(response).to have_gitlab_http_status(409)
+ end
end
describe 'Time tracking' do
diff --git a/spec/requests/api/project_clusters_spec.rb b/spec/requests/api/project_clusters_spec.rb
index fc0381159dd..a6e08ab3ab6 100644
--- a/spec/requests/api/project_clusters_spec.rb
+++ b/spec/requests/api/project_clusters_spec.rb
@@ -6,11 +6,12 @@ describe API::ProjectClusters do
include KubernetesHelpers
let(:current_user) { create(:user) }
- let(:non_member) { create(:user) }
- let(:project) { create(:project, :repository) }
+ let(:developer_user) { create(:user) }
+ let(:project) { create(:project) }
before do
project.add_maintainer(current_user)
+ project.add_developer(developer_user)
end
describe 'GET /projects/:id/clusters' do
@@ -22,10 +23,10 @@ describe API::ProjectClusters do
end
context 'non-authorized user' do
- it 'responds with 404' do
- get api("/projects/#{project.id}/clusters", non_member)
+ it 'responds with 403' do
+ get api("/projects/#{project.id}/clusters", developer_user)
- expect(response).to have_gitlab_http_status(404)
+ expect(response).to have_gitlab_http_status(403)
end
end
@@ -67,10 +68,10 @@ describe API::ProjectClusters do
end
context 'non-authorized user' do
- it 'responds with 404' do
- get api("/projects/#{project.id}/clusters/#{cluster_id}", non_member)
+ it 'responds with 403' do
+ get api("/projects/#{project.id}/clusters/#{cluster_id}", developer_user)
- expect(response).to have_gitlab_http_status(404)
+ expect(response).to have_gitlab_http_status(403)
end
end
@@ -147,31 +148,7 @@ describe API::ProjectClusters do
end
end
- shared_context 'kubernetes calls stubbed' do
- before do
- stub_kubeclient_discover(api_url)
- stub_kubeclient_get_namespace(api_url, namespace: namespace)
- stub_kubeclient_get_service_account(api_url, "#{namespace}-service-account", namespace: namespace)
- stub_kubeclient_put_service_account(api_url, "#{namespace}-service-account", namespace: namespace)
-
- stub_kubeclient_get_secret(
- api_url,
- {
- metadata_name: "#{namespace}-token",
- token: Base64.encode64('sample-token'),
- namespace: namespace
- }
- )
-
- stub_kubeclient_put_secret(api_url, "#{namespace}-token", namespace: namespace)
- stub_kubeclient_get_role_binding(api_url, "gitlab-#{namespace}", namespace: namespace)
- stub_kubeclient_put_role_binding(api_url, "gitlab-#{namespace}", namespace: namespace)
- end
- end
-
describe 'POST /projects/:id/clusters/user' do
- include_context 'kubernetes calls stubbed'
-
let(:api_url) { 'https://kubernetes.example.com' }
let(:namespace) { project.path }
let(:authorization_type) { 'rbac' }
@@ -195,10 +172,10 @@ describe API::ProjectClusters do
end
context 'non-authorized user' do
- it 'responds with 404' do
- post api("/projects/#{project.id}/clusters/user", non_member), params: cluster_params
+ it 'responds with 403' do
+ post api("/projects/#{project.id}/clusters/user", developer_user), params: cluster_params
- expect(response).to have_gitlab_http_status(404)
+ expect(response).to have_gitlab_http_status(403)
end
end
@@ -291,8 +268,6 @@ describe API::ProjectClusters do
end
describe 'PUT /projects/:id/clusters/:cluster_id' do
- include_context 'kubernetes calls stubbed'
-
let(:api_url) { 'https://kubernetes.example.com' }
let(:namespace) { 'new-namespace' }
let(:platform_kubernetes_attributes) { { namespace: namespace } }
@@ -316,10 +291,10 @@ describe API::ProjectClusters do
end
context 'non-authorized user' do
- it 'responds with 404' do
- put api("/projects/#{project.id}/clusters/#{cluster.id}", non_member), params: update_params
+ it 'responds with 403' do
+ put api("/projects/#{project.id}/clusters/#{cluster.id}", developer_user), params: update_params
- expect(response).to have_gitlab_http_status(404)
+ expect(response).to have_gitlab_http_status(403)
end
end
@@ -442,10 +417,10 @@ describe API::ProjectClusters do
end
context 'non-authorized user' do
- it 'responds with 404' do
- delete api("/projects/#{project.id}/clusters/#{cluster.id}", non_member), params: cluster_params
+ it 'responds with 403' do
+ delete api("/projects/#{project.id}/clusters/#{cluster.id}", developer_user), params: cluster_params
- expect(response).to have_gitlab_http_status(404)
+ expect(response).to have_gitlab_http_status(403)
end
end
diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb
index 5f7d2fa6d9c..c67412a44c1 100644
--- a/spec/requests/api/projects_spec.rb
+++ b/spec/requests/api/projects_spec.rb
@@ -2428,7 +2428,7 @@ describe API::Projects do
let(:housekeeping) { Projects::HousekeepingService.new(project) }
before do
- allow(Projects::HousekeepingService).to receive(:new).with(project).and_return(housekeeping)
+ allow(Projects::HousekeepingService).to receive(:new).with(project, :gc).and_return(housekeeping)
end
context 'when authenticated as owner' do
diff --git a/spec/requests/api/releases_spec.rb b/spec/requests/api/releases_spec.rb
index 8603fa2a73d..206e898381d 100644
--- a/spec/requests/api/releases_spec.rb
+++ b/spec/requests/api/releases_spec.rb
@@ -24,7 +24,7 @@ describe API::Releases do
project: project,
tag: 'v0.1',
author: maintainer,
- created_at: 2.days.ago)
+ released_at: 2.days.ago)
end
let!(:release_2) do
@@ -32,7 +32,7 @@ describe API::Releases do
project: project,
tag: 'v0.2',
author: maintainer,
- created_at: 1.day.ago)
+ released_at: 1.day.ago)
end
it 'returns 200 HTTP status' do
@@ -41,7 +41,7 @@ describe API::Releases do
expect(response).to have_gitlab_http_status(:ok)
end
- it 'returns releases ordered by created_at' do
+ it 'returns releases ordered by released_at' do
get api("/projects/#{project.id}/releases", maintainer)
expect(json_response.count).to eq(2)
@@ -56,6 +56,26 @@ describe API::Releases do
end
end
+ it 'returns an upcoming_release status for a future release' do
+ tomorrow = Time.now.utc + 1.day
+ create(:release, project: project, tag: 'v0.1', author: maintainer, released_at: tomorrow)
+
+ get api("/projects/#{project.id}/releases", maintainer)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response.first['upcoming_release']).to eq(true)
+ end
+
+ it 'returns an upcoming_release status for a past release' do
+ yesterday = Time.now.utc - 1.day
+ create(:release, project: project, tag: 'v0.1', author: maintainer, released_at: yesterday)
+
+ get api("/projects/#{project.id}/releases", maintainer)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response.first['upcoming_release']).to eq(false)
+ end
+
context 'when tag does not exist in git repository' do
let!(:release) { create(:release, project: project, tag: 'v1.1.5') }
@@ -316,6 +336,51 @@ describe API::Releases do
expect(project.releases.last.description).to eq('Super nice release')
end
+ it 'sets the released_at to the current time if the released_at parameter is not provided' do
+ now = Time.zone.parse('2015-08-25 06:00:00Z')
+ Timecop.freeze(now) do
+ post api("/projects/#{project.id}/releases", maintainer), params: params
+
+ expect(project.releases.last.released_at).to eq(now)
+ end
+ end
+
+ it 'sets the released_at to the value in the parameters if specified' do
+ params = {
+ name: 'New release',
+ tag_name: 'v0.1',
+ description: 'Super nice release',
+ released_at: '2019-03-20T10:00:00Z'
+ }
+ post api("/projects/#{project.id}/releases", maintainer), params: params
+
+ expect(project.releases.last.released_at).to eq('2019-03-20T10:00:00Z')
+ end
+
+ it 'assumes the utc timezone for released_at if the timezone is not provided' do
+ params = {
+ name: 'New release',
+ tag_name: 'v0.1',
+ description: 'Super nice release',
+ released_at: '2019-03-25 10:00:00'
+ }
+ post api("/projects/#{project.id}/releases", maintainer), params: params
+
+ expect(project.releases.last.released_at).to eq('2019-03-25T10:00:00Z')
+ end
+
+ it 'allows specifying a released_at with a local time zone' do
+ params = {
+ name: 'New release',
+ tag_name: 'v0.1',
+ description: 'Super nice release',
+ released_at: '2019-03-25T10:00:00+09:00'
+ }
+ post api("/projects/#{project.id}/releases", maintainer), params: params
+
+ expect(project.releases.last.released_at).to eq('2019-03-25T01:00:00Z')
+ end
+
context 'when description is empty' do
let(:params) do
{
@@ -540,6 +605,7 @@ describe API::Releases do
project: project,
tag: 'v0.1',
name: 'New release',
+ released_at: '2018-03-01T22:00:00Z',
description: 'Super nice release')
end
@@ -560,6 +626,7 @@ describe API::Releases do
expect(project.releases.last.tag).to eq('v0.1')
expect(project.releases.last.name).to eq('New release')
+ expect(project.releases.last.released_at).to eq('2018-03-01T22:00:00Z')
end
it 'matches response schema' do
@@ -568,6 +635,14 @@ describe API::Releases do
expect(response).to match_response_schema('public_api/v4/release')
end
+ it 'updates released_at' do
+ params = { released_at: '2015-10-10T05:00:00Z' }
+
+ put api("/projects/#{project.id}/releases/v0.1", maintainer), params: params
+
+ expect(project.releases.last.released_at).to eq('2015-10-10T05:00:00Z')
+ end
+
context 'when user tries to update sha' do
let(:params) { { sha: 'xxx' } }
diff --git a/spec/requests/api/runners_spec.rb b/spec/requests/api/runners_spec.rb
index 5548e3fd01a..f5ce3a3570e 100644
--- a/spec/requests/api/runners_spec.rb
+++ b/spec/requests/api/runners_spec.rb
@@ -584,6 +584,34 @@ describe API::Runners do
end
end
+ context 'when valid order_by is provided' do
+ context 'when sort order is not specified' do
+ it 'return jobs in descending order' do
+ get api("/runners/#{project_runner.id}/jobs?order_by=id", admin)
+
+ expect(response).to have_gitlab_http_status(200)
+ expect(response).to include_pagination_headers
+
+ expect(json_response).to be_an(Array)
+ expect(json_response.length).to eq(2)
+ expect(json_response.first).to include('id' => job_5.id)
+ end
+ end
+
+ context 'when sort order is specified as asc' do
+ it 'return jobs sorted in ascending order' do
+ get api("/runners/#{project_runner.id}/jobs?order_by=id&sort=asc", admin)
+
+ expect(response).to have_gitlab_http_status(200)
+ expect(response).to include_pagination_headers
+
+ expect(json_response).to be_an(Array)
+ expect(json_response.length).to eq(2)
+ expect(json_response.first).to include('id' => job_4.id)
+ end
+ end
+ end
+
context 'when invalid status is provided' do
it 'return 400' do
get api("/runners/#{project_runner.id}/jobs?status=non-existing", admin)
@@ -591,6 +619,22 @@ describe API::Runners do
expect(response).to have_gitlab_http_status(400)
end
end
+
+ context 'when invalid order_by is provided' do
+ it 'return 400' do
+ get api("/runners/#{project_runner.id}/jobs?order_by=non-existing", admin)
+
+ expect(response).to have_gitlab_http_status(400)
+ end
+ end
+
+ context 'when invalid sort is provided' do
+ it 'return 400' do
+ get api("/runners/#{project_runner.id}/jobs?sort=non-existing", admin)
+
+ expect(response).to have_gitlab_http_status(400)
+ end
+ end
end
context "when runner doesn't exist" do
diff --git a/spec/requests/api/user_counts_spec.rb b/spec/requests/api/user_counts_spec.rb
new file mode 100644
index 00000000000..c833bd047e2
--- /dev/null
+++ b/spec/requests/api/user_counts_spec.rb
@@ -0,0 +1,40 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe API::UserCounts do
+ let(:user) { create(:user) }
+ let(:project) { create(:project, :public) }
+
+ let!(:merge_request) { create(:merge_request, :simple, author: user, assignees: [user], source_project: project, title: "Test") }
+
+ describe 'GET /user_counts' do
+ context 'when unauthenticated' do
+ it 'returns authentication error' do
+ get api('/user_counts')
+
+ expect(response.status).to eq(401)
+ end
+ end
+
+ context 'when authenticated' do
+ it 'returns open counts for current user' do
+ get api('/user_counts', user)
+
+ expect(response.status).to eq(200)
+ expect(json_response).to be_a Hash
+ expect(json_response['merge_requests']).to eq(1)
+ end
+
+ it 'updates the mr count when a new mr is assigned' do
+ create(:merge_request, source_project: project, author: user, assignees: [user])
+
+ get api('/user_counts', user)
+
+ expect(response.status).to eq(200)
+ expect(json_response).to be_a Hash
+ expect(json_response['merge_requests']).to eq(2)
+ end
+ end
+ end
+end
diff --git a/spec/requests/rack_attack_global_spec.rb b/spec/requests/rack_attack_global_spec.rb
index 89adbc77a7f..d832963292c 100644
--- a/spec/requests/rack_attack_global_spec.rb
+++ b/spec/requests/rack_attack_global_spec.rb
@@ -102,6 +102,27 @@ describe 'Rack Attack global throttles' do
expect_rejection { get(*get_args) }
end
+
+ it 'logs RackAttack info into structured logs' do
+ requests_per_period.times do
+ get(*get_args)
+ expect(response).to have_http_status 200
+ end
+
+ arguments = {
+ message: 'Rack_Attack',
+ env: :throttle,
+ ip: '127.0.0.1',
+ request_method: 'GET',
+ fullpath: get_args.first,
+ user_id: user.id,
+ username: user.username
+ }
+
+ expect(Gitlab::AuthLogger).to receive(:error).with(arguments).once
+
+ expect_rejection { get(*get_args) }
+ end
end
context 'when the throttle is disabled' do
@@ -189,7 +210,15 @@ describe 'Rack Attack global throttles' do
expect(response).to have_http_status 200
end
- expect(Gitlab::AuthLogger).to receive(:error).once
+ arguments = {
+ message: 'Rack_Attack',
+ env: :throttle,
+ ip: '127.0.0.1',
+ request_method: 'GET',
+ fullpath: '/users/sign_in'
+ }
+
+ expect(Gitlab::AuthLogger).to receive(:error).with(arguments)
get url_that_does_not_require_authentication
end
@@ -345,7 +374,17 @@ describe 'Rack Attack global throttles' do
expect(response).to have_http_status 200
end
- expect(Gitlab::AuthLogger).to receive(:error).once
+ arguments = {
+ message: 'Rack_Attack',
+ env: :throttle,
+ ip: '127.0.0.1',
+ request_method: 'GET',
+ fullpath: '/dashboard/snippets',
+ user_id: user.id,
+ username: user.username
+ }
+
+ expect(Gitlab::AuthLogger).to receive(:error).with(arguments).once
get url_that_requires_authentication
end
diff --git a/spec/routing/api_routing_spec.rb b/spec/routing/api_routing_spec.rb
deleted file mode 100644
index 3c48ead4ff2..00000000000
--- a/spec/routing/api_routing_spec.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-require 'spec_helper'
-
-describe 'api', 'routing' do
- context 'when graphql is disabled' do
- before do
- stub_feature_flags(graphql: false)
- end
-
- it 'does not route to the GraphqlController' do
- expect(post('/api/graphql')).not_to route_to('graphql#execute')
- end
- end
-
- context 'when graphql is enabled' do
- before do
- stub_feature_flags(graphql: true)
- end
-
- it 'routes to the GraphqlController' do
- expect(post('/api/graphql')).to route_to('graphql#execute')
- end
- end
-end
diff --git a/spec/routing/project_routing_spec.rb b/spec/routing/project_routing_spec.rb
index 83775b1040e..6dde40d1cb6 100644
--- a/spec/routing/project_routing_spec.rb
+++ b/spec/routing/project_routing_spec.rb
@@ -693,4 +693,24 @@ describe 'project routing' do
it_behaves_like 'redirecting a legacy project path', "/gitlab/gitlabhq/settings/repository", "/gitlab/gitlabhq/-/settings/repository"
end
+
+ describe Projects::TemplatesController, 'routing' do
+ describe '#show' do
+ def show_with_template_type(template_type)
+ "/gitlab/gitlabhq/templates/#{template_type}/template_name"
+ end
+
+ it 'routes when :template_type is `merge_request`' do
+ expect(get(show_with_template_type('merge_request'))).to route_to('projects/templates#show', namespace_id: 'gitlab', project_id: 'gitlabhq', template_type: 'merge_request', key: 'template_name', format: 'json')
+ end
+
+ it 'routes when :template_type is `issue`' do
+ expect(get(show_with_template_type('issue'))).to route_to('projects/templates#show', namespace_id: 'gitlab', project_id: 'gitlabhq', template_type: 'issue', key: 'template_name', format: 'json')
+ end
+
+ it 'routes to application#route_not_found when :template_type is unknown' do
+ expect(get(show_with_template_type('invalid'))).to route_to('application#route_not_found', unmatched_route: 'gitlab/gitlabhq/templates/invalid/template_name')
+ end
+ end
+ end
end
diff --git a/spec/routing/uploads_routing_spec.rb b/spec/routing/uploads_routing_spec.rb
index 6a041ffdd6c..42e84774088 100644
--- a/spec/routing/uploads_routing_spec.rb
+++ b/spec/routing/uploads_routing_spec.rb
@@ -12,10 +12,19 @@ describe 'Uploads', 'routing' do
)
end
+ it 'allows creating uploads for users' do
+ expect(post('/uploads/user?id=1')).to route_to(
+ controller: 'uploads',
+ action: 'create',
+ model: 'user',
+ id: '1'
+ )
+ end
+
it 'does not allow creating uploads for other models' do
- UploadsController::MODEL_CLASSES.keys.compact.each do |model|
- next if model == 'personal_snippet'
+ unroutable_models = UploadsController::MODEL_CLASSES.keys.compact - %w(personal_snippet user)
+ unroutable_models.each do |model|
expect(post("/uploads/#{model}?id=1")).not_to be_routable
end
end
diff --git a/spec/rubocop/cop/graphql/authorize_types_spec.rb b/spec/rubocop/cop/graphql/authorize_types_spec.rb
new file mode 100644
index 00000000000..eae3e176d64
--- /dev/null
+++ b/spec/rubocop/cop/graphql/authorize_types_spec.rb
@@ -0,0 +1,66 @@
+# frozen_string_literal: true
+
+require 'fast_spec_helper'
+require 'rubocop'
+require 'rubocop/rspec/support'
+require_relative '../../../../rubocop/cop/graphql/authorize_types'
+
+describe RuboCop::Cop::Graphql::AuthorizeTypes do
+ include RuboCop::RSpec::ExpectOffense
+ include CopHelper
+
+ subject(:cop) { described_class.new }
+
+ context 'when in a type folder' do
+ before do
+ allow(cop).to receive(:in_type?).and_return(true)
+ end
+
+ it 'adds an offense when there is no authorize call' do
+ inspect_source(<<~TYPE)
+ module Types
+ class AType < BaseObject
+ field :a_thing
+ field :another_thing
+ end
+ end
+ TYPE
+
+ expect(cop.offenses.size).to eq 1
+ end
+
+ it 'does not add an offense for classes that have an authorize call' do
+ expect_no_offenses(<<~TYPE.strip)
+ module Types
+ class AType < BaseObject
+ graphql_name 'ATypeName'
+
+ authorize :an_ability, :second_ability
+
+ field :a_thing
+ end
+ end
+ TYPE
+ end
+
+ it 'does not add an offense for classes that only have an authorize call' do
+ expect_no_offenses(<<~TYPE.strip)
+ module Types
+ class AType < SuperClassWithFields
+ authorize :an_ability
+ end
+ end
+ TYPE
+ end
+
+ it 'does not add an offense for base types' do
+ expect_no_offenses(<<~TYPE)
+ module Types
+ class AType < BaseEnum
+ field :a_thing
+ end
+ end
+ TYPE
+ end
+ end
+end
diff --git a/spec/serializers/environment_status_entity_spec.rb b/spec/serializers/environment_status_entity_spec.rb
index 8a6a38fe5f8..f421432e8d6 100644
--- a/spec/serializers/environment_status_entity_spec.rb
+++ b/spec/serializers/environment_status_entity_spec.rb
@@ -9,7 +9,7 @@ describe EnvironmentStatusEntity do
let(:project) { deployment.project }
let(:merge_request) { create(:merge_request, :deployed_review_app, deployment: deployment) }
- let(:environment_status) { EnvironmentStatus.new(environment, merge_request, merge_request.diff_head_sha) }
+ let(:environment_status) { EnvironmentStatus.new(project, environment, merge_request, merge_request.diff_head_sha) }
let(:entity) { described_class.new(environment_status, request: request) }
subject { entity.as_json }
@@ -55,8 +55,14 @@ describe EnvironmentStatusEntity do
before do
project.add_maintainer(user)
allow(deployment).to receive(:prometheus_adapter).and_return(prometheus_adapter)
- allow(prometheus_adapter).to receive(:query).with(:deployment, deployment).and_return(simple_metrics)
allow(entity).to receive(:deployment).and_return(deployment)
+
+ expect_next_instance_of(DeploymentMetrics) do |deployment_metrics|
+ allow(deployment_metrics).to receive(:prometheus_adapter).and_return(prometheus_adapter)
+
+ allow(prometheus_adapter).to receive(:query)
+ .with(:deployment, deployment).and_return(simple_metrics)
+ end
end
context 'when deployment succeeded' do
diff --git a/spec/serializers/test_case_entity_spec.rb b/spec/serializers/test_case_entity_spec.rb
index 986c9feb07b..cc5f086ca4e 100644
--- a/spec/serializers/test_case_entity_spec.rb
+++ b/spec/serializers/test_case_entity_spec.rb
@@ -24,7 +24,7 @@ describe TestCaseEntity do
it 'contains correct test case details' do
expect(subject[:status]).to eq('failed')
- expect(subject[:name]).to eq('Test#sum when a is 2 and b is 2 returns summary')
+ expect(subject[:name]).to eq('Test#sum when a is 1 and b is 3 returns summary')
expect(subject[:classname]).to eq('spec.test_spec')
expect(subject[:execution_time]).to eq(2.22)
end
diff --git a/spec/serializers/test_reports_comparer_entity_spec.rb b/spec/serializers/test_reports_comparer_entity_spec.rb
index 59c058fe368..4a951bbbde4 100644
--- a/spec/serializers/test_reports_comparer_entity_spec.rb
+++ b/spec/serializers/test_reports_comparer_entity_spec.rb
@@ -53,13 +53,7 @@ describe TestReportsComparerEntity do
base_reports.get_suite('rspec').add_test_case(create_test_case_rspec_success)
base_reports.get_suite('junit').add_test_case(create_test_case_java_failed)
head_reports.get_suite('rspec').add_test_case(create_test_case_rspec_success)
- head_reports.get_suite('junit').add_test_case(create_test_case_java_resolved)
- end
-
- let(:create_test_case_java_resolved) do
- create_test_case_java_failed.tap do |test_case|
- test_case.instance_variable_set("@status", Gitlab::Ci::Reports::TestCase::STATUS_SUCCESS)
- end
+ head_reports.get_suite('junit').add_test_case(create_test_case_java_success)
end
it 'contains correct compared test reports details' do
diff --git a/spec/serializers/test_reports_comparer_serializer_spec.rb b/spec/serializers/test_reports_comparer_serializer_spec.rb
index 9ea86c0dd83..62dc6f486c5 100644
--- a/spec/serializers/test_reports_comparer_serializer_spec.rb
+++ b/spec/serializers/test_reports_comparer_serializer_spec.rb
@@ -44,13 +44,7 @@ describe TestReportsComparerSerializer do
base_reports.get_suite('rspec').add_test_case(create_test_case_rspec_success)
base_reports.get_suite('junit').add_test_case(create_test_case_java_failed)
head_reports.get_suite('rspec').add_test_case(create_test_case_rspec_success)
- head_reports.get_suite('junit').add_test_case(create_test_case_java_resolved)
- end
-
- let(:create_test_case_java_resolved) do
- create_test_case_java_failed.tap do |test_case|
- test_case.instance_variable_set("@status", Gitlab::Ci::Reports::TestCase::STATUS_SUCCESS)
- end
+ head_reports.get_suite('junit').add_test_case(create_test_case_java_success)
end
it 'matches the schema' do
diff --git a/spec/serializers/test_suite_comparer_entity_spec.rb b/spec/serializers/test_suite_comparer_entity_spec.rb
index f61331f53a0..4b2cca2c68c 100644
--- a/spec/serializers/test_suite_comparer_entity_spec.rb
+++ b/spec/serializers/test_suite_comparer_entity_spec.rb
@@ -11,16 +11,10 @@ describe TestSuiteComparerEntity do
let(:test_case_success) { create_test_case_rspec_success }
let(:test_case_failed) { create_test_case_rspec_failed }
- let(:test_case_resolved) do
- create_test_case_rspec_failed.tap do |test_case|
- test_case.instance_variable_set("@status", Gitlab::Ci::Reports::TestCase::STATUS_SUCCESS)
- end
- end
-
describe '#as_json' do
subject { entity.as_json }
- context 'when head sutie has a newly failed test case which does not exist in base' do
+ context 'when head suite has a newly failed test case which does not exist in base' do
before do
base_suite.add_test_case(test_case_success)
head_suite.add_test_case(test_case_failed)
@@ -41,7 +35,7 @@ describe TestSuiteComparerEntity do
end
end
- context 'when head sutie still has a failed test case which failed in base' do
+ context 'when head suite still has a failed test case which failed in base' do
before do
base_suite.add_test_case(test_case_failed)
head_suite.add_test_case(test_case_failed)
@@ -62,10 +56,10 @@ describe TestSuiteComparerEntity do
end
end
- context 'when head sutie has a success test case which failed in base' do
+ context 'when head suite has a success test case which failed in base' do
before do
base_suite.add_test_case(test_case_failed)
- head_suite.add_test_case(test_case_resolved)
+ head_suite.add_test_case(test_case_success)
end
it 'contains correct compared test suite details' do
@@ -74,13 +68,83 @@ describe TestSuiteComparerEntity do
expect(subject[:summary]).to include(total: 1, resolved: 1, failed: 0)
expect(subject[:new_failures]).to be_empty
subject[:resolved_failures].first.tap do |resolved_failure|
- expect(resolved_failure[:status]).to eq(test_case_resolved.status)
- expect(resolved_failure[:name]).to eq(test_case_resolved.name)
- expect(resolved_failure[:execution_time]).to eq(test_case_resolved.execution_time)
- expect(resolved_failure[:system_output]).to eq(test_case_resolved.system_output)
+ expect(resolved_failure[:status]).to eq(test_case_success.status)
+ expect(resolved_failure[:name]).to eq(test_case_success.name)
+ expect(resolved_failure[:execution_time]).to eq(test_case_success.execution_time)
+ expect(resolved_failure[:system_output]).to eq(test_case_success.system_output)
end
expect(subject[:existing_failures]).to be_empty
end
end
+
+ context 'limits amount of tests returned' do
+ before do
+ stub_const('TestSuiteComparerEntity::DEFAULT_MAX_TESTS', 2)
+ stub_const('TestSuiteComparerEntity::DEFAULT_MIN_TESTS', 1)
+ end
+
+ context 'prefers new over existing and resolved' do
+ before do
+ 3.times { add_new_failure }
+ 3.times { add_existing_failure }
+ 3.times { add_resolved_failure }
+ end
+
+ it 'returns 2 new failures, and 1 of resolved and existing' do
+ expect(subject[:summary]).to include(total: 9, resolved: 3, failed: 6)
+ expect(subject[:new_failures].count).to eq(2)
+ expect(subject[:existing_failures].count).to eq(1)
+ expect(subject[:resolved_failures].count).to eq(1)
+ end
+ end
+
+ context 'prefers existing over resolved' do
+ before do
+ 3.times { add_existing_failure }
+ 3.times { add_resolved_failure }
+ end
+
+ it 'returns 2 existing failures, and 1 resolved' do
+ expect(subject[:summary]).to include(total: 6, resolved: 3, failed: 3)
+ expect(subject[:new_failures].count).to eq(0)
+ expect(subject[:existing_failures].count).to eq(2)
+ expect(subject[:resolved_failures].count).to eq(1)
+ end
+ end
+
+ context 'limits amount of resolved' do
+ before do
+ 3.times { add_resolved_failure }
+ end
+
+ it 'returns 2 resolved failures' do
+ expect(subject[:summary]).to include(total: 3, resolved: 3, failed: 0)
+ expect(subject[:new_failures].count).to eq(0)
+ expect(subject[:existing_failures].count).to eq(0)
+ expect(subject[:resolved_failures].count).to eq(2)
+ end
+ end
+
+ private
+
+ def add_new_failure
+ failed_case = create_test_case_rspec_failed(SecureRandom.hex)
+ head_suite.add_test_case(failed_case)
+ end
+
+ def add_existing_failure
+ failed_case = create_test_case_rspec_failed(SecureRandom.hex)
+ base_suite.add_test_case(failed_case)
+ head_suite.add_test_case(failed_case)
+ end
+
+ def add_resolved_failure
+ case_name = SecureRandom.hex
+ failed_case = create_test_case_rspec_failed(case_name)
+ success_case = create_test_case_rspec_success(case_name)
+ base_suite.add_test_case(failed_case)
+ head_suite.add_test_case(success_case)
+ end
+ end
end
end
diff --git a/spec/services/auto_merge/base_service_spec.rb b/spec/services/auto_merge/base_service_spec.rb
index cd08e0b6f32..a409f21a7e4 100644
--- a/spec/services/auto_merge/base_service_spec.rb
+++ b/spec/services/auto_merge/base_service_spec.rb
@@ -59,6 +59,11 @@ describe AutoMerge::BaseService do
context 'when strategy is merge when pipeline succeeds' do
let(:service) { AutoMerge::MergeWhenPipelineSucceedsService.new(project, user) }
+ before do
+ pipeline = build(:ci_pipeline)
+ allow(merge_request).to receive(:actual_head_pipeline) { pipeline }
+ end
+
it 'sets the auto merge strategy' do
subject
@@ -116,11 +121,7 @@ describe AutoMerge::BaseService do
end
end
- describe '#cancel' do
- subject { service.cancel(merge_request) }
-
- let(:merge_request) { create(:merge_request, :merge_when_pipeline_succeeds) }
-
+ shared_examples_for 'Canceled or Dropped' do
it 'removes properies from the merge request' do
subject
@@ -168,6 +169,20 @@ describe AutoMerge::BaseService do
it 'does not yield block' do
expect { |b| service.execute(merge_request, &b) }.not_to yield_control
end
+ end
+ end
+
+ describe '#cancel' do
+ subject { service.cancel(merge_request) }
+
+ let(:merge_request) { create(:merge_request, :merge_when_pipeline_succeeds) }
+
+ it_behaves_like 'Canceled or Dropped'
+
+ context 'when failed to save' do
+ before do
+ allow(merge_request).to receive(:save) { false }
+ end
it 'returns error status' do
expect(subject[:status]).to eq(:error)
@@ -175,4 +190,24 @@ describe AutoMerge::BaseService do
end
end
end
+
+ describe '#abort' do
+ subject { service.abort(merge_request, reason) }
+
+ let(:merge_request) { create(:merge_request, :merge_when_pipeline_succeeds) }
+ let(:reason) { 'an error'}
+
+ it_behaves_like 'Canceled or Dropped'
+
+ context 'when failed to save' do
+ before do
+ allow(merge_request).to receive(:save) { false }
+ end
+
+ it 'returns error status' do
+ expect(subject[:status]).to eq(:error)
+ expect(subject[:message]).to eq("Can't abort the automatic merge")
+ end
+ end
+ end
end
diff --git a/spec/services/auto_merge/merge_when_pipeline_succeeds_service_spec.rb b/spec/services/auto_merge/merge_when_pipeline_succeeds_service_spec.rb
index a20bf8e17e4..931b52470c4 100644
--- a/spec/services/auto_merge/merge_when_pipeline_succeeds_service_spec.rb
+++ b/spec/services/auto_merge/merge_when_pipeline_succeeds_service_spec.rb
@@ -64,8 +64,11 @@ describe AutoMerge::MergeWhenPipelineSucceedsService do
end
it 'creates a system note' do
+ pipeline = build(:ci_pipeline)
+ allow(merge_request).to receive(:actual_head_pipeline) { pipeline }
+
note = merge_request.notes.last
- expect(note.note).to match %r{enabled an automatic merge when the pipeline for (\w+/\w+@)?\h{8}}
+ expect(note.note).to match "enabled an automatic merge when the pipeline for #{pipeline.sha}"
end
end
@@ -174,6 +177,17 @@ describe AutoMerge::MergeWhenPipelineSucceedsService do
end
end
+ describe "#abort" do
+ before do
+ service.abort(mr_merge_if_green_enabled, 'an error')
+ end
+
+ it 'posts a system note' do
+ note = mr_merge_if_green_enabled.notes.last
+ expect(note.note).to include 'aborted the automatic merge'
+ end
+ end
+
describe 'pipeline integration' do
context 'when there are multiple stages in the pipeline' do
let(:ref) { mr_merge_if_green_enabled.source_branch }
diff --git a/spec/services/auto_merge_service_spec.rb b/spec/services/auto_merge_service_spec.rb
index 93a22e60498..50dfc49a59c 100644
--- a/spec/services/auto_merge_service_spec.rb
+++ b/spec/services/auto_merge_service_spec.rb
@@ -161,4 +161,29 @@ describe AutoMergeService do
end
end
end
+
+ describe '#abort' do
+ subject { service.abort(merge_request, error) }
+
+ let(:merge_request) { create(:merge_request, :merge_when_pipeline_succeeds) }
+ let(:error) { 'an error' }
+
+ it 'delegates to a relevant service instance' do
+ expect_next_instance_of(AutoMerge::MergeWhenPipelineSucceedsService) do |service|
+ expect(service).to receive(:abort).with(merge_request, error)
+ end
+
+ subject
+ end
+
+ context 'when auto merge is not enabled' do
+ let(:merge_request) { create(:merge_request) }
+
+ it 'returns error' do
+ expect(subject[:message]).to eq("Can't abort the automatic merge")
+ expect(subject[:status]).to eq(:error)
+ expect(subject[:http_status]).to eq(406)
+ end
+ end
+ end
end
diff --git a/spec/services/branches/diverging_commit_counts_service_spec.rb b/spec/services/branches/diverging_commit_counts_service_spec.rb
index bfdbebdb7c1..370da773ab2 100644
--- a/spec/services/branches/diverging_commit_counts_service_spec.rb
+++ b/spec/services/branches/diverging_commit_counts_service_spec.rb
@@ -19,34 +19,13 @@ describe Branches::DivergingCommitCountsService do
expect(result).to eq(behind: 29, ahead: 2)
end
- context 'when gitaly_count_diverging_commits_no_max is enabled' do
- before do
- stub_feature_flags(gitaly_count_diverging_commits_no_max: true)
- end
-
- it 'calls diverging_commit_count without max count' do
- expect(repository.raw_repository)
- .to receive(:diverging_commit_count)
- .with(root_ref_sha, diverged_branch_sha)
- .and_return([29, 2])
-
- service.call(diverged_branch)
- end
- end
-
- context 'when gitaly_count_diverging_commits_no_max is disabled' do
- before do
- stub_feature_flags(gitaly_count_diverging_commits_no_max: false)
- end
-
- it 'calls diverging_commit_count with max count' do
- expect(repository.raw_repository)
- .to receive(:diverging_commit_count)
- .with(root_ref_sha, diverged_branch_sha, max_count: Repository::MAX_DIVERGING_COUNT)
- .and_return([29, 2])
+ it 'calls diverging_commit_count without max count' do
+ expect(repository.raw_repository)
+ .to receive(:diverging_commit_count)
+ .with(root_ref_sha, diverged_branch_sha)
+ .and_return([29, 2])
- service.call(diverged_branch)
- end
+ service.call(diverged_branch)
end
end
end
diff --git a/spec/services/deploy_tokens/create_service_spec.rb b/spec/services/deploy_tokens/create_service_spec.rb
index 886ffd4593d..fbb66fe4cb7 100644
--- a/spec/services/deploy_tokens/create_service_spec.rb
+++ b/spec/services/deploy_tokens/create_service_spec.rb
@@ -32,6 +32,22 @@ describe DeployTokens::CreateService do
end
end
+ context 'when username is empty string' do
+ let(:deploy_token_params) { attributes_for(:deploy_token, username: '') }
+
+ it 'converts it to nil' do
+ expect(subject.read_attribute(:username)).to be_nil
+ end
+ end
+
+ context 'when username is provided' do
+ let(:deploy_token_params) { attributes_for(:deploy_token, username: 'deployer') }
+
+ it 'keeps the provided username' do
+ expect(subject.read_attribute(:username)).to eq('deployer')
+ end
+ end
+
context 'when the deploy token is invalid' do
let(:deploy_token_params) { attributes_for(:deploy_token, read_repository: false, read_registry: false) }
diff --git a/spec/services/issuable/bulk_update_service_spec.rb b/spec/services/issuable/bulk_update_service_spec.rb
index aebc5ba2874..3d2d4b5f216 100644
--- a/spec/services/issuable/bulk_update_service_spec.rb
+++ b/spec/services/issuable/bulk_update_service_spec.rb
@@ -11,343 +11,371 @@ describe Issuable::BulkUpdateService do
.reverse_merge(issuable_ids: Array(issuables).map(&:id).join(','))
type = Array(issuables).first.model_name.param_key
- Issuable::BulkUpdateService.new(project, user, bulk_update_params).execute(type)
+ Issuable::BulkUpdateService.new(user, bulk_update_params).execute(type)
end
- describe 'close issues' do
- let(:issues) { create_list(:issue, 2, project: project) }
-
- it 'succeeds and returns the correct number of issues updated' do
- result = bulk_update(issues, state_event: 'close')
+ shared_examples 'updates milestones' do
+ it 'succeeds' do
+ result = bulk_update(issues, milestone_id: milestone.id)
expect(result[:success]).to be_truthy
expect(result[:count]).to eq(issues.count)
end
- it 'closes all the issues passed' do
- bulk_update(issues, state_event: 'close')
+ it 'updates the issues milestone' do
+ bulk_update(issues, milestone_id: milestone.id)
- expect(project.issues.opened).to be_empty
- expect(project.issues.closed).not_to be_empty
+ issues.each do |issue|
+ expect(issue.reload.milestone).to eq(milestone)
+ end
end
+ end
- context 'when issue for a different project is created' do
- let(:private_project) { create(:project, :private) }
- let(:issue) { create(:issue, project: private_project, author: user) }
+ context 'with project issues' do
+ describe 'close issues' do
+ let(:issues) { create_list(:issue, 2, project: project) }
- context 'when user has access to the project' do
- it 'closes all issues passed' do
- private_project.add_maintainer(user)
+ it 'succeeds and returns the correct number of issues updated' do
+ result = bulk_update(issues, state_event: 'close')
- bulk_update(issues + [issue], state_event: 'close')
+ expect(result[:success]).to be_truthy
+ expect(result[:count]).to eq(issues.count)
+ end
- expect(project.issues.opened).to be_empty
- expect(project.issues.closed).not_to be_empty
- expect(private_project.issues.closed).not_to be_empty
- end
+ it 'closes all the issues passed' do
+ bulk_update(issues, state_event: 'close')
+
+ expect(project.issues.opened).to be_empty
+ expect(project.issues.closed).not_to be_empty
end
- context 'when user does not have access to project' do
- it 'only closes all issues that the user has access to' do
- bulk_update(issues + [issue], state_event: 'close')
+ context 'when issue for a different project is created' do
+ let(:private_project) { create(:project, :private) }
+ let(:issue) { create(:issue, project: private_project, author: user) }
+
+ context 'when user has access to the project' do
+ it 'closes all issues passed' do
+ private_project.add_maintainer(user)
+
+ bulk_update(issues + [issue], state_event: 'close')
+
+ expect(project.issues.opened).to be_empty
+ expect(project.issues.closed).not_to be_empty
+ expect(private_project.issues.closed).not_to be_empty
+ end
+ end
+
+ context 'when user does not have access to project' do
+ it 'only closes all issues that the user has access to' do
+ bulk_update(issues + [issue], state_event: 'close')
- expect(project.issues.opened).to be_empty
- expect(project.issues.closed).not_to be_empty
- expect(private_project.issues.closed).to be_empty
+ expect(project.issues.opened).to be_empty
+ expect(project.issues.closed).not_to be_empty
+ expect(private_project.issues.closed).to be_empty
+ end
end
end
end
- end
- describe 'reopen issues' do
- let(:issues) { create_list(:closed_issue, 2, project: project) }
+ describe 'reopen issues' do
+ let(:issues) { create_list(:closed_issue, 2, project: project) }
- it 'succeeds and returns the correct number of issues updated' do
- result = bulk_update(issues, state_event: 'reopen')
+ it 'succeeds and returns the correct number of issues updated' do
+ result = bulk_update(issues, state_event: 'reopen')
- expect(result[:success]).to be_truthy
- expect(result[:count]).to eq(issues.count)
- end
+ expect(result[:success]).to be_truthy
+ expect(result[:count]).to eq(issues.count)
+ end
- it 'reopens all the issues passed' do
- bulk_update(issues, state_event: 'reopen')
+ it 'reopens all the issues passed' do
+ bulk_update(issues, state_event: 'reopen')
- expect(project.issues.closed).to be_empty
- expect(project.issues.opened).not_to be_empty
+ expect(project.issues.closed).to be_empty
+ expect(project.issues.opened).not_to be_empty
+ end
end
- end
- describe 'updating merge request assignee' do
- let(:merge_request) { create(:merge_request, target_project: project, source_project: project, assignees: [user]) }
+ describe 'updating merge request assignee' do
+ let(:merge_request) { create(:merge_request, target_project: project, source_project: project, assignees: [user]) }
- context 'when the new assignee ID is a valid user' do
- it 'succeeds' do
- new_assignee = create(:user)
- project.add_developer(new_assignee)
+ context 'when the new assignee ID is a valid user' do
+ it 'succeeds' do
+ new_assignee = create(:user)
+ project.add_developer(new_assignee)
- result = bulk_update(merge_request, assignee_ids: [user.id, new_assignee.id])
+ result = bulk_update(merge_request, assignee_ids: [user.id, new_assignee.id])
- expect(result[:success]).to be_truthy
- expect(result[:count]).to eq(1)
- end
+ expect(result[:success]).to be_truthy
+ expect(result[:count]).to eq(1)
+ end
- it 'updates the assignee to the user ID passed' do
- assignee = create(:user)
- project.add_developer(assignee)
+ it 'updates the assignee to the user ID passed' do
+ assignee = create(:user)
+ project.add_developer(assignee)
- expect { bulk_update(merge_request, assignee_ids: [assignee.id]) }
- .to change { merge_request.reload.assignee_ids }.from([user.id]).to([assignee.id])
+ expect { bulk_update(merge_request, assignee_ids: [assignee.id]) }
+ .to change { merge_request.reload.assignee_ids }.from([user.id]).to([assignee.id])
+ end
end
- end
- context "when the new assignee ID is #{IssuableFinder::NONE}" do
- it 'unassigns the issues' do
- expect { bulk_update(merge_request, assignee_ids: [IssuableFinder::NONE]) }
- .to change { merge_request.reload.assignee_ids }.to([])
+ context "when the new assignee ID is #{IssuableFinder::NONE}" do
+ it 'unassigns the issues' do
+ expect { bulk_update(merge_request, assignee_ids: [IssuableFinder::NONE]) }
+ .to change { merge_request.reload.assignee_ids }.to([])
+ end
end
- end
- context 'when the new assignee ID is not present' do
- it 'does not unassign' do
- expect { bulk_update(merge_request, assignee_ids: []) }
- .not_to change { merge_request.reload.assignee_ids }
+ context 'when the new assignee ID is not present' do
+ it 'does not unassign' do
+ expect { bulk_update(merge_request, assignee_ids: []) }
+ .not_to change { merge_request.reload.assignee_ids }
+ end
end
end
- end
- describe 'updating issue assignee' do
- let(:issue) { create(:issue, project: project, assignees: [user]) }
+ describe 'updating issue assignee' do
+ let(:issue) { create(:issue, project: project, assignees: [user]) }
- context 'when the new assignee ID is a valid user' do
- it 'succeeds' do
- new_assignee = create(:user)
- project.add_developer(new_assignee)
+ context 'when the new assignee ID is a valid user' do
+ it 'succeeds' do
+ new_assignee = create(:user)
+ project.add_developer(new_assignee)
- result = bulk_update(issue, assignee_ids: [new_assignee.id])
+ result = bulk_update(issue, assignee_ids: [new_assignee.id])
- expect(result[:success]).to be_truthy
- expect(result[:count]).to eq(1)
- end
+ expect(result[:success]).to be_truthy
+ expect(result[:count]).to eq(1)
+ end
- it 'updates the assignee to the user ID passed' do
- assignee = create(:user)
- project.add_developer(assignee)
- expect { bulk_update(issue, assignee_ids: [assignee.id]) }
- .to change { issue.reload.assignees.first }.from(user).to(assignee)
+ it 'updates the assignee to the user ID passed' do
+ assignee = create(:user)
+ project.add_developer(assignee)
+ expect { bulk_update(issue, assignee_ids: [assignee.id]) }
+ .to change { issue.reload.assignees.first }.from(user).to(assignee)
+ end
end
- end
- context "when the new assignee ID is #{IssuableFinder::NONE}" do
- it "unassigns the issues" do
- expect { bulk_update(issue, assignee_ids: [IssuableFinder::NONE.to_s]) }
- .to change { issue.reload.assignees.count }.from(1).to(0)
+ context "when the new assignee ID is #{IssuableFinder::NONE}" do
+ it "unassigns the issues" do
+ expect { bulk_update(issue, assignee_ids: [IssuableFinder::NONE.to_s]) }
+ .to change { issue.reload.assignees.count }.from(1).to(0)
+ end
end
- end
- context 'when the new assignee ID is not present' do
- it 'does not unassign' do
- expect { bulk_update(issue, assignee_ids: []) }
- .not_to change { issue.reload.assignees }
+ context 'when the new assignee ID is not present' do
+ it 'does not unassign' do
+ expect { bulk_update(issue, assignee_ids: []) }
+ .not_to change { issue.reload.assignees }
+ end
end
end
- end
-
- describe 'updating milestones' do
- let(:issue) { create(:issue, project: project) }
- let(:milestone) { create(:milestone, project: project) }
- it 'succeeds' do
- result = bulk_update(issue, milestone_id: milestone.id)
+ describe 'updating milestones' do
+ let(:issues) { [create(:issue, project: project)] }
+ let(:milestone) { create(:milestone, project: project) }
- expect(result[:success]).to be_truthy
- expect(result[:count]).to eq(1)
+ it_behaves_like 'updates milestones'
end
- it 'updates the issue milestone' do
- expect { bulk_update(issue, milestone_id: milestone.id) }
- .to change { issue.reload.milestone }.from(nil).to(milestone)
- end
- end
-
- describe 'updating labels' do
- def create_issue_with_labels(labels)
- create(:labeled_issue, project: project, labels: labels)
- end
+ describe 'updating labels' do
+ def create_issue_with_labels(labels)
+ create(:labeled_issue, project: project, labels: labels)
+ end
- let(:bug) { create(:label, project: project) }
- let(:regression) { create(:label, project: project) }
- let(:merge_requests) { create(:label, project: project) }
-
- let(:issue_all_labels) { create_issue_with_labels([bug, regression, merge_requests]) }
- let(:issue_bug_and_regression) { create_issue_with_labels([bug, regression]) }
- let(:issue_bug_and_merge_requests) { create_issue_with_labels([bug, merge_requests]) }
- let(:issue_no_labels) { create(:issue, project: project) }
- let(:issues) { [issue_all_labels, issue_bug_and_regression, issue_bug_and_merge_requests, issue_no_labels] }
-
- let(:labels) { [] }
- let(:add_labels) { [] }
- let(:remove_labels) { [] }
-
- let(:bulk_update_params) do
- {
- label_ids: labels.map(&:id),
- add_label_ids: add_labels.map(&:id),
- remove_label_ids: remove_labels.map(&:id)
- }
- end
+ let(:bug) { create(:label, project: project) }
+ let(:regression) { create(:label, project: project) }
+ let(:merge_requests) { create(:label, project: project) }
- before do
- bulk_update(issues, bulk_update_params)
- end
+ let(:issue_all_labels) { create_issue_with_labels([bug, regression, merge_requests]) }
+ let(:issue_bug_and_regression) { create_issue_with_labels([bug, regression]) }
+ let(:issue_bug_and_merge_requests) { create_issue_with_labels([bug, merge_requests]) }
+ let(:issue_no_labels) { create(:issue, project: project) }
+ let(:issues) { [issue_all_labels, issue_bug_and_regression, issue_bug_and_merge_requests, issue_no_labels] }
- context 'when label_ids are passed' do
- let(:issues) { [issue_all_labels, issue_no_labels] }
- let(:labels) { [bug, regression] }
+ let(:labels) { [] }
+ let(:add_labels) { [] }
+ let(:remove_labels) { [] }
- it 'updates the labels of all issues passed to the labels passed' do
- expect(issues.map(&:reload).map(&:label_ids)).to all(match_array(labels.map(&:id)))
+ let(:bulk_update_params) do
+ {
+ label_ids: labels.map(&:id),
+ add_label_ids: add_labels.map(&:id),
+ remove_label_ids: remove_labels.map(&:id)
+ }
end
- it 'does not update issues not passed in' do
- expect(issue_bug_and_regression.label_ids).to contain_exactly(bug.id, regression.id)
+ before do
+ bulk_update(issues, bulk_update_params)
end
- context 'when those label IDs are empty' do
- let(:labels) { [] }
+ context 'when label_ids are passed' do
+ let(:issues) { [issue_all_labels, issue_no_labels] }
+ let(:labels) { [bug, regression] }
- it 'updates the issues passed to have no labels' do
- expect(issues.map(&:reload).map(&:label_ids)).to all(be_empty)
+ it 'updates the labels of all issues passed to the labels passed' do
+ expect(issues.map(&:reload).map(&:label_ids)).to all(match_array(labels.map(&:id)))
end
- end
- end
- context 'when add_label_ids are passed' do
- let(:issues) { [issue_all_labels, issue_bug_and_merge_requests, issue_no_labels] }
- let(:add_labels) { [bug, regression, merge_requests] }
+ it 'does not update issues not passed in' do
+ expect(issue_bug_and_regression.label_ids).to contain_exactly(bug.id, regression.id)
+ end
- it 'adds those label IDs to all issues passed' do
- expect(issues.map(&:reload).map(&:label_ids)).to all(include(*add_labels.map(&:id)))
- end
+ context 'when those label IDs are empty' do
+ let(:labels) { [] }
- it 'does not update issues not passed in' do
- expect(issue_bug_and_regression.label_ids).to contain_exactly(bug.id, regression.id)
+ it 'updates the issues passed to have no labels' do
+ expect(issues.map(&:reload).map(&:label_ids)).to all(be_empty)
+ end
+ end
end
- end
- context 'when remove_label_ids are passed' do
- let(:issues) { [issue_all_labels, issue_bug_and_merge_requests, issue_no_labels] }
- let(:remove_labels) { [bug, regression, merge_requests] }
+ context 'when add_label_ids are passed' do
+ let(:issues) { [issue_all_labels, issue_bug_and_merge_requests, issue_no_labels] }
+ let(:add_labels) { [bug, regression, merge_requests] }
- it 'removes those label IDs from all issues passed' do
- expect(issues.map(&:reload).map(&:label_ids)).to all(be_empty)
- end
+ it 'adds those label IDs to all issues passed' do
+ expect(issues.map(&:reload).map(&:label_ids)).to all(include(*add_labels.map(&:id)))
+ end
- it 'does not update issues not passed in' do
- expect(issue_bug_and_regression.label_ids).to contain_exactly(bug.id, regression.id)
+ it 'does not update issues not passed in' do
+ expect(issue_bug_and_regression.label_ids).to contain_exactly(bug.id, regression.id)
+ end
end
- end
- context 'when add_label_ids and remove_label_ids are passed' do
- let(:issues) { [issue_all_labels, issue_bug_and_merge_requests, issue_no_labels] }
- let(:add_labels) { [bug] }
- let(:remove_labels) { [merge_requests] }
+ context 'when remove_label_ids are passed' do
+ let(:issues) { [issue_all_labels, issue_bug_and_merge_requests, issue_no_labels] }
+ let(:remove_labels) { [bug, regression, merge_requests] }
- it 'adds the label IDs to all issues passed' do
- expect(issues.map(&:reload).map(&:label_ids)).to all(include(bug.id))
- end
+ it 'removes those label IDs from all issues passed' do
+ expect(issues.map(&:reload).map(&:label_ids)).to all(be_empty)
+ end
- it 'removes the label IDs from all issues passed' do
- expect(issues.map(&:reload).map(&:label_ids).flatten).not_to include(merge_requests.id)
+ it 'does not update issues not passed in' do
+ expect(issue_bug_and_regression.label_ids).to contain_exactly(bug.id, regression.id)
+ end
end
- it 'does not update issues not passed in' do
- expect(issue_bug_and_regression.label_ids).to contain_exactly(bug.id, regression.id)
- end
- end
+ context 'when add_label_ids and remove_label_ids are passed' do
+ let(:issues) { [issue_all_labels, issue_bug_and_merge_requests, issue_no_labels] }
+ let(:add_labels) { [bug] }
+ let(:remove_labels) { [merge_requests] }
- context 'when add_label_ids and label_ids are passed' do
- let(:issues) { [issue_all_labels, issue_bug_and_regression, issue_bug_and_merge_requests] }
- let(:labels) { [merge_requests] }
- let(:add_labels) { [regression] }
+ it 'adds the label IDs to all issues passed' do
+ expect(issues.map(&:reload).map(&:label_ids)).to all(include(bug.id))
+ end
- it 'adds the label IDs to all issues passed' do
- expect(issues.map(&:reload).map(&:label_ids)).to all(include(regression.id))
- end
+ it 'removes the label IDs from all issues passed' do
+ expect(issues.map(&:reload).map(&:label_ids).flatten).not_to include(merge_requests.id)
+ end
- it 'ignores the label IDs parameter' do
- expect(issues.map(&:reload).map(&:label_ids)).to all(include(bug.id))
+ it 'does not update issues not passed in' do
+ expect(issue_bug_and_regression.label_ids).to contain_exactly(bug.id, regression.id)
+ end
end
- it 'does not update issues not passed in' do
- expect(issue_no_labels.label_ids).to be_empty
- end
- end
+ context 'when add_label_ids and label_ids are passed' do
+ let(:issues) { [issue_all_labels, issue_bug_and_regression, issue_bug_and_merge_requests] }
+ let(:labels) { [merge_requests] }
+ let(:add_labels) { [regression] }
- context 'when remove_label_ids and label_ids are passed' do
- let(:issues) { [issue_no_labels, issue_bug_and_regression] }
- let(:labels) { [merge_requests] }
- let(:remove_labels) { [regression] }
+ it 'adds the label IDs to all issues passed' do
+ expect(issues.map(&:reload).map(&:label_ids)).to all(include(regression.id))
+ end
- it 'removes the label IDs from all issues passed' do
- expect(issues.map(&:reload).map(&:label_ids).flatten).not_to include(regression.id)
- end
+ it 'ignores the label IDs parameter' do
+ expect(issues.map(&:reload).map(&:label_ids)).to all(include(bug.id))
+ end
- it 'ignores the label IDs parameter' do
- expect(issues.map(&:reload).map(&:label_ids).flatten).not_to include(merge_requests.id)
+ it 'does not update issues not passed in' do
+ expect(issue_no_labels.label_ids).to be_empty
+ end
end
- it 'does not update issues not passed in' do
- expect(issue_all_labels.label_ids).to contain_exactly(bug.id, regression.id, merge_requests.id)
- end
- end
+ context 'when remove_label_ids and label_ids are passed' do
+ let(:issues) { [issue_no_labels, issue_bug_and_regression] }
+ let(:labels) { [merge_requests] }
+ let(:remove_labels) { [regression] }
- context 'when add_label_ids, remove_label_ids, and label_ids are passed' do
- let(:issues) { [issue_bug_and_merge_requests, issue_no_labels] }
- let(:labels) { [regression] }
- let(:add_labels) { [bug] }
- let(:remove_labels) { [merge_requests] }
+ it 'removes the label IDs from all issues passed' do
+ expect(issues.map(&:reload).map(&:label_ids).flatten).not_to include(regression.id)
+ end
- it 'adds the label IDs to all issues passed' do
- expect(issues.map(&:reload).map(&:label_ids)).to all(include(bug.id))
- end
+ it 'ignores the label IDs parameter' do
+ expect(issues.map(&:reload).map(&:label_ids).flatten).not_to include(merge_requests.id)
+ end
- it 'removes the label IDs from all issues passed' do
- expect(issues.map(&:reload).map(&:label_ids).flatten).not_to include(merge_requests.id)
+ it 'does not update issues not passed in' do
+ expect(issue_all_labels.label_ids).to contain_exactly(bug.id, regression.id, merge_requests.id)
+ end
end
- it 'ignores the label IDs parameter' do
- expect(issues.map(&:reload).map(&:label_ids).flatten).not_to include(regression.id)
- end
+ context 'when add_label_ids, remove_label_ids, and label_ids are passed' do
+ let(:issues) { [issue_bug_and_merge_requests, issue_no_labels] }
+ let(:labels) { [regression] }
+ let(:add_labels) { [bug] }
+ let(:remove_labels) { [merge_requests] }
- it 'does not update issues not passed in' do
- expect(issue_bug_and_regression.label_ids).to contain_exactly(bug.id, regression.id)
+ it 'adds the label IDs to all issues passed' do
+ expect(issues.map(&:reload).map(&:label_ids)).to all(include(bug.id))
+ end
+
+ it 'removes the label IDs from all issues passed' do
+ expect(issues.map(&:reload).map(&:label_ids).flatten).not_to include(merge_requests.id)
+ end
+
+ it 'ignores the label IDs parameter' do
+ expect(issues.map(&:reload).map(&:label_ids).flatten).not_to include(regression.id)
+ end
+
+ it 'does not update issues not passed in' do
+ expect(issue_bug_and_regression.label_ids).to contain_exactly(bug.id, regression.id)
+ end
end
end
- end
- describe 'subscribe to issues' do
- let(:issues) { create_list(:issue, 2, project: project) }
+ describe 'subscribe to issues' do
+ let(:issues) { create_list(:issue, 2, project: project) }
- it 'subscribes the given user' do
- bulk_update(issues, subscription_event: 'subscribe')
+ it 'subscribes the given user' do
+ bulk_update(issues, subscription_event: 'subscribe')
- expect(issues).to all(be_subscribed(user, project))
+ expect(issues).to all(be_subscribed(user, project))
+ end
end
- end
- describe 'unsubscribe from issues' do
- let(:issues) do
- create_list(:closed_issue, 2, project: project) do |issue|
- issue.subscriptions.create(user: user, project: project, subscribed: true)
+ describe 'unsubscribe from issues' do
+ let(:issues) do
+ create_list(:closed_issue, 2, project: project) do |issue|
+ issue.subscriptions.create(user: user, project: project, subscribed: true)
+ end
+ end
+
+ it 'unsubscribes the given user' do
+ bulk_update(issues, subscription_event: 'unsubscribe')
+
+ issues.each do |issue|
+ expect(issue).not_to be_subscribed(user, project)
+ end
end
end
+ end
- it 'unsubscribes the given user' do
- bulk_update(issues, subscription_event: 'unsubscribe')
+ context 'with group issues' do
+ let(:group) { create(:group) }
- issues.each do |issue|
- expect(issue).not_to be_subscribed(user, project)
+ context 'updating milestone' do
+ let(:milestone) { create(:milestone, group: group) }
+ let(:project1) { create(:project, :repository, group: group) }
+ let(:project2) { create(:project, :repository, group: group) }
+ let(:issue1) { create(:issue, project: project1) }
+ let(:issue2) { create(:issue, project: project2) }
+ let(:issues) { [issue1, issue2] }
+
+ before do
+ group.add_maintainer(user)
end
+
+ it_behaves_like 'updates milestones'
end
end
end
diff --git a/spec/services/issues/update_service_spec.rb b/spec/services/issues/update_service_spec.rb
index 28fa5d12d9c..468e7c286d5 100644
--- a/spec/services/issues/update_service_spec.rb
+++ b/spec/services/issues/update_service_spec.rb
@@ -480,6 +480,22 @@ describe Issues::UpdateService, :mailer do
update_issue(description: "- [x] Task 1\n- [X] Task 2")
end
+ it 'does not check for spam on task status change' do
+ params = {
+ update_task: {
+ index: 1,
+ checked: false,
+ line_source: '- [x] Task 1',
+ line_number: 1
+ }
+ }
+ service = described_class.new(project, user, params)
+
+ expect(service).not_to receive(:spam_check)
+
+ service.execute(issue)
+ end
+
it 'creates system note about task status change' do
note1 = find_note('marked the task **Task 1** as completed')
note2 = find_note('marked the task **Task 2** as completed')
diff --git a/spec/services/merge_requests/create_from_issue_service_spec.rb b/spec/services/merge_requests/create_from_issue_service_spec.rb
index a0ac7dba89d..0e0da6a13ab 100644
--- a/spec/services/merge_requests/create_from_issue_service_spec.rb
+++ b/spec/services/merge_requests/create_from_issue_service_spec.rb
@@ -3,6 +3,8 @@
require 'spec_helper'
describe MergeRequests::CreateFromIssueService do
+ include ProjectForksHelper
+
let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
let(:label_ids) { create_pair(:label, project: project).map(&:id) }
@@ -10,139 +12,174 @@ describe MergeRequests::CreateFromIssueService do
let(:issue) { create(:issue, project: project, milestone_id: milestone_id) }
let(:custom_source_branch) { 'custom-source-branch' }
- subject(:service) { described_class.new(project, user, issue_iid: issue.iid) }
- subject(:service_with_custom_source_branch) { described_class.new(project, user, issue_iid: issue.iid, branch_name: custom_source_branch) }
+ subject(:service) { described_class.new(project, user, service_params) }
+ subject(:service_with_custom_source_branch) { described_class.new(project, user, branch_name: custom_source_branch, **service_params) }
before do
project.add_developer(user)
end
describe '#execute' do
- it 'returns an error with invalid issue iid' do
- result = described_class.new(project, user, issue_iid: -1).execute
+ shared_examples_for 'a service that creates a merge request from an issue' do
+ it 'returns an error when user can not create merge request on target project' do
+ result = described_class.new(project, create(:user), service_params).execute
- expect(result[:status]).to eq(:error)
- expect(result[:message]).to eq('Invalid issue iid')
- end
+ expect(result[:status]).to eq(:error)
+ expect(result[:message]).to eq('Not allowed to create merge request')
+ end
- it 'delegates issue search to IssuesFinder' do
- expect_any_instance_of(IssuesFinder).to receive(:find_by).once.and_call_original
+ it 'returns an error with invalid issue iid' do
+ result = described_class.new(project, user, issue_iid: -1).execute
- described_class.new(project, user, issue_iid: -1).execute
- end
-
- it "inherits labels" do
- issue.assign_attributes(label_ids: label_ids)
+ expect(result[:status]).to eq(:error)
+ expect(result[:message]).to eq('Invalid issue iid')
+ end
- result = service.execute
+ it 'creates a branch based on issue title' do
+ service.execute
- expect(result[:merge_request].label_ids).to eq(label_ids)
- end
+ expect(target_project.repository.branch_exists?(issue.to_branch_name)).to be_truthy
+ end
- it "inherits milestones" do
- result = service.execute
+ it 'creates a branch using passed name' do
+ service_with_custom_source_branch.execute
- expect(result[:merge_request].milestone_id).to eq(milestone_id)
- end
+ expect(target_project.repository.branch_exists?(custom_source_branch)).to be_truthy
+ end
- it 'delegates the branch creation to CreateBranchService' do
- expect_any_instance_of(CreateBranchService).to receive(:execute).once.and_call_original
+ it 'creates the new_merge_request system note' do
+ expect(SystemNoteService).to receive(:new_merge_request).with(issue, project, user, instance_of(MergeRequest))
- service.execute
- end
+ service.execute
+ end
- it 'creates a branch based on issue title' do
- service.execute
+ it 'creates the new_issue_branch system note when the branch could be created but the merge_request cannot be created' do
+ expect_any_instance_of(MergeRequest).to receive(:valid?).at_least(:once).and_return(false)
- expect(project.repository.branch_exists?(issue.to_branch_name)).to be_truthy
- end
+ expect(SystemNoteService).to receive(:new_issue_branch).with(issue, project, user, issue.to_branch_name, branch_project: target_project)
- it 'creates a branch using passed name' do
- service_with_custom_source_branch.execute
+ service.execute
+ end
- expect(project.repository.branch_exists?(custom_source_branch)).to be_truthy
- end
+ it 'creates a merge request' do
+ expect { service.execute }.to change(target_project.merge_requests, :count).by(1)
+ end
- it 'creates the new_merge_request system note' do
- expect(SystemNoteService).to receive(:new_merge_request).with(issue, project, user, instance_of(MergeRequest))
+ it 'sets the merge request author to current user' do
+ result = service.execute
- service.execute
- end
+ expect(result[:merge_request].author).to eq(user)
+ end
- it 'creates the new_issue_branch system note when the branch could be created but the merge_request cannot be created' do
- project.project_feature.update!(merge_requests_access_level: ProjectFeature::DISABLED)
+ it 'sets the merge request source branch to the new issue branch' do
+ result = service.execute
- expect(SystemNoteService).to receive(:new_issue_branch).with(issue, project, user, issue.to_branch_name)
+ expect(result[:merge_request].source_branch).to eq(issue.to_branch_name)
+ end
- service.execute
- end
+ it 'sets the merge request source branch to the passed branch name' do
+ result = service_with_custom_source_branch.execute
- it 'creates a merge request' do
- expect { service.execute }.to change(project.merge_requests, :count).by(1)
- end
+ expect(result[:merge_request].source_branch).to eq(custom_source_branch)
+ end
- it 'sets the merge request title to: "WIP: Resolves "$issue-title"' do
- result = service.execute
+ it 'sets the merge request target branch to the project default branch' do
+ result = service.execute
- expect(result[:merge_request].title).to eq("WIP: Resolve \"#{issue.title}\"")
- end
+ expect(result[:merge_request].target_branch).to eq(target_project.default_branch)
+ end
- it 'sets the merge request author to current user' do
- result = service.execute
+ it 'executes quick actions if the build service sets them in the description' do
+ allow(service).to receive(:merge_request).and_wrap_original do |m, *args|
+ m.call(*args).tap do |merge_request|
+ merge_request.description = "/assign #{user.to_reference}"
+ end
+ end
- expect(result[:merge_request].author).to eq(user)
- end
+ result = service.execute
- it 'sets the merge request source branch to the new issue branch' do
- result = service.execute
+ expect(result[:merge_request].assignees).to eq([user])
+ end
- expect(result[:merge_request].source_branch).to eq(issue.to_branch_name)
- end
+ context 'when ref branch is set' do
+ subject { described_class.new(project, user, ref: 'feature', **service_params).execute }
- it 'sets the merge request source branch to the passed branch name' do
- result = service_with_custom_source_branch.execute
+ it 'sets the merge request source branch to the new issue branch' do
+ expect(subject[:merge_request].source_branch).to eq(issue.to_branch_name)
+ end
- expect(result[:merge_request].source_branch).to eq(custom_source_branch)
- end
+ it 'sets the merge request target branch to the ref branch' do
+ expect(subject[:merge_request].target_branch).to eq('feature')
+ end
- it 'sets the merge request target branch to the project default branch' do
- result = service.execute
+ context 'when ref branch does not exist' do
+ subject { described_class.new(project, user, ref: 'no-such-branch', **service_params).execute }
- expect(result[:merge_request].target_branch).to eq(project.default_branch)
- end
+ it 'creates a merge request' do
+ expect { subject }.to change(target_project.merge_requests, :count).by(1)
+ end
- it 'executes quick actions if the build service sets them in the description' do
- allow(service).to receive(:merge_request).and_wrap_original do |m, *args|
- m.call(*args).tap do |merge_request|
- merge_request.description = "/assign #{user.to_reference}"
+ it 'sets the merge request target branch to the project default branch' do
+ expect(subject[:merge_request].target_branch).to eq(target_project.default_branch)
+ end
end
end
+ end
- result = service.execute
+ context 'no target_project_id specified' do
+ let(:service_params) { { issue_iid: issue.iid } }
+ let(:target_project) { project }
- expect(result[:merge_request].assignees).to eq([user])
- end
+ it_behaves_like 'a service that creates a merge request from an issue'
- context 'when ref branch is set' do
- subject { described_class.new(project, user, issue_iid: issue.iid, ref: 'feature').execute }
+ it "inherits labels" do
+ issue.assign_attributes(label_ids: label_ids)
- it 'sets the merge request source branch to the new issue branch' do
- expect(subject[:merge_request].source_branch).to eq(issue.to_branch_name)
+ result = service.execute
+
+ expect(result[:merge_request].label_ids).to eq(label_ids)
end
- it 'sets the merge request target branch to the ref branch' do
- expect(subject[:merge_request].target_branch).to eq('feature')
+ it "inherits milestones" do
+ result = service.execute
+
+ expect(result[:merge_request].milestone_id).to eq(milestone_id)
end
- context 'when ref branch does not exist' do
- subject { described_class.new(project, user, issue_iid: issue.iid, ref: 'no-such-branch').execute }
+ it 'sets the merge request title to: "WIP: Resolves "$issue-title"' do
+ result = service.execute
- it 'creates a merge request' do
- expect { subject }.to change(project.merge_requests, :count).by(1)
+ expect(result[:merge_request].title).to eq("WIP: Resolve \"#{issue.title}\"")
+ end
+ end
+
+ context 'target_project_id is specified' do
+ let(:service_params) { { issue_iid: issue.iid, target_project_id: target_project.id } }
+
+ context 'target project is not a fork of the project' do
+ let(:target_project) { create(:project, :repository) }
+
+ it 'returns an error about not finding the project' do
+ result = service.execute
+
+ expect(result[:status]).to eq(:error)
+ expect(result[:message]).to eq('Project not found')
end
- it 'sets the merge request target branch to the project default branch' do
- expect(subject[:merge_request].target_branch).to eq(project.default_branch)
+ it 'does not create merge request' do
+ expect { service.execute }.to change(target_project.merge_requests, :count).by(0)
+ end
+ end
+
+ context 'target project is a fork of project project' do
+ let(:target_project) { fork_project(project, user, repository: true) }
+
+ it_behaves_like 'a service that creates a merge request from an issue'
+
+ it 'sets the merge request title to: "WIP: $issue-branch-name' do
+ result = service.execute
+
+ expect(result[:merge_request].title).to eq("WIP: #{issue.to_branch_name.titleize.humanize}")
end
end
end
diff --git a/spec/services/merge_requests/merge_to_ref_service_spec.rb b/spec/services/merge_requests/merge_to_ref_service_spec.rb
index 61f99f82a76..14012b4ea2d 100644
--- a/spec/services/merge_requests/merge_to_ref_service_spec.rb
+++ b/spec/services/merge_requests/merge_to_ref_service_spec.rb
@@ -22,7 +22,6 @@ describe MergeRequests::MergeToRefService do
shared_examples_for 'successfully merges to ref with merge method' do
it 'writes commit to merge ref' do
repository = project.repository
- target_ref = merge_request.merge_ref_path
expect(repository.ref_exists?(target_ref)).to be(false)
@@ -33,7 +32,7 @@ describe MergeRequests::MergeToRefService do
expect(result[:status]).to eq(:success)
expect(result[:commit_id]).to be_present
expect(result[:source_id]).to eq(merge_request.source_branch_sha)
- expect(result[:target_id]).to eq(merge_request.target_branch_sha)
+ expect(result[:target_id]).to eq(repository.commit(first_parent_ref).sha)
expect(repository.ref_exists?(target_ref)).to be(true)
expect(ref_head.id).to eq(result[:commit_id])
end
@@ -74,17 +73,22 @@ describe MergeRequests::MergeToRefService do
describe '#execute' do
let(:service) do
- described_class.new(project, user, commit_message: 'Awesome message',
- should_remove_source_branch: true)
+ described_class.new(project, user, **params)
end
+ let(:params) { { commit_message: 'Awesome message', should_remove_source_branch: true } }
+
def process_merge_to_ref
perform_enqueued_jobs do
service.execute(merge_request)
end
end
- it_behaves_like 'successfully merges to ref with merge method'
+ it_behaves_like 'successfully merges to ref with merge method' do
+ let(:first_parent_ref) { 'refs/heads/master' }
+ let(:target_ref) { merge_request.merge_ref_path }
+ end
+
it_behaves_like 'successfully evaluates pre-condition checks'
context 'commit history comparison with regular MergeService' do
@@ -129,14 +133,22 @@ describe MergeRequests::MergeToRefService do
context 'when semi-linear merge method' do
let(:merge_method) { :rebase_merge }
- it_behaves_like 'successfully merges to ref with merge method'
+ it_behaves_like 'successfully merges to ref with merge method' do
+ let(:first_parent_ref) { 'refs/heads/master' }
+ let(:target_ref) { merge_request.merge_ref_path }
+ end
+
it_behaves_like 'successfully evaluates pre-condition checks'
end
context 'when fast-forward merge method' do
let(:merge_method) { :ff }
- it_behaves_like 'successfully merges to ref with merge method'
+ it_behaves_like 'successfully merges to ref with merge method' do
+ let(:first_parent_ref) { 'refs/heads/master' }
+ let(:target_ref) { merge_request.merge_ref_path }
+ end
+
it_behaves_like 'successfully evaluates pre-condition checks'
end
@@ -178,5 +190,43 @@ describe MergeRequests::MergeToRefService do
it { expect(todo).not_to be_done }
end
+
+ context 'when target ref is passed as a parameter' do
+ let(:params) { { commit_message: 'merge train', target_ref: target_ref } }
+
+ it_behaves_like 'successfully merges to ref with merge method' do
+ let(:first_parent_ref) { 'refs/heads/master' }
+ let(:target_ref) { 'refs/merge-requests/1/train' }
+ end
+ end
+
+ describe 'cascading merge refs' do
+ set(:project) { create(:project, :repository) }
+ let(:params) { { commit_message: 'Cascading merge', first_parent_ref: first_parent_ref, target_ref: target_ref } }
+
+ context 'when first merge happens' do
+ let(:merge_request) do
+ create(:merge_request, source_project: project, source_branch: 'feature',
+ target_project: project, target_branch: 'master')
+ end
+
+ it_behaves_like 'successfully merges to ref with merge method' do
+ let(:first_parent_ref) { 'refs/heads/master' }
+ let(:target_ref) { 'refs/merge-requests/1/train' }
+ end
+
+ context 'when second merge happens' do
+ let(:merge_request) do
+ create(:merge_request, source_project: project, source_branch: 'improve/awesome',
+ target_project: project, target_branch: 'master')
+ end
+
+ it_behaves_like 'successfully merges to ref with merge method' do
+ let(:first_parent_ref) { 'refs/merge-requests/1/train' }
+ let(:target_ref) { 'refs/merge-requests/2/train' }
+ end
+ end
+ end
+ end
end
end
diff --git a/spec/services/merge_requests/rebase_service_spec.rb b/spec/services/merge_requests/rebase_service_spec.rb
index 7e2f03d1097..ee9caaf2f47 100644
--- a/spec/services/merge_requests/rebase_service_spec.rb
+++ b/spec/services/merge_requests/rebase_service_spec.rb
@@ -6,10 +6,12 @@ describe MergeRequests::RebaseService do
include ProjectForksHelper
let(:user) { create(:user) }
+ let(:rebase_jid) { 'fake-rebase-jid' }
let(:merge_request) do
- create(:merge_request,
+ create :merge_request,
source_branch: 'feature_conflict',
- target_branch: 'master')
+ target_branch: 'master',
+ rebase_jid: rebase_jid
end
let(:project) { merge_request.project }
let(:repository) { project.repository.raw }
@@ -23,11 +25,11 @@ describe MergeRequests::RebaseService do
describe '#execute' do
context 'when another rebase is already in progress' do
before do
- allow(merge_request).to receive(:rebase_in_progress?).and_return(true)
+ allow(merge_request).to receive(:gitaly_rebase_in_progress?).and_return(true)
end
it 'saves the error message' do
- subject.execute(merge_request)
+ service.execute(merge_request)
expect(merge_request.reload.merge_error).to eq 'Rebase task canceled: Another rebase is already in progress'
end
@@ -36,6 +38,13 @@ describe MergeRequests::RebaseService do
expect(service.execute(merge_request)).to match(status: :error,
message: described_class::REBASE_ERROR)
end
+
+ it 'clears rebase_jid' do
+ expect { service.execute(merge_request) }
+ .to change { merge_request.rebase_jid }
+ .from(rebase_jid)
+ .to(nil)
+ end
end
shared_examples 'sequence of failure and success' do
@@ -43,14 +52,19 @@ describe MergeRequests::RebaseService do
allow(repository).to receive(:gitaly_operation_client).and_raise('Something went wrong')
service.execute(merge_request)
+ merge_request.reload
- expect(merge_request.reload.merge_error).to eq described_class::REBASE_ERROR
+ expect(merge_request.reload.merge_error).to eq(described_class::REBASE_ERROR)
+ expect(merge_request.rebase_jid).to eq(nil)
allow(repository).to receive(:gitaly_operation_client).and_call_original
+ merge_request.update!(rebase_jid: rebase_jid)
service.execute(merge_request)
+ merge_request.reload
- expect(merge_request.reload.merge_error).to eq nil
+ expect(merge_request.merge_error).to eq(nil)
+ expect(merge_request.rebase_jid).to eq(nil)
end
end
@@ -72,7 +86,7 @@ describe MergeRequests::RebaseService do
it 'saves a generic error message' do
subject.execute(merge_request)
- expect(merge_request.reload.merge_error).to eq described_class::REBASE_ERROR
+ expect(merge_request.reload.merge_error).to eq(described_class::REBASE_ERROR)
end
it 'returns an error' do
diff --git a/spec/services/namespaces/statistics_refresher_service_spec.rb b/spec/services/namespaces/statistics_refresher_service_spec.rb
new file mode 100644
index 00000000000..f4d9c96f7f4
--- /dev/null
+++ b/spec/services/namespaces/statistics_refresher_service_spec.rb
@@ -0,0 +1,58 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Namespaces::StatisticsRefresherService, '#execute' do
+ let(:group) { create(:group) }
+ let(:projects) { create_list(:project, 5, namespace: group) }
+ let(:service) { described_class.new }
+
+ context 'without a root storage statistics relation' do
+ it 'creates one' do
+ expect do
+ service.execute(group)
+ end.to change(Namespace::RootStorageStatistics, :count).by(1)
+
+ expect(group.reload.root_storage_statistics).to be_present
+ end
+
+ it 'recalculate the namespace statistics' do
+ expect_any_instance_of(Namespace::RootStorageStatistics).to receive(:recalculate!).once
+
+ service.execute(group)
+ end
+ end
+
+ context 'with a root storage statistics relation' do
+ before do
+ Namespace::AggregationSchedule.safe_find_or_create_by!(namespace_id: group.id)
+ end
+
+ it 'does not create one' do
+ expect do
+ service.execute(group)
+ end.not_to change(Namespace::RootStorageStatistics, :count)
+ end
+
+ it 'recalculate the namespace statistics' do
+ expect(Namespace::RootStorageStatistics)
+ .to receive(:safe_find_or_create_by!).with({ namespace_id: group.id })
+ .and_return(group.root_storage_statistics)
+
+ service.execute(group)
+ end
+ end
+
+ context 'when something goes wrong' do
+ before do
+ allow_any_instance_of(Namespace::RootStorageStatistics)
+ .to receive(:recalculate!).and_raise(ActiveRecord::ActiveRecordError)
+ end
+
+ it 'raises RefreshError' do
+ expect do
+ service.execute(group)
+ end.to raise_error(Namespaces::StatisticsRefresherService::RefresherError)
+ end
+ end
+end
diff --git a/spec/services/system_note_service_spec.rb b/spec/services/system_note_service_spec.rb
index 93fe3290d8b..157cfc46e69 100644
--- a/spec/services/system_note_service_spec.rb
+++ b/spec/services/system_note_service_spec.rb
@@ -332,7 +332,7 @@ describe SystemNoteService do
create(:merge_request, source_project: project, target_project: project)
end
- subject { described_class.merge_when_pipeline_succeeds(noteable, project, author, noteable.diff_head_commit) }
+ subject { described_class.merge_when_pipeline_succeeds(noteable, project, author, pipeline.sha) }
it_behaves_like 'a system note' do
let(:action) { 'merge' }
@@ -359,6 +359,22 @@ describe SystemNoteService do
end
end
+ describe '.abort_merge_when_pipeline_succeeds' do
+ let(:noteable) do
+ create(:merge_request, source_project: project, target_project: project)
+ end
+
+ subject { described_class.abort_merge_when_pipeline_succeeds(noteable, project, author, 'merge request was closed') }
+
+ it_behaves_like 'a system note' do
+ let(:action) { 'merge' }
+ end
+
+ it "posts the 'merge when pipeline succeeds' system note" do
+ expect(subject.note).to eq "aborted the automatic merge because merge request was closed"
+ end
+ end
+
describe '.change_title' do
let(:noteable) { create(:issue, project: project, title: 'Lorem ipsum') }
@@ -454,16 +470,32 @@ describe SystemNoteService do
end
describe '.new_issue_branch' do
- subject { described_class.new_issue_branch(noteable, project, author, "1-mepmep") }
+ let(:branch) { '1-mepmep' }
- it_behaves_like 'a system note' do
- let(:action) { 'branch' }
- end
+ subject { described_class.new_issue_branch(noteable, project, author, branch, branch_project: branch_project) }
- context 'when a branch is created from the new branch button' do
- it 'sets the note text' do
- expect(subject.note).to start_with("created branch [`1-mepmep`]")
+ shared_examples_for 'a system note for new issue branch' do
+ it_behaves_like 'a system note' do
+ let(:action) { 'branch' }
end
+
+ context 'when a branch is created from the new branch button' do
+ it 'sets the note text' do
+ expect(subject.note).to start_with("created branch [`#{branch}`]")
+ end
+ end
+ end
+
+ context 'branch_project is set' do
+ let(:branch_project) { create(:project, :repository) }
+
+ it_behaves_like 'a system note for new issue branch'
+ end
+
+ context 'branch_project is not set' do
+ let(:branch_project) { nil }
+
+ it_behaves_like 'a system note for new issue branch'
end
end
@@ -477,7 +509,7 @@ describe SystemNoteService do
end
it 'sets the new merge request note text' do
- expect(subject.note).to eq("created merge request #{merge_request.to_reference} to address this issue")
+ expect(subject.note).to eq("created merge request #{merge_request.to_reference(project)} to address this issue")
end
end
@@ -1132,7 +1164,7 @@ describe SystemNoteService do
end
it 'sets the note text' do
- expect(subject.note).to eq 'resolved all discussions'
+ expect(subject.note).to eq 'resolved all threads'
end
end
@@ -1159,16 +1191,30 @@ describe SystemNoteService do
end
it 'links to the diff in the system note' do
- expect(subject.note).to include('version 1')
-
diff_id = merge_request.merge_request_diff.id
line_code = change_position.line_code(project.repository)
- expect(subject.note).to include(diffs_project_merge_request_path(project, merge_request, diff_id: diff_id, anchor: line_code))
+ link = diffs_project_merge_request_path(project, merge_request, diff_id: diff_id, anchor: line_code)
+
+ expect(subject.note).to eq("changed this line in [version 1 of the diff](#{link})")
+ end
+
+ context 'discussion is on an image' do
+ let(:discussion) { create(:image_diff_note_on_merge_request, project: project).to_discussion }
+
+ it 'links to the diff in the system note' do
+ diff_id = merge_request.merge_request_diff.id
+ file_hash = change_position.file_hash
+ link = diffs_project_merge_request_path(project, merge_request, diff_id: diff_id, anchor: file_hash)
+
+ expect(subject.note).to eq("changed this file in [version 1 of the diff](#{link})")
+ end
end
end
- context 'when the change_position is invalid for the discussion' do
- let(:change_position) { project.commit(sample_commit.id) }
+ context 'when the change_position does not point to a valid version' do
+ before do
+ allow(merge_request).to receive(:version_params_for).and_return(nil)
+ end
it 'creates a new note in the discussion' do
# we need to completely rebuild the merge request object, or the `@discussions` on the merge request are not reloaded.
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index 3bd2408dc72..62fdc039b5e 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -139,6 +139,8 @@ RSpec.configure do |config|
allow(Feature).to receive(:enabled?)
.with(:force_autodevops_on_by_default, anything)
.and_return(false)
+
+ Gitlab::ThreadMemoryCache.cache_backend.clear
end
config.around(:example, :quarantine) do
diff --git a/spec/support/features/discussion_comments_shared_example.rb b/spec/support/features/discussion_comments_shared_example.rb
index 0f8af2c5d6d..7c8e57702ae 100644
--- a/spec/support/features/discussion_comments_shared_example.rb
+++ b/spec/support/features/discussion_comments_shared_example.rb
@@ -1,4 +1,4 @@
-shared_examples 'discussion comments' do |resource_name|
+shared_examples 'thread comments' do |resource_name|
let(:form_selector) { '.js-main-target-form' }
let(:dropdown_selector) { "#{form_selector} .comment-type-dropdown" }
let(:toggle_selector) { "#{dropdown_selector} .dropdown-toggle" }
@@ -48,7 +48,7 @@ shared_examples 'discussion comments' do |resource_name|
find(toggle_selector).click
end
- it 'has a "Comment" item (selected by default) and "Start discussion" item' do
+ it 'has a "Comment" item (selected by default) and "Start thread" item' do
expect(page).to have_selector menu_selector
find("#{menu_selector} li", match: :first)
@@ -59,7 +59,7 @@ shared_examples 'discussion comments' do |resource_name|
expect(items.first).to have_selector '.fa-check'
expect(items.first['class']).to match 'droplab-item-selected'
- expect(items.last).to have_content 'Start discussion'
+ expect(items.last).to have_content 'Start thread'
expect(items.last).to have_content "Discuss a specific suggestion or question#{' that needs to be resolved' if resource_name == 'merge request'}."
expect(items.last).not_to have_selector '.fa-check'
expect(items.last['class']).not_to match 'droplab-item-selected'
@@ -103,7 +103,7 @@ shared_examples 'discussion comments' do |resource_name|
expect(find(dropdown_selector)).to have_content 'Comment'
end
- describe 'when selecting "Start discussion"' do
+ describe 'when selecting "Start thread"' do
before do
find("#{menu_selector} li", match: :first)
all("#{menu_selector} li").last.click
@@ -114,9 +114,9 @@ shared_examples 'discussion comments' do |resource_name|
# on issues page, the submit input is a <button>, on other pages it is <input>
if button.tag_name == 'button'
- expect(find(submit_selector)).to have_content 'Start discussion'
+ expect(find(submit_selector)).to have_content 'Start thread'
else
- expect(find(submit_selector).value).to eq 'Start discussion'
+ expect(find(submit_selector).value).to eq 'Start thread'
end
expect(page).not_to have_selector menu_selector
@@ -124,17 +124,17 @@ shared_examples 'discussion comments' do |resource_name|
if resource_name =~ /(issue|merge request)/
it 'updates the close button text' do
- expect(find(close_selector)).to have_content "Start discussion & close #{resource_name}"
+ expect(find(close_selector)).to have_content "Start thread & close #{resource_name}"
end
it 'typing does not change the close button text' do
find("#{form_selector} .note-textarea").send_keys('b')
- expect(find(close_selector)).to have_content "Start discussion & close #{resource_name}"
+ expect(find(close_selector)).to have_content "Start thread & close #{resource_name}"
end
end
- describe 'creating a discussion' do
+ describe 'creating a thread' do
before do
find(submit_selector).click
wait_for_requests
@@ -150,7 +150,7 @@ shared_examples 'discussion comments' do |resource_name|
wait_for_requests
end
- it 'clicking "Start discussion" will post a discussion' do
+ it 'clicking "Start thread" will post a thread' do
new_comment = all(comments_selector).last
expect(new_comment).to have_content 'a'
@@ -176,10 +176,10 @@ shared_examples 'discussion comments' do |resource_name|
if resource_name == 'merge request'
let(:note_id) { find("#{comments_selector} .note:first-child", match: :first)['data-note-id'] }
- let(:reply_id) { find("#{comments_selector} .note:last-child", match: :first)['data-note-id'] }
+ let(:reply_id) { find("#{comments_selector} .note:last-of-type", match: :first)['data-note-id'] }
it 'can be replied to after resolving' do
- click_button "Resolve discussion"
+ click_button "Resolve thread"
wait_for_requests
refresh
@@ -188,10 +188,10 @@ shared_examples 'discussion comments' do |resource_name|
submit_reply('to reply or not reply')
end
- it 'shows resolved discussion when toggled' do
+ it 'shows resolved thread when toggled' do
submit_reply('a')
- click_button "Resolve discussion"
+ click_button "Resolve thread"
wait_for_requests
expect(page).to have_selector(".note-row-#{note_id}", visible: true)
@@ -205,7 +205,7 @@ shared_examples 'discussion comments' do |resource_name|
end
if resource_name == 'issue'
- it "clicking 'Start discussion & close #{resource_name}' will post a discussion and close the #{resource_name}" do
+ it "clicking 'Start thread & close #{resource_name}' will post a thread and close the #{resource_name}" do
find(close_selector).click
find(comments_selector, match: :first)
@@ -224,7 +224,7 @@ shared_examples 'discussion comments' do |resource_name|
find(toggle_selector).click
end
- it 'has "Start discussion" selected' do
+ it 'has "Start thread" selected' do
find("#{menu_selector} li", match: :first)
items = all("#{menu_selector} li")
@@ -232,7 +232,7 @@ shared_examples 'discussion comments' do |resource_name|
expect(items.first).not_to have_selector '.fa-check'
expect(items.first['class']).not_to match 'droplab-item-selected'
- expect(items.last).to have_content 'Start discussion'
+ expect(items.last).to have_content 'Start thread'
expect(items.last).to have_selector '.fa-check'
expect(items.last['class']).to match 'droplab-item-selected'
end
@@ -277,7 +277,7 @@ shared_examples 'discussion comments' do |resource_name|
expect(items.first).to have_selector '.fa-check'
expect(items.first['class']).to match 'droplab-item-selected'
- expect(items.last).to have_content 'Start discussion'
+ expect(items.last).to have_content 'Start thread'
expect(items.last).not_to have_selector '.fa-check'
expect(items.last['class']).not_to match 'droplab-item-selected'
end
@@ -299,13 +299,13 @@ shared_examples 'discussion comments' do |resource_name|
expect(find("#{form_selector} .js-note-target-reopen")).to have_content "Comment & reopen #{resource_name}"
end
- it "should show a 'Start discussion & reopen #{resource_name}' button when 'Start discussion' is selected" do
+ it "should show a 'Start thread & reopen #{resource_name}' button when 'Start thread' is selected" do
find(toggle_selector).click
find("#{menu_selector} li", match: :first)
all("#{menu_selector} li").last.click
- expect(find("#{form_selector} .js-note-target-reopen")).to have_content "Start discussion & reopen #{resource_name}"
+ expect(find("#{form_selector} .js-note-target-reopen")).to have_content "Start thread & reopen #{resource_name}"
end
end
end
diff --git a/spec/support/features/resolving_discussions_in_issues_shared_examples.rb b/spec/support/features/resolving_discussions_in_issues_shared_examples.rb
index 38e5fb155a4..8d0e03134d0 100644
--- a/spec/support/features/resolving_discussions_in_issues_shared_examples.rb
+++ b/spec/support/features/resolving_discussions_in_issues_shared_examples.rb
@@ -1,4 +1,4 @@
-shared_examples 'creating an issue for a discussion' do
+shared_examples 'creating an issue for a thread' do
it 'shows an issue with the title filled in' do
title_field = page.find_field('issue[title]')
diff --git a/spec/support/helpers/devise_helpers.rb b/spec/support/helpers/devise_helpers.rb
index d32bc2424c0..fb2a110422a 100644
--- a/spec/support/helpers/devise_helpers.rb
+++ b/spec/support/helpers/devise_helpers.rb
@@ -21,4 +21,16 @@ module DeviseHelpers
context.env
end
end
+
+ def with_omniauth_full_host(&block)
+ # The OmniAuth `full_host` parameter doesn't get set correctly (it gets set to something like `http://localhost`
+ # here), and causes integration tests to fail with 404s. We set the `full_host` by removing the request path (and
+ # anything after it) from the request URI.
+ omniauth_config_full_host = OmniAuth.config.full_host
+ OmniAuth.config.full_host = ->(request) { ActionDispatch::Request.new(request).base_url }
+
+ yield
+
+ OmniAuth.config.full_host = omniauth_config_full_host
+ end
end
diff --git a/spec/support/helpers/email_helpers.rb b/spec/support/helpers/email_helpers.rb
index a7175491fa0..ed049daba80 100644
--- a/spec/support/helpers/email_helpers.rb
+++ b/spec/support/helpers/email_helpers.rb
@@ -37,19 +37,8 @@ module EmailHelpers
ActionMailer::Base.deliveries.find { |d| d.to.include?(user.notification_email) }
end
- def have_referable_subject(referable, include_project: true, include_group: false, reply: false)
- context = []
-
- context << referable.project.name if include_project && referable.project
- context << referable.project.group.name if include_group && referable.project.group
-
- prefix =
- if context.any?
- context.join(' | ') + ' | '
- else
- ''
- end
-
+ def have_referable_subject(referable, include_project: true, reply: false)
+ prefix = (include_project && referable.project ? "#{referable.project.name} | " : '').freeze
prefix = "Re: #{prefix}" if reply
suffix = "#{referable.title} (#{referable.to_reference})"
diff --git a/spec/support/helpers/fake_u2f_device.rb b/spec/support/helpers/fake_u2f_device.rb
index a7605cd483a..22cd8152d77 100644
--- a/spec/support/helpers/fake_u2f_device.rb
+++ b/spec/support/helpers/fake_u2f_device.rb
@@ -32,6 +32,10 @@ class FakeU2fDevice
")
end
+ def fake_u2f_authentication
+ @page.execute_script("window.gl.u2fAuthenticate.renderAuthenticated('abc');")
+ end
+
private
def u2f_device(app_id)
diff --git a/spec/support/helpers/git_http_helpers.rb b/spec/support/helpers/git_http_helpers.rb
index cd49bb148f2..c83860d7b51 100644
--- a/spec/support/helpers/git_http_helpers.rb
+++ b/spec/support/helpers/git_http_helpers.rb
@@ -1,4 +1,8 @@
+require_relative 'workhorse_helpers'
+
module GitHttpHelpers
+ include WorkhorseHelpers
+
def clone_get(project, options = {})
get "/#{project}/info/refs", params: { service: 'git-upload-pack' }, headers: auth_env(*options.values_at(:user, :password, :spnego_request_token))
end
diff --git a/spec/support/helpers/login_helpers.rb b/spec/support/helpers/login_helpers.rb
index 0bb2d2510c2..0cb99b4e087 100644
--- a/spec/support/helpers/login_helpers.rb
+++ b/spec/support/helpers/login_helpers.rb
@@ -87,12 +87,17 @@ module LoginHelpers
click_link "oauth-login-#{provider}"
end
+ def fake_successful_u2f_authentication
+ allow(U2fRegistration).to receive(:authenticate).and_return(true)
+ FakeU2fDevice.new(page, nil).fake_u2f_authentication
+ end
+
def mock_auth_hash_with_saml_xml(provider, uid, email, saml_response)
response_object = { document: saml_xml(saml_response) }
mock_auth_hash(provider, uid, email, response_object: response_object)
end
- def mock_auth_hash(provider, uid, email, response_object: nil)
+ def configure_mock_auth(provider, uid, email, response_object: nil)
# The mock_auth configuration allows you to set per-provider (or default)
# authentication hashes to return during integration testing.
OmniAuth.config.mock_auth[provider.to_sym] = OmniAuth::AuthHash.new({
@@ -118,6 +123,11 @@ module LoginHelpers
response_object: response_object
}
})
+ end
+
+ def mock_auth_hash(provider, uid, email, response_object: nil)
+ configure_mock_auth(provider, uid, email, response_object: response_object)
+
original_env_config_omniauth_auth = Rails.application.env_config['omniauth.auth']
Rails.application.env_config['omniauth.auth'] = OmniAuth.config.mock_auth[provider.to_sym]
diff --git a/spec/support/helpers/position_tracer_helpers.rb b/spec/support/helpers/position_tracer_helpers.rb
new file mode 100644
index 00000000000..bbf6e06dd40
--- /dev/null
+++ b/spec/support/helpers/position_tracer_helpers.rb
@@ -0,0 +1,93 @@
+# frozen_string_literal: true
+
+module PositionTracerHelpers
+ def diff_refs(base_commit, head_commit)
+ Gitlab::Diff::DiffRefs.new(base_sha: base_commit.id, head_sha: head_commit.id)
+ end
+
+ def position(attrs = {})
+ attrs.reverse_merge!(
+ diff_refs: old_diff_refs
+ )
+ Gitlab::Diff::Position.new(attrs)
+ end
+
+ def expect_new_position(attrs, result = subject)
+ aggregate_failures("expect new position #{attrs.inspect}") do
+ if attrs.nil?
+ expect(result[:outdated]).to be_truthy
+ else
+ new_position = result[:position]
+
+ expect(result[:outdated]).to be_falsey
+ expect(new_position).not_to be_nil
+ expect(new_position.diff_refs).to eq(new_diff_refs)
+
+ attrs.each do |attr, value|
+ expect(new_position.send(attr)).to eq(value)
+ end
+ end
+ end
+ end
+
+ def expect_change_position(attrs, result = subject)
+ aggregate_failures("expect change position #{attrs.inspect}") do
+ change_position = result[:position]
+
+ expect(result[:outdated]).to be_truthy
+
+ if attrs.nil? || attrs.empty?
+ expect(change_position).to be_nil
+ else
+ expect(change_position).not_to be_nil
+ expect(change_position.diff_refs).to eq(change_diff_refs)
+
+ attrs.each do |attr, value|
+ expect(change_position.send(attr)).to eq(value)
+ end
+ end
+ end
+ end
+
+ def create_branch(new_name, branch_name)
+ CreateBranchService.new(project, current_user).execute(new_name, branch_name)
+ end
+
+ def create_file(branch_name, file_name, content)
+ Files::CreateService.new(
+ project,
+ current_user,
+ start_branch: branch_name,
+ branch_name: branch_name,
+ commit_message: "Create file",
+ file_path: file_name,
+ file_content: content
+ ).execute
+ project.commit(branch_name)
+ end
+
+ def update_file(branch_name, file_name, content)
+ Files::UpdateService.new(
+ project,
+ current_user,
+ start_branch: branch_name,
+ branch_name: branch_name,
+ commit_message: "Update file",
+ file_path: file_name,
+ file_content: content
+ ).execute
+ project.commit(branch_name)
+ end
+
+ def delete_file(branch_name, file_name)
+ Files::DeleteService.new(
+ project,
+ current_user,
+ start_branch: branch_name,
+ branch_name: branch_name,
+ commit_message: "Delete file",
+ file_path: file_name
+ ).execute
+ project.commit(branch_name)
+ end
+end
diff --git a/spec/support/helpers/reactive_caching_helpers.rb b/spec/support/helpers/reactive_caching_helpers.rb
index b76b53db0b9..528da37e8cf 100644
--- a/spec/support/helpers/reactive_caching_helpers.rb
+++ b/spec/support/helpers/reactive_caching_helpers.rb
@@ -10,7 +10,7 @@ module ReactiveCachingHelpers
def stub_reactive_cache(subject = nil, data = nil, *qualifiers)
allow(ReactiveCachingWorker).to receive(:perform_async)
allow(ReactiveCachingWorker).to receive(:perform_in)
- write_reactive_cache(subject, data, *qualifiers) unless data.nil?
+ write_reactive_cache(subject, data, *qualifiers) unless subject.nil?
end
def synchronous_reactive_cache(subject)
diff --git a/spec/support/matchers/gitaly_matchers.rb b/spec/support/matchers/gitaly_matchers.rb
index ebfabcd8f24..933ed22b5d0 100644
--- a/spec/support/matchers/gitaly_matchers.rb
+++ b/spec/support/matchers/gitaly_matchers.rb
@@ -9,6 +9,6 @@ end
RSpec::Matchers.define :gitaly_request_with_params do |params|
match do |actual|
- params.reduce(true) { |r, (key, val)| r && actual.send(key) == val }
+ params.reduce(true) { |r, (key, val)| r && actual[key.to_s] == val }
end
end
diff --git a/spec/support/shared_examples/features/comments_on_merge_request_files_shared_examples.rb b/spec/support/shared_examples/features/comments_on_merge_request_files_shared_examples.rb
index 221926aaf7e..2b36955a3c4 100644
--- a/spec/support/shared_examples/features/comments_on_merge_request_files_shared_examples.rb
+++ b/spec/support/shared_examples/features/comments_on_merge_request_files_shared_examples.rb
@@ -16,7 +16,7 @@ shared_examples 'comment on merge request file' do
visit(merge_request_path(merge_request))
page.within('.notes .discussion') do
- expect(page).to have_content("#{user.name} #{user.to_reference} started a discussion")
+ expect(page).to have_content("#{user.name} #{user.to_reference} started a thread")
expect(page).to have_content(sample_commit.line_code_path)
expect(page).to have_content('Line is wrong')
end
diff --git a/spec/support/shared_examples/models/services_fields_shared_examples.rb b/spec/support/shared_examples/models/services_fields_shared_examples.rb
new file mode 100644
index 00000000000..6fbd0da9383
--- /dev/null
+++ b/spec/support/shared_examples/models/services_fields_shared_examples.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+shared_examples 'issue tracker fields' do
+ let(:title) { 'custom title' }
+ let(:description) { 'custom description' }
+ let(:url) { 'http://issue_tracker.example.com' }
+
+ context 'when data are stored in the properties' do
+ describe '#update' do
+ before do
+ service.update(title: 'new_title', description: 'new description')
+ end
+
+ it 'removes title and description from properties' do
+ expect(service.reload.properties).not_to include('title', 'description')
+ end
+
+ it 'stores title & description in services table' do
+ expect(service.read_attribute(:title)).to eq('new_title')
+ expect(service.read_attribute(:description)).to eq('new description')
+ end
+ end
+
+ describe 'reading fields' do
+ it 'returns correct values' do
+ expect(service.title).to eq(title)
+ expect(service.description).to eq(description)
+ end
+ end
+ end
+end
diff --git a/spec/support/shared_examples/models/update_project_statistics_shared_examples.rb b/spec/support/shared_examples/models/update_project_statistics_shared_examples.rb
index 1b09c3dd636..aad63982e7a 100644
--- a/spec/support/shared_examples/models/update_project_statistics_shared_examples.rb
+++ b/spec/support/shared_examples/models/update_project_statistics_shared_examples.rb
@@ -25,16 +25,36 @@ shared_examples_for 'UpdateProjectStatistics' do
.to change { reload_stat }
.by(delta)
end
+
+ it 'schedules a namespace statistics worker' do
+ expect(Namespaces::ScheduleAggregationWorker)
+ .to receive(:perform_async).once
+
+ subject.save!
+ end
+
+ context 'when feature flag is disabled for the namespace' do
+ it 'does not schedules a namespace statistics worker' do
+ namespace = subject.project.root_ancestor
+
+ stub_feature_flags(update_statistics_namespace: false, namespace: namespace)
+
+ expect(Namespaces::ScheduleAggregationWorker)
+ .not_to receive(:perform_async)
+
+ subject.save!
+ end
+ end
end
context 'when updating' do
+ let(:delta) { 42 }
+
before do
subject.save!
end
it 'updates project statistics' do
- delta = 42
-
expect(ProjectStatistics)
.to receive(:increment_statistic)
.and_call_original
@@ -45,6 +65,42 @@ shared_examples_for 'UpdateProjectStatistics' do
.to change { reload_stat }
.by(delta)
end
+
+ it 'schedules a namespace statistics worker' do
+ expect(Namespaces::ScheduleAggregationWorker)
+ .to receive(:perform_async).once
+
+ subject.write_attribute(statistic_attribute, read_attribute + delta)
+ subject.save!
+ end
+
+ it 'avoids N + 1 queries' do
+ subject.write_attribute(statistic_attribute, read_attribute + delta)
+
+ control_count = ActiveRecord::QueryRecorder.new do
+ subject.save!
+ end
+
+ subject.write_attribute(statistic_attribute, read_attribute + delta)
+
+ expect do
+ subject.save!
+ end.not_to exceed_query_limit(control_count)
+ end
+
+ context 'when the feature flag is disabled for the namespace' do
+ it 'does not schedule a namespace statistics worker' do
+ namespace = subject.project.root_ancestor
+
+ stub_feature_flags(update_statistics_namespace: false, namespace: namespace)
+
+ expect(Namespaces::ScheduleAggregationWorker)
+ .not_to receive(:perform_async)
+
+ subject.write_attribute(statistic_attribute, read_attribute + delta)
+ subject.save!
+ end
+ end
end
context 'when destroying' do
@@ -59,11 +115,18 @@ shared_examples_for 'UpdateProjectStatistics' do
.to receive(:increment_statistic)
.and_call_original
- expect { subject.destroy }
+ expect { subject.destroy! }
.to change { reload_stat }
.by(delta)
end
+ it 'schedules a namespace statistics worker' do
+ expect(Namespaces::ScheduleAggregationWorker)
+ .to receive(:perform_async).once
+
+ subject.destroy!
+ end
+
context 'when it is destroyed from the project level' do
it 'does not update the project statistics' do
expect(ProjectStatistics)
@@ -72,6 +135,27 @@ shared_examples_for 'UpdateProjectStatistics' do
project.update(pending_delete: true)
project.destroy!
end
+
+ it 'does not schedule a namespace statistics worker' do
+ expect(Namespaces::ScheduleAggregationWorker)
+ .not_to receive(:perform_async)
+
+ project.update(pending_delete: true)
+ project.destroy!
+ end
+ end
+
+ context 'when feature flag is disabled for the namespace' do
+ it 'does not schedule a namespace statistics worker' do
+ namespace = subject.project.root_ancestor
+
+ stub_feature_flags(update_statistics_namespace: false, namespace: namespace)
+
+ expect(Namespaces::ScheduleAggregationWorker)
+ .not_to receive(:perform_async)
+
+ subject.destroy!
+ end
end
end
end
diff --git a/spec/support/shared_examples/requests/api/issues/merge_requests_count_shared_examples.rb b/spec/support/shared_examples/requests/api/issues/merge_requests_count_shared_examples.rb
new file mode 100644
index 00000000000..5f4e178f2e5
--- /dev/null
+++ b/spec/support/shared_examples/requests/api/issues/merge_requests_count_shared_examples.rb
@@ -0,0 +1,37 @@
+def get_issue
+ json_response.is_a?(Array) ? json_response.detect {|issue| issue['id'] == target_issue.id} : json_response
+end
+
+shared_examples 'accessible merge requests count' do
+ it 'returns anonymous accessible merge requests count' do
+ get api(api_url), params: { scope: 'all' }
+
+ issue = get_issue
+ expect(issue).not_to be_nil
+ expect(issue['merge_requests_count']).to eq(1)
+ end
+
+ it 'returns guest accessible merge requests count' do
+ get api(api_url, guest), params: { scope: 'all' }
+
+ issue = get_issue
+ expect(issue).not_to be_nil
+ expect(issue['merge_requests_count']).to eq(1)
+ end
+
+ it 'returns reporter accessible merge requests count' do
+ get api(api_url, user), params: { scope: 'all' }
+
+ issue = get_issue
+ expect(issue).not_to be_nil
+ expect(issue['merge_requests_count']).to eq(2)
+ end
+
+ it 'returns admin accessible merge requests count' do
+ get api(api_url, admin), params: { scope: 'all' }
+
+ issue = get_issue
+ expect(issue).not_to be_nil
+ expect(issue['merge_requests_count']).to eq(2)
+ end
+end
diff --git a/spec/support/test_reports/test_reports_helper.rb b/spec/support/test_reports/test_reports_helper.rb
index 45c6e04dbf3..6840fb9a860 100644
--- a/spec/support/test_reports/test_reports_helper.rb
+++ b/spec/support/test_reports/test_reports_helper.rb
@@ -1,36 +1,36 @@
module TestReportsHelper
- def create_test_case_rspec_success
+ def create_test_case_rspec_success(name = 'test_spec')
Gitlab::Ci::Reports::TestCase.new(
name: 'Test#sum when a is 1 and b is 3 returns summary',
- classname: 'spec.test_spec',
+ classname: "spec.#{name}",
file: './spec/test_spec.rb',
execution_time: 1.11,
status: Gitlab::Ci::Reports::TestCase::STATUS_SUCCESS)
end
- def create_test_case_rspec_failed
+ def create_test_case_rspec_failed(name = 'test_spec')
Gitlab::Ci::Reports::TestCase.new(
- name: 'Test#sum when a is 2 and b is 2 returns summary',
- classname: 'spec.test_spec',
+ name: 'Test#sum when a is 1 and b is 3 returns summary',
+ classname: "spec.#{name}",
file: './spec/test_spec.rb',
execution_time: 2.22,
system_output: sample_rspec_failed_message,
status: Gitlab::Ci::Reports::TestCase::STATUS_FAILED)
end
- def create_test_case_rspec_skipped
+ def create_test_case_rspec_skipped(name = 'test_spec')
Gitlab::Ci::Reports::TestCase.new(
name: 'Test#sum when a is 3 and b is 3 returns summary',
- classname: 'spec.test_spec',
+ classname: "spec.#{name}",
file: './spec/test_spec.rb',
execution_time: 3.33,
status: Gitlab::Ci::Reports::TestCase::STATUS_SKIPPED)
end
- def create_test_case_rspec_error
+ def create_test_case_rspec_error(name = 'test_spec')
Gitlab::Ci::Reports::TestCase.new(
name: 'Test#sum when a is 4 and b is 4 returns summary',
- classname: 'spec.test_spec',
+ classname: "spec.#{name}",
file: './spec/test_spec.rb',
execution_time: 4.44,
status: Gitlab::Ci::Reports::TestCase::STATUS_ERROR)
@@ -48,34 +48,34 @@ module TestReportsHelper
EOF
end
- def create_test_case_java_success
+ def create_test_case_java_success(name = 'addTest')
Gitlab::Ci::Reports::TestCase.new(
- name: 'addTest',
+ name: name,
classname: 'CalculatorTest',
execution_time: 5.55,
status: Gitlab::Ci::Reports::TestCase::STATUS_SUCCESS)
end
- def create_test_case_java_failed
+ def create_test_case_java_failed(name = 'addTest')
Gitlab::Ci::Reports::TestCase.new(
- name: 'subtractTest',
+ name: name,
classname: 'CalculatorTest',
execution_time: 6.66,
system_output: sample_java_failed_message,
status: Gitlab::Ci::Reports::TestCase::STATUS_FAILED)
end
- def create_test_case_java_skipped
+ def create_test_case_java_skipped(name = 'addTest')
Gitlab::Ci::Reports::TestCase.new(
- name: 'multiplyTest',
+ name: name,
classname: 'CalculatorTest',
execution_time: 7.77,
status: Gitlab::Ci::Reports::TestCase::STATUS_SKIPPED)
end
- def create_test_case_java_error
+ def create_test_case_java_error(name = 'addTest')
Gitlab::Ci::Reports::TestCase.new(
- name: 'divideTest',
+ name: name,
classname: 'CalculatorTest',
execution_time: 8.88,
status: Gitlab::Ci::Reports::TestCase::STATUS_ERROR)
diff --git a/spec/tasks/migrate/schema_check_rake_spec.rb b/spec/tasks/migrate/schema_check_rake_spec.rb
index 72fb1363dfb..1097a43cd8a 100644
--- a/spec/tasks/migrate/schema_check_rake_spec.rb
+++ b/spec/tasks/migrate/schema_check_rake_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
require 'rake'
-describe 'schema_version_check rake task', :quarantine do
+describe 'schema_version_check rake task' do
include StubENV
before :all do
@@ -15,8 +15,6 @@ describe 'schema_version_check rake task', :quarantine do
end
before do
- # Stub out db tasks
- allow(ActiveRecord::Tasks::DatabaseTasks).to receive(:migrate).and_return(true)
allow(ActiveRecord::Migrator).to receive(:current_version).and_return(Gitlab::Database::MIN_SCHEMA_VERSION)
# Ensure our check can re-run each time
@@ -24,23 +22,23 @@ describe 'schema_version_check rake task', :quarantine do
end
it 'allows migrations on databases meeting the min schema version requirement' do
- expect { run_rake_task('db:migrate') }.not_to raise_error
+ expect { run_rake_task('schema_version_check') }.not_to raise_error
end
it 'raises an error when schema version is too old to migrate' do
allow(ActiveRecord::Migrator).to receive(:current_version).and_return(25)
- expect { run_rake_task('db:migrate') }.to raise_error(RuntimeError, /current database version is too old to be migrated/)
+ expect { run_rake_task('schema_version_check') }.to raise_error(RuntimeError, /current database version is too old to be migrated/)
end
it 'skips running validation when passed the skip env variable' do
stub_env('SKIP_SCHEMA_VERSION_CHECK', 'true')
allow(ActiveRecord::Migrator).to receive(:current_version).and_return(25)
- expect { run_rake_task('db:migrate') }.not_to raise_error
+ expect { run_rake_task('schema_version_check') }.not_to raise_error
end
it 'allows migrations on fresh databases' do
allow(ActiveRecord::Migrator).to receive(:current_version).and_return(0)
- expect { run_rake_task('db:migrate') }.not_to raise_error
+ expect { run_rake_task('schema_version_check') }.not_to raise_error
end
def run_rake_task(task_name)
diff --git a/spec/uploaders/file_mover_spec.rb b/spec/uploaders/file_mover_spec.rb
index e474a714b10..5ee0a10f38d 100644
--- a/spec/uploaders/file_mover_spec.rb
+++ b/spec/uploaders/file_mover_spec.rb
@@ -3,79 +3,139 @@ require 'spec_helper'
describe FileMover do
include FileMoverHelpers
+ let(:user) { create(:user) }
let(:filename) { 'banana_sample.gif' }
- let(:temp_file_path) { File.join('uploads/-/system/temp', 'secret55', filename) }
+ let(:secret) { 'secret55' }
+ let(:temp_file_path) { File.join("uploads/-/system/user/#{user.id}", secret, filename) }
let(:temp_description) do
"test ![banana_sample](/#{temp_file_path}) "\
"same ![banana_sample](/#{temp_file_path}) "
end
- let(:file_path) { File.join('uploads/-/system/personal_snippet', snippet.id.to_s, 'secret55', filename) }
+ let(:file_path) { File.join('uploads/-/system/personal_snippet', snippet.id.to_s, secret, filename) }
let(:snippet) { create(:personal_snippet, description: temp_description) }
- subject { described_class.new(temp_file_path, snippet).execute }
+ let(:tmp_uploader) do
+ PersonalFileUploader.new(user, secret: secret)
+ end
+
+ let(:file) { fixture_file_upload('spec/fixtures/banana_sample.gif') }
+ subject { described_class.new(temp_file_path, from_model: user, to_model: snippet).execute }
describe '#execute' do
- before do
- expect(FileUtils).to receive(:mkdir_p).with(a_string_including(File.dirname(file_path)))
- expect(FileUtils).to receive(:move).with(a_string_including(temp_file_path), a_string_including(file_path))
- allow_any_instance_of(CarrierWave::SanitizedFile).to receive(:exists?).and_return(true)
- allow_any_instance_of(CarrierWave::SanitizedFile).to receive(:size).and_return(10)
+ let(:tmp_upload) { tmp_uploader.upload }
- stub_file_mover(temp_file_path)
+ before do
+ tmp_uploader.store!(file)
end
- context 'when move and field update successful' do
- it 'updates the description correctly' do
- subject
+ context 'local storage' do
+ before do
+ allow(FileUtils).to receive(:mkdir_p).with(a_string_including(File.dirname(file_path)))
+ allow(FileUtils).to receive(:move).with(a_string_including(temp_file_path), a_string_including(file_path))
+ allow_any_instance_of(CarrierWave::SanitizedFile).to receive(:exists?).and_return(true)
+ allow_any_instance_of(CarrierWave::SanitizedFile).to receive(:size).and_return(10)
- expect(snippet.reload.description)
- .to eq(
- "test ![banana_sample](/uploads/-/system/personal_snippet/#{snippet.id}/secret55/banana_sample.gif) "\
- "same ![banana_sample](/uploads/-/system/personal_snippet/#{snippet.id}/secret55/banana_sample.gif) "
- )
+ stub_file_mover(temp_file_path)
end
- it 'creates a new update record' do
- expect { subject }.to change { Upload.count }.by(1)
+ context 'when move and field update successful' do
+ it 'updates the description correctly' do
+ subject
+
+ expect(snippet.reload.description)
+ .to eq("test ![banana_sample](/uploads/-/system/personal_snippet/#{snippet.id}/secret55/banana_sample.gif) "\
+ "same ![banana_sample](/uploads/-/system/personal_snippet/#{snippet.id}/secret55/banana_sample.gif) ")
+ end
+
+ it 'updates existing upload record' do
+ expect { subject }
+ .to change { tmp_upload.reload.attributes.values_at('model_id', 'model_type') }
+ .from([user.id, 'User']).to([snippet.id, 'Snippet'])
+ end
+
+ it 'schedules a background migration' do
+ expect_any_instance_of(PersonalFileUploader).to receive(:schedule_background_upload).once
+
+ subject
+ end
end
- it 'schedules a background migration' do
- expect_any_instance_of(PersonalFileUploader).to receive(:schedule_background_upload).once
+ context 'when update_markdown fails' do
+ before do
+ expect(FileUtils).to receive(:move).with(a_string_including(file_path), a_string_including(temp_file_path))
+ end
- subject
+ subject { described_class.new(file_path, :non_existing_field, from_model: user, to_model: snippet).execute }
+
+ it 'does not update the description' do
+ subject
+
+ expect(snippet.reload.description)
+ .to eq("test ![banana_sample](/uploads/-/system/user/#{user.id}/secret55/banana_sample.gif) "\
+ "same ![banana_sample](/uploads/-/system/user/#{user.id}/secret55/banana_sample.gif) ")
+ end
+
+ it 'does not change the upload record' do
+ expect { subject }
+ .not_to change { tmp_upload.reload.attributes.values_at('model_id', 'model_type') }
+ end
end
end
- context 'when update_markdown fails' do
+ context 'when tmp uploader is not local storage' do
before do
- expect(FileUtils).to receive(:move).with(a_string_including(file_path), a_string_including(temp_file_path))
+ stub_uploads_object_storage(uploader: PersonalFileUploader)
+ allow_any_instance_of(PersonalFileUploader).to receive(:file_storage?) { false }
end
- subject { described_class.new(file_path, snippet, :non_existing_field).execute }
+ after do
+ FileUtils.rm_f(File.join('personal_snippet', snippet.id.to_s, secret, filename))
+ end
- it 'does not update the description' do
- subject
+ context 'when move and field update successful' do
+ it 'updates the description correctly' do
+ subject
- expect(snippet.reload.description)
- .to eq(
- "test ![banana_sample](/uploads/-/system/temp/secret55/banana_sample.gif) "\
- "same ![banana_sample](/uploads/-/system/temp/secret55/banana_sample.gif) "
- )
+ expect(snippet.reload.description)
+ .to eq("test ![banana_sample](/uploads/-/system/personal_snippet/#{snippet.id}/secret55/banana_sample.gif) "\
+ "same ![banana_sample](/uploads/-/system/personal_snippet/#{snippet.id}/secret55/banana_sample.gif) ")
+ end
+
+ it 'creates new target upload record an delete the old upload' do
+ expect { subject }
+ .to change { Upload.last.attributes.values_at('model_id', 'model_type') }
+ .from([user.id, 'User']).to([snippet.id, 'Snippet'])
+
+ expect(Upload.count).to eq(1)
+ end
end
- it 'does not create a new update record' do
- expect { subject }.not_to change { Upload.count }
+ context 'when update_markdown fails' do
+ subject { described_class.new(file_path, :non_existing_field, from_model: user, to_model: snippet).execute }
+
+ it 'does not update the description' do
+ subject
+
+ expect(snippet.reload.description)
+ .to eq("test ![banana_sample](/uploads/-/system/user/#{user.id}/secret55/banana_sample.gif) "\
+ "same ![banana_sample](/uploads/-/system/user/#{user.id}/secret55/banana_sample.gif) ")
+ end
+
+ it 'does not change the upload record' do
+ expect { subject }
+ .to change { Upload.last.attributes.values_at('model_id', 'model_type') }.from([user.id, 'User'])
+ end
end
end
end
context 'security' do
context 'when relative path is involved' do
- let(:temp_file_path) { File.join('uploads/-/system/temp', '..', 'another_subdir_of_temp') }
+ let(:temp_file_path) { File.join("uploads/-/system/user/#{user.id}", '..', 'another_subdir_of_temp') }
it 'does not trigger move if path is outside designated directory' do
- stub_file_mover('uploads/-/system/another_subdir_of_temp')
+ stub_file_mover("uploads/-/system/user/#{user.id}/another_subdir_of_temp")
expect(FileUtils).not_to receive(:move)
subject
diff --git a/spec/uploaders/file_uploader_spec.rb b/spec/uploaders/file_uploader_spec.rb
index 185c62491ce..04206de3dc6 100644
--- a/spec/uploaders/file_uploader_spec.rb
+++ b/spec/uploaders/file_uploader_spec.rb
@@ -184,40 +184,37 @@ describe FileUploader do
end
end
- describe '#cache!' do
- subject do
- uploader.store!(uploaded_file)
- end
+ context 'when remote file is used' do
+ let(:temp_file) { Tempfile.new("test") }
- context 'when remote file is used' do
- let(:temp_file) { Tempfile.new("test") }
+ let!(:fog_connection) do
+ stub_uploads_object_storage(described_class)
+ end
- let!(:fog_connection) do
- stub_uploads_object_storage(described_class)
- end
+ let(:filename) { "my file.txt" }
+ let(:uploaded_file) do
+ UploadedFile.new(temp_file.path, filename: filename, remote_id: "test/123123")
+ end
- let(:uploaded_file) do
- UploadedFile.new(temp_file.path, filename: "my file.txt", remote_id: "test/123123")
- end
+ let!(:fog_file) do
+ fog_connection.directories.new(key: 'uploads').files.create(
+ key: 'tmp/uploads/test/123123',
+ body: 'content'
+ )
+ end
- let!(:fog_file) do
- fog_connection.directories.new(key: 'uploads').files.create(
- key: 'tmp/uploads/test/123123',
- body: 'content'
- )
- end
+ before do
+ FileUtils.touch(temp_file)
- before do
- FileUtils.touch(temp_file)
- end
+ uploader.store!(uploaded_file)
+ end
- after do
- FileUtils.rm_f(temp_file)
- end
+ after do
+ FileUtils.rm_f(temp_file)
+ end
+ describe '#cache!' do
it 'file is stored remotely in permament location with sanitized name' do
- subject
-
expect(uploader).to be_exists
expect(uploader).not_to be_cached
expect(uploader).not_to be_file_storage
@@ -228,5 +225,18 @@ describe FileUploader do
expect(uploader.object_store).to eq(described_class::Store::REMOTE)
end
end
+
+ describe '#to_h' do
+ subject { uploader.to_h }
+
+ let(:filename) { 'my+file.txt' }
+
+ it 'generates URL using original file name instead of filename returned by object storage' do
+ # GCS returns a URL with a `+` instead of `%2B`
+ allow(uploader.file).to receive(:url).and_return('https://storage.googleapis.com/gitlab-test-uploads/@hashed/6b/86/6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b/64c5065e62100b1a12841644256a98be/my+file.txt')
+
+ expect(subject[:url]).to end_with(filename)
+ end
+ end
end
end
diff --git a/spec/validators/color_validator_spec.rb b/spec/validators/color_validator_spec.rb
new file mode 100644
index 00000000000..e5a38ac9372
--- /dev/null
+++ b/spec/validators/color_validator_spec.rb
@@ -0,0 +1,43 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe ColorValidator do
+ using RSpec::Parameterized::TableSyntax
+
+ subject do
+ Class.new do
+ include ActiveModel::Model
+ include ActiveModel::Validations
+ attr_accessor :color
+ validates :color, color: true
+ end.new
+ end
+
+ where(:color, :is_valid) do
+ '#000abc' | true
+ '#aaa' | true
+ '#BBB' | true
+ '#cCc' | true
+ '#ffff' | false
+ '#000111222' | false
+ 'invalid' | false
+ '000' | false
+ end
+
+ with_them do
+ it 'only accepts valid colors' do
+ subject.color = color
+
+ expect(subject.valid?).to eq(is_valid)
+ end
+ end
+
+ it 'fails fast for long invalid string' do
+ subject.color = '#' + ('0' * 50_000) + 'xxx'
+
+ expect do
+ Timeout.timeout(5.seconds) { subject.valid? }
+ end.not_to raise_error
+ end
+end
diff --git a/spec/workers/namespaces/prune_aggregation_schedules_worker_spec.rb b/spec/workers/namespaces/prune_aggregation_schedules_worker_spec.rb
new file mode 100644
index 00000000000..b069b080531
--- /dev/null
+++ b/spec/workers/namespaces/prune_aggregation_schedules_worker_spec.rb
@@ -0,0 +1,35 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Namespaces::PruneAggregationSchedulesWorker, '#perform', :clean_gitlab_redis_shared_state do
+ include ExclusiveLeaseHelpers
+
+ let(:namespaces) { create_list(:namespace, 5, :with_aggregation_schedule) }
+ let(:timeout) { Namespace::AggregationSchedule::DEFAULT_LEASE_TIMEOUT }
+
+ subject(:worker) { described_class.new }
+
+ before do
+ allow(Namespaces::RootStatisticsWorker)
+ .to receive(:perform_async).and_return(nil)
+
+ allow(Namespaces::RootStatisticsWorker)
+ .to receive(:perform_in).and_return(nil)
+
+ namespaces.each do |namespace|
+ lease_key = "namespace:namespaces_root_statistics:#{namespace.id}"
+ stub_exclusive_lease(lease_key, timeout: timeout)
+ end
+ end
+
+ it 'schedules a worker per pending aggregation' do
+ expect(Namespaces::RootStatisticsWorker)
+ .to receive(:perform_async).exactly(5).times
+
+ expect(Namespaces::RootStatisticsWorker)
+ .to receive(:perform_in).exactly(5).times
+
+ worker.perform
+ end
+end
diff --git a/spec/workers/namespaces/root_statistics_worker_spec.rb b/spec/workers/namespaces/root_statistics_worker_spec.rb
new file mode 100644
index 00000000000..8dd74b96d49
--- /dev/null
+++ b/spec/workers/namespaces/root_statistics_worker_spec.rb
@@ -0,0 +1,88 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Namespaces::RootStatisticsWorker, '#perform' do
+ let(:group) { create(:group, :with_aggregation_schedule) }
+
+ subject(:worker) { described_class.new }
+
+ context 'with a namespace' do
+ it 'executes refresher service' do
+ expect_any_instance_of(Namespaces::StatisticsRefresherService)
+ .to receive(:execute)
+
+ worker.perform(group.id)
+ end
+
+ it 'deletes namespace aggregated schedule row' do
+ worker.perform(group.id)
+
+ expect(group.reload.aggregation_schedule).to be_nil
+ end
+
+ context 'when something goes wrong when updating' do
+ before do
+ allow_any_instance_of(Namespaces::StatisticsRefresherService)
+ .to receive(:execute)
+ .and_raise(Namespaces::StatisticsRefresherService::RefresherError, 'error')
+ end
+
+ it 'does not delete the aggregation schedule' do
+ worker.perform(group.id)
+
+ expect(group.reload.aggregation_schedule).to be_present
+ end
+
+ it 'logs the error' do
+ # A Namespace::RootStatisticsWorker is scheduled when
+ # a Namespace::AggregationSchedule is created, so having
+ # create(:group, :with_aggregation_schedule), will execute
+ # another worker
+ allow_any_instance_of(Namespace::AggregationSchedule)
+ .to receive(:schedule_root_storage_statistics).and_return(nil)
+
+ expect(Gitlab::SidekiqLogger).to receive(:error).once
+
+ worker.perform(group.id)
+ end
+ end
+ end
+
+ context 'with no namespace' do
+ before do
+ group.destroy
+ end
+
+ it 'does not execute the refresher service' do
+ expect_any_instance_of(Namespaces::StatisticsRefresherService)
+ .not_to receive(:execute)
+
+ worker.perform(group.id)
+ end
+ end
+
+ context 'with a namespace with no aggregation scheduled' do
+ before do
+ group.aggregation_schedule.destroy
+ end
+
+ it 'does not execute the refresher service' do
+ expect_any_instance_of(Namespaces::StatisticsRefresherService)
+ .not_to receive(:execute)
+
+ worker.perform(group.id)
+ end
+ end
+
+ context 'when update_statistics_namespace is off' do
+ it 'does not create a new one' do
+ stub_feature_flags(update_statistics_namespace: false, namespace: group)
+
+ expect_any_instance_of(Namespaces::StatisticsRefresherService)
+ .not_to receive(:execute)
+
+ worker.perform(group.id)
+ end
+ end
+end
diff --git a/spec/workers/namespaces/schedule_aggregation_worker_spec.rb b/spec/workers/namespaces/schedule_aggregation_worker_spec.rb
new file mode 100644
index 00000000000..d4a49a3f53a
--- /dev/null
+++ b/spec/workers/namespaces/schedule_aggregation_worker_spec.rb
@@ -0,0 +1,77 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Namespaces::ScheduleAggregationWorker, '#perform', :clean_gitlab_redis_shared_state do
+ let(:group) { create(:group) }
+
+ subject(:worker) { described_class.new }
+
+ context 'when group is the root ancestor' do
+ context 'when aggregation schedule exists' do
+ it 'does not create a new one' do
+ stub_aggregation_schedule_statistics
+
+ Namespace::AggregationSchedule.safe_find_or_create_by!(namespace_id: group.id)
+
+ expect do
+ worker.perform(group.id)
+ end.not_to change(Namespace::AggregationSchedule, :count)
+ end
+ end
+
+ context 'when aggregation schedule does not exist' do
+ it 'creates one' do
+ stub_aggregation_schedule_statistics
+
+ expect do
+ worker.perform(group.id)
+ end.to change(Namespace::AggregationSchedule, :count).by(1)
+
+ expect(group.aggregation_schedule).to be_present
+ end
+ end
+
+ context 'when update_statistics_namespace is off' do
+ it 'does not create a new one' do
+ stub_feature_flags(update_statistics_namespace: false, namespace: group)
+
+ expect do
+ worker.perform(group.id)
+ end.not_to change(Namespace::AggregationSchedule, :count)
+ end
+ end
+ end
+
+ context 'when group is not the root ancestor' do
+ let(:parent_group) { create(:group) }
+ let(:group) { create(:group, parent: parent_group) }
+
+ it 'creates an aggregation schedule for the root' do
+ stub_aggregation_schedule_statistics
+
+ worker.perform(group.id)
+
+ expect(parent_group.aggregation_schedule).to be_present
+ end
+ end
+
+ context 'when namespace does not exist' do
+ it 'logs the error' do
+ expect(Gitlab::SidekiqLogger).to receive(:error).once
+
+ worker.perform(12345)
+ end
+ end
+
+ def stub_aggregation_schedule_statistics
+ # Namespace::Aggregations are deleted by
+ # Namespace::AggregationSchedule::schedule_root_storage_statistics,
+ # which is executed async. Stubing the service so instances are not deleted
+ # while still running the specs.
+ expect_next_instance_of(Namespace::AggregationSchedule) do |aggregation_schedule|
+ expect(aggregation_schedule)
+ .to receive(:schedule_root_storage_statistics)
+ end
+ end
+end
diff --git a/spec/workers/project_cache_worker_spec.rb b/spec/workers/project_cache_worker_spec.rb
index 51afb076da1..edc55920b8e 100644
--- a/spec/workers/project_cache_worker_spec.rb
+++ b/spec/workers/project_cache_worker_spec.rb
@@ -36,6 +36,11 @@ describe ProjectCacheWorker do
end
context 'with an existing project' do
+ before do
+ lease_key = "namespace:namespaces_root_statistics:#{project.namespace_id}"
+ stub_exclusive_lease_taken(lease_key, timeout: Namespace::AggregationSchedule::DEFAULT_LEASE_TIMEOUT)
+ end
+
it 'refreshes the method caches' do
expect_any_instance_of(Repository).to receive(:refresh_method_caches)
.with(%i(readme))
@@ -81,6 +86,10 @@ describe ProjectCacheWorker do
expect(UpdateProjectStatisticsWorker).not_to receive(:perform_in)
+ expect(Namespaces::ScheduleAggregationWorker)
+ .not_to receive(:perform_async)
+ .with(project.namespace_id)
+
worker.update_statistics(project, statistics)
end
end
@@ -98,6 +107,11 @@ describe ProjectCacheWorker do
.with(lease_timeout, project.id, statistics)
.and_call_original
+ expect(Namespaces::ScheduleAggregationWorker)
+ .to receive(:perform_async)
+ .with(project.namespace_id)
+ .twice
+
worker.update_statistics(project, statistics)
end
end
diff --git a/tmp/prometheus_multiproc_dir/puma/.gitkeep b/tmp/prometheus_multiproc_dir/puma/.gitkeep
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/tmp/prometheus_multiproc_dir/puma/.gitkeep
diff --git a/tmp/prometheus_multiproc_dir/sidekiq/.gitkeep b/tmp/prometheus_multiproc_dir/sidekiq/.gitkeep
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/tmp/prometheus_multiproc_dir/sidekiq/.gitkeep
diff --git a/tmp/prometheus_multiproc_dir/unicorn/.gitkeep b/tmp/prometheus_multiproc_dir/unicorn/.gitkeep
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/tmp/prometheus_multiproc_dir/unicorn/.gitkeep
diff --git a/yarn.lock b/yarn.lock
index 901f7fbd6fb..dc5e0662396 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -700,15 +700,15 @@
dependencies:
requireindex "~1.1.0"
-"@gitlab/svgs@^1.65.0":
- version "1.65.0"
- resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-1.65.0.tgz#48a3a64c0b5524de4e57d51b82a71274af17744d"
- integrity sha512-GC9JgVu4/2Ysc3hKFmX6TQV6tqvHZDcfd/DzBzYjy3rHO9qYMZFnw/CKCGa8LkU9F79vfDo3G8NSja7FDXMccw==
+"@gitlab/svgs@^1.67.0":
+ version "1.67.0"
+ resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-1.67.0.tgz#c7b94eca13b99fd3aaa737fb6dcc0abc41d3c579"
+ integrity sha512-hJOmWEs6RkjzyKkb1vc9wwKGZIBIP0coHkxu/KgOoxhBVudpGk4CH7xJ6UuB2TKpb0SEh5CC1CzRZfBYaFhsaA==
-"@gitlab/ui@^5.1.0":
- version "5.1.0"
- resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-5.1.0.tgz#b8c8f266edc68f616e92c0ba3a18a692002393e4"
- integrity sha512-IPgk5W7mSXcbni+zNuJeVU89Co72jSQAXTxU7AtmItt5XT6nI9US2ZAWNUl8XCiOOw81jzYv0PLp4bMiXdLkww==
+"@gitlab/ui@^5.5.0":
+ version "5.5.0"
+ resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-5.5.0.tgz#2000b2ed0c3825dd8c4430191023f4d03c923ecb"
+ integrity sha512-6e/AFFLDk/gm4wKnHM9rcpTRqCsWkPKW/Vjsnd6h4wyfif2/TusHeIn/jedQxUaORbO/XZKzg4V5COhXXbCx4w==
dependencies:
"@babel/standalone" "^7.0.0"
"@gitlab/vue-toasted" "^1.2.1"
@@ -1244,7 +1244,7 @@ abab@^2.0.0:
resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.0.tgz#aba0ab4c5eee2d4c79d3487d85450fb2376ebb0f"
integrity sha512-sY5AXXVZv4Y1VACTtR11UJCPHHudgY5i26Qj5TypE6DKlIApbwb5uqhXcJ5UUGbvZNRh7EeIoW+LrJumBsKp7w==
-abbrev@1, abbrev@1.0.x:
+abbrev@1:
version "1.0.9"
resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.0.9.tgz#91b4792588a7738c25f35dd6f63752a2f8776135"
integrity sha1-kbR5JYinc4wl813W9jdSovh3YTU=
@@ -1630,7 +1630,7 @@ async-limiter@~1.0.0:
resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8"
integrity sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==
-async@1.x, async@^1.5.2:
+async@^1.5.2:
version "1.5.2"
resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a"
integrity sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=
@@ -3993,18 +3993,6 @@ escaper@^2.5.3:
resolved "https://registry.yarnpkg.com/escaper/-/escaper-2.5.3.tgz#8b8fe90ba364054151ab7eff18b4ce43b1e13ab5"
integrity sha512-QGb9sFxBVpbzMggrKTX0ry1oiI4CSDAl9vIL702hzl1jGW8VZs7qfqTRX7WDOjoNDoEVGcEtu1ZOQgReSfT2kQ==
-escodegen@1.8.x:
- version "1.8.1"
- resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.8.1.tgz#5a5b53af4693110bebb0867aa3430dd3b70a1018"
- integrity sha1-WltTr0aTEQvrsIZ6o0MN07cKEBg=
- dependencies:
- esprima "^2.7.1"
- estraverse "^1.9.1"
- esutils "^2.0.2"
- optionator "^0.8.1"
- optionalDependencies:
- source-map "~0.2.0"
-
escodegen@^1.9.1:
version "1.11.0"
resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.11.0.tgz#b27a9389481d5bfd5bec76f7bb1eb3f8f4556589"
@@ -4213,11 +4201,6 @@ espree@^4.0.0, espree@^4.1.0:
acorn-jsx "^5.0.0"
eslint-visitor-keys "^1.0.0"
-esprima@2.7.x, esprima@^2.7.1:
- version "2.7.3"
- resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581"
- integrity sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=
-
esprima@^3.1.3:
version "3.1.3"
resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633"
@@ -4242,11 +4225,6 @@ esrecurse@^4.1.0:
dependencies:
estraverse "^4.1.0"
-estraverse@^1.9.1:
- version "1.9.3"
- resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-1.9.3.tgz#af67f2dc922582415950926091a4005d29c9bb44"
- integrity sha1-r2fy3JIlgkFZUJJgkaQAXSnJu0Q=
-
estraverse@^4.0.0, estraverse@^4.1.0, estraverse@^4.1.1, estraverse@^4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13"
@@ -4953,17 +4931,6 @@ glob-to-regexp@^0.3.0:
once "^1.3.0"
path-is-absolute "^1.0.0"
-glob@^5.0.15:
- version "5.0.15"
- resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1"
- integrity sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=
- dependencies:
- inflight "^1.0.4"
- inherits "2"
- minimatch "2 || 3"
- once "^1.3.0"
- path-is-absolute "^1.0.0"
-
global-dirs@^0.1.0:
version "0.1.1"
resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-0.1.1.tgz#b319c0dd4607f353f3be9cca4c72fc148c49f445"
@@ -5163,7 +5130,7 @@ handle-thing@^2.0.0:
resolved "https://registry.yarnpkg.com/handle-thing/-/handle-thing-2.0.0.tgz#0e039695ff50c93fc288557d696f3c1dc6776754"
integrity sha512-d4sze1JNC454Wdo2fkuyzCr6aHcbL6PGGuFAz0Li/NcOm1tCHGnWDRmJP85dh9IhQErTc2svWFEX5xHIOo//kQ==
-handlebars@^4.0.1, handlebars@^4.1.2:
+handlebars@^4.1.2:
version "4.1.2"
resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.1.2.tgz#b6b37c1ced0306b221e094fc7aca3ec23b131b67"
integrity sha512-nvfrjqvt9xQ8Z/w0ijewdD/vvWDTOweBUm96NTr66Wfvo1mJenBLwcYmPs3TIBP5ruzYGD7Hx/DaM9RmhroGPw==
@@ -5206,11 +5173,6 @@ has-cors@1.1.0:
resolved "https://registry.yarnpkg.com/has-cors/-/has-cors-1.1.0.tgz#5e474793f7ea9843d1bb99c23eef49ff126fff39"
integrity sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=
-has-flag@^1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa"
- integrity sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=
-
has-flag@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
@@ -6104,26 +6066,6 @@ istanbul-reports@^2.1.1:
dependencies:
handlebars "^4.1.2"
-istanbul@^0.4.5:
- version "0.4.5"
- resolved "https://registry.yarnpkg.com/istanbul/-/istanbul-0.4.5.tgz#65c7d73d4c4da84d4f3ac310b918fb0b8033733b"
- integrity sha1-ZcfXPUxNqE1POsMQuRj7C4Azczs=
- dependencies:
- abbrev "1.0.x"
- async "1.x"
- escodegen "1.8.x"
- esprima "2.7.x"
- glob "^5.0.15"
- handlebars "^4.0.1"
- js-yaml "3.x"
- mkdirp "0.5.x"
- nopt "3.x"
- once "1.x"
- resolve "1.1.x"
- supports-color "^3.1.0"
- which "^1.1.1"
- wordwrap "^1.0.0"
-
istextorbinary@^2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/istextorbinary/-/istextorbinary-2.2.1.tgz#a5231a08ef6dd22b268d0895084cf8d58b5bec53"
@@ -6593,7 +6535,7 @@ js-tokens@^3.0.2:
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b"
integrity sha1-mGbfOVECEw449/mWvOtlRDIJwls=
-js-yaml@3.x, js-yaml@^3.12.0, js-yaml@^3.9.0:
+js-yaml@^3.12.0, js-yaml@^3.9.0:
version "3.13.1"
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847"
integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==
@@ -7472,7 +7414,7 @@ minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1:
resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a"
integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=
-"minimatch@2 || 3", minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4, minimatch@~3.0.2:
+minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4, minimatch@~3.0.2:
version "3.0.4"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
@@ -7818,7 +7760,7 @@ nodemon@^1.18.9:
undefsafe "^2.0.2"
update-notifier "^2.5.0"
-"nopt@2 || 3", nopt@3.x:
+"nopt@2 || 3":
version "3.0.6"
resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9"
integrity sha1-xkZdvwirzU2zWTF/eaxopkayj/k=
@@ -8019,7 +7961,7 @@ on-headers@~1.0.1:
resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.1.tgz#928f5d0f470d49342651ea6794b0857c100693f7"
integrity sha1-ko9dD0cNSTQmUepnlLCFfBAGk/c=
-once@1.x, once@^1.3.0, once@^1.3.1, once@^1.4.0:
+once@^1.3.0, once@^1.3.1, once@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E=
@@ -9490,7 +9432,7 @@ resolve-url@^0.2.1:
resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a"
integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=
-resolve@1.1.7, resolve@1.1.x:
+resolve@1.1.7:
version "1.1.7"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b"
integrity sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=
@@ -10048,13 +9990,6 @@ source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1:
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
-source-map@~0.2.0:
- version "0.2.0"
- resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.2.0.tgz#dab73fbcfc2ba819b4de03bd6f6eaa48164b3f9d"
- integrity sha1-2rc/vPwrqBm03gO9b26qSBZLP50=
- dependencies:
- amdefine ">=0.0.4"
-
spdx-correct@~1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-1.0.2.tgz#4b3073d933ff51f3912f03ac5519498a4150db40"
@@ -10456,13 +10391,6 @@ supports-color@^2.0.0:
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7"
integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=
-supports-color@^3.1.0:
- version "3.2.3"
- resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6"
- integrity sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=
- dependencies:
- 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, supports-color@^5.5.0:
version "5.5.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
@@ -11635,7 +11563,7 @@ which-module@^2.0.0:
resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a"
integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=
-which@1, which@^1.1.1, which@^1.2.1, which@^1.2.14, which@^1.2.9, which@^1.3.0, which@^1.3.1:
+which@1, which@^1.2.1, which@^1.2.14, which@^1.2.9, which@^1.3.0, which@^1.3.1:
version "1.3.1"
resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==
@@ -11656,16 +11584,16 @@ widest-line@^2.0.0:
dependencies:
string-width "^2.1.1"
-wordwrap@^1.0.0, wordwrap@~1.0.0:
- version "1.0.0"
- resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb"
- integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=
-
wordwrap@~0.0.2:
version "0.0.3"
resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107"
integrity sha1-o9XabNXAvAAI03I0u68b7WMFkQc=
+wordwrap@~1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb"
+ integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=
+
worker-farm@^1.5.2:
version "1.5.2"
resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.5.2.tgz#32b312e5dc3d5d45d79ef44acc2587491cd729ae"