summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFilipa Lacerda <filipa@gitlab.com>2019-07-03 22:39:10 +0100
committerFilipa Lacerda <filipa@gitlab.com>2019-07-03 22:39:10 +0100
commit50be7237f41b0ac44b9aaf8b73c57993548d4c35 (patch)
treeecfeeae58829dadbd90de4f834c730d1d8c55e74
parent35331c435196ea1155eb15161f3f9a481a01501d (diff)
parent2ad75a4f96c4d377e18788966e7eefee4d78b6d2 (diff)
downloadgitlab-ce-update-todo-in-ui.tar.gz
Merge branch 'master' into update-todo-in-uiupdate-todo-in-ui
* master: (435 commits) Change occurrence of Sidekiq::Testing.inline! Fix order-dependent spec failure in appearance_spec.rb Put a failed example from appearance_spec in quarantine Cache PerformanceBar.allowed_user_ids list locally and in Redis Add Grafana to Admin > Monitoring menu when enabled Add changelog entry Add salesforce logo Move error_tracking_frontend specs to Jest Only save Peek session in Redis when Peek is enabled Migrate markdown header_spec.js to Jest Fix golint command in Go guide doc to be recursive Move images to their own dirs Gitlab -> GitLab Re-align CE and EE API docs Rename Release groups in issue_workflow.md Update api docs to finish aligning EE and CE docs Update locale.pot Update TODO: allow_collaboration column renaming Show upcoming status for releases Rebased and squashed commits ...
-rw-r--r--.gitlab/CODEOWNERS6
-rw-r--r--.gitlab/ci/docs.gitlab-ci.yml11
-rw-r--r--.gitlab/ci/frontend.gitlab-ci.yml29
-rw-r--r--.gitlab/ci/global.gitlab-ci.yml30
-rw-r--r--.gitlab/ci/memory.gitlab-ci.yml35
-rw-r--r--.gitlab/ci/rails.gitlab-ci.yml65
-rw-r--r--.gitlab/ci/reports.gitlab-ci.yml88
-rw-r--r--.gitlab/ci/review.gitlab-ci.yml19
-rw-r--r--.gitlab/ci/setup.gitlab-ci.yml14
-rw-r--r--.gitlab/ci/test-metadata.gitlab-ci.yml14
-rw-r--r--.gitlab/issue_templates/Database Reviewer.md34
-rw-r--r--CHANGELOG.md68
-rw-r--r--Dangerfile1
-rw-r--r--GITALY_SERVER_VERSION2
-rw-r--r--Gemfile10
-rw-r--r--Gemfile.lock10
-rw-r--r--PROCESS.md43
-rw-r--r--app/assets/images/auth_buttons/salesforce_64.pngbin0 -> 8774 bytes
-rw-r--r--app/assets/javascripts/behaviors/markdown/render_mermaid.js8
-rw-r--r--app/assets/javascripts/boards/components/board.js40
-rw-r--r--app/assets/javascripts/boards/components/board_blank_state.vue22
-rw-r--r--app/assets/javascripts/boards/components/board_list.vue4
-rw-r--r--app/assets/javascripts/boards/components/board_new_issue.vue13
-rw-r--r--app/assets/javascripts/boards/components/board_sidebar.js1
-rw-r--r--app/assets/javascripts/boards/components/issue_card_inner.vue25
-rw-r--r--app/assets/javascripts/boards/components/issue_time_estimate.vue10
-rw-r--r--app/assets/javascripts/boards/components/modal/empty_state.vue30
-rw-r--r--app/assets/javascripts/boards/components/modal/footer.vue11
-rw-r--r--app/assets/javascripts/boards/components/modal/header.vue7
-rw-r--r--app/assets/javascripts/boards/components/modal/list.vue4
-rw-r--r--app/assets/javascripts/boards/components/project_select.vue9
-rw-r--r--app/assets/javascripts/boards/components/sidebar/remove_issue.vue2
-rw-r--r--app/assets/javascripts/boards/index.js1
-rw-r--r--app/assets/javascripts/boards/mixins/sortable_default_options.js4
-rw-r--r--app/assets/javascripts/boards/models/list.js8
-rw-r--r--app/assets/javascripts/boards/stores/boards_store.js7
-rw-r--r--app/assets/javascripts/branches/divergence_graph.js62
-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/clusters/services/application_state_machine.js6
-rw-r--r--app/assets/javascripts/commons/polyfills.js1
-rw-r--r--app/assets/javascripts/diff_notes/components/comment_resolve_btn.js8
-rw-r--r--app/assets/javascripts/diffs/components/commit_item.vue4
-rw-r--r--app/assets/javascripts/diffs/components/compare_versions_dropdown.vue16
-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.vue11
-rw-r--r--app/assets/javascripts/diffs/components/diff_file_header.vue8
-rw-r--r--app/assets/javascripts/diffs/components/diff_gutter_avatars.vue29
-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.vue40
-rw-r--r--app/assets/javascripts/diffs/components/parallel_diff_comment_row.vue85
-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/filtered_search/available_dropdown_mappings.js6
-rw-r--r--app/assets/javascripts/filtered_search/components/recent_searches_dropdown_content.vue6
-rw-r--r--app/assets/javascripts/filtered_search/filtered_search_dropdown_manager.js6
-rw-r--r--app/assets/javascripts/filtered_search/filtered_search_manager.js3
-rw-r--r--app/assets/javascripts/gfm_auto_complete.js26
-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/ide_tree_list.vue7
-rw-r--r--app/assets/javascripts/ide/components/repo_editor.vue55
-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/stores/actions.js19
-rw-r--r--app/assets/javascripts/ide/stores/actions/file.js4
-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.js22
-rw-r--r--app/assets/javascripts/ide/stores/mutations/file.js6
-rw-r--r--app/assets/javascripts/ide/stores/state.js1
-rw-r--r--app/assets/javascripts/ide/stores/utils.js10
-rw-r--r--app/assets/javascripts/ide/utils.js2
-rw-r--r--app/assets/javascripts/issue_show/components/edit_actions.vue4
-rw-r--r--app/assets/javascripts/issue_show/components/fields/description.vue6
-rw-r--r--app/assets/javascripts/issue_show/components/fields/description_template.vue25
-rw-r--r--app/assets/javascripts/issue_show/components/fields/title.vue6
-rw-r--r--app/assets/javascripts/issue_show/components/locked_warning.vue7
-rw-r--r--app/assets/javascripts/jobs/components/job_log_controllers.vue8
-rw-r--r--app/assets/javascripts/jobs/components/sidebar.vue5
-rw-r--r--app/assets/javascripts/lib/graphql.js2
-rw-r--r--app/assets/javascripts/lib/utils/datetime_utility.js17
-rw-r--r--app/assets/javascripts/lib/utils/text_utility.js11
-rw-r--r--app/assets/javascripts/manual_ordering.js58
-rw-r--r--app/assets/javascripts/monitoring/components/charts/area.vue17
-rw-r--r--app/assets/javascripts/monitoring/components/charts/column.vue131
-rw-r--r--app/assets/javascripts/monitoring/components/dashboard.vue113
-rw-r--r--app/assets/javascripts/monitoring/components/empty_state.vue50
-rw-r--r--app/assets/javascripts/monitoring/monitoring_bundle.js14
-rw-r--r--app/assets/javascripts/monitoring/stores/actions.js21
-rw-r--r--app/assets/javascripts/monitoring/stores/mutation_types.js2
-rw-r--r--app/assets/javascripts/monitoring/stores/mutations.js7
-rw-r--r--app/assets/javascripts/monitoring/stores/state.js3
-rw-r--r--app/assets/javascripts/notes/components/comment_form.vue4
-rw-r--r--app/assets/javascripts/notes/components/discussion_actions.vue17
-rw-r--r--app/assets/javascripts/notes/components/discussion_counter.vue6
-rw-r--r--app/assets/javascripts/notes/components/discussion_notes.vue57
-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_form.vue4
-rw-r--r--app/assets/javascripts/notes/components/note_header.vue2
-rw-r--r--app/assets/javascripts/notes/components/noteable_discussion.vue29
-rw-r--r--app/assets/javascripts/notes/mixins/resolvable.js6
-rw-r--r--app/assets/javascripts/notes/stores/actions.js12
-rw-r--r--app/assets/javascripts/notes/stores/getters.js6
-rw-r--r--app/assets/javascripts/pages/dashboard/issues/index.js2
-rw-r--r--app/assets/javascripts/pages/groups/issues/index.js2
-rw-r--r--app/assets/javascripts/pages/projects/branches/index/index.js2
-rw-r--r--app/assets/javascripts/pages/projects/issues/index/index.js2
-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.vue72
-rw-r--r--app/assets/javascripts/pages/projects/shared/permissions/constants.js27
-rw-r--r--app/assets/javascripts/pages/projects/shared/permissions/mixins/settings_pannel_mixin.js26
-rw-r--r--app/assets/javascripts/pages/users/user_tabs.js4
-rw-r--r--app/assets/javascripts/performance_bar/components/detailed_metric.vue4
-rw-r--r--app/assets/javascripts/performance_bar/components/performance_bar_app.vue29
-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/pipelines/pipeline_details_mediator.js2
-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/reports/components/report_item.vue2
-rw-r--r--app/assets/javascripts/repository/components/breadcrumbs.vue2
-rw-r--r--app/assets/javascripts/repository/components/last_commit.vue135
-rw-r--r--app/assets/javascripts/repository/components/table/index.vue2
-rw-r--r--app/assets/javascripts/repository/components/table/row.vue53
-rw-r--r--app/assets/javascripts/repository/graphql.js17
-rw-r--r--app/assets/javascripts/repository/index.js31
-rw-r--r--app/assets/javascripts/repository/log_tree.js64
-rw-r--r--app/assets/javascripts/repository/queries/getCommit.query.graphql10
-rw-r--r--app/assets/javascripts/repository/queries/getCommits.query.graphql10
-rw-r--r--app/assets/javascripts/repository/queries/getFiles.query.graphql1
-rw-r--r--app/assets/javascripts/repository/queries/pathLastCommit.query.graphql6
-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/time_tracking/comparison_pane.vue10
-rw-r--r--app/assets/javascripts/sidebar/components/time_tracking/sidebar_time_tracking.vue1
-rw-r--r--app/assets/javascripts/sidebar/components/time_tracking/time_tracker.vue5
-rw-r--r--app/assets/javascripts/sidebar/mount_milestone_sidebar.js4
-rw-r--r--app/assets/javascripts/sidebar/sidebar_mediator.js2
-rw-r--r--app/assets/javascripts/sidebar/stores/sidebar_store.js3
-rw-r--r--app/assets/javascripts/visual_review_toolbar/components/comment.js50
-rw-r--r--app/assets/javascripts/visual_review_toolbar/components/constants.js8
-rw-r--r--app/assets/javascripts/visual_review_toolbar/components/index.js16
-rw-r--r--app/assets/javascripts/visual_review_toolbar/components/login.js3
-rw-r--r--app/assets/javascripts/visual_review_toolbar/components/note.js14
-rw-r--r--app/assets/javascripts/visual_review_toolbar/components/utils.js6
-rw-r--r--app/assets/javascripts/visual_review_toolbar/components/wrapper.js36
-rw-r--r--app/assets/javascripts/visual_review_toolbar/index.js9
-rw-r--r--app/assets/javascripts/visual_review_toolbar/store/state.js3
-rw-r--r--app/assets/javascripts/visual_review_toolbar/styles/toolbar.css48
-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/mr_widget_options.vue3
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/services/mr_widget_service.js4
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js3
-rw-r--r--app/assets/javascripts/vue_shared/components/file_row.vue2
-rw-r--r--app/assets/javascripts/vue_shared/components/issue/related_issuable_item.vue151
-rw-r--r--app/assets/javascripts/vue_shared/components/notes/placeholder_note.vue2
-rw-r--r--app/assets/javascripts/vue_shared/mixins/related_issuable_mixin.js3
-rw-r--r--app/assets/stylesheets/application.scss8
-rw-r--r--app/assets/stylesheets/components/related_items_list.scss81
-rw-r--r--app/assets/stylesheets/components/toast.scss4
-rw-r--r--app/assets/stylesheets/csslab.scss2
-rw-r--r--app/assets/stylesheets/errors.scss12
-rw-r--r--app/assets/stylesheets/framework.scss2
-rw-r--r--app/assets/stylesheets/framework/system_messages.scss10
-rw-r--r--app/assets/stylesheets/pages/boards.scss72
-rw-r--r--app/assets/stylesheets/pages/container_registry.scss6
-rw-r--r--app/assets/stylesheets/pages/diff.scss16
-rw-r--r--app/assets/stylesheets/pages/issuable.scss6
-rw-r--r--app/assets/stylesheets/pages/issues.scss14
-rw-r--r--app/assets/stylesheets/pages/notes.scss35
-rw-r--r--app/controllers/admin/application_settings_controller.rb2
-rw-r--r--app/controllers/application_controller.rb6
-rw-r--r--app/controllers/concerns/boards_responses.rb3
-rw-r--r--app/controllers/concerns/continue_params.rb2
-rw-r--r--app/controllers/concerns/internal_redirect.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/multiple_boards_actions.rb90
-rw-r--r--app/controllers/concerns/notes_actions.rb14
-rw-r--r--app/controllers/concerns/requires_whitelisted_monitoring_client.rb4
-rw-r--r--app/controllers/dashboard/projects_controller.rb1
-rw-r--r--app/controllers/dashboard/todos_controller.rb1
-rw-r--r--app/controllers/groups/clusters_controller.rb9
-rw-r--r--app/controllers/groups_controller.rb7
-rw-r--r--app/controllers/projects/application_controller.rb11
-rw-r--r--app/controllers/projects/boards_controller.rb2
-rw-r--r--app/controllers/projects/branches_controller.rb38
-rw-r--r--app/controllers/projects/forks_controller.rb18
-rw-r--r--app/controllers/projects/imports_controller.rb8
-rw-r--r--app/controllers/projects/issues_controller.rb5
-rw-r--r--app/controllers/projects/jobs_controller.rb2
-rw-r--r--app/controllers/projects/merge_requests/application_controller.rb7
-rw-r--r--app/controllers/projects/merge_requests/content_controller.rb22
-rw-r--r--app/controllers/projects/merge_requests_controller.rb6
-rw-r--r--app/controllers/projects/refs_controller.rb1
-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.rb2
-rw-r--r--app/controllers/registrations_controller.rb30
-rw-r--r--app/controllers/search_controller.rb2
-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/autocomplete/acts_as_taggable_on/tags_finder.rb3
-rw-r--r--app/finders/boards/visits_finder.rb26
-rw-r--r--app/finders/branches_finder.rb14
-rw-r--r--app/graphql/mutations/award_emojis/add.rb25
-rw-r--r--app/graphql/mutations/award_emojis/base.rb41
-rw-r--r--app/graphql/mutations/award_emojis/remove.rb33
-rw-r--r--app/graphql/mutations/award_emojis/toggle.rb40
-rw-r--r--app/graphql/mutations/base_mutation.rb7
-rw-r--r--app/graphql/types/award_emojis/award_emoji_type.rb46
-rw-r--r--app/graphql/types/ci/detailed_status_type.rb3
-rw-r--r--app/graphql/types/commit_type.rb30
-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/metadata_type.rb2
-rw-r--r--app/graphql/types/mutation_type.rb3
-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/project_type.rb4
-rw-r--r--app/graphql/types/query_type.rb5
-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.rb8
-rw-r--r--app/helpers/application_settings_helper.rb11
-rw-r--r--app/helpers/auth_helper.rb2
-rw-r--r--app/helpers/boards_helper.rb18
-rw-r--r--app/helpers/branches_helper.rb8
-rw-r--r--app/helpers/groups_helper.rb2
-rw-r--r--app/helpers/issuables_helper.rb5
-rw-r--r--app/helpers/issues_helper.rb1
-rw-r--r--app/helpers/onboarding_experiment_helper.rb7
-rw-r--r--app/helpers/recaptcha_experiment_helper.rb7
-rw-r--r--app/helpers/search_helper.rb5
-rw-r--r--app/helpers/snippets_helper.rb10
-rw-r--r--app/helpers/todos_helper.rb2
-rw-r--r--app/mailers/emails/notes.rb4
-rw-r--r--app/models/application_setting.rb26
-rw-r--r--app/models/application_setting_implementation.rb22
-rw-r--r--app/models/board.rb5
-rw-r--r--app/models/broadcast_message.rb2
-rw-r--r--app/models/ci/pipeline.rb5
-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/applications/runner.rb2
-rw-r--r--app/models/clusters/instance.rb4
-rw-r--r--app/models/clusters/platforms/kubernetes.rb49
-rw-r--r--app/models/concerns/cacheable_attributes.rb10
-rw-r--r--app/models/concerns/deployable.rb1
-rw-r--r--app/models/concerns/deployment_platform.rb16
-rw-r--r--app/models/concerns/issuable.rb6
-rw-r--r--app/models/concerns/relative_positioning.rb4
-rw-r--r--app/models/concerns/update_project_statistics.rb19
-rw-r--r--app/models/deploy_token.rb14
-rw-r--r--app/models/deployment.rb27
-rw-r--r--app/models/environment.rb19
-rw-r--r--app/models/group.rb4
-rw-r--r--app/models/issue.rb4
-rw-r--r--app/models/list.rb1
-rw-r--r--app/models/merge_request.rb5
-rw-r--r--app/models/merge_requests_closing_issues.rb35
-rw-r--r--app/models/namespace.rb10
-rw-r--r--app/models/namespace/aggregation_schedule.rb47
-rw-r--r--app/models/namespace/root_storage_statistics.rb38
-rw-r--r--app/models/note.rb2
-rw-r--r--app/models/pages_domain.rb10
-rw-r--r--app/models/postgresql/replication_slot.rb2
-rw-r--r--app/models/project.rb9
-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/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.rb41
-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/release.rb10
-rw-r--r--app/models/repository.rb41
-rw-r--r--app/models/service.rb2
-rw-r--r--app/models/snippet.rb4
-rw-r--r--app/models/todo.rb2
-rw-r--r--app/models/user.rb11
-rw-r--r--app/policies/award_emoji_policy.rb11
-rw-r--r--app/policies/clusters/instance_policy.rb3
-rw-r--r--app/policies/project_policy.rb3
-rw-r--r--app/policies/repository_policy.rb5
-rw-r--r--app/presenters/award_emoji_presenter.rb27
-rw-r--r--app/presenters/commit_presenter.rb8
-rw-r--r--app/serializers/board_simple_entity.rb1
-rw-r--r--app/serializers/merge_request_widget_entity.rb8
-rw-r--r--app/services/boards/create_service.rb2
-rw-r--r--app/services/boards/destroy_service.rb11
-rw-r--r--app/services/boards/update_service.rb9
-rw-r--r--app/services/boards/visits/latest_service.rb19
-rw-r--r--app/services/branches/diverging_commit_counts_service.rb32
-rw-r--r--app/services/deploy_tokens/create_service.rb4
-rw-r--r--app/services/issuable_base_service.rb13
-rw-r--r--app/services/merge_requests/create_from_issue_service.rb36
-rw-r--r--app/services/namespaces/statistics_refresher_service.rb22
-rw-r--r--app/services/pages_domains/obtain_lets_encrypt_certificate_service.rb10
-rw-r--r--app/services/projects/propagate_service_template.rb2
-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.rb9
-rw-r--r--app/services/users/update_service.rb10
-rw-r--r--app/uploaders/file_mover.rb82
-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/_localization.html.haml7
-rw-r--r--app/views/admin/application_settings/_logging.html.haml38
-rw-r--r--app/views/admin/application_settings/_spam.html.haml5
-rw-r--r--app/views/admin/application_settings/metrics_and_profiling.html.haml11
-rw-r--r--app/views/admin/application_settings/reporting.html.haml11
-rw-r--r--app/views/admin/runners/index.html.haml2
-rw-r--r--app/views/admin/services/_form.html.haml2
-rw-r--r--app/views/clusters/clusters/_form.html.haml2
-rw-r--r--app/views/devise/shared/_signup_box.html.haml2
-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/settings/_general.html.haml2
-rw-r--r--app/views/layouts/_head.html.haml2
-rw-r--r--app/views/layouts/fullscreen.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/personal_access_tokens/index.html.haml40
-rw-r--r--app/views/projects/_commit_button.html.haml2
-rw-r--r--app/views/projects/_files.html.haml4
-rw-r--r--app/views/projects/_merge_request_settings_description_text.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.haml4
-rw-r--r--app/views/projects/environments/show.html.haml28
-rw-r--r--app/views/projects/issues/_issues.html.haml2
-rw-r--r--app/views/projects/new.html.haml4
-rw-r--r--app/views/projects/notes/_actions.html.haml2
-rw-r--r--app/views/projects/pages_domains/_form.html.haml2
-rw-r--r--app/views/projects/registry/repositories/index.html.haml54
-rw-r--r--app/views/projects/tree/_tree_header.html.haml1
-rw-r--r--app/views/search/_category.html.haml1
-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/_issues.html.haml2
-rw-r--r--app/views/shared/_personal_access_tokens_created_container.html.haml7
-rw-r--r--app/views/shared/_personal_access_tokens_form.html.haml14
-rw-r--r--app/views/shared/_personal_access_tokens_table.html.haml23
-rw-r--r--app/views/shared/boards/components/_board.html.haml60
-rw-r--r--app/views/shared/boards/components/sidebar/_time_tracker.html.haml1
-rw-r--r--app/views/shared/issuable/_form.html.haml6
-rw-r--r--app/views/shared/issuable/_sort_dropdown.html.haml3
-rw-r--r--app/views/shared/milestones/_sidebar.html.haml6
-rw-r--r--app/views/shared/notes/_comment_button.html.haml4
-rw-r--r--app/views/shared/projects/_list.html.haml2
-rw-r--r--app/views/shared/tokens/_scopes_list.html.haml2
-rw-r--r--app/workers/all_queues.yml6
-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/pages_domain_ssl_renewal_cron_worker.rb14
-rw-r--r--app/workers/pages_domain_ssl_renewal_worker.rb13
-rw-r--r--changelogs/unreleased/11039-moved-code-difference-from-EE-to-CE.yml5
-rw-r--r--changelogs/unreleased/11888-regression-deploy-correlation-markers-on-monitoring-graphs-not-clickable.yml5
-rw-r--r--changelogs/unreleased/30355-use-hours-only-for-time-tracking.yml5
-rw-r--r--changelogs/unreleased/32452-multiple-discussions.yml5
-rw-r--r--changelogs/unreleased/44106-include-subgroups-in-group-activity.yml5
-rw-r--r--changelogs/unreleased/44949-do-not-update-updated_at-on-an-issue-when-reordering-it.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/45120-fix-ide-editor-to-update-size-on-show-change.yml5
-rw-r--r--changelogs/unreleased/50228-deploy-tokens-custom-username.yml5
-rw-r--r--changelogs/unreleased/50834-change-http-status-code-when-repository-disabled.yml5
-rw-r--r--changelogs/unreleased/51952-forking-via-webide.yml5
-rw-r--r--changelogs/unreleased/53811-issue-boards-to-core-projects-backend-ce.yml5
-rw-r--r--changelogs/unreleased/54595-incorrect-reaction-emoji-placement-in-discussion.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/58689-regroup-jump-button-in-discussion.yml6
-rw-r--r--changelogs/unreleased/58802-rename-webide.yml5
-rw-r--r--changelogs/unreleased/58808-fix-image-diff-on-text.yml5
-rw-r--r--changelogs/unreleased/59702-fix-notification-flags-for-ms-teams.yml5
-rw-r--r--changelogs/unreleased/60859-upload-after-delete.yml5
-rw-r--r--changelogs/unreleased/60860-keep-empty-folders-in-tree.yml5
-rw-r--r--changelogs/unreleased/60879-fix-reports-timing-out.yml5
-rw-r--r--changelogs/unreleased/61005-grafanaInAdminSettingsMonitoringMenu.yml5
-rw-r--r--changelogs/unreleased/61156-instance-level-cluster-pod-terminal-access.yml5
-rw-r--r--changelogs/unreleased/62124-new-threaded-discussion-design.yml5
-rw-r--r--changelogs/unreleased/62826-graphql-emoji-mutations.yml5
-rw-r--r--changelogs/unreleased/62938-wcag-aa-edited-text-color.yml5
-rw-r--r--changelogs/unreleased/62968-environment-details-header-border-misaligned.yml5
-rw-r--r--changelogs/unreleased/63200-reply-button-broken.yml5
-rw-r--r--changelogs/unreleased/63247-add-conf-toast-and-link.yml5
-rw-r--r--changelogs/unreleased/63479-jira-capitalization.yml5
-rw-r--r--changelogs/unreleased/63513-ensure-gitlab-jsoncache-includes-the-gitlab-version-in-the-cache-key.yml5
-rw-r--r--changelogs/unreleased/63590-pipeline-actions-cause-full-refresh.yml5
-rw-r--r--changelogs/unreleased/63656-runner-tags-search-dropdown-is-empty.yml5
-rw-r--r--changelogs/unreleased/63971-remove-istanbul.yml5
-rw-r--r--changelogs/unreleased/add-clusters-to-deployment.yml5
-rw-r--r--changelogs/unreleased/add-metrics-dashboard-permission-check.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/always-allow-prometheus-access-in-dev.yml5
-rw-r--r--changelogs/unreleased/always-display-environment-selector.yml5
-rw-r--r--changelogs/unreleased/asciidoc-enable-syntax-highlighting.yml5
-rw-r--r--changelogs/unreleased/bug-63162-duplicate_path_in_links.yml5
-rw-r--r--changelogs/unreleased/ce-11098-update-merge-request-settings-description-text.yml5
-rw-r--r--changelogs/unreleased/check-min-schema-migrate.yml5
-rw-r--r--changelogs/unreleased/dohtaset.yml5
-rw-r--r--changelogs/unreleased/dz-remove-deprecated-user-routes.yml5
-rw-r--r--changelogs/unreleased/fe-issue-reorder.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-jupyter-git-v3.yml5
-rw-r--r--changelogs/unreleased/fix-labels-in-hooks.yml5
-rw-r--r--changelogs/unreleased/fix-notes-emails-with-group-settings.yml5
-rw-r--r--changelogs/unreleased/gitaly-version-v1.49.0.yml5
-rw-r--r--changelogs/unreleased/graphql-tree-last-commit.yml5
-rw-r--r--changelogs/unreleased/id-extract-widget-into-different-request.yml5
-rw-r--r--changelogs/unreleased/id-stale-branches.yml5
-rw-r--r--changelogs/unreleased/mh-board-tooltips.yml5
-rw-r--r--changelogs/unreleased/mh-collapsible-boards.yml5
-rw-r--r--changelogs/unreleased/mh-colon-autocomplete.yml5
-rw-r--r--changelogs/unreleased/osw-persist-tmp-snippet-uploads.yml5
-rw-r--r--changelogs/unreleased/po-raw-changes-encoding.yml5
-rw-r--r--changelogs/unreleased/pre-releases-38105a.yml5
-rw-r--r--changelogs/unreleased/refactor-sentry.yml5
-rw-r--r--changelogs/unreleased/remove_group_and_instance_clusters_feature_flag.yml5
-rw-r--r--changelogs/unreleased/require-pipeline-when-enabling-only-allow-merge-if-pipeline-succeeds.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/set-higher-ttl-for-trace-write.yml5
-rw-r--r--changelogs/unreleased/sh-add-force-random-password-user-api.yml5
-rw-r--r--changelogs/unreleased/sh-add-gitaly-ref-caching-search-controller.yml5
-rw-r--r--changelogs/unreleased/sh-add-thread-memory-cache.yml5
-rw-r--r--changelogs/unreleased/sh-avoid-loading-pipeline-status.yml5
-rw-r--r--changelogs/unreleased/sh-cache-flipper-names-memory-cache.yml5
-rw-r--r--changelogs/unreleased/sh-cache-negative-entries-find-commit.yml5
-rw-r--r--changelogs/unreleased/sh-fix-issue-63910.yml5
-rw-r--r--changelogs/unreleased/sh-handle-nil-replication-lag.yml5
-rw-r--r--changelogs/unreleased/sh-improve-redis-peek.yml5
-rw-r--r--changelogs/unreleased/sh-omit-issues-links-on-poll.yml5
-rw-r--r--changelogs/unreleased/sh-optimize-todos-controller.yml5
-rw-r--r--changelogs/unreleased/sh-service-template-bug.yml5
-rw-r--r--changelogs/unreleased/sh-support-subnets-ip-rate-limiter.yml5
-rw-r--r--changelogs/unreleased/sh-update-mermaid.yml5
-rw-r--r--changelogs/unreleased/slugify.yml5
-rw-r--r--changelogs/unreleased/small-s-in-elasticsearch-in-code.yml5
-rw-r--r--changelogs/unreleased/small-s-in-elasticsearch.yml5
-rw-r--r--changelogs/unreleased/support-jsonb-default-value.yml5
-rw-r--r--changelogs/unreleased/tc-rake-orphan-artifacts.yml5
-rw-r--r--changelogs/unreleased/transaction-metrics.yml5
-rw-r--r--changelogs/unreleased/unicorn-sampler-fix.yml5
-rw-r--r--changelogs/unreleased/update-gitlab-runner-helm-chart-to-0-6-0.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-updateResolvableDiscussionsCounts-typo.yml5
-rw-r--r--config/boot.rb2
-rw-r--r--config/gitlab.yml.example2
-rw-r--r--config/initializers/0_inflections.rb8
-rw-r--r--config/initializers/0_thread_cache.rb3
-rw-r--r--config/initializers/1_settings.rb149
-rw-r--r--config/initializers/6_validations.rb21
-rw-r--r--config/initializers/7_prometheus_metrics.rb45
-rw-r--r--config/initializers/forbid_sidekiq_in_transactions.rb2
-rw-r--r--config/initializers/jira.rb2
-rw-r--r--config/initializers/peek.rb3
-rw-r--r--config/initializers/rack_attack_logging.rb14
-rw-r--r--config/initializers/sentry.rb13
-rw-r--r--config/initializers/transaction_metrics.rb3
-rw-r--r--config/routes.rb30
-rw-r--r--config/routes/api.rb4
-rw-r--r--config/routes/profile.rb14
-rw-r--r--config/routes/project.rb120
-rw-r--r--config/routes/repository.rb7
-rw-r--r--config/routes/snippets.rb2
-rw-r--r--config/routes/uploads.rb4
-rw-r--r--config/routes/user.rb25
-rw-r--r--config/sidekiq_queues.yml2
-rw-r--r--config/unicorn.rb.example16
-rw-r--r--config/unicorn.rb.example.development16
-rw-r--r--danger/only_documentation/Dangerfile24
-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/20190402150158_backport_enterprise_schema.rb48
-rw-r--r--db/migrate/20190513174947_enable_create_incident_issues_by_default.rb19
-rw-r--r--db/migrate/20190531153110_create_namespace_root_storage_statistics.rb22
-rw-r--r--db/migrate/20190605184422_create_namespace_aggregation_schedules.rb14
-rw-r--r--db/migrate/20190607145325_add_pages_domains_ssl_renew_index.rb25
-rw-r--r--db/migrate/20190611090827_add_time_tracking_limit_to_hours_to_application_settings.rb21
-rw-r--r--db/migrate/20190613044655_add_username_to_deploy_tokens.rb9
-rw-r--r--db/migrate/20190613073003_create_project_aliases.rb16
-rw-r--r--db/migrate/20190617123615_add_grafana_to_settings.rb18
-rw-r--r--db/migrate/20190623212503_add_cluster_id_to_deployments.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/20190627051902_add_cluster_id_index_fk_to_deployments.rb21
-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/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/post_migrate/20190625184066_remove_sentry_from_application_settings.rb38
-rw-r--r--db/schema.rb50
-rw-r--r--doc/README.md4
-rw-r--r--doc/administration/auth/google_secure_ldap.md2
-rw-r--r--doc/administration/auth/ldap-ee.md12
-rw-r--r--doc/administration/auth/ldap.md39
-rw-r--r--doc/administration/auth/oidc.md22
-rw-r--r--doc/administration/container_registry.md14
-rw-r--r--doc/administration/database_load_balancing.md18
-rw-r--r--doc/administration/geo/disaster_recovery/background_verification.md10
-rw-r--r--doc/administration/geo/disaster_recovery/bring_primary_back.md28
-rw-r--r--doc/administration/geo/disaster_recovery/index.md229
-rw-r--r--doc/administration/geo/disaster_recovery/planned_failover.md41
-rw-r--r--doc/administration/geo/replication/configuration.md175
-rw-r--r--doc/administration/geo/replication/database.md600
-rw-r--r--doc/administration/geo/replication/external_database.md160
-rw-r--r--doc/administration/geo/replication/faq.md16
-rw-r--r--doc/administration/geo/replication/high_availability.md278
-rw-r--r--doc/administration/geo/replication/index.md8
-rw-r--r--doc/administration/geo/replication/remove_geo_node.md45
-rw-r--r--doc/administration/geo/replication/troubleshooting.md341
-rw-r--r--doc/administration/geo/replication/updating_the_geo_nodes.md331
-rw-r--r--doc/administration/gitaly/index.md4
-rw-r--r--doc/administration/high_availability/README.md10
-rw-r--r--doc/administration/high_availability/database.md6
-rw-r--r--doc/administration/high_availability/gitaly.md42
-rw-r--r--doc/administration/high_availability/gitlab.md13
-rw-r--r--doc/administration/high_availability/monitoring_node.md2
-rw-r--r--doc/administration/high_availability/pgbouncer.md27
-rw-r--r--doc/administration/high_availability/redis.md75
-rw-r--r--doc/administration/logs.md2
-rw-r--r--doc/administration/monitoring/performance/grafana_configuration.md15
-rw-r--r--doc/administration/monitoring/prometheus/gitlab_metrics.md2
-rw-r--r--doc/administration/operations/extra_sidekiq_processes.md199
-rw-r--r--doc/api/group_boards.md277
-rw-r--r--doc/api/group_milestones.md15
-rw-r--r--doc/api/groups.md104
-rw-r--r--doc/api/issues.md139
-rw-r--r--doc/api/jobs.md2
-rw-r--r--doc/api/merge_request_approvals.md8
-rw-r--r--doc/api/merge_requests.md190
-rw-r--r--doc/api/milestones.md15
-rw-r--r--doc/api/namespaces.md16
-rw-r--r--doc/api/notification_settings.md51
-rw-r--r--doc/api/project_aliases.md111
-rw-r--r--doc/api/project_snippets.md6
-rw-r--r--doc/api/projects.md223
-rw-r--r--doc/api/protected_branches.md154
-rw-r--r--doc/api/search.md4
-rw-r--r--doc/api/services.md33
-rw-r--r--doc/api/settings.md75
-rw-r--r--doc/api/users.md60
-rw-r--r--doc/ci/README.md3
-rw-r--r--doc/ci/docker/using_docker_build.md9
-rw-r--r--doc/ci/docker/using_docker_images.md107
-rw-r--r--doc/ci/examples/test-scala-application.md6
-rw-r--r--doc/ci/merge_request_pipelines/index.md145
-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/variables/README.md2
-rw-r--r--doc/ci/variables/predefined_variables.md4
-rw-r--r--doc/customization/system_header_and_footer_messages.md3
-rw-r--r--doc/development/README.md1
-rw-r--r--doc/development/api_graphql_styleguide.md8
-rw-r--r--doc/development/architecture.md20
-rw-r--r--doc/development/chatops_on_gitlabcom.md9
-rw-r--r--doc/development/code_comments.md14
-rw-r--r--doc/development/code_review.md3
-rw-r--r--doc/development/contributing/issue_workflow.md120
-rw-r--r--doc/development/contributing/merge_request_workflow.md6
-rw-r--r--doc/development/contributing/style_guides.md4
-rw-r--r--doc/development/database_debugging.md18
-rw-r--r--doc/development/documentation/index.md8
-rw-r--r--doc/development/documentation/site_architecture/global_nav.md34
-rw-r--r--doc/development/documentation/site_architecture/index.md42
-rw-r--r--doc/development/documentation/styleguide.md142
-rw-r--r--doc/development/ee_features.md28
-rw-r--r--doc/development/elasticsearch.md47
-rw-r--r--doc/development/fe_guide/accessibility.md12
-rw-r--r--doc/development/fe_guide/style_guide_scss.md9
-rw-r--r--doc/development/fe_guide/vue.md11
-rw-r--r--doc/development/feature_flags.md128
-rw-r--r--doc/development/feature_flags/controls.md123
-rw-r--r--doc/development/feature_flags/development.md131
-rw-r--r--doc/development/feature_flags/index.md12
-rw-r--r--doc/development/feature_flags/process.md131
-rw-r--r--doc/development/geo.md36
-rw-r--r--doc/development/git_object_deduplication.md6
-rw-r--r--doc/development/gitaly.md12
-rw-r--r--doc/development/go_guide/index.md2
-rw-r--r--doc/development/i18n/externalization.md45
-rw-r--r--doc/development/new_fe_guide/tips.md10
-rw-r--r--doc/development/performance.md2
-rw-r--r--doc/development/pry_debugging.md2
-rw-r--r--doc/development/reusing_abstractions.md36
-rw-r--r--doc/development/rolling_out_changes_using_feature_flags.md226
-rw-r--r--doc/development/testing_guide/best_practices.md2
-rw-r--r--doc/development/testing_guide/end_to_end/dynamic_element_validation.md12
-rw-r--r--doc/development/testing_guide/end_to_end/page_objects.md6
-rw-r--r--doc/development/testing_guide/end_to_end/quick_start_guide.md12
-rw-r--r--doc/development/testing_guide/frontend_testing.md18
-rw-r--r--doc/development/testing_guide/review_apps.md2
-rw-r--r--doc/gitlab-basics/command-line-commands.md16
-rw-r--r--doc/install/installation.md2
-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.md12
-rw-r--r--doc/install/requirements.md12
-rw-r--r--doc/integration/README.md4
-rw-r--r--doc/integration/elasticsearch.md32
-rw-r--r--doc/integration/jenkins.md40
-rw-r--r--doc/integration/jenkins_deprecated.md8
-rw-r--r--doc/public_access/public_access.md6
-rw-r--r--doc/push_rules/push_rules.md4
-rw-r--r--doc/raketasks/backup_restore.md315
-rw-r--r--doc/raketasks/cleanup.md45
-rw-r--r--doc/raketasks/web_hooks.md60
-rw-r--r--doc/security/rack_attack.md5
-rw-r--r--doc/subscriptions/index.md20
-rw-r--r--doc/topics/application_development_platform/index.md17
-rw-r--r--doc/topics/autodevops/index.md45
-rw-r--r--doc/university/README.md2
-rw-r--r--doc/university/process/README.md6
-rw-r--r--doc/university/support/README.md2
-rw-r--r--doc/update/upgrading_from_ce_to_ee.md22
-rw-r--r--doc/user/admin_area/index.md67
-rw-r--r--doc/user/admin_area/monitoring/health_check.md51
-rw-r--r--doc/user/admin_area/settings/continuous_integration.md29
-rw-r--r--doc/user/admin_area/settings/terms.md2
-rw-r--r--doc/user/application_security/container_scanning/index.md5
-rw-r--r--doc/user/application_security/dast/index.md5
-rw-r--r--doc/user/application_security/dependency_scanning/analyzers.md133
-rw-r--r--doc/user/application_security/dependency_scanning/index.md78
-rw-r--r--doc/user/application_security/index.md25
-rw-r--r--doc/user/application_security/sast/index.md13
-rw-r--r--doc/user/asciidoc.md2
-rw-r--r--doc/user/clusters/applications.md5
-rw-r--r--doc/user/gitlab_com/index.md10
-rw-r--r--doc/user/group/clusters/index.md8
-rw-r--r--doc/user/group/contribution_analytics/index.md18
-rw-r--r--doc/user/group/epics/index.md6
-rw-r--r--doc/user/group/index.md15
-rw-r--r--doc/user/group/insights/index.md3
-rw-r--r--doc/user/group/saml_sso/scim_setup.md32
-rw-r--r--doc/user/img/color_inline_colorchip_render_gfm.pngbin4684 -> 0 bytes
-rw-r--r--doc/user/img/markdown_inline_diffs_tags_rendered.pngbin1804 -> 0 bytes
-rw-r--r--doc/user/img/math_inline_sup_render_gfm.pngbin1119 -> 0 bytes
-rw-r--r--doc/user/img/task_list_ordered_render_gfm.pngbin2855 -> 0 bytes
-rw-r--r--doc/user/index.md4
-rw-r--r--doc/user/markdown.md1533
-rw-r--r--doc/user/operations_dashboard/index.md11
-rw-r--r--doc/user/permissions.md9
-rw-r--r--doc/user/profile/account/img/2fa.pngbin22047 -> 0 bytes
-rw-r--r--doc/user/profile/account/img/2fa_auth.pngbin14535 -> 0 bytes
-rw-r--r--doc/user/profile/account/img/2fa_u2f_authenticate.pngbin17582 -> 0 bytes
-rw-r--r--doc/user/profile/account/img/2fa_u2f_register.pngbin35186 -> 0 bytes
-rw-r--r--doc/user/profile/account/two_factor_authentication.md151
-rw-r--r--doc/user/project/canary_deployments.md3
-rw-r--r--doc/user/project/clusters/index.md27
-rw-r--r--doc/user/project/clusters/kubernetes_pod_logs.md4
-rw-r--r--doc/user/project/clusters/serverless/img/function-endpoint.pngbin0 -> 42436 bytes
-rw-r--r--doc/user/project/clusters/serverless/index.md319
-rw-r--r--doc/user/project/container_registry.md14
-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.md12
-rw-r--r--doc/user/project/import/gemnasium.md4
-rw-r--r--doc/user/project/index.md23
-rw-r--r--doc/user/project/insights/index.md3
-rw-r--r--doc/user/project/integrations/github.md2
-rw-r--r--doc/user/project/integrations/hipchat.md2
-rw-r--r--doc/user/project/integrations/jira.md14
-rw-r--r--doc/user/project/integrations/jira_cloud_configuration.md12
-rw-r--r--doc/user/project/integrations/jira_server_configuration.md2
-rw-r--r--doc/user/project/integrations/project_services.md2
-rw-r--r--doc/user/project/integrations/prometheus.md2
-rw-r--r--doc/user/project/integrations/prometheus_library/haproxy.md4
-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/issues/index.md2
-rw-r--r--doc/user/project/merge_requests/merge_request_approvals.md8
-rw-r--r--doc/user/project/merge_requests/merge_when_pipeline_succeeds.md17
-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/pages/getting_started_part_three.md39
-rw-r--r--doc/user/project/pages/getting_started_part_two.md18
-rw-r--r--doc/user/project/pages/index.md7
-rw-r--r--doc/user/project/pages/introduction.md6
-rw-r--r--doc/user/project/pipelines/job_artifacts.md3
-rw-r--r--doc/user/project/quick_actions.md1
-rw-r--r--doc/user/project/settings/index.md10
-rw-r--r--doc/user/project/web_ide/index.md12
-rw-r--r--doc/workflow/gitlab_flow.md2
-rw-r--r--doc/workflow/notifications.md24
-rw-r--r--doc/workflow/time_tracking.md10
-rw-r--r--lib/after_commit_queue.rb14
-rw-r--r--lib/api/boards.rb2
-rw-r--r--lib/api/boards_responses.rb2
-rw-r--r--lib/api/branches.rb5
-rw-r--r--lib/api/commits.rb5
-rw-r--r--lib/api/entities.rb14
-rw-r--r--lib/api/group_boards.rb2
-rw-r--r--lib/api/helpers.rb4
-rw-r--r--lib/api/helpers/services_helpers.rb10
-rw-r--r--lib/api/issues.rb6
-rw-r--r--lib/api/merge_requests.rb2
-rw-r--r--lib/api/releases.rb2
-rw-r--r--lib/api/settings.rb10
-rw-r--r--lib/api/todos.rb4
-rw-r--r--lib/api/users.rb1
-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.rb4
-rw-r--r--lib/feature/gitaly.rb7
-rw-r--r--lib/gitlab.rb4
-rw-r--r--lib/gitlab/asciidoc.rb3
-rw-r--r--lib/gitlab/asciidoc/syntax_highlighter/html_pipeline_adapter.rb15
-rw-r--r--lib/gitlab/auth/ip_rate_limiter.rb17
-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/ansi2html.rb4
-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/Code-Quality.gitlab-ci.yml2
-rw-r--r--lib/gitlab/ci/templates/Pages/Jekyll.gitlab-ci.yml1
-rw-r--r--lib/gitlab/ci/trace.rb2
-rw-r--r--lib/gitlab/cleanup/orphan_job_artifact_files.rb132
-rw-r--r--lib/gitlab/cleanup/orphan_job_artifact_files_batch.rb80
-rw-r--r--lib/gitlab/cluster/lifecycle_events.rb3
-rw-r--r--lib/gitlab/config/loader/yaml.rb34
-rw-r--r--lib/gitlab/database.rb56
-rw-r--r--lib/gitlab/database/migration_helpers.rb3
-rw-r--r--lib/gitlab/diff/lines_unfolder.rb2
-rw-r--r--lib/gitlab/git/raw_diff_change.rb4
-rw-r--r--lib/gitlab/git/repository.rb5
-rw-r--r--lib/gitlab/gitaly_client/commit_service.rb40
-rw-r--r--lib/gitlab/gon_helper.rb4
-rw-r--r--lib/gitlab/graphql/authorize/authorize_field_service.rb2
-rw-r--r--lib/gitlab/graphql/authorize/authorize_resource.rb12
-rw-r--r--lib/gitlab/graphql/copy_field_description.rb21
-rw-r--r--lib/gitlab/graphql/errors.rb1
-rw-r--r--lib/gitlab/graphql/find_argument_in_parent.rb32
-rw-r--r--lib/gitlab/graphql/loaders/pipeline_for_sha_loader.rb25
-rw-r--r--lib/gitlab/issuable_metadata.rb4
-rw-r--r--lib/gitlab/json_cache.rb2
-rw-r--r--lib/gitlab/legacy_github_import/release_formatter.rb1
-rw-r--r--lib/gitlab/lets_encrypt.rb16
-rw-r--r--lib/gitlab/lets_encrypt/client.rb10
-rw-r--r--lib/gitlab/metrics/dashboard/base_service.rb8
-rw-r--r--lib/gitlab/metrics/system.rb14
-rw-r--r--lib/gitlab/optimistic_locking.rb1
-rw-r--r--lib/gitlab/path_regex.rb1
-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/search/found_blob.rb2
-rw-r--r--lib/gitlab/sentry.rb2
-rw-r--r--lib/gitlab/thread_memory_cache.rb15
-rw-r--r--lib/gitlab/time_tracking_formatter.rb10
-rw-r--r--lib/gitlab/utils/deep_size.rb79
-rw-r--r--lib/peek/views/redis.rb82
-rw-r--r--lib/tasks/gitlab/backup.rake4
-rw-r--r--lib/tasks/gitlab/cleanup.rake25
-rw-r--r--lib/tasks/migrate/schema_check.rake20
-rw-r--r--lib/tasks/migrate/setup_postgresql.rake14
-rw-r--r--lib/tasks/yarn.rake2
-rw-r--r--locale/ar_SA/gitlab.po6
-rw-r--r--locale/bg/gitlab.po6
-rw-r--r--locale/bn_BD/gitlab.po6
-rw-r--r--locale/bn_IN/gitlab.po6
-rw-r--r--locale/ca_ES/gitlab.po6
-rw-r--r--locale/cs_CZ/gitlab.po6
-rw-r--r--locale/cy_GB/gitlab.po6
-rw-r--r--locale/da_DK/gitlab.po6
-rw-r--r--locale/de/gitlab.po6
-rw-r--r--locale/el_GR/gitlab.po6
-rw-r--r--locale/eo/gitlab.po6
-rw-r--r--locale/es/gitlab.po6
-rw-r--r--locale/et_EE/gitlab.po6
-rw-r--r--locale/fil_PH/gitlab.po6
-rw-r--r--locale/fr/gitlab.po6
-rw-r--r--locale/gitlab.pot500
-rw-r--r--locale/gl_ES/gitlab.po6
-rw-r--r--locale/he_IL/gitlab.po6
-rw-r--r--locale/hi_IN/gitlab.po6
-rw-r--r--locale/hr_HR/gitlab.po6
-rw-r--r--locale/hu_HU/gitlab.po6
-rw-r--r--locale/id_ID/gitlab.po6
-rw-r--r--locale/it/gitlab.po6
-rw-r--r--locale/ja/gitlab.po6
-rw-r--r--locale/ka_GE/gitlab.po6
-rw-r--r--locale/ko/gitlab.po6
-rw-r--r--locale/mn_MN/gitlab.po6
-rw-r--r--locale/nb_NO/gitlab.po6
-rw-r--r--locale/nl_NL/gitlab.po6
-rw-r--r--locale/pa_IN/gitlab.po6
-rw-r--r--locale/pl_PL/gitlab.po6
-rw-r--r--locale/pt_BR/gitlab.po6
-rw-r--r--locale/pt_PT/gitlab.po6
-rw-r--r--locale/ro_RO/gitlab.po6
-rw-r--r--locale/ru/gitlab.po6
-rw-r--r--locale/sk_SK/gitlab.po6
-rw-r--r--locale/sq_AL/gitlab.po6
-rw-r--r--locale/sr_CS/gitlab.po6
-rw-r--r--locale/sr_SP/gitlab.po6
-rw-r--r--locale/sv_SE/gitlab.po6
-rw-r--r--locale/sw_KE/gitlab.po6
-rw-r--r--locale/tr_TR/gitlab.po6
-rw-r--r--locale/uk/gitlab.po6
-rw-r--r--locale/zh_CN/gitlab.po6
-rw-r--r--locale/zh_HK/gitlab.po6
-rw-r--r--locale/zh_TW/gitlab.po6
-rw-r--r--package.json11
-rw-r--r--qa/qa.rb5
-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/sub_menus/project.rb29
-rw-r--r--qa/qa/page/project/sub_menus/settings.rb9
-rw-r--r--qa/qa/page/settings/common.rb2
-rw-r--r--qa/qa/resource/api_fabricator.rb7
-rw-r--r--qa/qa/resource/group.rb4
-rw-r--r--qa/qa/resource/kubernetes_cluster.rb2
-rw-r--r--qa/qa/resource/merge_request_from_fork.rb2
-rw-r--r--qa/qa/resource/project.rb28
-rw-r--r--qa/qa/resource/user.rb2
-rw-r--r--qa/qa/runtime/api/client.rb19
-rw-r--r--qa/qa/service/shellout.rb2
-rw-r--r--qa/qa/specs/features/api/3_create/repository/project_archive_compare_spec.rb75
-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/3_create/repository/add_file_template_spec.rb3
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/snippet/create_snippet_spec.rb8
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/web_ide/add_file_template_spec.rb3
-rw-r--r--qa/qa/support/api.rb5
-rw-r--r--qa/spec/runtime/api/client_spec.rb36
-rw-r--r--rubocop/cop/graphql/authorize_types.rb61
-rw-r--r--rubocop/rubocop.rb1
-rwxr-xr-xscripts/generate-gems-memory-metrics-static18
-rwxr-xr-xscripts/generate-gems-size-metrics-static30
-rwxr-xr-xscripts/generate-memory-metrics-on-boot11
-rwxr-xr-xscripts/memory-static20
-rwxr-xr-xscripts/memory-static-objects27
-rw-r--r--scripts/prepare_build.sh10
-rwxr-xr-xscripts/review_apps/review-apps.sh102
-rwxr-xr-xscripts/trigger-build9
-rw-r--r--spec/controllers/admin/clusters/applications_controller_spec.rb10
-rw-r--r--spec/controllers/admin/clusters_controller_spec.rb76
-rw-r--r--spec/controllers/concerns/continue_params_spec.rb8
-rw-r--r--spec/controllers/concerns/internal_redirect_spec.rb77
-rw-r--r--spec/controllers/dashboard/todos_controller_spec.rb28
-rw-r--r--spec/controllers/groups/boards_controller_spec.rb2
-rw-r--r--spec/controllers/groups/clusters_controller_spec.rb80
-rw-r--r--spec/controllers/groups_controller_spec.rb7
-rw-r--r--spec/controllers/projects/boards_controller_spec.rb2
-rw-r--r--spec/controllers/projects/branches_controller_spec.rb94
-rw-r--r--spec/controllers/projects/forks_controller_spec.rb16
-rw-r--r--spec/controllers/projects/issues_controller_spec.rb44
-rw-r--r--spec/controllers/projects/merge_requests/content_controller_spec.rb60
-rw-r--r--spec/controllers/projects/notes_controller_spec.rb2
-rw-r--r--spec/controllers/projects/services_controller_spec.rb10
-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/registrations_controller_spec.rb17
-rw-r--r--spec/controllers/search_controller_spec.rb17
-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/award_emoji.rb2
-rw-r--r--spec/factories/clusters/clusters.rb2
-rw-r--r--spec/factories/deployments.rb4
-rw-r--r--spec/factories/namespace/aggregation_schedules.rb7
-rw-r--r--spec/factories/namespace/root_storage_statistics.rb7
-rw-r--r--spec/factories/namespaces.rb8
-rw-r--r--spec/factories/pages_domains.rb1
-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_settings_spec.rb70
-rw-r--r--spec/features/boards/sidebar_spec.rb22
-rw-r--r--spec/features/container_registry_spec.rb2
-rw-r--r--spec/features/discussion_comments/commit_spec.rb20
-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.rb78
-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/gfm_autocomplete_spec.rb70
-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_suggests_changes_on_diff_spec.rb4
-rw-r--r--spec/features/projects/clusters/applications_spec.rb23
-rw-r--r--spec/features/projects/environments/environment_metrics_spec.rb39
-rw-r--r--spec/features/projects/files/user_edits_files_spec.rb40
-rw-r--r--spec/features/projects/files/user_reads_pipeline_status_spec.rb2
-rw-r--r--spec/features/projects/releases/user_views_releases_spec.rb12
-rw-r--r--spec/features/projects/services/user_activates_jira_spec.rb28
-rw-r--r--spec/features/projects/settings/repository_settings_spec.rb6
-rw-r--r--spec/features/projects/show/user_sees_last_commit_ci_status_spec.rb4
-rw-r--r--spec/features/raven_js_spec.rb2
-rw-r--r--spec/features/snippets/user_creates_snippet_spec.rb2
-rw-r--r--spec/features/users/signup_spec.rb2
-rw-r--r--spec/features/users/terms_spec.rb15
-rw-r--r--spec/finders/autocomplete/acts_as_taggable_on/tags_finder_spec.rb8
-rw-r--r--spec/finders/boards/visits_finder_spec.rb59
-rw-r--r--spec/finders/branches_finder_spec.rb9
-rw-r--r--spec/finders/releases_finder_spec.rb6
-rw-r--r--spec/fixtures/api/schemas/entities/merge_request_widget.json3
-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/boards/modal_store_spec.js2
-rw-r--r--spec/frontend/boards/services/board_service_spec.js390
-rw-r--r--spec/frontend/branches/divergence_graph_spec.js32
-rw-r--r--spec/frontend/clusters/services/application_state_machine_spec.js16
-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/helpers/vuex_action_helper.js7
-rw-r--r--spec/frontend/helpers/vuex_action_helper_spec.js166
-rw-r--r--spec/frontend/ide/utils_spec.js44
-rw-r--r--spec/frontend/lib/utils/datetime_utility_spec.js6
-rw-r--r--spec/frontend/lib/utils/text_utility_spec.js19
-rw-r--r--spec/frontend/notes/components/discussion_notes_spec.js40
-rw-r--r--spec/frontend/notes/components/discussion_reply_placeholder_spec.js14
-rw-r--r--spec/frontend/repository/components/__snapshots__/last_commit_spec.js.snap16
-rw-r--r--spec/frontend/repository/components/last_commit_spec.js21
-rw-r--r--spec/frontend/repository/components/table/__snapshots__/row_spec.js.snap14
-rw-r--r--spec/frontend/repository/components/table/row_spec.js2
-rw-r--r--spec/frontend/repository/log_tree_spec.js129
-rw-r--r--spec/frontend/test_setup.js19
-rw-r--r--spec/frontend/vue_shared/components/issue/related_issuable_item_spec.js6
-rw-r--r--spec/frontend/vue_shared/components/markdown/header_spec.js107
-rw-r--r--spec/graphql/gitlab_schema_spec.rb2
-rw-r--r--spec/graphql/types/award_emojis/award_emoji_type_spec.rb11
-rw-r--r--spec/graphql/types/commit_type_spec.rb11
-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/graphql/types/tree/tree_type_spec.rb2
-rw-r--r--spec/helpers/markup_helper_spec.rb37
-rw-r--r--spec/helpers/onboarding_experiment_helper_spec.rb38
-rw-r--r--spec/helpers/recaptcha_experiment_helper_spec.rb23
-rw-r--r--spec/helpers/search_helper_spec.rb6
-rw-r--r--spec/initializers/6_validations_spec.rb20
-rw-r--r--spec/javascripts/boards/boards_store_spec.js10
-rw-r--r--spec/javascripts/boards/components/board_spec.js61
-rw-r--r--spec/javascripts/boards/components/issue_time_estimate_spec.js70
-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.js3
-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/filtered_search/visual_token_value_spec.js2
-rw-r--r--spec/javascripts/ide/components/ide_tree_list_spec.js14
-rw-r--r--spec/javascripts/ide/components/repo_editor_spec.js63
-rw-r--r--spec/javascripts/ide/stores/actions/file_spec.js37
-rw-r--r--spec/javascripts/ide/stores/actions_spec.js78
-rw-r--r--spec/javascripts/ide/stores/mutations/file_spec.js13
-rw-r--r--spec/javascripts/ide/stores/mutations_spec.js79
-rw-r--r--spec/javascripts/ide/stores/utils_spec.js26
-rw-r--r--spec/javascripts/monitoring/charts/area_spec.js15
-rw-r--r--spec/javascripts/monitoring/charts/column_spec.js58
-rw-r--r--spec/javascripts/monitoring/dashboard_spec.js96
-rw-r--r--spec/javascripts/monitoring/mock_data.js13
-rw-r--r--spec/javascripts/monitoring/store/actions_spec.js17
-rw-r--r--spec/javascripts/monitoring/store/mutations_spec.js15
-rw-r--r--spec/javascripts/notes/components/noteable_discussion_spec.js52
-rw-r--r--spec/javascripts/notes/stores/actions_spec.js16
-rw-r--r--spec/javascripts/notes/stores/getters_spec.js20
-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/registry/components/collapsible_container_spec.js18
-rw-r--r--spec/javascripts/registry/components/table_registry_spec.js19
-rw-r--r--spec/javascripts/releases/components/release_block_spec.js12
-rw-r--r--spec/javascripts/sidebar/components/time_tracking/time_tracker_spec.js25
-rw-r--r--spec/javascripts/test_bundle.js4
-rw-r--r--spec/javascripts/vue_mr_widget/components/states/mr_widget_unresolved_discussions_spec.js8
-rw-r--r--spec/javascripts/vue_mr_widget/mock_data.js3
-rw-r--r--spec/javascripts/vue_mr_widget/mr_widget_options_spec.js2
-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.rb2
-rw-r--r--spec/lib/gitlab/asciidoc_spec.rb68
-rw-r--r--spec/lib/gitlab/auth/ip_rate_limiter_spec.rb65
-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/ci/ansi2html_spec.rb8
-rw-r--r--spec/lib/gitlab/ci/build/prerequisite/kubernetes_namespace_spec.rb22
-rw-r--r--spec/lib/gitlab/ci/config_spec.rb21
-rw-r--r--spec/lib/gitlab/ci/trace/stream_spec.rb10
-rw-r--r--spec/lib/gitlab/cleanup/orphan_job_artifact_files_batch_spec.rb66
-rw-r--r--spec/lib/gitlab/cleanup/orphan_job_artifact_files_spec.rb68
-rw-r--r--spec/lib/gitlab/config/loader/yaml_spec.rb72
-rw-r--r--spec/lib/gitlab/database/migration_helpers_spec.rb18
-rw-r--r--spec/lib/gitlab/diff/lines_unfolder_spec.rb33
-rw-r--r--spec/lib/gitlab/git/repository_spec.rb18
-rw-r--r--spec/lib/gitlab/gitaly_client/commit_service_spec.rb13
-rw-r--r--spec/lib/gitlab/graphql/authorize/authorize_field_service_spec.rb82
-rw-r--r--spec/lib/gitlab/graphql/authorize/authorize_resource_spec.rb53
-rw-r--r--spec/lib/gitlab/graphql/copy_field_description_spec.rb21
-rw-r--r--spec/lib/gitlab/graphql/find_argument_in_parent_spec.rb44
-rw-r--r--spec/lib/gitlab/graphql/loaders/pipeline_for_sha_loader_spec.rb20
-rw-r--r--spec/lib/gitlab/import_export/all_models.yml1
-rw-r--r--spec/lib/gitlab/import_export/project.json2
-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/issuable_sorter_spec.rb2
-rw-r--r--spec/lib/gitlab/json_cache_spec.rb35
-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/lets_encrypt/client_spec.rb36
-rw-r--r--spec/lib/gitlab/lets_encrypt_spec.rb56
-rw-r--r--spec/lib/gitlab/metrics/dashboard/dynamic_dashboard_service_spec.rb8
-rw-r--r--spec/lib/gitlab/metrics/dashboard/finder_spec.rb11
-rw-r--r--spec/lib/gitlab/metrics/dashboard/project_dashboard_service_spec.rb6
-rw-r--r--spec/lib/gitlab/metrics/dashboard/system_dashboard_service_spec.rb10
-rw-r--r--spec/lib/gitlab/metrics/system_spec.rb4
-rw-r--r--spec/lib/gitlab/performance_bar_spec.rb27
-rw-r--r--spec/lib/gitlab/reference_extractor_spec.rb6
-rw-r--r--spec/lib/gitlab/time_tracking_formatter_spec.rb43
-rw-r--r--spec/lib/gitlab/utils/deep_size_spec.rb43
-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/backport_enterprise_schema_spec.rb41
-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/application_setting_spec.rb30
-rw-r--r--spec/models/broadcast_message_spec.rb6
-rw-r--r--spec/models/ci/pipeline_spec.rb11
-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/platforms/kubernetes_spec.rb43
-rw-r--r--spec/models/concerns/cacheable_attributes_spec.rb9
-rw-r--r--spec/models/concerns/deployable_spec.rb14
-rw-r--r--spec/models/concerns/deployment_platform_spec.rb10
-rw-r--r--spec/models/concerns/mentionable_spec.rb2
-rw-r--r--spec/models/deploy_token_spec.rb35
-rw-r--r--spec/models/deployment_spec.rb66
-rw-r--r--spec/models/environment_spec.rb63
-rw-r--r--spec/models/group_spec.rb29
-rw-r--r--spec/models/internal_id_spec.rb2
-rw-r--r--spec/models/merge_request_spec.rb2
-rw-r--r--spec/models/namespace/aggregation_schedule_spec.rb78
-rw-r--r--spec/models/namespace/root_storage_statistics_spec.rb75
-rw-r--r--spec/models/namespace_spec.rb18
-rw-r--r--spec/models/pages_domain_spec.rb26
-rw-r--r--spec/models/postgresql/replication_slot_spec.rb8
-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/gitlab_issue_tracker_service_spec.rb43
-rw-r--r--spec/models/project_services/jira_service_spec.rb148
-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_spec.rb1
-rw-r--r--spec/models/release_spec.rb10
-rw-r--r--spec/models/repository_spec.rb55
-rw-r--r--spec/models/service_spec.rb9
-rw-r--r--spec/models/user_spec.rb4
-rw-r--r--spec/policies/award_emoji_policy_spec.rb54
-rw-r--r--spec/policies/clusters/instance_policy_spec.rb18
-rw-r--r--spec/presenters/award_emoji_presenter_spec.rb36
-rw-r--r--spec/requests/api/branches_spec.rb10
-rw-r--r--spec/requests/api/commits_spec.rb14
-rw-r--r--spec/requests/api/graphql/mutations/award_emojis/add_spec.rb100
-rw-r--r--spec/requests/api/graphql/mutations/award_emojis/remove_spec.rb80
-rw-r--r--spec/requests/api/graphql/mutations/award_emojis/toggle_spec.rb142
-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/project/tree/tree_spec.rb18
-rw-r--r--spec/requests/api/helpers_spec.rb6
-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.rb25
-rw-r--r--spec/requests/api/project_clusters_spec.rb61
-rw-r--r--spec/requests/api/releases_spec.rb81
-rw-r--r--spec/requests/api/users_spec.rb19
-rw-r--r--spec/requests/rack_attack_global_spec.rb43
-rw-r--r--spec/routing/project_routing_spec.rb20
-rw-r--r--spec/routing/routing_spec.rb30
-rw-r--r--spec/routing/uploads_routing_spec.rb13
-rw-r--r--spec/rubocop/cop/graphql/authorize_types_spec.rb66
-rw-r--r--spec/services/boards/visits/latest_service_spec.rb59
-rw-r--r--spec/services/branches/diverging_commit_counts_service_spec.rb31
-rw-r--r--spec/services/deploy_tokens/create_service_spec.rb16
-rw-r--r--spec/services/merge_requests/create_from_issue_service_spec.rb205
-rw-r--r--spec/services/merge_requests/merge_service_spec.rb6
-rw-r--r--spec/services/namespaces/statistics_refresher_service_spec.rb58
-rw-r--r--spec/services/pages_domains/obtain_lets_encrypt_certificate_service_spec.rb12
-rw-r--r--spec/services/projects/propagate_service_template_spec.rb2
-rw-r--r--spec/services/system_note_service_spec.rb60
-rw-r--r--spec/spec_helper.rb8
-rw-r--r--spec/support/api/boards_shared_examples.rb10
-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/email_helpers.rb15
-rw-r--r--spec/support/helpers/graphql_helpers.rb5
-rw-r--r--spec/support/helpers/jira_service_helper.rb6
-rw-r--r--spec/support/helpers/metrics_dashboard_helpers.rb8
-rw-r--r--spec/support/helpers/prometheus_helpers.rb4
-rw-r--r--spec/support/helpers/stub_configuration.rb11
-rw-r--r--spec/support/helpers/test_env.rb3
-rw-r--r--spec/support/inspect_squelch.rb7
-rw-r--r--spec/support/matchers/gitaly_matchers.rb2
-rw-r--r--spec/support/shared_examples/application_setting_examples.rb39
-rw-r--r--spec/support/shared_examples/ci_trace_shared_examples.rb4
-rw-r--r--spec/support/shared_examples/features/comments_on_merge_request_files_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/graphql/mutation_shared_examples.rb34
-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/shared_examples/services/boards/issues_move_service.rb62
-rw-r--r--spec/support/sidekiq.rb4
-rw-r--r--spec/tasks/gitlab/cleanup_rake_spec.rb29
-rw-r--r--spec/tasks/migrate/schema_check_rake_spec.rb48
-rw-r--r--spec/uploaders/file_mover_spec.rb132
-rw-r--r--spec/validators/color_validator_spec.rb43
-rw-r--r--spec/views/layouts/nav/sidebar/_project.html.haml_spec.rb2
-rw-r--r--spec/views/projects/services/_form.haml_spec.rb6
-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.rb66
-rw-r--r--spec/workers/pages_domain_ssl_renewal_cron_worker_spec.rb62
-rw-r--r--spec/workers/pages_domain_ssl_renewal_worker_spec.rb46
-rw-r--r--spec/workers/reactive_caching_worker_spec.rb7
-rw-r--r--tmp/prometheus_multiproc_dir/puma/.gitkeep (renamed from app/graphql/mutations/.keep)0
-rw-r--r--tmp/prometheus_multiproc_dir/sidekiq/.gitkeep0
-rw-r--r--tmp/prometheus_multiproc_dir/unicorn/.gitkeep0
-rw-r--r--vendor/jupyter/values.yaml2
-rw-r--r--yarn.lock482
2078 files changed, 23805 insertions, 31132 deletions
diff --git a/.gitlab/CODEOWNERS b/.gitlab/CODEOWNERS
index 0ca6d7a350a..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
@@ -19,3 +19,5 @@ db/ @abrandl @NikolayS
/lib/gitlab/ci/templates/ @nolith @zj
/lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml @DylanGriffith @mayra-cabrera @tkuah
/lib/gitlab/ci/templates/Security/ @plafoucriere @gonzoyumo @twoodham
+/ee/app/models/project_alias.rb @patrickbajao
+/ee/lib/api/project_aliases.rb @patrickbajao
diff --git a/.gitlab/ci/docs.gitlab-ci.yml b/.gitlab/ci/docs.gitlab-ci.yml
index 5aa1a856405..6acbce6cf0c 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.
@@ -66,6 +65,10 @@ docs lint:
- scripts/lint-changelog-yaml
- 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 --ignore-front-matter --rules \
+ MD004,MD032,MD034
# 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 75c79bb213f..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,8 +70,10 @@ gitlab:assets:compile pull-cache:
cache:
policy: pull
except:
- - master@gitlab-org/gitlab-ce
- - master@gitlab-org/gitlab-ee
+ refs:
+ - master@gitlab-org/gitlab-ce
+ - master@gitlab-org/gitlab-ee
+ - /(^docs[\/-].*|.*-docs$)/
.compile-assets-metadata:
extends: .dedicated-runner
@@ -80,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
@@ -106,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
@@ -165,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
@@ -188,8 +191,8 @@ jest:
paths:
- coverage-frontend/
- junit_jest.xml
- reports:
- junit: junit_jest.xml
+# reports:
+# junit: junit_jest.xml
cache:
key: jest
paths:
@@ -228,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 b7ef4b31743..4da7f404767 100644
--- a/.gitlab/ci/global.gitlab-ci.yml
+++ b/.gitlab/ci/global.gitlab-ci.yml
@@ -28,16 +28,26 @@
policy: pull
stage: test
-.dedicated-no-docs-pull-cache-job:
- extends: .dedicated-pull-cache-job
+.no-docs:
except:
- - /(^docs[\/-].*|.*-docs$)/
+ refs:
+ - /(^docs[\/-].*|.*-docs$)/
-.dedicated-no-docs-and-no-qa-pull-cache-job:
- extends: .dedicated-pull-cache-job
+.no-docs-and-no-qa:
except:
- - /(^docs[\/-].*|.*-docs$)/
- - /(^qa[\/-].*|.*-qa$)/
+ refs:
+ - /(^docs[\/-].*|.*-docs$)/
+ - /(^qa[\/-].*|.*-qa$)/
+
+.dedicated-no-docs-pull-cache-job:
+ extends:
+ - .dedicated-pull-cache-job
+ - .no-docs
+
+.dedicated-no-docs-and-no-qa-pull-cache-job:
+ extends:
+ - .dedicated-pull-cache-job
+ - .no-docs-and-no-qa
# Jobs that do not need a DB
.dedicated-no-docs-no-db-pull-cache-job:
@@ -45,6 +55,12 @@
variables:
SETUP_DB: "false"
+# Jobs that need a dedicated runner, with no cache
+.dedicated-no-docs:
+ extends:
+ - .dedicated-runner
+ - .no-docs
+
.single-script-job-dedicated-runner:
extends: .dedicated-runner
image: ruby:2.6-alpine
diff --git a/.gitlab/ci/memory.gitlab-ci.yml b/.gitlab/ci/memory.gitlab-ci.yml
index 50b843df585..ffe5dbdc31b 100644
--- a/.gitlab/ci/memory.gitlab-ci.yml
+++ b/.gitlab/ci/memory.gitlab-ci.yml
@@ -5,15 +5,38 @@ memory-static:
# Loads each of gems in the Gemfile and checks how much memory they consume when they are required.
# 'derailed_benchmarks' internally uses 'get_process_mem'
- - scripts/memory-static 'tmp/memory_static_full_report.txt' 'tmp/memory_static_metrics.txt'
+ - bundle exec derailed bundle:mem > tmp/memory_bundle_mem.txt
+ - scripts/generate-gems-size-metrics-static tmp/memory_bundle_mem.txt >> 'tmp/memory_metrics.txt'
# Outputs detailed information about objects created while gems are loaded.
# 'derailed_benchmarks' internally uses 'memory_profiler'
- - scripts/memory-static-objects 'tmp/memory_static_objects_full_report.txt' 'tmp/memory_static_metrics.txt'
+ - bundle exec derailed bundle:objects > tmp/memory_bundle_objects.txt
+ - scripts/generate-gems-memory-metrics-static tmp/memory_bundle_objects.txt >> 'tmp/memory_metrics.txt'
artifacts:
paths:
- - tmp/memory_static_full_report.txt
- - tmp/memory_static_objects_full_report.txt
- - tmp/memory_static_metrics.txt
+ - tmp/memory_*.txt
reports:
- metrics: tmp/memory_static_metrics.txt
+ 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 529a0de696b..01c96e06547 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: 20
+ parallel: 25
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: 20
+ parallel: 25
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,8 +245,8 @@ 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
+ - 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/reports.gitlab-ci.yml b/.gitlab/ci/reports.gitlab-ci.yml
index d0e09dbf2f8..89b5ae38072 100644
--- a/.gitlab/ci/reports.gitlab-ci.yml
+++ b/.gitlab/ci/reports.gitlab-ci.yml
@@ -1,98 +1,26 @@
include:
- template: Code-Quality.gitlab-ci.yml
+ - template: Security/SAST.gitlab-ci.yml
+ - template: Security/Dependency-Scanning.gitlab-ci.yml
code_quality:
- extends: .dedicated-no-docs-no-db-pull-cache-job
+ extends: .dedicated-no-docs
# gitlab-org runners set `privileged: false` but we need to have it set to true
# since we're using Docker in Docker
tags: []
before_script: []
cache: {}
dependencies: []
- variables:
- SETUP_DB: "false"
sast:
- extends: .dedicated-no-docs-no-db-pull-cache-job
- image: docker:stable
+ extends: .dedicated-no-docs
+ before_script: []
+ tags: []
variables:
SAST_CONFIDENCE_LEVEL: 2
DOCKER_DRIVER: overlay2
- allow_failure: true
- tags: []
- before_script: []
- cache: {}
- dependencies: []
- services:
- - docker:stable-dind
- script:
- - | # this is required to avoid undesirable reset of Docker image ENV variables being set on build stage
- function propagate_env_vars() {
- CURRENT_ENV=$(printenv)
-
- for VAR_NAME; do
- echo $CURRENT_ENV | grep "${VAR_NAME}=" > /dev/null && echo "--env $VAR_NAME "
- done
- }
- - export SP_VERSION=$(echo "$CI_SERVER_VERSION" | sed 's/^\([0-9]*\)\.\([0-9]*\).*/\1-\2-stable/')
- - |
- docker run \
- $(propagate_env_vars \
- SAST_ANALYZER_IMAGES \
- SAST_ANALYZER_IMAGE_PREFIX \
- SAST_ANALYZER_IMAGE_TAG \
- SAST_DEFAULT_ANALYZERS \
- SAST_BRAKEMAN_LEVEL \
- SAST_GOSEC_LEVEL \
- SAST_FLAWFINDER_LEVEL \
- SAST_DOCKER_CLIENT_NEGOTIATION_TIMEOUT \
- SAST_PULL_ANALYZER_IMAGE_TIMEOUT \
- SAST_RUN_ANALYZER_TIMEOUT \
- ) \
- --volume "$PWD:/code" \
- --volume /var/run/docker.sock:/var/run/docker.sock \
- "registry.gitlab.com/gitlab-org/security-products/sast:$SP_VERSION" /app/bin/run /code
- artifacts:
- reports:
- sast: gl-sast-report.json
dependency_scanning:
- extends: .dedicated-no-docs-no-db-pull-cache-job
- image: docker:stable
- variables:
- DOCKER_DRIVER: overlay2
- allow_failure: true
- tags: []
before_script: []
- cache: {}
- dependencies: []
- services:
- - docker:stable-dind
- script:
- - export SP_VERSION=$(echo "$CI_SERVER_VERSION" | sed 's/^\([0-9]*\)\.\([0-9]*\).*/\1-\2-stable/')
- - | # this is required to avoid undesirable reset of Docker image ENV variables being set on build stage
- function propagate_env_vars() {
- CURRENT_ENV=$(printenv)
-
- for VAR_NAME; do
- echo $CURRENT_ENV | grep "${VAR_NAME}=" > /dev/null && echo "--env $VAR_NAME "
- done
- }
- - |
- docker run \
- $(propagate_env_vars \
- DS_ANALYZER_IMAGES \
- DS_ANALYZER_IMAGE_PREFIX \
- DS_ANALYZER_IMAGE_TAG \
- DS_DEFAULT_ANALYZERS \
- DEP_SCAN_DISABLE_REMOTE_CHECKS \
- DS_DOCKER_CLIENT_NEGOTIATION_TIMEOUT \
- DS_PULL_ANALYZER_IMAGE_TIMEOUT \
- DS_RUN_ANALYZER_TIMEOUT \
- ) \
- --volume "$PWD:/code" \
- --volume /var/run/docker.sock:/var/run/docker.sock \
- "registry.gitlab.com/gitlab-org/security-products/dependency-scanning:$SP_VERSION" /code
- artifacts:
- reports:
- dependency_scanning: gl-dependency-scanning-report.json
+ tags: []
+ extends: .dedicated-no-docs
diff --git a/.gitlab/ci/review.gitlab-ci.yml b/.gitlab/ci/review.gitlab-ci.yml
index 9b764028be9..61fd48fd72e 100644
--- a/.gitlab/ci/review.gitlab-ci.yml
+++ b/.gitlab/ci/review.gitlab-ci.yml
@@ -77,6 +77,7 @@ schedule:review-build-cng:
.review-deploy-base: &review-deploy-base
<<: *review-base
allow_failure: true
+ retry: 2
stage: review
variables:
HOST_SUFFIX: "${CI_ENVIRONMENT_SLUG}"
@@ -95,10 +96,16 @@ schedule:review-build-cng:
- install_api_client_dependencies_with_apk
- source scripts/review_apps/review-apps.sh
script:
- - perform_review_app_deployment
+ - check_kube_domain
+ - ensure_namespace
+ - install_tiller
+ - install_external_dns
+ - download_chart
+ - deploy || display_deployment_debug
+ - wait_for_review_app_to_be_accessible
+ - add_license
artifacts:
- paths:
- - review_app_url.txt
+ paths: [review_app_url.txt]
expire_in: 2 days
when: always
@@ -108,8 +115,6 @@ review-deploy:
schedule:review-deploy:
<<: *review-deploy-base
<<: *review-schedules-only
- script:
- - perform_review_app_deployment
review-stop:
<<: *review-base
@@ -124,11 +129,11 @@ review-stop:
script:
- source scripts/review_apps/review-apps.sh
- delete
- - cleanup
.review-qa-base: &review-qa-base
<<: *review-docker
allow_failure: true
+ retry: 2
stage: qa
variables:
<<: *review-docker-variables
@@ -231,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/.gitlab/issue_templates/Database Reviewer.md b/.gitlab/issue_templates/Database Reviewer.md
deleted file mode 100644
index acbaf5c1965..00000000000
--- a/.gitlab/issue_templates/Database Reviewer.md
+++ /dev/null
@@ -1,34 +0,0 @@
-#### Database Reviewer Checklist
-
-Thank you for becoming a ~database reviewer! Please work on the list
-below to complete your setup. For any question, reach out to #database
-an mention `@abrandl`.
-
-- [ ] Change issue title to include your name: `Database Reviewer Checklist: Your Name`
-- [ ] Review general [code review guide](https://docs.gitlab.com/ee/development/code_review.html)
-- [ ] Review [database review documentation](https://about.gitlab.com/handbook/engineering/workflow/code-review/database.html)
-- [ ] Familiarize with [migration helpers](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/lib/gitlab/database/migration_helpers.rb) and review usage in existing migrations
-- [ ] Read [database migration style guide](https://docs.gitlab.com/ee/development/migration_style_guide.html)
-- [ ] Familiarize with best practices in [database guides](https://docs.gitlab.com/ee/development/#database-guides)
-- [ ] Watch [Optimising Rails Database Queries: Episode 1](https://www.youtube.com/watch?v=79GurlaxhsI)
-- [ ] Read [Understanding EXPLAIN plans](https://docs.gitlab.com/ee/development/understanding_explain_plans.html)
-- [ ] Review [database best practices](https://docs.gitlab.com/ee/development/#best-practices)
-- [ ] Review how we use [database instances restored from a backup](https://ops.gitlab.net/gitlab-com/gl-infra/gitlab-restore/postgres-gprd) for testing and make sure you're set up to execute pipelines (check [README.md](https://ops.gitlab.net/gitlab-com/gl-infra/gitlab-restore/postgres-gprd/blob/master/README.md) and reach out to @abrandl since this is currently subject to being changed)
-- [ ] Get yourself added to [`@gl-database`](https://gitlab.com/groups/gl-database/-/group_members) group and respond to @-mentions to the group (reach out to any maintainer on the group to get added). You will get TODOs on gitlab.com for group mentions.
-- [ ] Make sure you have proper access to at least a read-only replica in staging and production
-- [ ] Indicate in `data/team.yml` your role as a database reviewer ([example MR](https://gitlab.com/gitlab-com/www-gitlab-com/merge_requests/19600/diffs)). Assign MR to your manager for merge.
-- [ ] Send one MR to improve the [review documentation](https://about.gitlab.com/handbook/engineering/workflow/code-review/database.html) or the [issue template](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/.gitlab/issue_templates/Database%20Reviewer.md)
-
-Note that *approving and accepting* merge requests is *restricted* to
-Database Maintainers only. As a reviewer, pass the MR to a maintainer
-for approval.
-
-You're all set! Watch out for TODOs on GitLab.com.
-
-###### Where to go for questions?
-
-Reach out to `#database` on Slack and mention `@abrandl` for any questions.
-
-cc @abrandl
-
-/label ~meta ~database
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8922c5b4938..0b73585722f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,44 @@
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)
+
+- Fix missing API notification flags for Microsoft Teams. !29824 (Seiji Suenaga)
+- Fixed 'diff version changes' link not working. !29825
+- Fix label serialization in issue and note hooks. !29850
+- Include the GitLab version in the cache key for Gitlab::JsonCache. !29938
+- Prevent EE backport migrations from running if CE is not migrated. !30002
+- Silence backup warnings when CRON=1 in use. !30033
+- Fix comment emails not respecting group-level notification email.
+
+### Performance (1 change)
+
+- Omit issues links in merge request entity API response. !29917
+
+
+## 12.0.1 (2019-06-24)
+
+- No changes.
+
## 12.0.0 (2019-06-22)
### Security (10 changes)
@@ -312,6 +350,15 @@ entry.
- Moves snowplow to CE repo.
+## 11.11.4 (2019-06-26)
+
+### Fixed (3 changes)
+
+- Fix Fogbugz Importer not working. !29383
+- Fix scrolling to top on assignee change. !29500
+- Fix IDE commit using latest ref in branch and overriding contents. !29769
+
+
## 11.11.3 (2019-06-10)
### Fixed (5 changes)
@@ -525,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/Dangerfile b/Dangerfile
index d0a605f8d8e..094d55e8652 100644
--- a/Dangerfile
+++ b/Dangerfile
@@ -19,4 +19,5 @@ unless helper.release_automation?
danger.import_dangerfile(path: 'danger/single_codebase')
danger.import_dangerfile(path: 'danger/gitlab_ui_wg')
danger.import_dangerfile(path: 'danger/ce_ee_vue_templates')
+ danger.import_dangerfile(path: 'danger/only_documentation')
end
diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION
index 9db5ea12f52..7f3a46a841e 100644
--- a/GITALY_SERVER_VERSION
+++ b/GITALY_SERVER_VERSION
@@ -1 +1 @@
-1.48.0
+1.49.0
diff --git a/Gemfile b/Gemfile
index b9ce2422153..1264d75eac6 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
@@ -211,7 +211,7 @@ gem 'discordrb-webhooks-blackst0ne', '~> 3.3', require: false
# HipChat integration
gem 'hipchat', '~> 1.5.0'
-# JIRA integration
+# Jira integration
gem 'jira-ruby', '~> 1.4'
# Flowdock integration
@@ -300,13 +300,16 @@ gem 'peek-pg', '~> 1.3.0', group: :postgres
gem 'peek-rblineprof', '~> 0.2.0'
gem 'peek-redis', '~> 1.2.0'
+# Memory benchmarks
+gem 'derailed_benchmarks', require: false
+
# Metrics
group :metrics do
gem 'method_source', '~> 0.8', require: false
gem 'influxdb', '~> 0.2', require: false
# Prometheus
- gem 'prometheus-client-mmap', '~> 0.9.4'
+ gem 'prometheus-client-mmap', '~> 0.9.6'
gem 'raindrops', '~> 0.18'
end
@@ -374,7 +377,6 @@ group :development, :test do
gem 'activerecord_sane_schema_dumper', '1.0'
gem 'stackprof', '~> 0.2.10', require: false
- gem 'derailed_benchmarks', require: false
gem 'simple_po_parser', '~> 1.1.2', require: false
diff --git a/Gemfile.lock b/Gemfile.lock
index 4881faac0e0..5b648d43137 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)
@@ -304,8 +306,6 @@ GEM
gitaly-proto (1.32.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)
@@ -652,7 +652,7 @@ GEM
parser
unparser
procto (0.0.3)
- prometheus-client-mmap (0.9.4)
+ prometheus-client-mmap (0.9.6)
pry (0.11.3)
coderay (~> 1.1.0)
method_source (~> 0.9.0)
@@ -1056,6 +1056,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)
@@ -1093,7 +1094,6 @@ DEPENDENCIES
gettext_i18n_rails_js (~> 1.3)
gitaly-proto (~> 1.32.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)
@@ -1173,7 +1173,7 @@ DEPENDENCIES
peek-redis (~> 1.2.0)
pg (~> 1.1)
premailer-rails (~> 1.9.7)
- prometheus-client-mmap (~> 0.9.4)
+ prometheus-client-mmap (~> 0.9.6)
pry-byebug (~> 3.5.1)
pry-rails (~> 0.3.4)
puma (~> 3.12)
diff --git a/PROCESS.md b/PROCESS.md
index 07b150ea463..22b68b0aaca 100644
--- a/PROCESS.md
+++ b/PROCESS.md
@@ -84,43 +84,28 @@ star, smile, etc.). Some good tips about code reviews can be found in our
[Code Review Guidelines]: https://docs.gitlab.com/ce/development/code_review.html
-## Feature freeze on the 7th for the release on the 22nd
-
-The feature freeze on the 7th has been discontinued. The [transition period overview](https://gitlab.com/gitlab-org/release/docs/blob/21cbd409dd5f157fe252f254f3e897f01908abe2/general/deploy/auto-deploy-transition.md#transition)
-describes the change to this process. During the transition period, the only guarantee that
-a change will be included in the release on the 22nd is if the change has been
-deployed to GitLab.com prior to this date.
+## Feature flags
-### Feature flags
+Overview and details of feature flag processes in development of GitLab itself is described in [feature flags process documentation](https://docs.gitlab.com/ee/development/feature_flags/process.html).
-Merge requests that make changes hidden behind a feature flag, or remove an
-existing feature flag because a feature is deemed stable, may be merged (and
-picked into the stable branches) up to the 19th of the month. Such merge
-requests should have the ~"feature flag" label assigned, and don't require a
-corresponding exception request to be created.
+Guides on how to include feature flags in your backend/frontend code while developing GitLab are described in [developing with feature flags documentation](https://docs.gitlab.com/ee/development/feature_flags/developing.html).
-A level of common sense should be applied when deciding whether to have a feature
-behind a feature flag off or on by default.
+Getting access and how to expose the feature to users is detailed in [controlling feature flags documentation](https://docs.gitlab.com/ee/development/feature_flags/controls.html).
-The following guidelines can be applied to help make this decision:
+## Feature proposals from the 22nd to the 1st
-* If the feature is not fully ready or functioning, the feature flag should be disabled by default.
-* If the feature is ready but there are concerns about performance or impact, the feature flag should be enabled by default, but
-disabled via chatops before deployment on GitLab.com environments. If the performance concern is confirmed, the final release should have the feature flag disabled by default.
-* In most other cases, the feature flag can be enabled by default.
+To allow the Product and Engineering teams time to discuss issues that will be placed into an upcoming milestone,
+Product Managers must have their proposal for that milestone ready by the 22nd of each month.
-For more information on rolling out changes using feature flags, read [through the documentation](https://docs.gitlab.com/ee/development/rolling_out_changes_using_feature_flags.html).
+This proposal will be shared with Engineering for discussion, feedback, and planning.
+The plan for the upcoming milestone must be finalized by the 1st of the month, one week before kickoff on the 8th.
-In order to build the final package and present the feature for self-hosted
-customers, the feature flag should be removed. This should happen before the
-22nd, ideally _at least_ 2 days before. That means MRs with feature
-flags being picked at the 19th would have quite a tight schedule, so picking
-these _earlier_ is preferable.
+## Feature freeze on the 7th for the release on the 22nd
-While rare, release managers may decide to reject picking a change into a stable
-branch, even when feature flags are used. This might be necessary if the changes
-are deemed problematic, too invasive, or there simply isn't enough time to
-properly test how the changes behave on GitLab.com.
+The feature freeze on the 7th has been discontinued. [Transition period overview](https://gitlab.com/gitlab-org/release/docs/blob/21cbd409dd5f157fe252f254f3e897f01908abe2/general/deploy/auto-deploy-transition.md#transition)
+describes the change to this process. During the transition period, the only guarantee that
+a change will be included in the release on the 22nd is if the change has been
+deployed to GitLab.com prior to this date.
### Between the 1st and the 7th
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/behaviors/markdown/render_mermaid.js b/app/assets/javascripts/behaviors/markdown/render_mermaid.js
index d0b7f3ff7a2..b23de36f860 100644
--- a/app/assets/javascripts/behaviors/markdown/render_mermaid.js
+++ b/app/assets/javascripts/behaviors/markdown/render_mermaid.js
@@ -59,6 +59,14 @@ export default function renderMermaid($els) {
mermaid.init(undefined, el, id => {
const svg = document.getElementById(id);
+ // As of https://github.com/knsv/mermaid/commit/57b780a0d,
+ // Mermaid will make two init callbacks:one to initialize the
+ // flow charts, and another to initialize the Gannt charts.
+ // Guard against an error caused by double initialization.
+ if (svg.classList.contains('mermaid')) {
+ return;
+ }
+
svg.classList.add('mermaid');
// pre > code > svg
diff --git a/app/assets/javascripts/boards/components/board.js b/app/assets/javascripts/boards/components/board.js
index 45b9e57f9ab..c6122fbc686 100644
--- a/app/assets/javascripts/boards/components/board.js
+++ b/app/assets/javascripts/boards/components/board.js
@@ -1,6 +1,7 @@
+import $ from 'jquery';
import Sortable from 'sortablejs';
import Vue from 'vue';
-import { n__ } from '~/locale';
+import { n__, s__ } from '~/locale';
import Icon from '~/vue_shared/components/icon.vue';
import Tooltip from '~/vue_shared/directives/tooltip';
import AccessorUtilities from '../../lib/utils/accessor';
@@ -53,12 +54,19 @@ export default Vue.extend({
const { issuesSize } = this.list;
return `${n__('%d issue', '%d issues', issuesSize)}`;
},
+ caretTooltip() {
+ return this.list.isExpanded ? s__('Boards|Collapse') : s__('Boards|Expand');
+ },
isNewIssueShown() {
return (
this.list.type === 'backlog' ||
(!this.disabled && this.list.type !== 'closed' && this.list.type !== 'blank')
);
},
+ uniqueKey() {
+ // eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings
+ return `boards.${this.boardId}.${this.list.type}.${this.list.id}`;
+ },
},
watch: {
filter: {
@@ -72,31 +80,34 @@ export default Vue.extend({
},
},
mounted() {
- this.sortableOptions = getBoardSortableDefaultOptions({
+ const instance = this;
+
+ const sortableOptions = getBoardSortableDefaultOptions({
disabled: this.disabled,
group: 'boards',
draggable: '.is-draggable',
handle: '.js-board-handle',
- onEnd: e => {
+ onEnd(e) {
sortableEnd();
+ const sortable = this;
+
if (e.newIndex !== undefined && e.oldIndex !== e.newIndex) {
- const order = this.sortable.toArray();
+ const order = sortable.toArray();
const list = boardsStore.findList('id', parseInt(e.item.dataset.id, 10));
- this.$nextTick(() => {
+ instance.$nextTick(() => {
boardsStore.moveList(list, order);
});
}
},
});
- this.sortable = Sortable.create(this.$el.parentNode, this.sortableOptions);
+ Sortable.create(this.$el.parentNode, sortableOptions);
},
created() {
if (this.list.isExpandable && AccessorUtilities.isLocalStorageAccessSafe()) {
- const isCollapsed =
- localStorage.getItem(`boards.${this.boardId}.${this.list.type}.expanded`) === 'false';
+ const isCollapsed = localStorage.getItem(`${this.uniqueKey}.expanded`) === 'false';
this.list.isExpanded = !isCollapsed;
}
@@ -105,16 +116,17 @@ export default Vue.extend({
showNewIssueForm() {
this.$refs['board-list'].showIssueForm = !this.$refs['board-list'].showIssueForm;
},
- toggleExpanded(e) {
- if (this.list.isExpandable && !e.target.classList.contains('js-no-trigger-collapse')) {
+ toggleExpanded() {
+ if (this.list.isExpandable) {
this.list.isExpanded = !this.list.isExpanded;
if (AccessorUtilities.isLocalStorageAccessSafe()) {
- localStorage.setItem(
- `boards.${this.boardId}.${this.list.type}.expanded`,
- this.list.isExpanded,
- );
+ localStorage.setItem(`${this.uniqueKey}.expanded`, this.list.isExpanded);
}
+
+ // When expanding/collapsing, the tooltip on the caret button sometimes stays open.
+ // Close all tooltips manually to prevent dangling tooltips.
+ $('.tooltip').tooltip('hide');
}
},
},
diff --git a/app/assets/javascripts/boards/components/board_blank_state.vue b/app/assets/javascripts/boards/components/board_blank_state.vue
index 1cbd31729cd..f58149c9f7b 100644
--- a/app/assets/javascripts/boards/components/board_blank_state.vue
+++ b/app/assets/javascripts/boards/components/board_blank_state.vue
@@ -1,4 +1,5 @@
<script>
+import { __ } from '~/locale';
/* global ListLabel */
import Cookies from 'js-cookie';
import boardsStore from '../stores/boards_store';
@@ -7,8 +8,8 @@ export default {
data() {
return {
predefinedLabels: [
- new ListLabel({ title: 'To Do', color: '#F0AD4E' }),
- new ListLabel({ title: 'Doing', color: '#5CB85C' }),
+ new ListLabel({ title: __('To Do'), color: '#F0AD4E' }),
+ new ListLabel({ title: __('Doing'), color: '#5CB85C' }),
],
};
},
@@ -58,7 +59,11 @@ export default {
<template>
<div class="board-blank-state p-3">
- <p>Add the following default lists to your Issue Board with one click:</p>
+ <p>
+ {{
+ __('BoardBlankState|Add the following default lists to your Issue Board with one click:')
+ }}
+ </p>
<ul class="list-unstyled board-blank-state-list">
<li v-for="(label, index) in predefinedLabels" :key="index">
<span
@@ -70,18 +75,21 @@ export default {
</li>
</ul>
<p>
- Starting out with the default set of lists will get you right on the way to making the most of
- your board.
+ {{
+ __(
+ 'BoardBlankState|Starting out with the default set of lists will get you right on the way to making the most of your board.',
+ )
+ }}
</p>
<button
class="btn btn-success btn-inverted btn-block"
type="button"
@click.stop="addDefaultLists"
>
- Add default lists
+ {{ __('BoardBlankState|Add default lists') }}
</button>
<button class="btn btn-default btn-block" type="button" @click.stop="clearBlankState">
- Nevermind, I'll use my own
+ {{ __("BoardBlankState|Nevermind, I'll use my own") }}
</button>
</div>
</template>
diff --git a/app/assets/javascripts/boards/components/board_list.vue b/app/assets/javascripts/boards/components/board_list.vue
index b1a8b13f3ac..787ff110bf8 100644
--- a/app/assets/javascripts/boards/components/board_list.vue
+++ b/app/assets/javascripts/boards/components/board_list.vue
@@ -227,7 +227,7 @@ export default {
:class="{ 'd-none': !list.isExpanded, 'd-flex flex-column': list.isExpanded }"
class="board-list-component position-relative h-100"
>
- <div v-if="loading" class="board-list-loading text-center" aria-label="Loading issues">
+ <div v-if="loading" class="board-list-loading text-center" :aria-label="__('Loading issues')">
<gl-loading-icon />
</div>
<board-new-issue
@@ -257,7 +257,7 @@ export default {
/>
<li v-if="showCount" class="board-list-count text-center" data-issue-id="-1">
<gl-loading-icon v-show="list.loadingMore" label="Loading more issues" />
- <span v-if="list.issues.length === list.issuesSize"> Showing all issues </span>
+ <span v-if="list.issues.length === list.issuesSize">{{ __('Showing all issues') }}</span>
<span v-else> Showing {{ list.issues.length }} of {{ list.issuesSize }} issues </span>
</li>
</ul>
diff --git a/app/assets/javascripts/boards/components/board_new_issue.vue b/app/assets/javascripts/boards/components/board_new_issue.vue
index cc6af8e88cd..4180023b7db 100644
--- a/app/assets/javascripts/boards/components/board_new_issue.vue
+++ b/app/assets/javascripts/boards/components/board_new_issue.vue
@@ -102,9 +102,9 @@ export default {
<div class="board-card position-relative p-3 rounded">
<form @submit="submit($event)">
<div v-if="error" class="flash-container">
- <div class="flash-alert">An error occurred. Please try again.</div>
+ <div class="flash-alert">{{ __('An error occurred. Please try again.') }}</div>
</div>
- <label :for="list.id + '-title'" class="label-bold"> Title </label>
+ <label :for="list.id + '-title'" class="label-bold">{{ __('Title') }}</label>
<input
:id="list.id + '-title'"
ref="input"
@@ -122,12 +122,11 @@ export default {
class="float-left"
variant="success"
type="submit"
+ >{{ __('Submit issue') }}</gl-button
>
- Submit issue
- </gl-button>
- <gl-button class="float-right" type="button" variant="default" @click="cancel">
- Cancel
- </gl-button>
+ <gl-button class="float-right" type="button" variant="default" @click="cancel">{{
+ __('Cancel')
+ }}</gl-button>
</div>
</form>
</div>
diff --git a/app/assets/javascripts/boards/components/board_sidebar.js b/app/assets/javascripts/boards/components/board_sidebar.js
index c587b276fa3..2ace0060c42 100644
--- a/app/assets/javascripts/boards/components/board_sidebar.js
+++ b/app/assets/javascripts/boards/components/board_sidebar.js
@@ -38,6 +38,7 @@ export default Vue.extend({
issue: {},
list: {},
loadingAssignees: false,
+ timeTrackingLimitToHours: boardsStore.timeTracking.limitToHours,
};
},
computed: {
diff --git a/app/assets/javascripts/boards/components/issue_card_inner.vue b/app/assets/javascripts/boards/components/issue_card_inner.vue
index a8516f178fc..7f554c99669 100644
--- a/app/assets/javascripts/boards/components/issue_card_inner.vue
+++ b/app/assets/javascripts/boards/components/issue_card_inner.vue
@@ -124,7 +124,7 @@ export default {
return `${this.rootPath}${assignee.username}`;
},
avatarUrlTitle(assignee) {
- return `Avatar for ${assignee.name}`;
+ return sprintf(__(`Avatar for %{assigneeName}`), { assigneeName: assignee.name });
},
showLabel(label) {
if (!label.id) return false;
@@ -160,9 +160,10 @@ export default {
:title="__('Confidential')"
class="confidential-icon append-right-4"
:aria-label="__('Confidential')"
- /><a :href="issue.path" :title="issue.title" class="js-no-trigger" @mousemove.stop>{{
- issue.title
- }}</a>
+ />
+ <a :href="issue.path" :title="issue.title" class="js-no-trigger" @mousemove.stop>
+ {{ issue.title }}
+ </a>
</h4>
</div>
<div v-if="showLabelFooter" class="board-card-labels prepend-top-4 d-flex flex-wrap">
@@ -204,13 +205,13 @@ export default {
placement="bottom"
class="board-issue-path block-truncated bold"
>{{ issueReferencePath }}</tooltip-on-truncate
- >#{{ issue.iid }}
+ >
+ #{{ issue.iid }}
</span>
<span class="board-info-items prepend-top-8 d-inline-block">
- <issue-due-date v-if="issue.dueDate" :date="issue.dueDate" /><issue-time-estimate
- v-if="issue.timeEstimate"
- :estimate="issue.timeEstimate"
- /><issue-card-weight
+ <issue-due-date v-if="issue.dueDate" :date="issue.dueDate" />
+ <issue-time-estimate v-if="issue.timeEstimate" :estimate="issue.timeEstimate" />
+ <issue-card-weight
v-if="issue.weight"
:weight="issue.weight"
@click="filterByWeight(issue.weight)"
@@ -230,7 +231,8 @@ export default {
tooltip-placement="bottom"
>
<span class="js-assignee-tooltip">
- <span class="bold d-block">Assignee</span> {{ assignee.name }}
+ <span class="bold d-block">{{ __('Assignee') }}</span>
+ {{ assignee.name }}
<span class="text-white-50">@{{ assignee.username }}</span>
</span>
</user-avatar-link>
@@ -240,9 +242,8 @@ export default {
:title="assigneeCounterTooltip"
class="avatar-counter"
data-placement="bottom"
+ >{{ assigneeCounterLabel }}</span
>
- {{ assigneeCounterLabel }}
- </span>
</div>
</div>
</div>
diff --git a/app/assets/javascripts/boards/components/issue_time_estimate.vue b/app/assets/javascripts/boards/components/issue_time_estimate.vue
index 98c1d29db16..3385aad5b11 100644
--- a/app/assets/javascripts/boards/components/issue_time_estimate.vue
+++ b/app/assets/javascripts/boards/components/issue_time_estimate.vue
@@ -2,6 +2,7 @@
import { GlTooltip } from '@gitlab/ui';
import Icon from '~/vue_shared/components/icon.vue';
import { parseSeconds, stringifyTime } from '~/lib/utils/datetime_utility';
+import boardsStore from '../stores/boards_store';
export default {
components: {
@@ -14,12 +15,17 @@ export default {
required: true,
},
},
+ data() {
+ return {
+ limitToHours: boardsStore.timeTracking.limitToHours,
+ };
+ },
computed: {
title() {
- return stringifyTime(parseSeconds(this.estimate), true);
+ return stringifyTime(parseSeconds(this.estimate, { limitToHours: this.limitToHours }), true);
},
timeEstimate() {
- return stringifyTime(parseSeconds(this.estimate));
+ return stringifyTime(parseSeconds(this.estimate, { limitToHours: this.limitToHours }));
},
},
};
diff --git a/app/assets/javascripts/boards/components/modal/empty_state.vue b/app/assets/javascripts/boards/components/modal/empty_state.vue
index 091700de93f..66f59009714 100644
--- a/app/assets/javascripts/boards/components/modal/empty_state.vue
+++ b/app/assets/javascripts/boards/components/modal/empty_state.vue
@@ -1,4 +1,5 @@
<script>
+import { __, sprintf } from '~/locale';
import ModalStore from '../../stores/modal_store';
import modalMixin from '../../mixins/modal_mixins';
@@ -20,19 +21,20 @@ export default {
computed: {
contents() {
const obj = {
- title: "You haven't added any issues to your project yet",
- content: `
- An issue can be a bug, a todo or a feature request that needs to be
- discussed in a project. Besides, issues are searchable and filterable.
- `,
+ title: __("You haven't added any issues to your project yet"),
+ content: __(
+ 'An issue can be a bug, a todo or a feature request that needs to be discussed in a project. Besides, issues are searchable and filterable.',
+ ),
};
if (this.activeTab === 'selected') {
- obj.title = "You haven't selected any issues yet";
- obj.content = `
- Go back to <strong>Open issues</strong> and select some issues
- to add to your board.
- `;
+ obj.title = __("You haven't selected any issues yet");
+ obj.content = sprintf(
+ __(
+ 'Go back to %{startTag}Open issues%{endTag} and select some issues to add to your board.',
+ ),
+ { startTag: '<strong>', endTag: '</strong>' },
+ );
}
return obj;
@@ -51,16 +53,16 @@ export default {
<div class="text-content">
<h4>{{ contents.title }}</h4>
<p v-html="contents.content"></p>
- <a v-if="activeTab === 'all'" :href="newIssuePath" class="btn btn-success btn-inverted">
- New issue
- </a>
+ <a v-if="activeTab === 'all'" :href="newIssuePath" class="btn btn-success btn-inverted">{{
+ __('New issue')
+ }}</a>
<button
v-if="activeTab === 'selected'"
class="btn btn-default"
type="button"
@click="changeTab('all')"
>
- Open issues
+ {{ __('Open issues') }}
</button>
</div>
</div>
diff --git a/app/assets/javascripts/boards/components/modal/footer.vue b/app/assets/javascripts/boards/components/modal/footer.vue
index d4afd9d59da..a1d634c8f19 100644
--- a/app/assets/javascripts/boards/components/modal/footer.vue
+++ b/app/assets/javascripts/boards/components/modal/footer.vue
@@ -1,8 +1,7 @@
<script>
import Flash from '../../../flash';
-import { __ } from '../../../locale';
+import { __, n__ } from '../../../locale';
import ListsDropdown from './lists_dropdown.vue';
-import { pluralize } from '../../../lib/utils/text_utility';
import ModalStore from '../../stores/modal_store';
import modalMixin from '../../mixins/modal_mixins';
import boardsStore from '../../stores/boards_store';
@@ -24,8 +23,8 @@ export default {
},
submitText() {
const count = ModalStore.selectedCount();
-
- return `Add ${count > 0 ? count : ''} ${pluralize('issue', count)}`;
+ if (!count) return __('Add issues');
+ return n__(`Add %d issue`, `Add %d issues`, count);
},
},
methods: {
@@ -68,11 +67,11 @@ export default {
<button :disabled="submitDisabled" class="btn btn-success" type="button" @click="addIssues">
{{ submitText }}
</button>
- <span class="inline add-issues-footer-to-list"> to list </span>
+ <span class="inline add-issues-footer-to-list">{{ __('to list') }}</span>
<lists-dropdown />
</div>
<button class="btn btn-default float-right" type="button" @click="toggleModal(false)">
- Cancel
+ {{ __('Cancel') }}
</button>
</footer>
</template>
diff --git a/app/assets/javascripts/boards/components/modal/header.vue b/app/assets/javascripts/boards/components/modal/header.vue
index 1cfa6d39362..7a696035dc8 100644
--- a/app/assets/javascripts/boards/components/modal/header.vue
+++ b/app/assets/javascripts/boards/components/modal/header.vue
@@ -1,4 +1,5 @@
<script>
+import { __ } from '~/locale';
import ModalFilters from './filters';
import ModalTabs from './tabs.vue';
import ModalStore from '../../stores/modal_store';
@@ -30,10 +31,10 @@ export default {
computed: {
selectAllText() {
if (ModalStore.selectedCount() !== this.issues.length || this.issues.length === 0) {
- return 'Select all';
+ return __('Select all');
}
- return 'Deselect all';
+ return __('Deselect all');
},
showSearch() {
return this.activeTab === 'all' && !this.loading && this.issuesCount > 0;
@@ -57,7 +58,7 @@ export default {
type="button"
class="close"
data-dismiss="modal"
- aria-label="Close"
+ :aria-label="__('Close')"
@click="toggleModal(false)"
>
<span aria-hidden="true">×</span>
diff --git a/app/assets/javascripts/boards/components/modal/list.vue b/app/assets/javascripts/boards/components/modal/list.vue
index 28d2019af2f..1802b543687 100644
--- a/app/assets/javascripts/boards/components/modal/list.vue
+++ b/app/assets/javascripts/boards/components/modal/list.vue
@@ -123,7 +123,9 @@ export default {
class="empty-state add-issues-empty-state-filter text-center"
>
<div class="svg-content"><img :src="emptyStateSvg" /></div>
- <div class="text-content"><h4>There are no issues to show.</h4></div>
+ <div class="text-content">
+ <h4>{{ __('There are no issues to show.') }}</h4>
+ </div>
</div>
<div v-for="(group, index) in groupedIssues" :key="index" class="add-issues-list-column">
<div v-for="issue in group" v-if="showIssue(issue)" :key="issue.id" class="board-card-parent">
diff --git a/app/assets/javascripts/boards/components/project_select.vue b/app/assets/javascripts/boards/components/project_select.vue
index 8274647744f..a1cf1866faf 100644
--- a/app/assets/javascripts/boards/components/project_select.vue
+++ b/app/assets/javascripts/boards/components/project_select.vue
@@ -1,4 +1,5 @@
<script>
+import { __ } from '~/locale';
import $ from 'jquery';
import _ from 'underscore';
import Icon from '~/vue_shared/components/icon.vue';
@@ -27,7 +28,7 @@ export default {
},
computed: {
selectedProjectName() {
- return this.selectedProject.name || 'Select a project';
+ return this.selectedProject.name || __('Select a project');
},
},
mounted() {
@@ -81,7 +82,7 @@ export default {
<template>
<div>
- <label class="label-bold prepend-top-10"> Project </label>
+ <label class="label-bold prepend-top-10">{{ __('Project') }}</label>
<div ref="projectsDropdown" class="dropdown dropdown-projects">
<button
class="dropdown-menu-toggle wide"
@@ -92,9 +93,9 @@ export default {
{{ selectedProjectName }} <icon name="chevron-down" />
</button>
<div class="dropdown-menu dropdown-menu-selectable dropdown-menu-full-width">
- <div class="dropdown-title">Projects</div>
+ <div class="dropdown-title">{{ __('Projects') }}</div>
<div class="dropdown-input">
- <input class="dropdown-input-field" type="search" placeholder="Search projects" />
+ <input class="dropdown-input-field" type="search" :placeholder="__('Search projects')" />
<icon name="search" class="dropdown-input-search" data-hidden="true" />
</div>
<div class="dropdown-content"></div>
diff --git a/app/assets/javascripts/boards/components/sidebar/remove_issue.vue b/app/assets/javascripts/boards/components/sidebar/remove_issue.vue
index 4ab2b17301f..b84722244d1 100644
--- a/app/assets/javascripts/boards/components/sidebar/remove_issue.vue
+++ b/app/assets/javascripts/boards/components/sidebar/remove_issue.vue
@@ -76,7 +76,7 @@ export default Vue.extend({
<template>
<div class="block list">
<button class="btn btn-default btn-block" type="button" @click="removeIssue">
- Remove from board
+ {{ __('Remove from board') }}
</button>
</div>
</template>
diff --git a/app/assets/javascripts/boards/index.js b/app/assets/javascripts/boards/index.js
index f2f37d22b97..a020765f335 100644
--- a/app/assets/javascripts/boards/index.js
+++ b/app/assets/javascripts/boards/index.js
@@ -49,6 +49,7 @@ export default () => {
}
boardsStore.create();
+ boardsStore.setTimeTrackingLimitToHours($boardApp.dataset.timeTrackingLimitToHours);
issueBoardsApp = new Vue({
el: $boardApp,
diff --git a/app/assets/javascripts/boards/mixins/sortable_default_options.js b/app/assets/javascripts/boards/mixins/sortable_default_options.js
index 983b28d2e67..68ea28e68d9 100644
--- a/app/assets/javascripts/boards/mixins/sortable_default_options.js
+++ b/app/assets/javascripts/boards/mixins/sortable_default_options.js
@@ -1,7 +1,7 @@
/* global DocumentTouch */
import $ from 'jquery';
-import sortableConfig from '../../sortable/sortable_config';
+import sortableConfig from 'ee_else_ce/sortable/sortable_config';
export function sortableStart() {
$('.has-tooltip')
@@ -20,7 +20,7 @@ export function getBoardSortableDefaultOptions(obj) {
'ontouchstart' in window || (window.DocumentTouch && document instanceof DocumentTouch);
const defaultSortOptions = Object.assign({}, sortableConfig, {
- filter: '.board-delete, .btn',
+ filter: '.no-drag',
delay: touchEnabled ? 100 : 0,
scrollSensitivity: touchEnabled ? 60 : 100,
scrollSpeed: 20,
diff --git a/app/assets/javascripts/boards/models/list.js b/app/assets/javascripts/boards/models/list.js
index a9d88f19146..cd553d0c4af 100644
--- a/app/assets/javascripts/boards/models/list.js
+++ b/app/assets/javascripts/boards/models/list.js
@@ -26,6 +26,12 @@ const TYPES = {
isExpandable: false,
isBlank: true,
},
+ default: {
+ // includes label, assignee, and milestone lists
+ isPreset: false,
+ isExpandable: true,
+ isBlank: false,
+ },
};
class List {
@@ -249,7 +255,7 @@ class List {
}
getTypeInfo(type) {
- return TYPES[type] || {};
+ return TYPES[type] || TYPES.default;
}
onNewIssueResponse(issue, data) {
diff --git a/app/assets/javascripts/boards/stores/boards_store.js b/app/assets/javascripts/boards/stores/boards_store.js
index 4b3b44574a8..4ba4cde6bae 100644
--- a/app/assets/javascripts/boards/stores/boards_store.js
+++ b/app/assets/javascripts/boards/stores/boards_store.js
@@ -12,6 +12,9 @@ import eventHub from '../eventhub';
const boardsStore = {
disabled: false,
+ timeTracking: {
+ limitToHours: false,
+ },
scopedLabels: {
helpLink: '',
enabled: false,
@@ -222,6 +225,10 @@ const boardsStore = {
setIssueDetail(issueDetail) {
this.detail.issue = issueDetail;
},
+
+ setTimeTrackingLimitToHours(limitToHours) {
+ this.timeTracking.limitToHours = parseBoolean(limitToHours);
+ },
};
BoardsStoreEE.initEESpecific(boardsStore);
diff --git a/app/assets/javascripts/branches/divergence_graph.js b/app/assets/javascripts/branches/divergence_graph.js
index 670e8e9eb60..96bc6a5f8e8 100644
--- a/app/assets/javascripts/branches/divergence_graph.js
+++ b/app/assets/javascripts/branches/divergence_graph.js
@@ -1,23 +1,49 @@
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(`.js-branch-${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/clusters/services/application_state_machine.js b/app/assets/javascripts/clusters/services/application_state_machine.js
index 17ea4d77795..6e632519d8a 100644
--- a/app/assets/javascripts/clusters/services/application_state_machine.js
+++ b/app/assets/javascripts/clusters/services/application_state_machine.js
@@ -80,6 +80,9 @@ const applicationStateMachine = {
installFailed: false,
},
},
+ [NOT_INSTALLABLE]: {
+ target: NOT_INSTALLABLE,
+ },
// This is possible in artificial environments for E2E testing
[INSTALLED]: {
target: INSTALLED,
@@ -108,6 +111,9 @@ const applicationStateMachine = {
updateSuccessful: false,
},
},
+ [NOT_INSTALLABLE]: {
+ target: NOT_INSTALLABLE,
+ },
[UNINSTALL_EVENT]: {
target: UNINSTALLING,
effects: {
diff --git a/app/assets/javascripts/commons/polyfills.js b/app/assets/javascripts/commons/polyfills.js
index d0cc4897aeb..a4394ab7e92 100644
--- a/app/assets/javascripts/commons/polyfills.js
+++ b/app/assets/javascripts/commons/polyfills.js
@@ -12,6 +12,7 @@ import 'core-js/es/promise/finally';
import 'core-js/es/string/code-point-at';
import 'core-js/es/string/from-code-point';
import 'core-js/es/string/includes';
+import 'core-js/es/string/starts-with';
import 'core-js/es/symbol';
import 'core-js/es/map';
import 'core-js/es/weak-map';
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/commit_item.vue b/app/assets/javascripts/diffs/components/commit_item.vue
index aaa9f8b759a..58d5b658b17 100644
--- a/app/assets/javascripts/diffs/components/commit_item.vue
+++ b/app/assets/javascripts/diffs/components/commit_item.vue
@@ -49,6 +49,8 @@ export default {
return this.author.id ? this.author.id : '';
},
authorUrl() {
+ // TODO: when the vue i18n rules are merged need to disable @gitlab/i18n/no-non-i18n-strings
+ // name: 'mailto:' is a false positive: https://gitlab.com/gitlab-org/frontend/eslint-plugin-i18n/issues/26#possible-false-positives
return this.author.web_url || `mailto:${this.commit.author_email}`;
},
authorAvatar() {
@@ -80,7 +82,7 @@ export default {
v-html="commit.title_html"
></a>
- <span class="commit-row-message d-block d-sm-none"> &middot; {{ commit.short_id }} </span>
+ <span class="commit-row-message d-block d-sm-none">&middot; {{ commit.short_id }}</span>
<button
v-if="commit.description_html"
diff --git a/app/assets/javascripts/diffs/components/compare_versions_dropdown.vue b/app/assets/javascripts/diffs/components/compare_versions_dropdown.vue
index 80aec84f574..1dcdb65d5c7 100644
--- a/app/assets/javascripts/diffs/components/compare_versions_dropdown.vue
+++ b/app/assets/javascripts/diffs/components/compare_versions_dropdown.vue
@@ -1,6 +1,6 @@
<script>
import Icon from '~/vue_shared/components/icon.vue';
-import { n__, __ } from '~/locale';
+import { n__, __, sprintf } from '~/locale';
import TimeAgo from '~/vue_shared/components/time_ago_tooltip.vue';
export default {
@@ -54,11 +54,7 @@ export default {
},
methods: {
commitsText(version) {
- return n__(
- `${version.commits_count} commit,`,
- `${version.commits_count} commits,`,
- version.commits_count,
- );
+ return n__(`%d commit,`, `%d commits,`, version.commits_count);
},
href(version) {
if (this.isBase(version)) {
@@ -76,7 +72,7 @@ export default {
if (this.targetBranch && (this.isBase(version) || !version)) {
return this.targetBranch.branchName;
}
- return `version ${version.version_index}`;
+ return sprintf(__(`version %{versionIndex}`), { versionIndex: version.version_index });
},
isActive(version) {
if (!version) {
@@ -125,9 +121,9 @@ export default {
<div>
<strong>
{{ versionName(version) }}
- <template v-if="isBase(version)">
- (base)
- </template>
+ <template v-if="isBase(version)">{{
+ s__('DiffsCompareBaseBranch|(base)')
+ }}</template>
</strong>
</div>
<div>
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.vue b/app/assets/javascripts/diffs/components/diff_file.vue
index f5876a73eff..63350fafefa 100644
--- a/app/assets/javascripts/diffs/components/diff_file.vue
+++ b/app/assets/javascripts/diffs/components/diff_file.vue
@@ -151,21 +151,22 @@ export default {
<div v-if="forkMessageVisible" class="js-file-fork-suggestion-section file-fork-suggestion">
<span class="file-fork-suggestion-note">
- You're not allowed to <span class="js-file-fork-suggestion-section-action">edit</span> files
- in this project directly. Please fork this project, make your changes there, and submit a
- merge request.
+ {{ sprintf(__("You're not allowed to %{tag_start}edit%{tag_end} files in this project
+ directly. Please fork this project, make your changes there, and submit a merge request."),
+ { tag_start: '<span class="js-file-fork-suggestion-section-action">', tag_end: '</span>' })
+ }}
</span>
<a
:href="file.fork_path"
class="js-fork-suggestion-button btn btn-grouped btn-inverted btn-success"
- >Fork</a
+ >{{ __('Fork') }}</a
>
<button
class="js-cancel-fork-suggestion-button btn btn-grouped"
type="button"
@click="hideForkMessage"
>
- Cancel
+ {{ __('Cancel') }}
</button>
</div>
<gl-loading-icon v-if="showLoadingIcon" class="diff-content loading" />
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 7cf3d90d468..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>
@@ -74,9 +63,9 @@ export default {
<button
v-if="discussionsExpanded"
type="button"
- aria-label="Show comments"
+ :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..ca3285e9afd 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: {
@@ -32,10 +35,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 +54,22 @@ 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
+ :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/parallel_diff_comment_row.vue b/app/assets/javascripts/diffs/components/parallel_diff_comment_row.vue
index d2e54edca85..c00b0e010ff 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: {
@@ -29,24 +32,30 @@ export default {
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 +90,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 +115,49 @@ 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
+ :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
+ :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/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/filtered_search/available_dropdown_mappings.js b/app/assets/javascripts/filtered_search/available_dropdown_mappings.js
index 891086b4142..f280f3cd26c 100644
--- a/app/assets/javascripts/filtered_search/available_dropdown_mappings.js
+++ b/app/assets/javascripts/filtered_search/available_dropdown_mappings.js
@@ -10,7 +10,7 @@ import { mergeUrlParams } from '../lib/utils/url_utility';
export default class AvailableDropdownMappings {
constructor(
container,
- baseEndpoint,
+ runnerTagsEndpoint,
labelsEndpoint,
milestonesEndpoint,
groupsOnly,
@@ -18,7 +18,7 @@ export default class AvailableDropdownMappings {
includeDescendantGroups,
) {
this.container = container;
- this.baseEndpoint = baseEndpoint;
+ this.runnerTagsEndpoint = runnerTagsEndpoint;
this.labelsEndpoint = labelsEndpoint;
this.milestonesEndpoint = milestonesEndpoint;
this.groupsOnly = groupsOnly;
@@ -149,7 +149,7 @@ export default class AvailableDropdownMappings {
}
getRunnerTagsEndpoint() {
- return `${this.baseEndpoint}/admin/runners/tag_list.json`;
+ return `${this.runnerTagsEndpoint}.json`;
}
getMergeRequestTargetBranchesEndpoint() {
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/filtered_search/filtered_search_dropdown_manager.js b/app/assets/javascripts/filtered_search/filtered_search_dropdown_manager.js
index 1cbfd7f9bb9..835d3bf8a53 100644
--- a/app/assets/javascripts/filtered_search/filtered_search_dropdown_manager.js
+++ b/app/assets/javascripts/filtered_search/filtered_search_dropdown_manager.js
@@ -8,7 +8,7 @@ import FilteredSearchVisualTokens from './filtered_search_visual_tokens';
export default class FilteredSearchDropdownManager {
constructor({
- baseEndpoint = '',
+ runnerTagsEndpoint = '',
labelsEndpoint = '',
milestonesEndpoint = '',
tokenizer,
@@ -19,7 +19,7 @@ export default class FilteredSearchDropdownManager {
filteredSearchTokenKeys,
}) {
this.container = FilteredSearchContainer.container;
- this.baseEndpoint = baseEndpoint.replace(/\/$/, '');
+ this.runnerTagsEndpoint = runnerTagsEndpoint.replace(/\/$/, '');
this.labelsEndpoint = labelsEndpoint.replace(/\/$/, '');
this.milestonesEndpoint = milestonesEndpoint.replace(/\/$/, '');
this.tokenizer = tokenizer;
@@ -51,7 +51,7 @@ export default class FilteredSearchDropdownManager {
const supportedTokens = this.filteredSearchTokenKeys.getKeys();
const availableMappings = new AvailableDropdownMappings(
this.container,
- this.baseEndpoint,
+ this.runnerTagsEndpoint,
this.labelsEndpoint,
this.milestonesEndpoint,
this.groupsOnly,
diff --git a/app/assets/javascripts/filtered_search/filtered_search_manager.js b/app/assets/javascripts/filtered_search/filtered_search_manager.js
index 450e0725f2e..d1f52b91d9e 100644
--- a/app/assets/javascripts/filtered_search/filtered_search_manager.js
+++ b/app/assets/javascripts/filtered_search/filtered_search_manager.js
@@ -85,7 +85,8 @@ export default class FilteredSearchManager {
if (this.filteredSearchInput) {
this.tokenizer = FilteredSearchTokenizer;
this.dropdownManager = new FilteredSearchDropdownManager({
- baseEndpoint: this.filteredSearchInput.getAttribute('data-base-endpoint') || '',
+ runnerTagsEndpoint:
+ this.filteredSearchInput.getAttribute('data-runner-tags-endpoint') || '',
labelsEndpoint: this.filteredSearchInput.getAttribute('data-labels-endpoint') || '',
milestonesEndpoint: this.filteredSearchInput.getAttribute('data-milestones-endpoint') || '',
tokenizer: this.tokenizer,
diff --git a/app/assets/javascripts/gfm_auto_complete.js b/app/assets/javascripts/gfm_auto_complete.js
index 3b73dd83c9f..b308cd9c236 100644
--- a/app/assets/javascripts/gfm_auto_complete.js
+++ b/app/assets/javascripts/gfm_auto_complete.js
@@ -318,6 +318,7 @@ class GfmAutoComplete {
}
setupLabels($input) {
+ const instance = this;
const fetchData = this.fetchData.bind(this);
const LABEL_COMMAND = { LABEL: '/label', UNLABEL: '/unlabel', RELABEL: '/relabel' };
let command = '';
@@ -348,7 +349,6 @@ class GfmAutoComplete {
}));
},
matcher(flag, subtext) {
- const match = GfmAutoComplete.defaultMatcher(flag, subtext, this.app.controllers);
const subtextNodes = subtext
.split(/\n+/g)
.pop()
@@ -366,6 +366,27 @@ class GfmAutoComplete {
return null;
});
+ // If any label matches the inserted text after the last `~`, suggest those labels,
+ // even if any spaces or funky characters were typed.
+ // This allows matching labels like "Accepting merge requests".
+ const labels = instance.cachedData[flag];
+ if (labels) {
+ if (!subtext.includes(flag)) {
+ // Do not match if there is no `~` before the cursor
+ return null;
+ }
+ const lastCandidate = subtext.split(flag).pop();
+ if (labels.find(label => label.title.startsWith(lastCandidate))) {
+ return lastCandidate;
+ }
+ } else {
+ // Load all labels into the autocompleter.
+ // This needs to happen if e.g. editing a label in an existing comment, because normally
+ // label data would only be loaded only once you type `~`.
+ fetchData(this.$inputor, this.at);
+ }
+
+ const match = GfmAutoComplete.defaultMatcher(flag, subtext, this.app.controllers);
return match && match.length ? match[1] : null;
},
filter(query, data, searchKey) {
@@ -563,8 +584,9 @@ class GfmAutoComplete {
const accentAChar = decodeURI('%C3%80');
const accentYChar = decodeURI('%C3%BF');
+ // Holy regex, batman!
const regexp = new RegExp(
- `^(?:\\B|[^a-zA-Z0-9_\`${atSymbolsWithoutBar}]|\\s)${resultantFlag}(?!${atSymbolsWithBar})((?:[A-Za-z${accentAChar}-${accentYChar}0-9_'.+-]|[^\\x00-\\x7a])*)$`,
+ `^(?:\\B|[^a-zA-Z0-9_\`${atSymbolsWithoutBar}]|\\s)${resultantFlag}(?!${atSymbolsWithBar})((?:[A-Za-z${accentAChar}-${accentYChar}0-9_'.+-:]|[^\\x00-\\x7a])*)$`,
'gi',
);
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/ide_tree_list.vue b/app/assets/javascripts/ide/components/ide_tree_list.vue
index 95782b2c88a..1af86a94482 100644
--- a/app/assets/javascripts/ide/components/ide_tree_list.vue
+++ b/app/assets/javascripts/ide/components/ide_tree_list.vue
@@ -30,6 +30,9 @@ export default {
showLoading() {
return !this.currentTree || this.currentTree.loading;
},
+ actualTreeList() {
+ return this.currentTree.tree.filter(entry => !entry.moved);
+ },
},
mounted() {
this.updateViewer(this.viewerType);
@@ -54,9 +57,9 @@ export default {
<slot name="header"></slot>
</header>
<div class="ide-tree-body h-100">
- <template v-if="currentTree.tree.length">
+ <template v-if="actualTreeList.length">
<file-row
- v-for="file in currentTree.tree"
+ v-for="file in actualTreeList"
:key="file.key"
:file="file"
:level="0"
diff --git a/app/assets/javascripts/ide/components/repo_editor.vue b/app/assets/javascripts/ide/components/repo_editor.vue
index b0c4969c5e4..5fcb11a232e 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: {
@@ -40,27 +41,36 @@ export default {
},
showContentViewer() {
return (
- (this.shouldHideEditor || this.file.viewMode === 'preview') &&
+ (this.shouldHideEditor || this.isPreviewViewMode) &&
(this.viewer !== viewerTypes.mr || !this.file.mrChange)
);
},
showDiffViewer() {
return this.shouldHideEditor && this.file.mrChange && this.viewer === viewerTypes.mr;
},
+ isEditorViewMode() {
+ return this.file.viewMode === 'editor';
+ },
+ isPreviewViewMode() {
+ return this.file.viewMode === 'preview';
+ },
editTabCSS() {
return {
- active: this.file.viewMode === 'editor',
+ active: this.isEditorViewMode,
};
},
previewTabCSS() {
return {
- active: this.file.viewMode === 'preview',
+ active: this.isPreviewViewMode,
};
},
fileType() {
const info = viewerInformationForPath(this.file.path);
return (info && info.id) || '';
},
+ showEditor() {
+ return !this.shouldHideEditor && this.isEditorViewMode;
+ },
},
watch: {
file(newVal, oldVal) {
@@ -89,7 +99,7 @@ export default {
}
},
rightPanelCollapsed() {
- this.editor.updateDimensions();
+ this.refreshEditorDimensions();
},
viewer() {
if (!this.file.pending) {
@@ -98,11 +108,17 @@ export default {
},
panelResizing() {
if (!this.panelResizing) {
- this.editor.updateDimensions();
+ this.refreshEditorDimensions();
}
},
rightPaneIsOpen() {
- this.editor.updateDimensions();
+ this.refreshEditorDimensions();
+ },
+ showEditor(val) {
+ if (val) {
+ // We need to wait for the editor to actually be rendered.
+ this.$nextTick(() => this.refreshEditorDimensions());
+ }
},
},
beforeDestroy() {
@@ -145,7 +161,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;
});
},
@@ -212,6 +235,11 @@ export default {
eol: this.model.eol,
});
},
+ refreshEditorDimensions() {
+ if (this.showEditor) {
+ this.editor.updateDimensions();
+ }
+ },
},
viewerTypes,
};
@@ -227,12 +255,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">
@@ -240,16 +264,15 @@ 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" />
</div>
<file-templates-bar v-if="showFileTemplatesBar(file.name)" />
<div
- v-show="!shouldHideEditor && file.viewMode === 'editor'"
+ v-show="showEditor"
ref="editor"
:class="{
'is-readonly': isCommitModeActive,
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/stores/actions.js b/app/assets/javascripts/ide/stores/actions.js
index 5429b834708..8c0119a1fed 100644
--- a/app/assets/javascripts/ide/stores/actions.js
+++ b/app/assets/javascripts/ide/stores/actions.js
@@ -8,6 +8,7 @@ import * as types from './mutation_types';
import { decorateFiles } from '../lib/files';
import { stageKeys } from '../constants';
import service from '../services';
+import router from '../ide_router';
export const redirectToUrl = (self, url) => visitUrl(url);
@@ -61,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',
@@ -207,10 +208,7 @@ export const deleteEntry = ({ commit, dispatch, state }, path) => {
}
commit(types.DELETE_ENTRY, path);
-
- if (entry.parentPath && state.entries[entry.parentPath].tree.length === 0) {
- dispatch('deleteEntry', entry.parentPath);
- }
+ dispatch('stageChange', path);
dispatch('triggerFilesChange');
};
@@ -238,10 +236,15 @@ export const renameEntry = (
parentPath: newParentPath,
});
});
- }
+ } else {
+ const newPath = parentPath ? `${parentPath}/${name}` : name;
+ const newEntry = state.entries[newPath];
+ commit(types.TOGGLE_FILE_CHANGED, { file: newEntry, changed: true });
- if (!entryPath && !entry.tempFile) {
- dispatch('deleteEntry', path);
+ if (entry.opened) {
+ router.push(`/project${newEntry.url}`);
+ commit(types.TOGGLE_FILE_OPEN, entry.path);
+ }
}
dispatch('triggerFilesChange');
diff --git a/app/assets/javascripts/ide/stores/actions/file.js b/app/assets/javascripts/ide/stores/actions/file.js
index dc40a1fa6a2..7627b6e03af 100644
--- a/app/assets/javascripts/ide/stores/actions/file.js
+++ b/app/assets/javascripts/ide/stores/actions/file.js
@@ -73,7 +73,9 @@ export const getFileData = (
.getFileData(joinPaths(gon.relative_url_root || '', url.replace('/-/', '/')))
.then(({ data, headers }) => {
const normalizedHeaders = normalizeHeaders(headers);
- setPageTitle(decodeURI(normalizedHeaders['PAGE-TITLE']));
+ let title = normalizedHeaders['PAGE-TITLE'];
+ title = file.prevPath ? title.replace(file.prevPath, file.path) : title;
+ setPageTitle(decodeURI(title));
if (data) commit(types.SET_FILE_DATA, { data, file });
if (openFile) commit(types.TOGGLE_FILE_OPEN, path);
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 ae42b87c9a7..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,
@@ -216,15 +229,16 @@ export default {
Vue.set(state.entries, newPath, {
...oldEntry,
id: newPath,
- key: `${newPath}-${oldEntry.type}-${oldEntry.id}`,
+ key: `${newPath}-${oldEntry.type}-${oldEntry.path}`,
path: newPath,
name: entryPath ? oldEntry.name : name,
tempFile: true,
prevPath: oldEntry.tempFile ? null : oldEntry.path,
url: oldEntry.url.replace(new RegExp(`${oldEntry.path}/?$`), newPath),
tree: [],
- parentPath,
raw: '',
+ opened: false,
+ parentPath,
});
oldEntry.moved = true;
@@ -241,10 +255,6 @@ export default {
state.changedFiles = state.changedFiles.concat(newEntry);
}
- if (state.entries[newPath].opened) {
- state.openFiles.push(state.entries[newPath]);
- }
-
if (oldEntry.tempFile) {
const filterMethod = f => f.path !== oldEntry.path;
diff --git a/app/assets/javascripts/ide/stores/mutations/file.js b/app/assets/javascripts/ide/stores/mutations/file.js
index 6ca246c1d63..c88244492e0 100644
--- a/app/assets/javascripts/ide/stores/mutations/file.js
+++ b/app/assets/javascripts/ide/stores/mutations/file.js
@@ -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 4e7a8765abe..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;
}
@@ -147,11 +148,12 @@ export const createCommitPayload = ({
commit_message: state.commitMessage || getters.preBuiltCommitMessage,
actions: getCommitFiles(rootState.stagedFiles).map(f => ({
action: commitActionForFile(f),
- file_path: f.path,
+ file_path: f.moved ? f.movedPath : f.path,
previous_path: f.prevPath === '' ? undefined : f.prevPath,
- content: f.content || undefined,
+ 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/ide/utils.js b/app/assets/javascripts/ide/utils.js
index d895eca7af0..ae579fef25f 100644
--- a/app/assets/javascripts/ide/utils.js
+++ b/app/assets/javascripts/ide/utils.js
@@ -3,7 +3,7 @@ import { commitItemIconMap } from './constants';
export const getCommitIconMap = file => {
if (file.deleted) {
return commitItemIconMap.deleted;
- } else if (file.tempFile) {
+ } else if (file.tempFile && !file.prevPath) {
return commitItemIconMap.addition;
}
diff --git a/app/assets/javascripts/issue_show/components/edit_actions.vue b/app/assets/javascripts/issue_show/components/edit_actions.vue
index 42a3de62772..b2f9296c68b 100644
--- a/app/assets/javascripts/issue_show/components/edit_actions.vue
+++ b/app/assets/javascripts/issue_show/components/edit_actions.vue
@@ -73,7 +73,9 @@ export default {
Save changes
<i v-if="formState.updateLoading" class="fa fa-spinner fa-spin" aria-hidden="true"> </i>
</button>
- <button class="btn btn-default float-right" type="button" @click="closeForm">Cancel</button>
+ <button class="btn btn-default float-right" type="button" @click="closeForm">
+ {{ __('Cancel') }}
+ </button>
<button
v-if="shouldShowDeleteButton"
:class="{ disabled: deleteLoading }"
diff --git a/app/assets/javascripts/issue_show/components/fields/description.vue b/app/assets/javascripts/issue_show/components/fields/description.vue
index d27dd873125..447d7bf21a5 100644
--- a/app/assets/javascripts/issue_show/components/fields/description.vue
+++ b/app/assets/javascripts/issue_show/components/fields/description.vue
@@ -39,7 +39,7 @@ export default {
<template>
<div class="common-note-form">
- <label class="sr-only" for="issue-description"> Description </label>
+ <label class="sr-only" for="issue-description">{{ __('Description') }}</label>
<markdown-field
:markdown-preview-path="markdownPreviewPath"
:markdown-docs-path="markdownDocsPath"
@@ -55,8 +55,8 @@ export default {
qa-description-textarea"
dir="auto"
data-supports-quick-actions="false"
- 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="updateIssuable"
@keydown.ctrl.enter="updateIssuable"
>
diff --git a/app/assets/javascripts/issue_show/components/fields/description_template.vue b/app/assets/javascripts/issue_show/components/fields/description_template.vue
index 14f0acf6540..6f955928d8e 100644
--- a/app/assets/javascripts/issue_show/components/fields/description_template.vue
+++ b/app/assets/javascripts/issue_show/components/fields/description_template.vue
@@ -56,22 +56,31 @@ export default {
data-selected="null"
data-toggle="dropdown"
>
- <span class="dropdown-toggle-text"> Choose a template </span>
+ <span class="dropdown-toggle-text">{{ __('Choose a template') }}</span>
<i aria-hidden="true" class="fa fa-chevron-down"> </i>
</button>
<div class="dropdown-menu dropdown-select">
<div class="dropdown-title">
Choose a template
- <button class="dropdown-title-button dropdown-menu-close" aria-label="Close" type="button">
+ <button
+ class="dropdown-title-button dropdown-menu-close"
+ :aria-label="__('Close')"
+ type="button"
+ >
<i aria-hidden="true" class="fa fa-times dropdown-menu-close-icon"> </i>
</button>
</div>
<div class="dropdown-input">
- <input type="search" class="dropdown-input-field" placeholder="Filter" autocomplete="off" />
+ <input
+ type="search"
+ class="dropdown-input-field"
+ :placeholder="__('Filter')"
+ autocomplete="off"
+ />
<i aria-hidden="true" class="fa fa-search dropdown-input-search"> </i>
<i
role="button"
- aria-label="Clear templates search input"
+ :aria-label="__('Clear templates search input')"
class="fa fa-times dropdown-input-clear js-dropdown-input-clear"
>
</i>
@@ -79,8 +88,12 @@ export default {
<div class="dropdown-content"></div>
<div class="dropdown-footer">
<ul class="dropdown-footer-list">
- <li><a class="no-template"> No template </a></li>
- <li><a class="reset-template"> Reset template </a></li>
+ <li>
+ <a class="no-template">{{ __('No template') }}</a>
+ </li>
+ <li>
+ <a class="reset-template">{{ __('Reset template') }}</a>
+ </li>
</ul>
</div>
</div>
diff --git a/app/assets/javascripts/issue_show/components/fields/title.vue b/app/assets/javascripts/issue_show/components/fields/title.vue
index ce4baf17d09..34eb0451d53 100644
--- a/app/assets/javascripts/issue_show/components/fields/title.vue
+++ b/app/assets/javascripts/issue_show/components/fields/title.vue
@@ -14,7 +14,7 @@ export default {
<template>
<fieldset>
- <label class="sr-only" for="issuable-title"> Title </label>
+ <label class="sr-only" for="issuable-title">{{ __('Title') }}</label>
<input
id="issuable-title"
ref="input"
@@ -22,8 +22,8 @@ export default {
class="form-control qa-title-input"
dir="auto"
type="text"
- placeholder="Title"
- aria-label="Title"
+ :placeholder="__('Title')"
+ :aria-label="__('Title')"
@keydown.meta.enter="updateIssuable"
@keydown.ctrl.enter="updateIssuable"
/>
diff --git a/app/assets/javascripts/issue_show/components/locked_warning.vue b/app/assets/javascripts/issue_show/components/locked_warning.vue
index 639221473b1..2f3e611e089 100644
--- a/app/assets/javascripts/issue_show/components/locked_warning.vue
+++ b/app/assets/javascripts/issue_show/components/locked_warning.vue
@@ -10,8 +10,9 @@ export default {
<template>
<div class="alert alert-danger">
- Someone edited the issue at the same time you did. Please check out
- <a :href="currentPath" target="_blank" rel="nofollow">the issue</a> and make sure your changes
- will not unintentionally remove theirs.
+ {{ sprintf(__("Someone edited the issue at the same time you did. Please check out
+ %{linkStart}%the issue%{linkEnd} and make sure your changes will not unintentionally remove
+ theirs."), { linkStart: `<a href="${currentPath}" target="_blank" rel="nofollow">` linkEnd: '</a
+ >', }) }}
</div>
</template>
diff --git a/app/assets/javascripts/jobs/components/job_log_controllers.vue b/app/assets/javascripts/jobs/components/job_log_controllers.vue
index 607b2bd1c74..156735441ca 100644
--- a/app/assets/javascripts/jobs/components/job_log_controllers.vue
+++ b/app/assets/javascripts/jobs/components/job_log_controllers.vue
@@ -3,7 +3,7 @@ import { GlTooltipDirective, GlLink, GlButton } from '@gitlab/ui';
import { polyfillSticky } from '~/lib/utils/sticky';
import Icon from '~/vue_shared/components/icon.vue';
import { numberToHumanSize } from '~/lib/utils/number_utils';
-import { sprintf } from '~/locale';
+import { __, sprintf } from '~/locale';
import scrollDown from '../svg/scroll_down.svg';
export default {
@@ -50,7 +50,7 @@ export default {
},
computed: {
jobLogSize() {
- return sprintf('Showing last %{size} of log -', {
+ return sprintf(__('Showing last %{size} of log -'), {
size: numberToHumanSize(this.size),
});
},
@@ -74,14 +74,12 @@ export default {
<div class="js-truncated-info truncated-info d-none d-sm-block float-left">
<template v-if="isTraceSizeVisible">
{{ jobLogSize }}
-
<gl-link
v-if="rawPath"
:href="rawPath"
class="js-raw-link text-plain text-underline prepend-left-5"
+ >{{ s__('Job|Complete Raw') }}</gl-link
>
- {{ s__('Job|Complete Raw') }}
- </gl-link>
</template>
</div>
<!-- eo truncate information -->
diff --git a/app/assets/javascripts/jobs/components/sidebar.vue b/app/assets/javascripts/jobs/components/sidebar.vue
index 24276c06486..e9704584c9f 100644
--- a/app/assets/javascripts/jobs/components/sidebar.vue
+++ b/app/assets/javascripts/jobs/components/sidebar.vue
@@ -1,4 +1,5 @@
<script>
+import { __, sprintf } from '~/locale';
import _ from 'underscore';
import { mapActions, mapState } from 'vuex';
import { GlLink, GlButton } from '@gitlab/ui';
@@ -63,7 +64,9 @@ export default {
let t = this.job.metadata.timeout_human_readable;
if (this.job.metadata.timeout_source !== '') {
- t += ` (from ${this.job.metadata.timeout_source})`;
+ t += sprintf(__(` (from %{timeoutSource})`), {
+ timeoutSource: this.job.metadata.timeout_source,
+ });
}
return t;
diff --git a/app/assets/javascripts/lib/graphql.js b/app/assets/javascripts/lib/graphql.js
index 5857f9e22ae..c05db4a5c71 100644
--- a/app/assets/javascripts/lib/graphql.js
+++ b/app/assets/javascripts/lib/graphql.js
@@ -22,7 +22,7 @@ export default (resolvers = {}, config = {}) => {
return new ApolloClient({
link: ApolloLink.split(
- operation => operation.getContext().hasUpload,
+ operation => operation.getContext().hasUpload || operation.getContext().isSingleRequest,
createUploadLink(httpOptions),
new BatchHttpLink(httpOptions),
),
diff --git a/app/assets/javascripts/lib/utils/datetime_utility.js b/app/assets/javascripts/lib/utils/datetime_utility.js
index d521c462ad8..062d21ed247 100644
--- a/app/assets/javascripts/lib/utils/datetime_utility.js
+++ b/app/assets/javascripts/lib/utils/datetime_utility.js
@@ -479,9 +479,13 @@ export const pikadayToString = date => {
* Seconds can be negative or positive, zero or non-zero. Can be configured for any day
* or week length.
*/
-export const parseSeconds = (seconds, { daysPerWeek = 5, hoursPerDay = 8 } = {}) => {
+export const parseSeconds = (
+ seconds,
+ { daysPerWeek = 5, hoursPerDay = 8, limitToHours = false } = {},
+) => {
const DAYS_PER_WEEK = daysPerWeek;
const HOURS_PER_DAY = hoursPerDay;
+ const SECONDS_PER_MINUTE = 60;
const MINUTES_PER_HOUR = 60;
const MINUTES_PER_WEEK = DAYS_PER_WEEK * HOURS_PER_DAY * MINUTES_PER_HOUR;
const MINUTES_PER_DAY = HOURS_PER_DAY * MINUTES_PER_HOUR;
@@ -493,9 +497,18 @@ export const parseSeconds = (seconds, { daysPerWeek = 5, hoursPerDay = 8 } = {})
minutes: 1,
};
- let unorderedMinutes = Math.abs(seconds / MINUTES_PER_HOUR);
+ if (limitToHours) {
+ timePeriodConstraints.weeks = 0;
+ timePeriodConstraints.days = 0;
+ }
+
+ let unorderedMinutes = Math.abs(seconds / SECONDS_PER_MINUTE);
return _.mapObject(timePeriodConstraints, minutesPerPeriod => {
+ if (minutesPerPeriod === 0) {
+ return 0;
+ }
+
const periodCount = Math.floor(unorderedMinutes / minutesPerPeriod);
unorderedMinutes -= periodCount * minutesPerPeriod;
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/manual_ordering.js b/app/assets/javascripts/manual_ordering.js
new file mode 100644
index 00000000000..012d1e70410
--- /dev/null
+++ b/app/assets/javascripts/manual_ordering.js
@@ -0,0 +1,58 @@
+import Sortable from 'sortablejs';
+import { s__ } from '~/locale';
+import createFlash from '~/flash';
+import {
+ getBoardSortableDefaultOptions,
+ sortableStart,
+} from '~/boards/mixins/sortable_default_options';
+import axios from '~/lib/utils/axios_utils';
+
+const updateIssue = (url, issueList, { move_before_id, move_after_id }) =>
+ axios
+ .put(`${url}/reorder`, {
+ move_before_id,
+ move_after_id,
+ group_full_path: issueList.dataset.groupFullPath,
+ })
+ .catch(() => {
+ createFlash(s__("ManualOrdering|Couldn't save the order of the issues"));
+ });
+
+const initManualOrdering = () => {
+ const issueList = document.querySelector('.manual-ordering');
+
+ if (!issueList || !(gon.features && gon.features.manualSorting) || !(gon.current_user_id > 0)) {
+ return;
+ }
+
+ Sortable.create(
+ issueList,
+ getBoardSortableDefaultOptions({
+ scroll: true,
+ dataIdAttr: 'data-id',
+ fallbackOnBody: false,
+ group: {
+ name: 'issues',
+ },
+ draggable: 'li.issue',
+ onStart: () => {
+ sortableStart();
+ },
+ onUpdate: event => {
+ const el = event.item;
+
+ const url = el.getAttribute('url');
+
+ const prev = el.previousElementSibling;
+ const next = el.nextElementSibling;
+
+ const beforeId = prev && parseInt(prev.dataset.id, 10);
+ const afterId = next && parseInt(next.dataset.id, 10);
+
+ updateIssue(url, issueList, { move_after_id: afterId, move_before_id: beforeId });
+ },
+ }),
+ );
+};
+
+export default initManualOrdering;
diff --git a/app/assets/javascripts/monitoring/components/charts/area.vue b/app/assets/javascripts/monitoring/components/charts/area.vue
index 9de4e96e4da..81773bd140e 100644
--- a/app/assets/javascripts/monitoring/components/charts/area.vue
+++ b/app/assets/javascripts/monitoring/components/charts/area.vue
@@ -1,4 +1,6 @@
<script>
+import { __ } from '~/locale';
+import { GlLink } from '@gitlab/ui';
import { GlAreaChart, GlChartSeriesLabel } from '@gitlab/ui/dist/charts';
import dateFormat from 'dateformat';
import { debounceByAnimationFrame, roundOffFloat } from '~/lib/utils/common_utils';
@@ -13,6 +15,7 @@ export default {
components: {
GlAreaChart,
GlChartSeriesLabel,
+ GlLink,
Icon,
},
inheritAttrs: false,
@@ -43,6 +46,10 @@ export default {
required: false,
default: () => [],
},
+ projectPath: {
+ type: String,
+ required: true,
+ },
thresholds: {
type: Array,
required: false,
@@ -54,6 +61,7 @@ export default {
tooltip: {
title: '',
content: [],
+ commitUrl: '',
isDeployment: false,
sha: '',
},
@@ -99,7 +107,7 @@ export default {
chartOptions() {
return {
xAxis: {
- name: 'Time',
+ name: __('Time'),
type: 'time',
axisLabel: {
formatter: date => dateFormat(date, 'h:MM TT'),
@@ -194,12 +202,13 @@ export default {
this.tooltip.title = dateFormat(params.value, 'dd mmm yyyy, h:MMTT');
this.tooltip.content = [];
params.seriesData.forEach(seriesData => {
- if (seriesData.componentSubType === graphTypes.deploymentData) {
- this.tooltip.isDeployment = true;
+ this.tooltip.isDeployment = seriesData.componentSubType === graphTypes.deploymentData;
+ if (this.tooltip.isDeployment) {
const [deploy] = this.recentDeployments.filter(
deployment => deployment.createdAt === seriesData.value[0],
);
this.tooltip.sha = deploy.sha.substring(0, 8);
+ this.tooltip.commitUrl = deploy.commitUrl;
} else {
const { seriesName, color } = seriesData;
// seriesData.value contains the chart's [x, y] value pair
@@ -258,7 +267,7 @@ export default {
</template>
<div slot="tooltipContent" class="d-flex align-items-center">
<icon name="commit" class="mr-2" />
- {{ tooltip.sha }}
+ <gl-link :href="tooltip.commitUrl">{{ tooltip.sha }}</gl-link>
</div>
</template>
<template v-else>
diff --git a/app/assets/javascripts/monitoring/components/charts/column.vue b/app/assets/javascripts/monitoring/components/charts/column.vue
new file mode 100644
index 00000000000..05a2036f4c3
--- /dev/null
+++ b/app/assets/javascripts/monitoring/components/charts/column.vue
@@ -0,0 +1,131 @@
+<script>
+import { GlColumnChart } from '@gitlab/ui/dist/charts';
+import { debounceByAnimationFrame } from '~/lib/utils/common_utils';
+import { getSvgIconPathContent } from '~/lib/utils/icon_utils';
+import { chartHeight } from '../../constants';
+import { makeDataSeries } from '~/helpers/monitor_helper';
+
+export default {
+ components: {
+ GlColumnChart,
+ },
+ inheritAttrs: false,
+ props: {
+ graphData: {
+ type: Object,
+ required: true,
+ validator(data) {
+ return (
+ Array.isArray(data.queries) &&
+ data.queries.filter(query => {
+ if (Array.isArray(query.result)) {
+ return (
+ query.result.filter(res => Array.isArray(res.values)).length === query.result.length
+ );
+ }
+ return false;
+ }).length === data.queries.length
+ );
+ },
+ containerWidth: {
+ type: Number,
+ required: true,
+ },
+ },
+ },
+ data() {
+ return {
+ width: 0,
+ height: chartHeight,
+ svgs: {},
+ debouncedResizeCallback: {},
+ };
+ },
+ computed: {
+ chartData() {
+ const queryData = this.graphData.queries.reduce((acc, query) => {
+ const series = makeDataSeries(query.result, {
+ name: this.formatLegendLabel(query),
+ });
+
+ return acc.concat(series);
+ }, []);
+
+ return {
+ values: queryData[0].data,
+ };
+ },
+ xAxisTitle() {
+ return this.graphData.queries[0].result[0].x_label !== undefined
+ ? this.graphData.queries[0].result[0].x_label
+ : '';
+ },
+ yAxisTitle() {
+ return this.graphData.queries[0].result[0].y_label !== undefined
+ ? this.graphData.queries[0].result[0].y_label
+ : '';
+ },
+ xAxisType() {
+ return this.graphData.x_type !== undefined ? this.graphData.x_type : 'category';
+ },
+ dataZoomConfig() {
+ const handleIcon = this.svgs['scroll-handle'];
+
+ return handleIcon ? { handleIcon } : {};
+ },
+ chartOptions() {
+ return {
+ dataZoom: this.dataZoomConfig,
+ };
+ },
+ },
+ watch: {
+ containerWidth: 'onResize',
+ },
+ beforeDestroy() {
+ window.removeEventListener('resize', this.debouncedResizeCallback);
+ },
+ created() {
+ this.debouncedResizeCallback = debounceByAnimationFrame(this.onResize);
+ window.addEventListener('resize', this.debouncedResizeCallback);
+ this.setSvg('scroll-handle');
+ },
+ methods: {
+ formatLegendLabel(query) {
+ return `${query.label}`;
+ },
+ onResize() {
+ const { width } = this.$refs.columnChart.$el.getBoundingClientRect();
+ this.width = width;
+ },
+ setSvg(name) {
+ getSvgIconPathContent(name)
+ .then(path => {
+ if (path) {
+ this.$set(this.svgs, name, `path://${path}`);
+ }
+ })
+ .catch(() => {});
+ },
+ },
+};
+</script>
+<template>
+ <div class="prometheus-graph col-12 col-lg-6">
+ <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>
+ <gl-column-chart
+ ref="columnChart"
+ v-bind="$attrs"
+ :data="chartData"
+ :option="chartOptions"
+ :width="width"
+ :height="height"
+ :x-axis-title="xAxisTitle"
+ :y-axis-title="yAxisTitle"
+ :x-axis-type="xAxisType"
+ />
+ </div>
+</template>
diff --git a/app/assets/javascripts/monitoring/components/dashboard.vue b/app/assets/javascripts/monitoring/components/dashboard.vue
index 0a652329dfe..2cbda8ea05d 100644
--- a/app/assets/javascripts/monitoring/components/dashboard.vue
+++ b/app/assets/javascripts/monitoring/components/dashboard.vue
@@ -106,17 +106,24 @@ export default {
},
customMetricsPath: {
type: String,
- required: true,
+ required: false,
+ default: invalidUrl,
},
validateQueryPath: {
type: String,
- required: true,
+ required: false,
+ default: invalidUrl,
},
dashboardEndpoint: {
type: String,
required: false,
default: invalidUrl,
},
+ currentDashboard: {
+ type: String,
+ required: false,
+ default: '',
+ },
},
data() {
return {
@@ -139,10 +146,15 @@ export default {
'deploymentData',
'metricsWithData',
'useDashboardEndpoint',
+ 'allDashboards',
+ 'multipleDashboardsEnabled',
]),
groupsWithData() {
return this.groups.filter(group => this.chartsWithData(group.metrics).length > 0);
},
+ selectedDashboardText() {
+ return this.currentDashboard || (this.allDashboards[0] && this.allDashboards[0].display_name);
+ },
},
created() {
this.setEndpoints({
@@ -150,6 +162,7 @@ export default {
environmentsEndpoint: this.environmentsEndpoint,
deploymentsEndpoint: this.deploymentsEndpoint,
dashboardEndpoint: this.dashboardEndpoint,
+ currentDashboard: this.currentDashboard,
});
this.timeWindows = timeWindows;
@@ -234,12 +247,30 @@ export default {
</script>
<template>
- <div v-if="!showEmptyState" class="prometheus-graphs">
+ <div class="prometheus-graphs">
<div class="gl-p-3 border-bottom bg-gray-light d-flex justify-content-between">
<div
v-if="environmentsEndpoint"
class="dropdowns d-flex align-items-center justify-content-between"
>
+ <div v-if="multipleDashboardsEnabled" class="d-flex align-items-center">
+ <label class="mb-0">{{ __('Dashboard') }}</label>
+ <gl-dropdown
+ class="ml-2 mr-3 js-dashboards-dropdown"
+ toggle-class="dropdown-menu-toggle"
+ :text="selectedDashboardText"
+ >
+ <gl-dropdown-item
+ v-for="dashboard in allDashboards"
+ :key="dashboard.path"
+ :active="dashboard.path === currentDashboard"
+ active-class="is-active"
+ :href="`?dashboard=${dashboard.path}`"
+ >
+ {{ dashboard.display_name || dashboard.path }}
+ </gl-dropdown-item>
+ </gl-dropdown>
+ </div>
<div class="d-flex align-items-center">
<strong>{{ s__('Metrics|Environment') }}</strong>
<gl-dropdown
@@ -253,11 +284,12 @@ export default {
:key="environment.id"
:active="environment.name === currentEnvironmentName"
active-class="is-active"
+ :href="environment.metrics_path"
>{{ environment.name }}</gl-dropdown-item
>
</gl-dropdown>
</div>
- <div class="d-flex align-items-center prepend-left-8">
+ <div v-if="!showEmptyState" class="d-flex align-items-center prepend-left-8">
<strong>{{ s__('Metrics|Show last') }}</strong>
<gl-dropdown
class="prepend-left-10 js-time-window-dropdown"
@@ -276,7 +308,7 @@ export default {
</div>
</div>
<div class="d-flex">
- <div v-if="isEE && canAddMetrics">
+ <div v-if="isEE && canAddMetrics && !showEmptyState">
<gl-button
v-gl-modal-directive="$options.addMetric.modalId"
class="js-add-metric-button text-success border-success"
@@ -317,40 +349,43 @@ export default {
</gl-button>
</div>
</div>
- <graph-group
- v-for="(groupData, index) in groupsWithData"
- :key="index"
- :name="groupData.group"
- :show-panels="showPanels"
- >
- <monitor-area-chart
- v-for="(graphData, graphIndex) in chartsWithData(groupData.metrics)"
- :key="graphIndex"
- :graph-data="graphData"
- :deployment-data="deploymentData"
- :thresholds="getGraphAlertValues(graphData.queries)"
- :container-width="elWidth"
- group-id="monitor-area-chart"
+ <div v-if="!showEmptyState">
+ <graph-group
+ v-for="(groupData, index) in groupsWithData"
+ :key="index"
+ :name="groupData.group"
+ :show-panels="showPanels"
>
- <alert-widget
- v-if="isEE && prometheusAlertsAvailable && alertsEndpoint && graphData"
- :alerts-endpoint="alertsEndpoint"
- :relevant-queries="graphData.queries"
- :alerts-to-manage="getGraphAlerts(graphData.queries)"
- @setAlerts="setAlerts"
- />
- </monitor-area-chart>
- </graph-group>
+ <monitor-area-chart
+ v-for="(graphData, graphIndex) in chartsWithData(groupData.metrics)"
+ :key="graphIndex"
+ :project-path="projectPath"
+ :graph-data="graphData"
+ :deployment-data="deploymentData"
+ :thresholds="getGraphAlertValues(graphData.queries)"
+ :container-width="elWidth"
+ group-id="monitor-area-chart"
+ >
+ <alert-widget
+ v-if="isEE && prometheusAlertsAvailable && alertsEndpoint && graphData"
+ :alerts-endpoint="alertsEndpoint"
+ :relevant-queries="graphData.queries"
+ :alerts-to-manage="getGraphAlerts(graphData.queries)"
+ @setAlerts="setAlerts"
+ />
+ </monitor-area-chart>
+ </graph-group>
+ </div>
+ <empty-state
+ v-else
+ :selected-state="emptyState"
+ :documentation-path="documentationPath"
+ :settings-path="settingsPath"
+ :clusters-path="clustersPath"
+ :empty-getting-started-svg-path="emptyGettingStartedSvgPath"
+ :empty-loading-svg-path="emptyLoadingSvgPath"
+ :empty-no-data-svg-path="emptyNoDataSvgPath"
+ :empty-unable-to-connect-svg-path="emptyUnableToConnectSvgPath"
+ />
</div>
- <empty-state
- v-else
- :selected-state="emptyState"
- :documentation-path="documentationPath"
- :settings-path="settingsPath"
- :clusters-path="clustersPath"
- :empty-getting-started-svg-path="emptyGettingStartedSvgPath"
- :empty-loading-svg-path="emptyLoadingSvgPath"
- :empty-no-data-svg-path="emptyNoDataSvgPath"
- :empty-unable-to-connect-svg-path="emptyUnableToConnectSvgPath"
- />
</template>
diff --git a/app/assets/javascripts/monitoring/components/empty_state.vue b/app/assets/javascripts/monitoring/components/empty_state.vue
index 0e141d02ead..a3c6de14aa4 100644
--- a/app/assets/javascripts/monitoring/components/empty_state.vue
+++ b/app/assets/javascripts/monitoring/components/empty_state.vue
@@ -1,4 +1,6 @@
<script>
+import { __ } from '~/locale';
+
export default {
props: {
documentationPath: {
@@ -41,35 +43,35 @@ export default {
states: {
gettingStarted: {
svgUrl: this.emptyGettingStartedSvgPath,
- title: 'Get started with performance monitoring',
- description: `Stay updated about the performance and health
- of your environment by configuring Prometheus to monitor your deployments.`,
- buttonText: 'Install on clusters',
+ title: __('Get started with performance monitoring'),
+ description: __(`Stay updated about the performance and health
+ of your environment by configuring Prometheus to monitor your deployments.`),
+ buttonText: __('Install on clusters'),
buttonPath: this.clustersPath,
- secondaryButtonText: 'Configure existing installation',
+ secondaryButtonText: __('Configure existing installation'),
secondaryButtonPath: this.settingsPath,
},
loading: {
svgUrl: this.emptyLoadingSvgPath,
- title: 'Waiting for performance data',
- description: `Creating graphs uses the data from the Prometheus server.
- If this takes a long time, ensure that data is available.`,
- buttonText: 'View documentation',
+ title: __('Waiting for performance data'),
+ description: __(`Creating graphs uses the data from the Prometheus server.
+ If this takes a long time, ensure that data is available.`),
+ buttonText: __('View documentation'),
buttonPath: this.documentationPath,
},
noData: {
svgUrl: this.emptyNoDataSvgPath,
- title: 'No data found',
- description: `You are connected to the Prometheus server, but there is currently
- no data to display.`,
- buttonText: 'Configure Prometheus',
+ title: __('No data found'),
+ description: __(`You are connected to the Prometheus server, but there is currently
+ no data to display.`),
+ buttonText: __('Configure Prometheus'),
buttonPath: this.settingsPath,
},
unableToConnect: {
svgUrl: this.emptyUnableToConnectSvgPath,
- title: 'Unable to connect to Prometheus server',
+ title: __('Unable to connect to Prometheus server'),
description: 'Ensure connectivity is available from the GitLab server to the ',
- buttonText: 'View documentation',
+ buttonText: __('View documentation'),
buttonPath: this.documentationPath,
},
},
@@ -90,7 +92,9 @@ export default {
<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 class="state-svg svg-content">
+ <img :src="currentState.svgUrl" />
+ </div>
</div>
<div class="col-12">
@@ -98,20 +102,22 @@ export default {
<h4 class="state-title text-center">{{ currentState.title }}</h4>
<p class="state-description">
{{ currentState.description }}
- <a v-if="showButtonDescription" :href="settingsPath"> Prometheus server </a>
+ <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.buttonPath"
+ :href="currentState.buttonPath"
+ class="btn btn-success"
+ >{{ currentState.buttonText }}</a
+ >
<a
v-if="currentState.secondaryButtonPath"
:href="currentState.secondaryButtonPath"
class="btn"
+ >{{ currentState.secondaryButtonText }}</a
>
- {{ currentState.secondaryButtonText }}
- </a>
</div>
</div>
</div>
diff --git a/app/assets/javascripts/monitoring/monitoring_bundle.js b/app/assets/javascripts/monitoring/monitoring_bundle.js
index 1d33537b3b2..97d149e9ad5 100644
--- a/app/assets/javascripts/monitoring/monitoring_bundle.js
+++ b/app/assets/javascripts/monitoring/monitoring_bundle.js
@@ -1,5 +1,6 @@
import Vue from 'vue';
import { parseBoolean } from '~/lib/utils/common_utils';
+import { getParameterValues } from '~/lib/utils/url_utility';
import Dashboard from 'ee_else_ce/monitoring/components/dashboard.vue';
import store from './stores';
@@ -7,10 +8,14 @@ export default (props = {}) => {
const el = document.getElementById('prometheus-graphs');
if (el && el.dataset) {
- store.dispatch(
- 'monitoringDashboard/setDashboardEnabled',
- gon.features.environmentMetricsUsePrometheusEndpoint,
- );
+ if (gon.features) {
+ store.dispatch('monitoringDashboard/setFeatureFlags', {
+ prometheusEndpointEnabled: gon.features.environmentMetricsUsePrometheusEndpoint,
+ multipleDashboardsEnabled: gon.features.environmentMetricsShowMultipleDashboards,
+ });
+ }
+
+ const [currentDashboard] = getParameterValues('dashboard');
// eslint-disable-next-line no-new
new Vue({
@@ -20,6 +25,7 @@ export default (props = {}) => {
return createElement(Dashboard, {
props: {
...el.dataset,
+ currentDashboard,
hasMetrics: parseBoolean(el.dataset.hasMetrics),
...props,
},
diff --git a/app/assets/javascripts/monitoring/stores/actions.js b/app/assets/javascripts/monitoring/stores/actions.js
index f41e215cb5d..0fa2a5d6370 100644
--- a/app/assets/javascripts/monitoring/stores/actions.js
+++ b/app/assets/javascripts/monitoring/stores/actions.js
@@ -35,14 +35,24 @@ export const setEndpoints = ({ commit }, endpoints) => {
commit(types.SET_ENDPOINTS, endpoints);
};
-export const setDashboardEnabled = ({ commit }, enabled) => {
- commit(types.SET_DASHBOARD_ENABLED, enabled);
+export const setFeatureFlags = (
+ { commit },
+ { prometheusEndpointEnabled, multipleDashboardsEnabled },
+) => {
+ commit(types.SET_DASHBOARD_ENABLED, prometheusEndpointEnabled);
+ commit(types.SET_MULTIPLE_DASHBOARDS_ENABLED, multipleDashboardsEnabled);
};
export const requestMetricsDashboard = ({ commit }) => {
commit(types.REQUEST_METRICS_DATA);
};
-export const receiveMetricsDashboardSuccess = ({ commit, dispatch }, { response, params }) => {
+export const receiveMetricsDashboardSuccess = (
+ { state, commit, dispatch },
+ { response, params },
+) => {
+ if (state.multipleDashboardsEnabled) {
+ commit(types.SET_ALL_DASHBOARDS, response.all_dashboards);
+ }
commit(types.RECEIVE_METRICS_DATA_SUCCESS, response.dashboard.panel_groups);
dispatch('fetchPrometheusMetrics', params);
};
@@ -95,6 +105,11 @@ export const fetchMetricsData = ({ state, dispatch }, params) => {
export const fetchDashboard = ({ state, dispatch }, params) => {
dispatch('requestMetricsDashboard');
+ if (state.currentDashboard) {
+ // eslint-disable-next-line no-param-reassign
+ params.dashboard = state.currentDashboard;
+ }
+
return axios
.get(state.dashboardEndpoint, { params })
.then(resp => resp.data)
diff --git a/app/assets/javascripts/monitoring/stores/mutation_types.js b/app/assets/javascripts/monitoring/stores/mutation_types.js
index 63894e83362..2c78a0b9315 100644
--- a/app/assets/javascripts/monitoring/stores/mutation_types.js
+++ b/app/assets/javascripts/monitoring/stores/mutation_types.js
@@ -10,6 +10,8 @@ export const RECEIVE_ENVIRONMENTS_DATA_FAILURE = 'RECEIVE_ENVIRONMENTS_DATA_FAIL
export const SET_QUERY_RESULT = 'SET_QUERY_RESULT';
export const SET_TIME_WINDOW = 'SET_TIME_WINDOW';
export const SET_DASHBOARD_ENABLED = 'SET_DASHBOARD_ENABLED';
+export const SET_MULTIPLE_DASHBOARDS_ENABLED = 'SET_MULTIPLE_DASHBOARDS_ENABLED';
+export const SET_ALL_DASHBOARDS = 'SET_ALL_DASHBOARDS';
export const SET_ENDPOINTS = 'SET_ENDPOINTS';
export const SET_GETTING_STARTED_EMPTY_STATE = 'SET_GETTING_STARTED_EMPTY_STATE';
export const SET_NO_DATA_EMPTY_STATE = 'SET_NO_DATA_EMPTY_STATE';
diff --git a/app/assets/javascripts/monitoring/stores/mutations.js b/app/assets/javascripts/monitoring/stores/mutations.js
index d4b816e2717..a85a7723c1f 100644
--- a/app/assets/javascripts/monitoring/stores/mutations.js
+++ b/app/assets/javascripts/monitoring/stores/mutations.js
@@ -74,10 +74,14 @@ export default {
state.environmentsEndpoint = endpoints.environmentsEndpoint;
state.deploymentsEndpoint = endpoints.deploymentsEndpoint;
state.dashboardEndpoint = endpoints.dashboardEndpoint;
+ state.currentDashboard = endpoints.currentDashboard;
},
[types.SET_DASHBOARD_ENABLED](state, enabled) {
state.useDashboardEndpoint = enabled;
},
+ [types.SET_MULTIPLE_DASHBOARDS_ENABLED](state, enabled) {
+ state.multipleDashboardsEnabled = enabled;
+ },
[types.SET_GETTING_STARTED_EMPTY_STATE](state) {
state.emptyState = 'gettingStarted';
},
@@ -85,4 +89,7 @@ export default {
state.showEmptyState = true;
state.emptyState = 'noData';
},
+ [types.SET_ALL_DASHBOARDS](state, dashboards) {
+ state.allDashboards = dashboards;
+ },
};
diff --git a/app/assets/javascripts/monitoring/stores/state.js b/app/assets/javascripts/monitoring/stores/state.js
index c33529cd588..de711d6ccae 100644
--- a/app/assets/javascripts/monitoring/stores/state.js
+++ b/app/assets/javascripts/monitoring/stores/state.js
@@ -8,10 +8,13 @@ export default () => ({
deploymentsEndpoint: null,
dashboardEndpoint: invalidUrl,
useDashboardEndpoint: false,
+ multipleDashboardsEnabled: false,
emptyState: 'gettingStarted',
showEmptyState: true,
groups: [],
deploymentData: [],
environments: [],
metricsWithData: [],
+ allDashboards: [],
+ currentDashboard: null,
});
diff --git a/app/assets/javascripts/notes/components/comment_form.vue b/app/assets/javascripts/notes/components/comment_form.vue
index 075c28e8d07..5a4b5f9398b 100644
--- a/app/assets/javascripts/notes/components/comment_form.vue
+++ b/app/assets/javascripts/notes/components/comment_form.vue
@@ -65,7 +65,7 @@ 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';
@@ -418,7 +418,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/discussion_actions.vue b/app/assets/javascripts/notes/components/discussion_actions.vue
index 22cca756ef6..f4570c1292c 100644
--- a/app/assets/javascripts/notes/components/discussion_actions.vue
+++ b/app/assets/javascripts/notes/components/discussion_actions.vue
@@ -40,7 +40,11 @@ export default {
<template>
<div class="discussion-with-resolve-btn">
- <reply-placeholder class="qa-discussion-reply" @onClick="$emit('showReplyForm')" />
+ <reply-placeholder
+ :button-text="s__('MergeRequests|Reply...')"
+ class="qa-discussion-reply"
+ @onClick="$emit('showReplyForm')"
+ />
<resolve-discussion-button
v-if="discussion.resolvable"
:is-resolving="isResolving"
@@ -53,6 +57,17 @@ export default {
v-if="shouldShowJumpToNextDiscussion"
@onClick="$emit('jumpToNextDiscussion')"
/>
+ <resolve-with-issue-button
+ v-if="discussion.resolvable && resolveWithIssuePath"
+ :url="resolveWithIssuePath"
+ />
+ </div>
+
+ <div
+ v-if="discussion.resolvable && shouldShowJumpToNextDiscussion"
+ class="btn-group discussion-actions ml-sm-2"
+ >
+ <jump-to-next-discussion-button @onClick="$emit('jumpToNextDiscussion')" />
</div>
</div>
</template>
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 228bb652597..2ff0fee62f3 100644
--- a/app/assets/javascripts/notes/components/discussion_notes.vue
+++ b/app/assets/javascripts/notes/components/discussion_notes.vue
@@ -1,11 +1,11 @@
<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';
@@ -72,6 +72,7 @@ export default {
},
},
methods: {
+ ...mapActions(['toggleDiscussion']),
componentName(note) {
if (note.isPlaceholderNote) {
if (note.placeholderType === SYSTEM_NOTE) {
@@ -101,12 +102,12 @@ export default {
<component
:is="componentName(firstNote)"
:note="componentData(firstNote)"
- :line="line"
+ :line="line || diffLine"
:commit="commit"
:help-page-path="helpPagePath"
:show-reply-button="userCanReply"
- @handle-delete-note="$emit('deleteNote')"
- @start-replying="$emit('startReplying')"
+ @handleDeleteNote="$emit('deleteNote')"
+ @startReplying="$emit('startReplying')"
>
<note-edited-text
v-if="discussion.resolved"
@@ -118,23 +119,29 @@ 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"
- @handle-delete-note="$emit('deleteNote')"
+ <div
+ :class="discussion.diff_discussion ? 'discussion-collapsible bordered-box clearfix' : ''"
+ >
+ <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>
+ </div>
</template>
<template v-else>
<component
@@ -144,12 +151,12 @@ export default {
:note="componentData(note)"
:help-page-path="helpPagePath"
:line="diffLine"
- @handle-delete-note="$emit('deleteNote')"
+ @handleDeleteNote="$emit('deleteNote')"
>
<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_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_form.vue b/app/assets/javascripts/notes/components/note_form.vue
index 042ed196933..01be4f2b094 100644
--- a/app/assets/javascripts/notes/components/note_form.vue
+++ b/app/assets/javascripts/notes/components/note_form.vue
@@ -283,11 +283,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>
diff --git a/app/assets/javascripts/notes/components/note_header.vue b/app/assets/javascripts/notes/components/note_header.vue
index fbf82fab9e9..6466ab3acbe 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
diff --git a/app/assets/javascripts/notes/components/noteable_discussion.vue b/app/assets/javascripts/notes/components/noteable_discussion.vue
index 10b15a9c38c..a71a89cfffc 100644
--- a/app/assets/javascripts/notes/components/noteable_discussion.vue
+++ b/app/assets/javascripts/notes/components/noteable_discussion.vue
@@ -126,16 +126,13 @@ export default {
return this.discussion.resolved_by_push ? __('Automatically resolved') : __('Resolved');
},
shouldShowJumpToNextDiscussion() {
- return this.showJumpToNextDiscussion(
- this.discussion.id,
- this.discussionsByDiffOrder ? 'diff' : 'discussion',
- );
+ return this.showJumpToNextDiscussion(this.discussionsByDiffOrder ? 'diff' : 'discussion');
},
shouldRenderDiffs() {
return this.discussion.diff_discussion && this.renderDiffFile;
},
shouldGroupReplies() {
- return !this.shouldRenderDiffs && !this.discussion.diff_discussion;
+ return !this.shouldRenderDiffs;
},
wrapperComponent() {
return this.shouldRenderDiffs ? diffWithNote : 'div';
@@ -177,22 +174,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}',
);
}
@@ -253,6 +248,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,
@@ -366,7 +366,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>
@@ -379,7 +378,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/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/stores/actions.js b/app/assets/javascripts/notes/stores/actions.js
index 63658d49a05..9054b4779aa 100644
--- a/app/assets/javascripts/notes/stores/actions.js
+++ b/app/assets/javascripts/notes/stores/actions.js
@@ -51,7 +51,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 +67,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 +117,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 +135,7 @@ export const createNewNote = ({ commit, dispatch }, { endpoint, data }) =>
dispatch('updateMergeRequestWidget');
dispatch('startTaskList');
- dispatch('updateResolvableDiscussonsCounts');
+ dispatch('updateResolvableDiscussionsCounts');
}
return res;
});
@@ -168,7 +168,7 @@ export const toggleResolveNote = ({ commit, dispatch }, { endpoint, isResolved,
commit(mutationType, res);
- dispatch('updateResolvableDiscussonsCounts');
+ dispatch('updateResolvableDiscussionsCounts');
dispatch('updateMergeRequestWidget');
});
@@ -442,7 +442,7 @@ export const startTaskList = ({ dispatch }) =>
}),
);
-export const updateResolvableDiscussonsCounts = ({ commit }) =>
+export const updateResolvableDiscussionsCounts = ({ commit }) =>
commit(types.UPDATE_RESOLVABLE_DISCUSSIONS_COUNTS);
export const submitSuggestion = (
diff --git a/app/assets/javascripts/notes/stores/getters.js b/app/assets/javascripts/notes/stores/getters.js
index d7982be3e4b..8aa8f5037b3 100644
--- a/app/assets/javascripts/notes/stores/getters.js
+++ b/app/assets/javascripts/notes/stores/getters.js
@@ -61,15 +61,13 @@ export const unresolvedDiscussionsCount = state => state.unresolvedDiscussionsCo
export const resolvableDiscussionsCount = state => state.resolvableDiscussionsCount;
export const hasUnresolvedDiscussions = state => state.hasUnresolvedDiscussions;
-export const showJumpToNextDiscussion = (state, getters) => (discussionId, mode = 'discussion') => {
+export const showJumpToNextDiscussion = (state, getters) => (mode = 'discussion') => {
const orderedDiffs =
mode !== 'discussion'
? getters.unresolvedDiscussionsIdsByDiff
: getters.unresolvedDiscussionsIdsByDate;
- const indexOf = orderedDiffs.indexOf(discussionId);
-
- return indexOf !== -1 && indexOf < orderedDiffs.length - 1;
+ return orderedDiffs.length > 1;
};
export const isDiscussionResolved = (state, getters) => discussionId =>
diff --git a/app/assets/javascripts/pages/dashboard/issues/index.js b/app/assets/javascripts/pages/dashboard/issues/index.js
index 9055738f86e..2ffeed8a584 100644
--- a/app/assets/javascripts/pages/dashboard/issues/index.js
+++ b/app/assets/javascripts/pages/dashboard/issues/index.js
@@ -2,6 +2,7 @@ import projectSelect from '~/project_select';
import initFilteredSearch from '~/pages/search/init_filtered_search';
import IssuableFilteredSearchTokenKeys from '~/filtered_search/issuable_filtered_search_token_keys';
import { FILTERED_SEARCH } from '~/pages/constants';
+import initManualOrdering from '~/manual_ordering';
document.addEventListener('DOMContentLoaded', () => {
initFilteredSearch({
@@ -10,4 +11,5 @@ document.addEventListener('DOMContentLoaded', () => {
});
projectSelect();
+ initManualOrdering();
});
diff --git a/app/assets/javascripts/pages/groups/issues/index.js b/app/assets/javascripts/pages/groups/issues/index.js
index 35d4b034654..23fb5656008 100644
--- a/app/assets/javascripts/pages/groups/issues/index.js
+++ b/app/assets/javascripts/pages/groups/issues/index.js
@@ -2,6 +2,7 @@ import projectSelect from '~/project_select';
import initFilteredSearch from '~/pages/search/init_filtered_search';
import { FILTERED_SEARCH } from '~/pages/constants';
import IssuableFilteredSearchTokenKeys from 'ee_else_ce/filtered_search/issuable_filtered_search_token_keys';
+import initManualOrdering from '~/manual_ordering';
document.addEventListener('DOMContentLoaded', () => {
IssuableFilteredSearchTokenKeys.addExtraTokensForIssues();
@@ -12,4 +13,5 @@ document.addEventListener('DOMContentLoaded', () => {
filteredSearchTokenKeys: IssuableFilteredSearchTokenKeys,
});
projectSelect();
+ initManualOrdering();
});
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/index/index.js b/app/assets/javascripts/pages/projects/issues/index/index.js
index c34aff02111..c73ebb31eb3 100644
--- a/app/assets/javascripts/pages/projects/issues/index/index.js
+++ b/app/assets/javascripts/pages/projects/issues/index/index.js
@@ -7,6 +7,7 @@ import initFilteredSearch from '~/pages/search/init_filtered_search';
import { FILTERED_SEARCH } from '~/pages/constants';
import { ISSUABLE_INDEX } from '~/pages/projects/constants';
import IssuableFilteredSearchTokenKeys from 'ee_else_ce/filtered_search/issuable_filtered_search_token_keys';
+import initManualOrdering from '~/manual_ordering';
document.addEventListener('DOMContentLoaded', () => {
IssuableFilteredSearchTokenKeys.addExtraTokensForIssues();
@@ -19,4 +20,5 @@ document.addEventListener('DOMContentLoaded', () => {
new ShortcutsNavigation();
new UsersSelect();
+ initManualOrdering();
});
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 dea7c586868..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,16 +1,26 @@
<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 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,
projectFeatureToggle,
projectSettingRow,
},
+ mixins: [settingsMixin],
props: {
currentSettings: {
@@ -37,6 +47,11 @@ export default {
required: false,
default: false,
},
+ packagesAvailable: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
visibilityHelpPath: {
type: String,
required: false,
@@ -67,8 +82,12 @@ export default {
required: false,
default: '',
},
+ packagesHelpPath: {
+ type: String,
+ required: false,
+ default: '',
+ },
},
-
data() {
const defaults = {
visibilityOptions,
@@ -91,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;
},
@@ -106,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;
},
@@ -148,24 +167,6 @@ export default {
}
},
- repositoryAccessLevel(value, oldValue) {
- if (value < oldValue) {
- // sub-features cannot have more premissive access level
- this.mergeRequestsAccessLevel = Math.min(this.mergeRequestsAccessLevel, value);
- this.buildsAccessLevel = Math.min(this.buildsAccessLevel, value);
-
- if (value === 0) {
- this.containerRegistryEnabled = false;
- this.lfsEnabled = false;
- }
- } else if (oldValue === 0) {
- this.mergeRequestsAccessLevel = value;
- this.buildsAccessLevel = value;
- this.containerRegistryEnabled = true;
- this.lfsEnabled = true;
- }
- },
-
issuesAccessLevel(value, oldValue) {
if (value === 0) toggleHiddenClassBySelector('.issues-feature', true);
else if (oldValue === 0) toggleHiddenClassBySelector('.issues-feature', false);
@@ -207,23 +208,20 @@ 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>
+ <i aria-hidden="true" data-hidden="true" class="fa fa-chevron-down"></i>
</div>
</div>
<span class="form-text text-muted">{{ visibilityLevelDescription }}</span>
@@ -299,6 +297,18 @@ export default {
name="project[lfs_enabled]"
/>
</project-setting-row>
+ <project-setting-row
+ v-if="packagesAvailable"
+ :help-path="packagesHelpPath"
+ label="Packages"
+ help-text="Every project can have its own space to store its packages"
+ >
+ <project-feature-toggle
+ v-model="packagesEnabled"
+ :disabled-input="!repositoryEnabled"
+ name="project[packages_enabled]"
+ />
+ </project-setting-row>
</div>
<project-setting-row label="Wiki" help-text="Pages for project documentation">
<project-feature-setting
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/pages/projects/shared/permissions/mixins/settings_pannel_mixin.js b/app/assets/javascripts/pages/projects/shared/permissions/mixins/settings_pannel_mixin.js
new file mode 100644
index 00000000000..fcbd81416f2
--- /dev/null
+++ b/app/assets/javascripts/pages/projects/shared/permissions/mixins/settings_pannel_mixin.js
@@ -0,0 +1,26 @@
+export default {
+ data() {
+ return {
+ packagesEnabled: false,
+ };
+ },
+ watch: {
+ repositoryAccessLevel(value, oldValue) {
+ if (value < oldValue) {
+ // sub-features cannot have more premissive access level
+ this.mergeRequestsAccessLevel = Math.min(this.mergeRequestsAccessLevel, value);
+ this.buildsAccessLevel = Math.min(this.buildsAccessLevel, value);
+
+ if (value === 0) {
+ this.containerRegistryEnabled = false;
+ this.lfsEnabled = false;
+ }
+ } else if (oldValue === 0) {
+ this.mergeRequestsAccessLevel = value;
+ this.buildsAccessLevel = value;
+ this.containerRegistryEnabled = true;
+ this.lfsEnabled = true;
+ }
+ },
+ },
+};
diff --git a/app/assets/javascripts/pages/users/user_tabs.js b/app/assets/javascripts/pages/users/user_tabs.js
index 7f800d20835..1d8b388e935 100644
--- a/app/assets/javascripts/pages/users/user_tabs.js
+++ b/app/assets/javascripts/pages/users/user_tabs.js
@@ -18,12 +18,12 @@ import UserOverviewBlock from './user_overview_block';
*
* <ul class="nav-links">
* <li class="activity-tab active">
- * <a data-action="activity" data-target="#activity" data-toggle="tab" href="/u/username">
+ * <a data-action="activity" data-target="#activity" data-toggle="tab" href="/username">
* Activity
* </a>
* </li>
* <li class="groups-tab">
- * <a data-action="groups" data-target="#groups" data-toggle="tab" href="/u/username/groups">
+ * <a data-action="groups" data-target="#groups" data-toggle="tab" href="/users/username/groups">
* Groups
* </a>
* </li>
diff --git a/app/assets/javascripts/performance_bar/components/detailed_metric.vue b/app/assets/javascripts/performance_bar/components/detailed_metric.vue
index 8f3ba9779fb..d5f1cea8356 100644
--- a/app/assets/javascripts/performance_bar/components/detailed_metric.vue
+++ b/app/assets/javascripts/performance_bar/components/detailed_metric.vue
@@ -92,7 +92,9 @@ export default {
</template>
<template v-else>
<tr>
- <td>No {{ header.toLowerCase() }} for this request.</td>
+ <td>
+ {{ sprintf(__('No %{header} for this request.'), { header: header.toLowerCase() }) }}
+ </td>
</tr>
</template>
</table>
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 48515cf785c..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,13 +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: {
@@ -35,15 +34,20 @@ export default {
},
},
detailedMetrics: [
- { metric: 'pg', header: 'SQL queries', details: 'queries', keys: ['sql'] },
+ { metric: 'pg', header: s__('PerformanceBar|SQL queries'), details: 'queries', keys: ['sql'] },
{
metric: 'gitaly',
- header: 'Gitaly calls',
+ header: s__('PerformanceBar|Gitaly calls'),
details: 'details',
keys: ['feature', 'request'],
},
+ {
+ metric: 'redis',
+ header: 'Redis calls',
+ details: 'details',
+ keys: ['cmd'],
+ },
],
- simpleMetrics: ['redis'],
data() {
return { currentRequestId: '' };
},
@@ -99,7 +103,8 @@ export default {
class="current-host"
:class="{ canary: currentRequest.details.host.canary }"
>
- <span v-html="birdEmoji"></span> {{ currentRequest.details.host.hostname }}
+ <span v-html="birdEmoji"></span>
+ {{ currentRequest.details.host.hostname }}
</span>
</div>
<detailed-metric
@@ -118,16 +123,10 @@ export default {
data-toggle="modal"
data-target="#modal-peek-line-profile"
>
- profile
+ {{ s__('PerformanceBar|profile') }}
</button>
- <a v-else :href="profileUrl"> profile </a>
+ <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
@@ -139,7 +138,7 @@ export default {
id="peek-view-trace"
class="view"
>
- <a :href="currentRequest.details.tracing.tracing_url"> trace </a>
+ <a :href="currentRequest.details.tracing.tracing_url">{{ s__('PerformanceBar|trace') }}</a>
</div>
<request-selector
v-if="currentRequest"
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/pipelines/pipeline_details_mediator.js b/app/assets/javascripts/pipelines/pipeline_details_mediator.js
index d67d88c4dba..c8819cf35cf 100644
--- a/app/assets/javascripts/pipelines/pipeline_details_mediator.js
+++ b/app/assets/javascripts/pipelines/pipeline_details_mediator.js
@@ -1,8 +1,8 @@
import Visibility from 'visibilityjs';
+import PipelineStore from 'ee_else_ce/pipelines/stores/pipeline_store';
import Flash from '../flash';
import Poll from '../lib/utils/poll';
import { __ } from '../locale';
-import PipelineStore from './stores/pipeline_store';
import PipelineService from './services/pipeline_service';
export default class pipelinesMediator {
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/reports/components/report_item.vue b/app/assets/javascripts/reports/components/report_item.vue
index 01a30809e1a..2be9c37b00a 100644
--- a/app/assets/javascripts/reports/components/report_item.vue
+++ b/app/assets/javascripts/reports/components/report_item.vue
@@ -1,6 +1,6 @@
<script>
import IssueStatusIcon from '~/reports/components/issue_status_icon.vue';
-import { components, componentNames } from '~/reports/components/issue_body';
+import { components, componentNames } from 'ee_else_ce/reports/components/issue_body';
export default {
name: 'ReportItem',
diff --git a/app/assets/javascripts/repository/components/breadcrumbs.vue b/app/assets/javascripts/repository/components/breadcrumbs.vue
index 0d4d431855c..67963dc1923 100644
--- a/app/assets/javascripts/repository/components/breadcrumbs.vue
+++ b/app/assets/javascripts/repository/components/breadcrumbs.vue
@@ -36,7 +36,7 @@ export default {
to: `/tree/${this.ref}${path}`,
});
},
- [{ name: this.projectShortPath, path: '/', to: `/tree/${this.ref}` }],
+ [{ name: this.projectShortPath, path: '/', to: `/tree/${this.ref}/` }],
);
},
},
diff --git a/app/assets/javascripts/repository/components/last_commit.vue b/app/assets/javascripts/repository/components/last_commit.vue
index f25cee9bb57..26493556063 100644
--- a/app/assets/javascripts/repository/components/last_commit.vue
+++ b/app/assets/javascripts/repository/components/last_commit.vue
@@ -1,10 +1,9 @@
<script>
-import { GlTooltipDirective, GlLink, GlButton } from '@gitlab/ui';
+import { GlTooltipDirective, GlLink, GlButton, GlLoadingIcon } from '@gitlab/ui';
import { sprintf, s__ } from '~/locale';
import Icon from '../../vue_shared/components/icon.vue';
import UserAvatarLink from '../../vue_shared/components/user_avatar/user_avatar_link.vue';
import TimeagoTooltip from '../../vue_shared/components/time_ago_tooltip.vue';
-import CommitPipelineStatus from '../../projects/tree/components/commit_pipeline_status_component.vue';
import CiIcon from '../../vue_shared/components/ci_icon.vue';
import ClipboardButton from '../../vue_shared/components/clipboard_button.vue';
import getRefMixin from '../mixins/get_ref';
@@ -16,11 +15,11 @@ export default {
Icon,
UserAvatarLink,
TimeagoTooltip,
- CommitPipelineStatus,
ClipboardButton,
CiIcon,
GlLink,
GlButton,
+ GlLoadingIcon,
},
directives: {
GlTooltip: GlTooltipDirective,
@@ -39,7 +38,10 @@ export default {
path: this.currentPath.replace(/^\//, ''),
};
},
- update: data => data.project.repository.tree.commit,
+ update: data => data.project.repository.tree.lastCommit,
+ context: {
+ isSingleRequest: true,
+ },
},
},
props: {
@@ -59,14 +61,14 @@ export default {
computed: {
statusTitle() {
return sprintf(s__('Commits|Commit: %{commitText}'), {
- commitText: this.commit.pipeline.detailedStatus.text,
+ commitText: this.commit.latestPipeline.detailedStatus.text,
});
},
isLoading() {
return this.$apollo.queries.commit.loading;
},
showCommitId() {
- return this.commit.id.substr(0, 8);
+ return this.commit.sha.substr(0, 8);
},
},
methods: {
@@ -78,68 +80,75 @@ export default {
</script>
<template>
- <div v-if="!isLoading" class="info-well d-none d-sm-flex project-last-commit commit p-3">
- <user-avatar-link
- v-if="commit.author"
- :link-href="commit.author.webUrl"
- :img-src="commit.author.avatarUrl"
- :img-size="40"
- class="avatar-cell"
- />
- <div class="commit-detail flex-list">
- <div class="commit-content qa-commit-content">
- <gl-link :href="commit.webUrl" class="commit-row-message item-title">
- {{ commit.title }}
- </gl-link>
- <gl-button
- v-if="commit.description"
- :class="{ open: showDescription }"
- :aria-label="__('Show commit description')"
- class="text-expander"
- @click="toggleShowDescription"
- >
- <icon name="ellipsis_h" />
- </gl-button>
- <div class="committer">
+ <div class="info-well d-none d-sm-flex project-last-commit commit p-3">
+ <gl-loading-icon v-if="isLoading" size="md" class="mx-auto" />
+ <template v-else>
+ <user-avatar-link
+ v-if="commit.author"
+ :link-href="commit.author.webUrl"
+ :img-src="commit.author.avatarUrl"
+ :img-size="40"
+ class="avatar-cell"
+ />
+ <div class="commit-detail flex-list">
+ <div class="commit-content qa-commit-content">
+ <gl-link :href="commit.webUrl" class="commit-row-message item-title">
+ {{ commit.title }}
+ </gl-link>
+ <gl-button
+ v-if="commit.description"
+ :class="{ open: showDescription }"
+ :aria-label="__('Show commit description')"
+ class="text-expander"
+ @click="toggleShowDescription"
+ >
+ <icon name="ellipsis_h" />
+ </gl-button>
+ <div class="committer">
+ <gl-link
+ v-if="commit.author"
+ :href="commit.author.webUrl"
+ class="commit-author-link js-user-link"
+ >
+ {{ commit.author.name }}
+ </gl-link>
+ authored
+ <timeago-tooltip :time="commit.authoredDate" tooltip-placement="bottom" />
+ </div>
+ <pre
+ v-if="commit.description"
+ v-show="showDescription"
+ class="commit-row-description append-bottom-8"
+ >
+ {{ commit.description }}
+ </pre>
+ </div>
+ <div class="commit-actions flex-row">
<gl-link
- v-if="commit.author"
- :href="commit.author.webUrl"
- class="commit-author-link js-user-link"
+ v-if="commit.latestPipeline"
+ v-gl-tooltip
+ :href="commit.latestPipeline.detailedStatus.detailsPath"
+ :title="statusTitle"
+ class="js-commit-pipeline"
>
- {{ commit.author.name }}
+ <ci-icon
+ :status="commit.latestPipeline.detailedStatus"
+ :size="24"
+ :aria-label="statusTitle"
+ />
</gl-link>
- authored
- <timeago-tooltip :time="commit.authoredDate" tooltip-placement="bottom" />
- </div>
- <pre
- v-if="commit.description"
- v-show="showDescription"
- class="commit-row-description append-bottom-8"
- >
- {{ commit.description }}
- </pre>
- </div>
- <div class="commit-actions flex-row">
- <gl-link
- v-if="commit.pipeline"
- v-gl-tooltip
- :href="commit.pipeline.detailedStatus.detailsPath"
- :title="statusTitle"
- class="js-commit-pipeline"
- >
- <ci-icon :status="commit.pipeline.detailedStatus" :size="24" :aria-label="statusTitle" />
- </gl-link>
- <div class="commit-sha-group d-flex">
- <div class="label label-monospace monospace">
- {{ showCommitId }}
+ <div class="commit-sha-group d-flex">
+ <div class="label label-monospace monospace">
+ {{ showCommitId }}
+ </div>
+ <clipboard-button
+ :text="commit.sha"
+ :title="__('Copy commit SHA to clipboard')"
+ tooltip-placement="bottom"
+ />
</div>
- <clipboard-button
- :text="commit.id"
- :title="__('Copy commit SHA to clipboard')"
- tooltip-placement="bottom"
- />
</div>
</div>
- </div>
+ </template>
</div>
</template>
diff --git a/app/assets/javascripts/repository/components/table/index.vue b/app/assets/javascripts/repository/components/table/index.vue
index 891e3fe9d16..1e66ccbfa29 100644
--- a/app/assets/javascripts/repository/components/table/index.vue
+++ b/app/assets/javascripts/repository/components/table/index.vue
@@ -131,7 +131,9 @@ export default {
v-for="entry in val"
:id="entry.id"
:key="`${entry.flatPath}-${entry.id}`"
+ :project-path="projectPath"
:current-path="path"
+ :name="entry.name"
:path="entry.flatPath"
:type="entry.type"
:url="entry.webUrl"
diff --git a/app/assets/javascripts/repository/components/table/row.vue b/app/assets/javascripts/repository/components/table/row.vue
index 4519f82fc93..3e060e9ecb6 100644
--- a/app/assets/javascripts/repository/components/table/row.vue
+++ b/app/assets/javascripts/repository/components/table/row.vue
@@ -1,12 +1,30 @@
<script>
-import { GlBadge } from '@gitlab/ui';
+import { GlBadge, GlLink, GlSkeletonLoading } from '@gitlab/ui';
import { visitUrl } from '~/lib/utils/url_utility';
+import TimeagoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
import { getIconName } from '../../utils/icon';
import getRefMixin from '../../mixins/get_ref';
+import getCommit from '../../queries/getCommit.query.graphql';
export default {
components: {
GlBadge,
+ GlLink,
+ GlSkeletonLoading,
+ TimeagoTooltip,
+ },
+ apollo: {
+ commit: {
+ query: getCommit,
+ variables() {
+ return {
+ fileName: this.name,
+ type: this.type,
+ path: this.currentPath,
+ projectPath: this.projectPath,
+ };
+ },
+ },
},
mixins: [getRefMixin],
props: {
@@ -14,10 +32,18 @@ export default {
type: String,
required: true,
},
+ projectPath: {
+ type: String,
+ required: true,
+ },
currentPath: {
type: String,
required: true,
},
+ name: {
+ type: String,
+ required: true,
+ },
path: {
type: String,
required: true,
@@ -37,6 +63,11 @@ export default {
default: null,
},
},
+ data() {
+ return {
+ commit: null,
+ };
+ },
computed: {
routerLinkTo() {
return this.isFolder ? { path: `/tree/${this.ref}/${this.path}` } : null;
@@ -73,20 +104,26 @@ export default {
</script>
<template>
- <tr v-once :class="`file_${id}`" class="tree-item" @click="openRow">
+ <tr :class="`file_${id}`" class="tree-item" @click="openRow">
<td class="tree-item-file-name">
<i :aria-label="type" role="img" :class="iconName" class="fa fa-fw"></i>
<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">
- @ <a href="#" class="commit-sha">{{ shortSha }}</a>
+ @ <gl-link href="#" class="commit-sha">{{ shortSha }}</gl-link>
</template>
</td>
- <td class="d-none d-sm-table-cell tree-commit"></td>
- <td class="tree-time-ago text-right"></td>
+ <td class="d-none d-sm-table-cell tree-commit">
+ <gl-link v-if="commit" :href="commit.commitPath" class="str-truncated-100 tree-commit-link">
+ {{ commit.message }}
+ </gl-link>
+ <gl-skeleton-loading v-else :lines="1" class="h-auto" />
+ </td>
+ <td class="tree-time-ago text-right">
+ <timeago-tooltip v-if="commit" :time="commit.committedDate" tooltip-placement="bottom" />
+ <gl-skeleton-loading v-else :lines="1" class="ml-auto h-auto w-50" />
+ </td>
</tr>
</template>
diff --git a/app/assets/javascripts/repository/graphql.js b/app/assets/javascripts/repository/graphql.js
index ef147ec15cb..6cb253c8169 100644
--- a/app/assets/javascripts/repository/graphql.js
+++ b/app/assets/javascripts/repository/graphql.js
@@ -3,6 +3,7 @@ import VueApollo from 'vue-apollo';
import { IntrospectionFragmentMatcher } from 'apollo-cache-inmemory';
import createDefaultClient from '~/lib/graphql';
import introspectionQueryResultData from './fragmentTypes.json';
+import { fetchLogsTree } from './log_tree';
Vue.use(VueApollo);
@@ -13,7 +14,21 @@ const fragmentMatcher = new IntrospectionFragmentMatcher({
});
const defaultClient = createDefaultClient(
- {},
+ {
+ Query: {
+ commit(_, { path, fileName, type }) {
+ return new Promise(resolve => {
+ fetchLogsTree(defaultClient, path, '0', {
+ resolve,
+ entry: {
+ name: fileName,
+ type,
+ },
+ });
+ });
+ },
+ },
+ },
{
cacheConfig: {
fragmentMatcher,
diff --git a/app/assets/javascripts/repository/index.js b/app/assets/javascripts/repository/index.js
index d9216e88676..ea051eaa414 100644
--- a/app/assets/javascripts/repository/index.js
+++ b/app/assets/javascripts/repository/index.js
@@ -16,6 +16,7 @@ export default function setupVueRepositoryList() {
projectPath,
projectShortPath,
ref,
+ commits: [],
},
});
@@ -49,23 +50,19 @@ export default function setupVueRepositoryList() {
},
});
- const commitEl = document.getElementById('js-last-commit');
-
- if (commitEl) {
- // eslint-disable-next-line no-new
- new Vue({
- el: commitEl,
- router,
- apolloProvider,
- render(h) {
- return h(LastCommit, {
- props: {
- currentPath: this.$route.params.pathMatch,
- },
- });
- },
- });
- }
+ // eslint-disable-next-line no-new
+ new Vue({
+ el: document.getElementById('js-last-commit'),
+ router,
+ apolloProvider,
+ render(h) {
+ return h(LastCommit, {
+ props: {
+ currentPath: this.$route.params.pathMatch,
+ },
+ });
+ },
+ });
return new Vue({
el,
diff --git a/app/assets/javascripts/repository/log_tree.js b/app/assets/javascripts/repository/log_tree.js
new file mode 100644
index 00000000000..2c19aca2397
--- /dev/null
+++ b/app/assets/javascripts/repository/log_tree.js
@@ -0,0 +1,64 @@
+import axios from '~/lib/utils/axios_utils';
+import getCommits from './queries/getCommits.query.graphql';
+import getProjectPath from './queries/getProjectPath.query.graphql';
+import getRef from './queries/getRef.query.graphql';
+
+let fetchpromise;
+let resolvers = [];
+
+export function normalizeData(data) {
+ return data.map(d => ({
+ sha: d.commit.id,
+ message: d.commit.message,
+ committedDate: d.commit.committed_date,
+ commitPath: d.commit_path,
+ fileName: d.file_name,
+ type: d.type,
+ __typename: 'LogTreeCommit',
+ }));
+}
+
+export function resolveCommit(commits, { resolve, entry }) {
+ const commit = commits.find(c => c.fileName === entry.name && c.type === entry.type);
+
+ if (commit) {
+ resolve(commit);
+ }
+}
+
+export function fetchLogsTree(client, path, offset, resolver = null) {
+ if (resolver) {
+ resolvers.push(resolver);
+ }
+
+ if (fetchpromise) return fetchpromise;
+
+ const { projectPath } = client.readQuery({ query: getProjectPath });
+ const { ref } = client.readQuery({ query: getRef });
+
+ fetchpromise = axios
+ .get(`${gon.gitlab_url}/${projectPath}/refs/${ref}/logs_tree${path ? `/${path}` : ''}`, {
+ params: { format: 'json', offset },
+ })
+ .then(({ data, headers }) => {
+ const headerLogsOffset = headers['more-logs-offset'];
+ const { commits } = client.readQuery({ query: getCommits });
+ const newCommitData = [...commits, ...normalizeData(data)];
+ client.writeQuery({
+ query: getCommits,
+ data: { commits: newCommitData },
+ });
+
+ resolvers.forEach(r => resolveCommit(newCommitData, r));
+
+ fetchpromise = null;
+
+ if (headerLogsOffset) {
+ fetchLogsTree(client, path, headerLogsOffset);
+ } else {
+ resolvers = [];
+ }
+ });
+
+ return fetchpromise;
+}
diff --git a/app/assets/javascripts/repository/queries/getCommit.query.graphql b/app/assets/javascripts/repository/queries/getCommit.query.graphql
new file mode 100644
index 00000000000..e2a2d831e47
--- /dev/null
+++ b/app/assets/javascripts/repository/queries/getCommit.query.graphql
@@ -0,0 +1,10 @@
+query getCommit($fileName: String!, $type: String!, $path: String!) {
+ commit(path: $path, fileName: $fileName, type: $type) @client {
+ sha
+ message
+ committedDate
+ commitPath
+ fileName
+ type
+ }
+}
diff --git a/app/assets/javascripts/repository/queries/getCommits.query.graphql b/app/assets/javascripts/repository/queries/getCommits.query.graphql
new file mode 100644
index 00000000000..df9e67cc440
--- /dev/null
+++ b/app/assets/javascripts/repository/queries/getCommits.query.graphql
@@ -0,0 +1,10 @@
+query getCommits {
+ commits @client {
+ sha
+ message
+ committedDate
+ commitPath
+ fileName
+ type
+ }
+}
diff --git a/app/assets/javascripts/repository/queries/getFiles.query.graphql b/app/assets/javascripts/repository/queries/getFiles.query.graphql
index ef924fde556..4c24fc4087f 100644
--- a/app/assets/javascripts/repository/queries/getFiles.query.graphql
+++ b/app/assets/javascripts/repository/queries/getFiles.query.graphql
@@ -1,5 +1,6 @@
fragment TreeEntry on Entry {
id
+ name
flatPath
type
}
diff --git a/app/assets/javascripts/repository/queries/pathLastCommit.query.graphql b/app/assets/javascripts/repository/queries/pathLastCommit.query.graphql
index 90901f54d54..3bdfd979fa4 100644
--- a/app/assets/javascripts/repository/queries/pathLastCommit.query.graphql
+++ b/app/assets/javascripts/repository/queries/pathLastCommit.query.graphql
@@ -2,8 +2,8 @@ query pathLastCommit($projectPath: ID!, $path: String, $ref: String!) {
project(fullPath: $projectPath) {
repository {
tree(path: $path, ref: $ref) {
- commit {
- id
+ lastCommit {
+ sha
title
message
webUrl
@@ -13,7 +13,7 @@ query pathLastCommit($projectPath: ID!, $path: String, $ref: String!) {
avatarUrl
webUrl
}
- pipeline {
+ latestPipeline {
detailedStatus {
detailsPath
icon
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/time_tracking/comparison_pane.vue b/app/assets/javascripts/sidebar/components/time_tracking/comparison_pane.vue
index f4d926cd3ec..bc263bc36e4 100644
--- a/app/assets/javascripts/sidebar/components/time_tracking/comparison_pane.vue
+++ b/app/assets/javascripts/sidebar/components/time_tracking/comparison_pane.vue
@@ -28,11 +28,16 @@ export default {
type: String,
required: true,
},
+ limitToHours: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
},
computed: {
parsedTimeRemaining() {
const diffSeconds = this.timeEstimate - this.timeSpent;
- return parseSeconds(diffSeconds);
+ return parseSeconds(diffSeconds, { limitToHours: this.limitToHours });
},
timeRemainingHumanReadable() {
return stringifyTime(this.parsedTimeRemaining);
@@ -65,9 +70,6 @@ export default {
:title="timeRemainingTooltip"
:class="timeRemainingStatusClass"
class="compare-meter"
- data-toggle="tooltip"
- data-placement="top"
- role="timeRemainingDisplay"
>
<gl-progress-bar :value="timeRemainingPercent" :variant="progressBarVariant" />
<div class="compare-display-container">
diff --git a/app/assets/javascripts/sidebar/components/time_tracking/sidebar_time_tracking.vue b/app/assets/javascripts/sidebar/components/time_tracking/sidebar_time_tracking.vue
index 8e8b9f19b6e..018b30d2a67 100644
--- a/app/assets/javascripts/sidebar/components/time_tracking/sidebar_time_tracking.vue
+++ b/app/assets/javascripts/sidebar/components/time_tracking/sidebar_time_tracking.vue
@@ -53,6 +53,7 @@ export default {
:time-spent="store.totalTimeSpent"
:human-time-estimate="store.humanTimeEstimate"
:human-time-spent="store.humanTotalTimeSpent"
+ :limit-to-hours="store.timeTrackingLimitToHours"
:root-path="store.rootPath"
/>
</div>
diff --git a/app/assets/javascripts/sidebar/components/time_tracking/time_tracker.vue b/app/assets/javascripts/sidebar/components/time_tracking/time_tracker.vue
index d84d5344935..682ca600b6a 100644
--- a/app/assets/javascripts/sidebar/components/time_tracking/time_tracker.vue
+++ b/app/assets/javascripts/sidebar/components/time_tracking/time_tracker.vue
@@ -37,6 +37,10 @@ export default {
required: false,
default: '',
},
+ limitToHours: {
+ type: Boolean,
+ default: false,
+ },
rootPath: {
type: String,
required: true,
@@ -129,6 +133,7 @@ export default {
:time-spent="timeSpent"
:time-spent-human-readable="humanTimeSpent"
:time-estimate-human-readable="humanTimeEstimate"
+ :limit-to-hours="limitToHours"
/>
<transition name="help-state-toggle">
<time-tracking-help-state v-if="showHelpState" :root-path="rootPath" />
diff --git a/app/assets/javascripts/sidebar/mount_milestone_sidebar.js b/app/assets/javascripts/sidebar/mount_milestone_sidebar.js
index 1ebdbec7bc9..d934463382f 100644
--- a/app/assets/javascripts/sidebar/mount_milestone_sidebar.js
+++ b/app/assets/javascripts/sidebar/mount_milestone_sidebar.js
@@ -1,5 +1,6 @@
import Vue from 'vue';
import timeTracker from './components/time_tracking/time_tracker.vue';
+import { parseBoolean } from '~/lib/utils/common_utils';
export default class SidebarMilestone {
constructor() {
@@ -7,7 +8,7 @@ export default class SidebarMilestone {
if (!el) return;
- const { timeEstimate, timeSpent, humanTimeEstimate, humanTimeSpent } = el.dataset;
+ const { timeEstimate, timeSpent, humanTimeEstimate, humanTimeSpent, limitToHours } = el.dataset;
// eslint-disable-next-line no-new
new Vue({
@@ -22,6 +23,7 @@ export default class SidebarMilestone {
timeSpent: parseInt(timeSpent, 10),
humanTimeEstimate,
humanTimeSpent,
+ limitToHours: parseBoolean(limitToHours),
rootPath: '/',
},
}),
diff --git a/app/assets/javascripts/sidebar/sidebar_mediator.js b/app/assets/javascripts/sidebar/sidebar_mediator.js
index 22ac8df9699..643fe6c00b6 100644
--- a/app/assets/javascripts/sidebar/sidebar_mediator.js
+++ b/app/assets/javascripts/sidebar/sidebar_mediator.js
@@ -1,7 +1,7 @@
import { visitUrl } from '../lib/utils/url_utility';
import Flash from '../flash';
import Service from './services/sidebar_service';
-import Store from './stores/sidebar_store';
+import Store from 'ee_else_ce/sidebar/stores/sidebar_store';
import { __ } from '~/locale';
export default class SidebarMediator {
diff --git a/app/assets/javascripts/sidebar/stores/sidebar_store.js b/app/assets/javascripts/sidebar/stores/sidebar_store.js
index 7b8b4c5d856..63c4a2a3f84 100644
--- a/app/assets/javascripts/sidebar/stores/sidebar_store.js
+++ b/app/assets/javascripts/sidebar/stores/sidebar_store.js
@@ -8,7 +8,7 @@ export default class SidebarStore {
}
initSingleton(options) {
- const { currentUser, rootPath, editable } = options;
+ const { currentUser, rootPath, editable, timeTrackingLimitToHours } = options;
this.currentUser = currentUser;
this.rootPath = rootPath;
this.editable = editable;
@@ -16,6 +16,7 @@ export default class SidebarStore {
this.totalTimeSpent = 0;
this.humanTimeEstimate = '';
this.humanTimeSpent = '';
+ this.timeTrackingLimitToHours = timeTrackingLimitToHours;
this.assignees = [];
this.isFetching = {
assignees: true,
diff --git a/app/assets/javascripts/visual_review_toolbar/components/comment.js b/app/assets/javascripts/visual_review_toolbar/components/comment.js
index 2fec96d1435..04bfb5e9532 100644
--- a/app/assets/javascripts/visual_review_toolbar/components/comment.js
+++ b/app/assets/javascripts/visual_review_toolbar/components/comment.js
@@ -1,54 +1,62 @@
import { BLACK, COMMENT_BOX, MUTED, LOGOUT } from './constants';
-import { clearNote, note, postError } from './note';
-import { buttonClearStyles, selectCommentBox, selectCommentButton, selectNote } from './utils';
+import { clearNote, postError } from './note';
+import {
+ buttonClearStyles,
+ selectCommentBox,
+ selectCommentButton,
+ selectNote,
+ selectNoteContainer,
+} from './utils';
const comment = `
<div>
<textarea id="${COMMENT_BOX}" name="${COMMENT_BOX}" rows="3" placeholder="Enter your feedback or idea" class="gitlab-input" aria-required="true"></textarea>
- ${note}
<p class="gitlab-metadata-note">Additional metadata will be included: browser, OS, current page, user agent, and viewport dimensions.</p>
</div>
<div class="gitlab-button-wrapper">
- <button class="gitlab-button gitlab-button-secondary" style="${buttonClearStyles}" type="button" id="${LOGOUT}"> Logout </button>
+ <button class="gitlab-button gitlab-button-secondary" style="${buttonClearStyles}" type="button" id="${LOGOUT}"> Log out </button>
<button class="gitlab-button gitlab-button-success" style="${buttonClearStyles}" type="button" id="gitlab-comment-button"> Send feedback </button>
</div>
`;
-const resetCommentBox = () => {
- const commentBox = selectCommentBox();
+const resetCommentButton = () => {
const commentButton = selectCommentButton();
/* eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings */
commentButton.innerText = 'Send feedback';
commentButton.classList.replace('gitlab-button-secondary', 'gitlab-button-success');
commentButton.style.opacity = 1;
+};
+const resetCommentBox = () => {
+ const commentBox = selectCommentBox();
commentBox.style.pointerEvents = 'auto';
commentBox.style.color = BLACK;
};
-const resetCommentButton = () => {
+const resetCommentText = () => {
const commentBox = selectCommentBox();
- const currentNote = selectNote();
-
commentBox.value = '';
- currentNote.innerText = '';
};
const resetComment = () => {
- resetCommentBox();
resetCommentButton();
+ resetCommentBox();
+ resetCommentText();
};
-const confirmAndClear = mergeRequestId => {
+const confirmAndClear = feedbackInfo => {
const commentButton = selectCommentButton();
const currentNote = selectNote();
+ const noteContainer = selectNoteContainer();
/* eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings */
commentButton.innerText = 'Feedback sent';
- /* eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings */
- currentNote.innerText = `Your comment was successfully posted to merge request #${mergeRequestId}`;
- setTimeout(resetComment, 2000);
+ noteContainer.style.visibility = 'visible';
+ currentNote.insertAdjacentHTML('beforeend', feedbackInfo);
+
+ setTimeout(resetComment, 1000);
+ setTimeout(clearNote, 6000);
};
const setInProgressState = () => {
@@ -71,6 +79,7 @@ const postComment = ({
innerWidth,
innerHeight,
projectId,
+ projectPath,
mergeRequestId,
mrUrl,
token,
@@ -86,6 +95,7 @@ const postComment = ({
/* eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings */
postError('Your comment appears to be empty.', COMMENT_BOX);
resetCommentBox();
+ resetCommentButton();
return;
}
@@ -114,18 +124,24 @@ const postComment = ({
})
.then(response => {
if (response.ok) {
- confirmAndClear(mergeRequestId);
- return;
+ return response.json();
}
throw new Error(`${response.status}: ${response.statusText}`);
})
+ .then(data => {
+ const commentId = data.notes[0].id;
+ const feedbackLink = `${mrUrl}/${projectPath}/merge_requests/${mergeRequestId}#note_${commentId}`;
+ const feedbackInfo = `Feedback sent. View at <a class="gitlab-link" href="${feedbackLink}">${projectPath} #${mergeRequestId} (comment ${commentId})</a>`;
+ confirmAndClear(feedbackInfo);
+ })
.catch(err => {
postError(
`Your comment could not be sent. Please try again. Error: ${err.message}`,
COMMENT_BOX,
);
resetCommentBox();
+ resetCommentButton();
});
};
diff --git a/app/assets/javascripts/visual_review_toolbar/components/constants.js b/app/assets/javascripts/visual_review_toolbar/components/constants.js
index 32ed1153515..07fcb179d15 100644
--- a/app/assets/javascripts/visual_review_toolbar/components/constants.js
+++ b/app/assets/javascripts/visual_review_toolbar/components/constants.js
@@ -2,10 +2,12 @@
const COLLAPSE_BUTTON = 'gitlab-collapse';
const COMMENT_BOX = 'gitlab-comment';
const COMMENT_BUTTON = 'gitlab-comment-button';
-const FORM = 'gitlab-form-wrapper';
+const FORM = 'gitlab-form';
+const FORM_CONTAINER = 'gitlab-form-wrapper';
const LOGIN = 'gitlab-login';
const LOGOUT = 'gitlab-logout-button';
const NOTE = 'gitlab-validation-note';
+const NOTE_CONTAINER = 'gitlab-note-wrapper';
const REMEMBER_TOKEN = 'gitlab-remember_token';
const REVIEW_CONTAINER = 'gitlab-review-container';
const TOKEN_BOX = 'gitlab-token';
@@ -16,16 +18,18 @@ const BLACK = 'rgba(46, 46, 46, 1)';
const CLEAR = 'rgba(255, 255, 255, 0)';
const MUTED = 'rgba(223, 223, 223, 0.5)';
const RED = 'rgba(219, 59, 33, 1)';
-const WHITE = 'rgba(255, 255, 255, 1)';
+const WHITE = 'rgba(250, 250, 250, 1)';
export {
COLLAPSE_BUTTON,
COMMENT_BOX,
COMMENT_BUTTON,
FORM,
+ FORM_CONTAINER,
LOGIN,
LOGOUT,
NOTE,
+ NOTE_CONTAINER,
REMEMBER_TOKEN,
REVIEW_CONTAINER,
TOKEN_BOX,
diff --git a/app/assets/javascripts/visual_review_toolbar/components/index.js b/app/assets/javascripts/visual_review_toolbar/components/index.js
index 43581818152..50b52d7d3a2 100644
--- a/app/assets/javascripts/visual_review_toolbar/components/index.js
+++ b/app/assets/javascripts/visual_review_toolbar/components/index.js
@@ -1,22 +1,32 @@
import { comment, postComment } from './comment';
-import { COLLAPSE_BUTTON, COMMENT_BUTTON, LOGIN, LOGOUT, REVIEW_CONTAINER } from './constants';
+import {
+ COLLAPSE_BUTTON,
+ COMMENT_BUTTON,
+ FORM_CONTAINER,
+ LOGIN,
+ LOGOUT,
+ REVIEW_CONTAINER,
+} from './constants';
import { authorizeUser, login } from './login';
+import { note } from './note';
import { selectContainer } from './utils';
-import { form, logoutUser, toggleForm } from './wrapper';
+import { buttonAndForm, logoutUser, toggleForm } from './wrapper';
import { collapseButton } from './wrapper_icons';
export {
authorizeUser,
+ buttonAndForm,
collapseButton,
comment,
- form,
login,
logoutUser,
+ note,
postComment,
selectContainer,
toggleForm,
COLLAPSE_BUTTON,
COMMENT_BUTTON,
+ FORM_CONTAINER,
LOGIN,
LOGOUT,
REVIEW_CONTAINER,
diff --git a/app/assets/javascripts/visual_review_toolbar/components/login.js b/app/assets/javascripts/visual_review_toolbar/components/login.js
index ce713cdc520..0a71299f041 100644
--- a/app/assets/javascripts/visual_review_toolbar/components/login.js
+++ b/app/assets/javascripts/visual_review_toolbar/components/login.js
@@ -1,5 +1,5 @@
import { LOGIN, REMEMBER_TOKEN, TOKEN_BOX } from './constants';
-import { clearNote, note, postError } from './note';
+import { clearNote, postError } from './note';
import { buttonClearStyles, selectRemember, selectToken } from './utils';
import { addCommentForm } from './wrapper';
@@ -7,7 +7,6 @@ const login = `
<div>
<label for="${TOKEN_BOX}" class="gitlab-label">Enter your <a class="gitlab-link" href="https://docs.gitlab.com/ee/user/profile/personal_access_tokens.html">personal access token</a></label>
<input class="gitlab-input" type="password" id="${TOKEN_BOX}" name="${TOKEN_BOX}" aria-required="true" autocomplete="current-password">
- ${note}
</div>
<div class="gitlab-checkbox-wrapper">
<input type="checkbox" id="${REMEMBER_TOKEN}" name="${REMEMBER_TOKEN}" value="remember">
diff --git a/app/assets/javascripts/visual_review_toolbar/components/note.js b/app/assets/javascripts/visual_review_toolbar/components/note.js
index dfebf58fd95..0150f640aae 100644
--- a/app/assets/javascripts/visual_review_toolbar/components/note.js
+++ b/app/assets/javascripts/visual_review_toolbar/components/note.js
@@ -1,14 +1,19 @@
-import { NOTE, RED } from './constants';
-import { selectById, selectNote } from './utils';
+import { NOTE, NOTE_CONTAINER, RED } from './constants';
+import { selectById, selectNote, selectNoteContainer } from './utils';
const note = `
- <p id=${NOTE} class='gitlab-message'></p>
+ <div id="${NOTE_CONTAINER}" style="visibility: hidden;">
+ <p id="${NOTE}" class="gitlab-message"></p>
+ </div>
`;
const clearNote = inputId => {
const currentNote = selectNote();
+ const noteContainer = selectNoteContainer();
+
currentNote.innerText = '';
currentNote.style.color = '';
+ noteContainer.style.visibility = 'hidden';
if (inputId) {
const field = document.getElementById(inputId);
@@ -18,10 +23,13 @@ const clearNote = inputId => {
const postError = (message, inputId) => {
const currentNote = selectNote();
+ const noteContainer = selectNoteContainer();
const field = selectById(inputId);
field.style.borderColor = RED;
currentNote.style.color = RED;
currentNote.innerText = message;
+ noteContainer.style.visibility = 'visible';
+ setTimeout(clearNote.bind(null, inputId), 5000);
};
export { clearNote, note, postError };
diff --git a/app/assets/javascripts/visual_review_toolbar/components/utils.js b/app/assets/javascripts/visual_review_toolbar/components/utils.js
index 7bc2e5a905b..00f4460925d 100644
--- a/app/assets/javascripts/visual_review_toolbar/components/utils.js
+++ b/app/assets/javascripts/visual_review_toolbar/components/utils.js
@@ -5,7 +5,9 @@ import {
COMMENT_BOX,
COMMENT_BUTTON,
FORM,
+ FORM_CONTAINER,
NOTE,
+ NOTE_CONTAINER,
REMEMBER_TOKEN,
REVIEW_CONTAINER,
TOKEN_BOX,
@@ -24,7 +26,9 @@ const selectCommentBox = () => document.getElementById(COMMENT_BOX);
const selectCommentButton = () => document.getElementById(COMMENT_BUTTON);
const selectContainer = () => document.getElementById(REVIEW_CONTAINER);
const selectForm = () => document.getElementById(FORM);
+const selectFormContainer = () => document.getElementById(FORM_CONTAINER);
const selectNote = () => document.getElementById(NOTE);
+const selectNoteContainer = () => document.getElementById(NOTE_CONTAINER);
const selectRemember = () => document.getElementById(REMEMBER_TOKEN);
const selectToken = () => document.getElementById(TOKEN_BOX);
@@ -36,7 +40,9 @@ export {
selectCommentBox,
selectCommentButton,
selectForm,
+ selectFormContainer,
selectNote,
+ selectNoteContainer,
selectRemember,
selectToken,
};
diff --git a/app/assets/javascripts/visual_review_toolbar/components/wrapper.js b/app/assets/javascripts/visual_review_toolbar/components/wrapper.js
index 233b7ec496c..f2eaf1d7916 100644
--- a/app/assets/javascripts/visual_review_toolbar/components/wrapper.js
+++ b/app/assets/javascripts/visual_review_toolbar/components/wrapper.js
@@ -1,15 +1,28 @@
import { comment } from './comment';
-import { CLEAR, FORM, WHITE } from './constants';
+import { CLEAR, FORM, FORM_CONTAINER, WHITE } from './constants';
import { login } from './login';
-import { selectCollapseButton, selectContainer, selectForm } from './utils';
+import { clearNote } from './note';
+import {
+ selectCollapseButton,
+ selectForm,
+ selectFormContainer,
+ selectNoteContainer,
+} from './utils';
import { commentIcon, compressIcon } from './wrapper_icons';
const form = content => `
- <form id=${FORM}>
+ <form id="${FORM}">
${content}
</form>
`;
+const buttonAndForm = ({ content, toggleButton }) => `
+ <div id="${FORM_CONTAINER}" class="gitlab-form-open">
+ ${toggleButton}
+ ${form(content)}
+ </div>
+`;
+
const addCommentForm = () => {
const formWrapper = selectForm();
formWrapper.innerHTML = comment;
@@ -31,13 +44,15 @@ function logoutUser() {
return;
}
+ clearNote();
addLoginForm();
}
function toggleForm() {
- const container = selectContainer();
const collapseButton = selectCollapseButton();
const currentForm = selectForm();
+ const formContainer = selectFormContainer();
+ const noteContainer = selectNoteContainer();
const OPEN = 'open';
const CLOSED = 'closed';
@@ -49,7 +64,7 @@ function toggleForm() {
const openButtonClasses = ['gitlab-collapse-closed', 'gitlab-collapse-open'];
const closedButtonClasses = [...openButtonClasses].reverse();
- const openContainerClasses = ['gitlab-closed-wrapper', 'gitlab-open-wrapper'];
+ const openContainerClasses = ['gitlab-wrapper-closed', 'gitlab-wrapper-open'];
const closedContainerClasses = [...openContainerClasses].reverse();
const stateVals = {
@@ -72,11 +87,16 @@ function toggleForm() {
const nextState = collapseButton.classList.contains('gitlab-collapse-open') ? CLOSED : OPEN;
const currentVals = stateVals[nextState];
- container.classList.replace(...currentVals.containerClasses);
- container.style.backgroundColor = currentVals.backgroundColor;
+ formContainer.classList.replace(...currentVals.containerClasses);
+ formContainer.style.backgroundColor = currentVals.backgroundColor;
+ formContainer.classList.toggle('gitlab-form-open');
currentForm.style.display = currentVals.display;
collapseButton.classList.replace(...currentVals.buttonClasses);
collapseButton.innerHTML = currentVals.icon;
+
+ if (noteContainer && noteContainer.innerText.length > 0) {
+ noteContainer.style.display = currentVals.display;
+ }
}
-export { addCommentForm, addLoginForm, form, logoutUser, toggleForm };
+export { addCommentForm, addLoginForm, buttonAndForm, logoutUser, toggleForm };
diff --git a/app/assets/javascripts/visual_review_toolbar/index.js b/app/assets/javascripts/visual_review_toolbar/index.js
index 941d77e25b4..f94eb88835a 100644
--- a/app/assets/javascripts/visual_review_toolbar/index.js
+++ b/app/assets/javascripts/visual_review_toolbar/index.js
@@ -1,6 +1,6 @@
import './styles/toolbar.css';
-import { form, selectContainer, REVIEW_CONTAINER } from './components';
+import { buttonAndForm, note, selectContainer, REVIEW_CONTAINER } from './components';
import { debounce, eventLookup, getInitialView, initializeState, updateWindowSize } from './store';
/*
@@ -20,12 +20,11 @@ import { debounce, eventLookup, getInitialView, initializeState, updateWindowSiz
window.addEventListener('load', () => {
initializeState(window, document);
- const { content, toggleButton } = getInitialView(window);
+ const mainContent = buttonAndForm(getInitialView(window));
const container = document.createElement('div');
-
container.setAttribute('id', REVIEW_CONTAINER);
- container.insertAdjacentHTML('beforeend', toggleButton);
- container.insertAdjacentHTML('beforeend', form(content));
+ container.insertAdjacentHTML('beforeend', note);
+ container.insertAdjacentHTML('beforeend', mainContent);
document.body.insertBefore(container, document.body.firstChild);
diff --git a/app/assets/javascripts/visual_review_toolbar/store/state.js b/app/assets/javascripts/visual_review_toolbar/store/state.js
index f5ede6e85b2..22702d524b8 100644
--- a/app/assets/javascripts/visual_review_toolbar/store/state.js
+++ b/app/assets/javascripts/visual_review_toolbar/store/state.js
@@ -34,7 +34,7 @@ const initializeState = (wind, doc) => {
const browser = getBrowserId(userAgent);
const scriptEl = doc.getElementById('review-app-toolbar-script');
- const { projectId, mergeRequestId, mrUrl } = scriptEl.dataset;
+ const { projectId, mergeRequestId, mrUrl, projectPath } = scriptEl.dataset;
// This mutates our default state object above. It's weird but it makes the linter happy.
Object.assign(state, {
@@ -46,6 +46,7 @@ const initializeState = (wind, doc) => {
mrUrl,
platform,
projectId,
+ projectPath,
userAgent,
});
};
diff --git a/app/assets/javascripts/visual_review_toolbar/styles/toolbar.css b/app/assets/javascripts/visual_review_toolbar/styles/toolbar.css
index 342b3599a44..00a55c0027a 100644
--- a/app/assets/javascripts/visual_review_toolbar/styles/toolbar.css
+++ b/app/assets/javascripts/visual_review_toolbar/styles/toolbar.css
@@ -6,23 +6,42 @@
pointer-events: none;
}
-#gitlab-form-wrapper {
+#gitlab-comment {
+ background-color: #fafafa;
+}
+
+#gitlab-form {
+ display: flex;
+ flex-direction: column;
+ width: 100%;
+ margin-bottom: 0;
+}
+
+#gitlab-note-wrapper {
display: flex;
flex-direction: column;
- width: 100%
+ background-color: #fafafa;
+ border-radius: 4px;
+ margin-bottom: .5rem;
+ padding: 1rem;
+}
+
+#gitlab-form-wrapper {
+ overflow: auto;
+ display: flex;
+ flex-direction: row-reverse;
+ border-radius: 4px;
}
#gitlab-review-container {
max-width: 22rem;
max-height: 22rem;
- overflow: scroll;
+ overflow: auto;
+ display: flex;
+ flex-direction: column;
position: fixed;
bottom: 1rem;
right: 1rem;
- display: flex;
- flex-direction: row-reverse;
- padding: 1rem;
- background-color: #fff;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell,
'Helvetica Neue', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol',
'Noto Color Emoji';
@@ -31,12 +50,12 @@
color: #2e2e2e;
}
-.gitlab-open-wrapper {
+.gitlab-wrapper-open {
max-width: 22rem;
max-height: 22rem;
}
-.gitlab-closed-wrapper {
+.gitlab-wrapper-closed {
max-width: 3.4rem;
max-height: 3.4rem;
}
@@ -47,7 +66,7 @@
}
.gitlab-button-secondary {
- background: none #fff;
+ background: none #fafafa;
margin: 0 .5rem;
border: 1px solid #e3e3e3;
}
@@ -113,6 +132,11 @@
align-items: baseline;
}
+.gitlab-form-open {
+ padding: 1rem;
+ background-color: #fafafa;
+}
+
.gitlab-label {
font-weight: 600;
display: inline-block;
@@ -126,6 +150,10 @@
background-image: none;
}
+.gitlab-link:hover {
+ text-decoration: underline;
+}
+
.gitlab-message {
padding: .25rem 0;
margin: 0;
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/mr_widget_options.vue b/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue
index 41386178a1e..a79da476890 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
@@ -162,7 +162,8 @@ export default {
removeWIPPath: store.removeWIPPath,
sourceBranchPath: store.sourceBranchPath,
ciEnvironmentsStatusPath: store.ciEnvironmentsStatusPath,
- statusPath: store.statusPath,
+ mergeRequestBasicPath: store.mergeRequestBasicPath,
+ mergeRequestWidgetPath: store.mergeRequestWidgetPath,
mergeActionsContentPath: store.mergeActionsContentPath,
rebasePath: store.rebasePath,
};
diff --git a/app/assets/javascripts/vue_merge_request_widget/services/mr_widget_service.js b/app/assets/javascripts/vue_merge_request_widget/services/mr_widget_service.js
index 0bb70bfd658..1dae53039d5 100644
--- a/app/assets/javascripts/vue_merge_request_widget/services/mr_widget_service.js
+++ b/app/assets/javascripts/vue_merge_request_widget/services/mr_widget_service.js
@@ -30,11 +30,11 @@ export default class MRWidgetService {
}
poll() {
- return axios.get(`${this.endpoints.statusPath}?serializer=basic`);
+ return axios.get(this.endpoints.mergeRequestBasicPath);
}
checkStatus() {
- return axios.get(`${this.endpoints.statusPath}?serializer=widget`);
+ return axios.get(this.endpoints.mergeRequestWidgetPath);
}
fetchMergeActionsContent() {
diff --git a/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js b/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js
index bfa3e7f4a59..581fee7477f 100644
--- a/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js
+++ b/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js
@@ -86,7 +86,8 @@ export default class MergeRequestStore {
this.mergePath = data.merge_path;
this.ffOnlyEnabled = data.ff_only_enabled;
this.shouldBeRebased = Boolean(data.should_be_rebased);
- this.statusPath = data.status_path;
+ this.mergeRequestBasicPath = data.merge_request_basic_path;
+ this.mergeRequestWidgetPath = data.merge_request_widget_path;
this.emailPatchesPath = data.email_patches_path;
this.plainDiffPath = data.plain_diff_path;
this.newBlobPath = data.new_blob_path;
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/issue/related_issuable_item.vue b/app/assets/javascripts/vue_shared/components/issue/related_issuable_item.vue
index 05ad7710a62..eb0f666422f 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
@@ -1,6 +1,6 @@
<script>
import '~/commons/bootstrap';
-import { GlTooltipDirective } from '@gitlab/ui';
+import { GlTooltip, GlTooltipDirective } from '@gitlab/ui';
import { sprintf } from '~/locale';
import IssueMilestone from '../../components/issue/issue_milestone.vue';
import IssueAssignees from '../../components/issue/issue_assignees.vue';
@@ -13,6 +13,7 @@ export default {
IssueMilestone,
IssueAssignees,
CiIcon,
+ GlTooltip,
},
directives: {
GlTooltip: GlTooltipDirective,
@@ -24,11 +25,6 @@ export default {
required: false,
default: false,
},
- greyLinkWhenMerged: {
- type: Boolean,
- required: false,
- default: false,
- },
},
computed: {
stateTitle() {
@@ -41,10 +37,12 @@ export default {
},
);
},
- issueableLinkClass() {
- return this.greyLinkWhenMerged
- ? `sortable-link ${this.state === 'merged' ? ' text-secondary' : ''}`
- : 'sortable-link';
+ heightStyle() {
+ return {
+ minHeight: '32px',
+ width: '0px',
+ visibility: 'hidden',
+ };
},
},
};
@@ -56,20 +54,25 @@ export default {
'issuable-info-container': !canReorder,
'card-body': canReorder,
}"
- class="item-body d-flex align-items-center p-2 p-lg-3 p-xl-2 pl-xl-3"
+ class="item-body d-flex align-items-center p-2 p-lg-3 py-xl-2 px-xl-3"
>
<div class="item-contents d-flex align-items-center flex-wrap flex-grow-1 flex-xl-nowrap">
- <div class="item-title d-flex align-items-center mb-1 mb-xl-0">
- <icon
- v-if="hasState"
- v-tooltip
- :css-classes="iconClass"
- :name="iconName"
- :size="16"
- :title="stateTitle"
- :aria-label="state"
- data-html="true"
- />
+ <!-- Title area: Status icon (XL) and title -->
+ <div class="item-title d-flex align-items-center mb-xl-0">
+ <span ref="iconElementXL">
+ <icon
+ v-if="hasState"
+ ref="iconElementXL"
+ :css-classes="iconClass"
+ :name="iconName"
+ :size="16"
+ :title="stateTitle"
+ :aria-label="state"
+ />
+ </span>
+ <gl-tooltip :target="() => $refs.iconElementXL">
+ <span v-html="stateTitle"></span>
+ </gl-tooltip>
<icon
v-if="confidential"
v-gl-tooltip
@@ -79,55 +82,81 @@ export default {
class="confidential-icon append-right-4 align-self-baseline align-self-md-auto mt-xl-0"
:aria-label="__('Confidential')"
/>
- <a :href="computedPath" :class="issueableLinkClass">{{ title }}</a>
+ <a :href="computedPath" class="sortable-link">{{ title }}</a>
</div>
- <div class="item-meta d-flex flex-wrap mt-xl-0 justify-content-xl-end flex-xl-nowrap">
- <div
- class="d-flex align-items-center item-path-id order-md-0 mt-md-0 mt-1 ml-xl-2 mr-xl-auto"
- >
- <icon
- v-if="hasState"
- v-tooltip
- :css-classes="iconClass"
- :name="iconName"
- :size="16"
- :title="stateTitle"
- :aria-label="state"
- data-html="true"
- class="d-xl-none"
- />
- <span v-tooltip :title="itemPath" class="path-id-text d-inline-block">{{
- itemPath
- }}</span>
- {{ pathIdSeparator }}{{ itemId }}
- </div>
+
+ <!-- Info area: meta, path, and assignees -->
+ <div class="item-info-area d-flex flex-xl-grow-1 flex-shrink-0">
+ <!-- Meta area: path and attributes -->
+ <!-- If there is no room beside the path, meta attributes are put ABOVE it (flex-wrap-reverse). -->
+ <!-- See design: https://gitlab-org.gitlab.io/gitlab-design/hosted/pedro/%2383-issue-mr-rows-cards-spec-previews/#artboard16 -->
<div
- class="item-meta-child d-flex align-items-center order-0 flex-wrap mr-md-1 ml-md-auto ml-xl-2 flex-xl-nowrap"
+ class="item-meta d-flex flex-wrap-reverse justify-content-start justify-content-md-between"
>
- <span v-if="hasPipeline" class="mr-ci-status pr-2">
- <a :href="pipelineStatus.details_path">
- <ci-icon v-gl-tooltip :status="pipelineStatus" :title="pipelineStatusTooltip" />
- </a>
- </span>
- <issue-milestone
- v-if="hasMilestone"
- :milestone="milestone"
- class="d-flex align-items-center item-milestone"
- />
- <slot name="dueDate"></slot>
- <slot name="weight"></slot>
+ <!-- Path area: status icon (<XL), path, issue # -->
+ <div
+ class="item-path-area item-path-id d-flex align-items-center mr-2 mt-2 mt-xl-0 ml-xl-2"
+ >
+ <span ref="iconElement">
+ <icon
+ v-if="hasState"
+ :css-classes="iconClass"
+ :name="iconName"
+ :title="stateTitle"
+ :aria-label="state"
+ data-html="true"
+ class="d-xl-none"
+ />
+ </span>
+ <gl-tooltip :target="() => this.$refs.iconElement">
+ <span v-html="stateTitle"></span>
+ </gl-tooltip>
+ <span v-gl-tooltip :title="itemPath" class="path-id-text d-inline-block">{{
+ itemPath
+ }}</span>
+ <span>{{ pathIdSeparator }}{{ itemId }}</span>
+ </div>
+
+ <!-- Attributes area: CI, epic count, weight, milestone -->
+ <!-- They have a different order on large screen sizes -->
+ <div class="item-attributes-area d-flex align-items-center mt-2 mt-xl-0">
+ <span v-if="hasPipeline" class="mr-ci-status order-md-last">
+ <a :href="pipelineStatus.details_path">
+ <ci-icon v-gl-tooltip :status="pipelineStatus" :title="pipelineStatusTooltip" />
+ </a>
+ </span>
+
+ <issue-milestone
+ v-if="hasMilestone"
+ :milestone="milestone"
+ class="d-flex align-items-center item-milestone order-md-first ml-md-0"
+ />
+
+ <!-- Flex order for slots is defined in the parent component: e.g. related_issues_block.vue -->
+ <slot name="dueDate"></slot>
+ <slot name="weight"></slot>
+
+ <issue-assignees
+ v-if="hasAssignees"
+ :assignees="assignees"
+ class="item-assignees align-items-center align-self-end flex-shrink-0 order-md-2 d-none d-md-flex"
+ />
+ </div>
</div>
+
+ <!-- Assignees. On small layouts, these are put here, at the end of the card. -->
<issue-assignees
- v-if="assignees.length"
+ v-if="assignees.length !== 0"
:assignees="assignees"
- class="item-assignees d-inline-flex align-items-center align-self-end ml-auto ml-md-0 mb-md-0 order-2 flex-xl-grow-0 mt-xl-0 mr-xl-1"
+ class="item-assignees d-flex align-items-center align-self-end flex-shrink-0 d-md-none ml-2"
/>
</div>
</div>
+
<button
v-if="canRemove"
ref="removeButton"
- v-tooltip
+ v-gl-tooltip
: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"
@@ -137,5 +166,9 @@ export default {
>
<icon :size="16" class="btn-item-remove-icon" name="close" />
</button>
+
+ <!-- This element serves to set the issue card's height at a minimum of 32 px. -->
+ <!-- It fixes #59594: when the remove button is missing, issues have inconsistent heights. -->
+ <span :style="heightStyle"></span>
</div>
</template>
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/mixins/related_issuable_mixin.js b/app/assets/javascripts/vue_shared/mixins/related_issuable_mixin.js
index 8e0e4baa75a..3c727cb7b3f 100644
--- a/app/assets/javascripts/vue_shared/mixins/related_issuable_mixin.js
+++ b/app/assets/javascripts/vue_shared/mixins/related_issuable_mixin.js
@@ -126,6 +126,9 @@ const mixins = {
hasTitle() {
return this.title.length > 0;
},
+ hasAssignees() {
+ return this.assignees.length > 0;
+ },
hasMilestone() {
return !_.isEmpty(this.milestone);
},
diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss
index a2f518cd24e..d5ef66af31a 100644
--- a/app/assets/stylesheets/application.scss
+++ b/app/assets/stylesheets/application.scss
@@ -11,10 +11,10 @@
// like a table or typography then make changes in the framework/ directory.
// If you need to add unique style that should affect only one page - use pages/
// directory.
-@import "../../../node_modules/at.js/dist/css/jquery.atwho";
-@import "../../../node_modules/pikaday/scss/pikaday";
-@import "../../../node_modules/dropzone/dist/basic";
-@import "../../../node_modules/select2/select2";
+@import "at.js/dist/css/jquery.atwho";
+@import "pikaday/scss/pikaday";
+@import "dropzone/dist/basic";
+@import "select2/select2";
// GitLab UI framework
@import "framework";
diff --git a/app/assets/stylesheets/components/related_items_list.scss b/app/assets/stylesheets/components/related_items_list.scss
index 7f9cf1266b1..59224d37744 100644
--- a/app/assets/stylesheets/components/related_items_list.scss
+++ b/app/assets/stylesheets/components/related_items_list.scss
@@ -83,6 +83,20 @@ $item-weight-max-width: 48px;
flex-basis: 100%;
}
+ .item-attributes-area {
+ > * {
+ margin-left: 8px;
+ }
+
+ .board-card-info {
+ margin-right: 0;
+ }
+
+ @include media-breakpoint-down(sm) {
+ margin-left: -8px;
+ }
+ }
+
.item-milestone,
.item-weight {
cursor: help;
@@ -101,39 +115,39 @@ $item-weight-max-width: 48px;
.item-weight {
max-width: $item-weight-max-width;
}
+}
- .item-assignees {
- .user-avatar-link {
- margin-right: -$gl-padding-4;
-
- &:nth-of-type(1) {
- z-index: 2;
- }
+.item-assignees {
+ .user-avatar-link {
+ margin-right: -$gl-padding-4;
- &:nth-of-type(2) {
- z-index: 1;
- }
+ &:nth-of-type(1) {
+ z-index: 2;
+ }
- &:last-child {
- margin-right: 0;
- }
+ &:nth-of-type(2) {
+ z-index: 1;
}
- .avatar {
- height: $gl-padding;
- width: $gl-padding;
+ &:last-child {
margin-right: 0;
- vertical-align: bottom;
}
+ }
- .avatar-counter {
- height: $gl-padding;
- border: 1px solid transparent;
- background-color: $gl-text-color-tertiary;
- font-weight: $gl-font-weight-bold;
- padding: 0 $gl-padding-4;
- line-height: $gl-padding;
- }
+ .avatar {
+ height: $gl-padding;
+ width: $gl-padding;
+ margin-right: 0;
+ vertical-align: bottom;
+ }
+
+ .avatar-counter {
+ height: $gl-padding;
+ border: 1px solid transparent;
+ background-color: $gl-text-color-tertiary;
+ font-weight: $gl-font-weight-bold;
+ padding: 0 $gl-padding-4;
+ line-height: $gl-padding;
}
}
@@ -150,12 +164,6 @@ $item-weight-max-width: 48px;
.issue-token-state-icon-closed {
display: block;
}
-
- @include media-breakpoint-down(sm) {
- &:not(.mr-item-path) {
- order: 1;
- }
- }
}
.btn-item-remove {
@@ -179,6 +187,10 @@ $item-weight-max-width: 48px;
}
@include media-breakpoint-up(sm) {
+ .item-info-area {
+ flex-basis: 100%;
+ }
+
.sortable-link {
max-width: 90%;
}
@@ -241,7 +253,8 @@ $item-weight-max-width: 48px;
.item-title {
min-width: 0;
width: auto;
- flex-basis: unset;
+ flex-basis: auto;
+ flex-shrink: 1;
font-weight: $gl-font-weight-normal;
.issue-token-state-icon-open,
@@ -250,6 +263,10 @@ $item-weight-max-width: 48px;
margin-right: $gl-padding-8;
}
}
+
+ .item-info-area {
+ flex-basis: auto;
+ }
}
.item-contents {
diff --git a/app/assets/stylesheets/components/toast.scss b/app/assets/stylesheets/components/toast.scss
index 33e1c4e5349..acbd909d595 100644
--- a/app/assets/stylesheets/components/toast.scss
+++ b/app/assets/stylesheets/components/toast.scss
@@ -21,7 +21,7 @@
background-color: rgba($gray-900, $toast-background-opacity);
@include media-breakpoint-down(xs) {
- .action:first-child {
+ .action:first-of-type {
// Ensures actions buttons are right aligned on mobile
margin-left: auto;
}
@@ -33,7 +33,7 @@
text-transform: none;
font-size: $gl-font-size;
- &:first-child {
+ &:first-of-type {
padding-right: 0;
}
}
diff --git a/app/assets/stylesheets/csslab.scss b/app/assets/stylesheets/csslab.scss
index acaa41e2677..87c59cd42c0 100644
--- a/app/assets/stylesheets/csslab.scss
+++ b/app/assets/stylesheets/csslab.scss
@@ -1 +1 @@
-@import "../../../node_modules/@gitlab/csslab/dist/css/csslab-slim";
+@import "@gitlab/csslab/dist/css/csslab-slim";
diff --git a/app/assets/stylesheets/errors.scss b/app/assets/stylesheets/errors.scss
index 8c32b6c8985..d287215096e 100644
--- a/app/assets/stylesheets/errors.scss
+++ b/app/assets/stylesheets/errors.scss
@@ -2,12 +2,12 @@
* This is a minimal stylesheet, meant to be used for error pages.
*/
@import 'framework/variables';
-@import '../../../node_modules/bootstrap/scss/functions';
-@import '../../../node_modules/bootstrap/scss/variables';
-@import '../../../node_modules/bootstrap/scss/mixins';
-@import '../../../node_modules/bootstrap/scss/reboot';
-@import '../../../node_modules/bootstrap/scss/buttons';
-@import '../../../node_modules/bootstrap/scss/forms';
+@import 'bootstrap/scss/functions';
+@import 'bootstrap/scss/variables';
+@import 'bootstrap/scss/mixins';
+@import 'bootstrap/scss/reboot';
+@import 'bootstrap/scss/buttons';
+@import 'bootstrap/scss/forms';
$body-color: #666;
$header-color: #456;
diff --git a/app/assets/stylesheets/framework.scss b/app/assets/stylesheets/framework.scss
index 14f4652e847..9b1d9d51f9c 100644
--- a/app/assets/stylesheets/framework.scss
+++ b/app/assets/stylesheets/framework.scss
@@ -2,7 +2,7 @@
@import 'framework/variables_overrides';
@import 'framework/mixins';
-@import '../../../node_modules/@gitlab/ui/scss/gitlab_ui';
+@import '@gitlab/ui/scss/gitlab_ui';
@import 'bootstrap_migration';
@import 'framework/layout';
diff --git a/app/assets/stylesheets/framework/system_messages.scss b/app/assets/stylesheets/framework/system_messages.scss
index 6205ccaa52f..5c298d5a588 100644
--- a/app/assets/stylesheets/framework/system_messages.scss
+++ b/app/assets/stylesheets/framework/system_messages.scss
@@ -98,14 +98,4 @@
top: auto;
bottom: auto;
}
-
- .content-wrapper {
- .with-system-header & {
- margin-top: 0;
- }
-
- .with-system-footer & {
- margin-top: 0;
- }
- }
}
diff --git a/app/assets/stylesheets/pages/boards.scss b/app/assets/stylesheets/pages/boards.scss
index 5e3652db48f..343cca96851 100644
--- a/app/assets/stylesheets/pages/boards.scss
+++ b/app/assets/stylesheets/pages/boards.scss
@@ -92,9 +92,20 @@
width: 400px;
}
- &.is-expandable {
- .board-header {
- cursor: pointer;
+ .board-title-caret {
+ cursor: pointer;
+ border-radius: $border-radius-default;
+ padding: 4px;
+
+ &:hover {
+ background-color: $gray-dark;
+ transition: background-color 0.1s linear;
+ }
+ }
+
+ &:not(.is-collapsed) {
+ .board-title-caret {
+ margin: 0 $gl-padding-4 0 -10px;
}
}
@@ -102,20 +113,51 @@
width: 50px;
.board-title {
- > span {
- width: 100%;
- margin-top: -12px;
+ flex-direction: column;
+ height: 100%;
+ padding: $gl-padding-8 0;
+ }
+
+ .board-title-caret {
+ margin-top: 1px;
+ }
+
+ .user-avatar-link,
+ .milestone-icon {
+ margin-top: $gl-padding-8;
+ transform: rotate(90deg);
+ }
+
+ .board-title-text {
+ flex-grow: 0;
+ margin: $gl-padding-8 0;
+
+ .board-title-main-text {
display: block;
- transform: rotate(90deg) translate(35px, 0);
- overflow: initial;
+ }
+
+ .board-title-sub-text {
+ display: none;
}
}
- .board-title-expandable-toggle {
- position: absolute;
- top: 50%;
- left: 50%;
- margin-left: -10px;
+ .issue-count-badge {
+ border: 0;
+ white-space: nowrap;
+ }
+
+ .board-title-text > span,
+ .issue-count-badge > span {
+ height: 16px;
+
+ // Force the height to be equal to the parent's width while centering the contents.
+ // The contents *should* be about 16 px.
+ // We do this because the flow of elements isn't affected by the rotate transform, so we must ensure that a
+ // rotated element has square dimensions so it won't overlap with its siblings.
+ margin: calc(50% - 8px) 0;
+
+ transform: rotate(90deg);
+ transform-origin: center;
}
}
}
@@ -152,12 +194,14 @@
}
.board-title {
+ align-items: center;
font-size: 1em;
border-bottom: 1px solid $border-color;
+ padding: $gl-padding-8 $gl-padding;
}
.board-title-text {
- margin: $gl-vert-padding auto $gl-vert-padding 0;
+ flex-grow: 1;
}
.board-delete {
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..623c44e062f 100644
--- a/app/assets/stylesheets/pages/diff.scss
+++ b/app/assets/stylesheets/pages/diff.scss
@@ -1093,6 +1093,17 @@ table.code {
line-height: 0;
}
+.discussion-collapsible {
+ margin: 0 $gl-padding $gl-padding 71px;
+}
+
+.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 +1121,11 @@ table.code {
padding-right: 0;
}
}
+
+ .discussion-collapsible {
+ margin: $gl-padding;
+ margin-top: 0;
+ }
}
.image-diff-overlay,
diff --git a/app/assets/stylesheets/pages/issuable.scss b/app/assets/stylesheets/pages/issuable.scss
index dcbb23684d1..6a0127eb51c 100644
--- a/app/assets/stylesheets/pages/issuable.scss
+++ b/app/assets/stylesheets/pages/issuable.scss
@@ -594,18 +594,18 @@
padding: 16px 0;
small {
- color: $gray-darkest;
+ color: $gray-700;
}
}
.edited-text {
- color: $gray-darkest;
+ color: $gray-700;
display: block;
margin: 16px 0 0;
font-size: 85%;
.author-link {
- color: $gray-darkest;
+ color: $gray-700;
}
}
diff --git a/app/assets/stylesheets/pages/issues.scss b/app/assets/stylesheets/pages/issues.scss
index 48289c8f381..8359a60ec9f 100644
--- a/app/assets/stylesheets/pages/issues.scss
+++ b/app/assets/stylesheets/pages/issues.scss
@@ -1,4 +1,18 @@
.issues-list {
+ &.manual-ordering {
+ background-color: $gray-light;
+ border-radius: $border-radius-default;
+ padding: $gl-padding-8;
+
+ .issue {
+ background-color: $white-light;
+ margin-bottom: $gl-padding-8;
+ border-radius: $border-radius-default;
+ border: 1px solid $gray-100;
+ box-shadow: 0 1px 2px $issue-boards-card-shadow;
+ }
+ }
+
.issue {
padding: 10px 0 10px $gl-padding;
position: relative;
diff --git a/app/assets/stylesheets/pages/notes.scss b/app/assets/stylesheets/pages/notes.scss
index 5cacd42bf0d..7bd1a4138e4 100644
--- a/app/assets/stylesheets/pages/notes.scss
+++ b/app/assets/stylesheets/pages/notes.scss
@@ -134,6 +134,16 @@ $note-form-margin-left: 72px;
}
}
+ .discussion-toggle-replies {
+ border-top: 0;
+ border-radius: 4px 4px 0 0;
+
+ &.collapsed {
+ border: 0;
+ border-radius: 4px;
+ }
+ }
+
.note-created-ago,
.note-updated-at {
white-space: normal;
@@ -462,6 +472,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 +535,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%;
+ }
}
}
@@ -628,7 +657,7 @@ $note-form-margin-left: 72px;
.note-headline-meta {
.system-note-separator {
- color: $gl-text-color-disabled;
+ color: $gray-700;
}
.note-timestamp {
@@ -657,6 +686,10 @@ $note-form-margin-left: 72px;
margin-left: -1px;
}
+ .btn-group > .discussion-create-issue-btn {
+ margin-left: -2px;
+ }
+
svg {
height: 15px;
}
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/application_controller.rb b/app/controllers/application_controller.rb
index 7321f719deb..75108bf2646 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -516,4 +516,10 @@ class ApplicationController < ActionController::Base
def sentry_context
Gitlab::Sentry.context(current_user)
end
+
+ def allow_gitaly_ref_name_caching
+ ::Gitlab::GitalyClient.allow_ref_name_caching do
+ yield
+ end
+ end
end
diff --git a/app/controllers/concerns/boards_responses.rb b/app/controllers/concerns/boards_responses.rb
index 7625600e452..9da2f888ead 100644
--- a/app/controllers/concerns/boards_responses.rb
+++ b/app/controllers/concerns/boards_responses.rb
@@ -3,8 +3,9 @@
module BoardsResponses
include Gitlab::Utils::StrongMemoize
+ # Overridden on EE module
def board_params
- params.require(:board).permit(:name, :weight, :milestone_id, :assignee_id, label_ids: [])
+ params.require(:board).permit(:name)
end
def parent
diff --git a/app/controllers/concerns/continue_params.rb b/app/controllers/concerns/continue_params.rb
index 54c0510497f..d5830f6648c 100644
--- a/app/controllers/concerns/continue_params.rb
+++ b/app/controllers/concerns/continue_params.rb
@@ -6,7 +6,7 @@ module ContinueParams
def continue_params
continue_params = params[:continue]
- return unless continue_params
+ return {} unless continue_params
continue_params = continue_params.permit(:to, :notice, :notice_now)
continue_params[:to] = safe_redirect_path(continue_params[:to])
diff --git a/app/controllers/concerns/internal_redirect.rb b/app/controllers/concerns/internal_redirect.rb
index 6785e6972d0..fa3716502a0 100644
--- a/app/controllers/concerns/internal_redirect.rb
+++ b/app/controllers/concerns/internal_redirect.rb
@@ -5,8 +5,8 @@ module InternalRedirect
def safe_redirect_path(path)
return unless path
- # Verify that the string starts with a `/` but not a double `/`.
- return unless path =~ %r{^/\w.*$}
+ # Verify that the string starts with a `/` and a known route character.
+ return unless path =~ %r{^/[-\w].*$}
uri = URI(path)
# Ignore anything path of the redirect except for the path, querystring and,
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/multiple_boards_actions.rb b/app/controllers/concerns/multiple_boards_actions.rb
new file mode 100644
index 00000000000..95a6800f55c
--- /dev/null
+++ b/app/controllers/concerns/multiple_boards_actions.rb
@@ -0,0 +1,90 @@
+# frozen_string_literal: true
+
+module MultipleBoardsActions
+ include Gitlab::Utils::StrongMemoize
+ extend ActiveSupport::Concern
+
+ included do
+ include BoardsActions
+
+ before_action :redirect_to_recent_board, only: [:index]
+ before_action :authenticate_user!, only: [:recent]
+ before_action :authorize_create_board!, only: [:create]
+ before_action :authorize_admin_board!, only: [:create, :update, :destroy]
+ end
+
+ def recent
+ recent_visits = ::Boards::VisitsFinder.new(parent, current_user).latest(4)
+ recent_boards = recent_visits.map(&:board)
+
+ render json: serialize_as_json(recent_boards)
+ end
+
+ def create
+ board = Boards::CreateService.new(parent, current_user, board_params).execute
+
+ respond_to do |format|
+ format.json do
+ if board.persisted?
+ extra_json = { board_path: board_path(board) }
+ render json: serialize_as_json(board).merge(extra_json)
+ else
+ render json: board.errors, status: :unprocessable_entity
+ end
+ end
+ end
+ end
+
+ def update
+ service = Boards::UpdateService.new(parent, current_user, board_params)
+
+ respond_to do |format|
+ format.json do
+ if service.execute(board)
+ extra_json = { board_path: board_path(board) }
+ render json: serialize_as_json(board).merge(extra_json)
+ else
+ render json: board.errors, status: :unprocessable_entity
+ end
+ end
+ end
+ end
+
+ def destroy
+ service = Boards::DestroyService.new(parent, current_user)
+ service.execute(board)
+
+ respond_to do |format|
+ format.json { head :ok }
+ format.html { redirect_to boards_path, status: :found }
+ end
+ end
+
+ private
+
+ def redirect_to_recent_board
+ return if request.format.json? || !parent.multiple_issue_boards_available? || !latest_visited_board
+
+ redirect_to board_path(latest_visited_board.board)
+ end
+
+ def latest_visited_board
+ @latest_visited_board ||= Boards::VisitsFinder.new(parent, current_user).latest
+ end
+
+ def authorize_create_board!
+ check_multiple_group_issue_boards_available! if group?
+ end
+
+ def authorize_admin_board!
+ return render_404 unless can?(current_user, :admin_board, parent)
+ end
+
+ def serializer
+ BoardSerializer.new(current_user: current_user)
+ end
+
+ def serialize_as_json(resource)
+ serializer.represent(resource, serializer: 'board', include_full_project_path: board.group_board?)
+ end
+end
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/concerns/requires_whitelisted_monitoring_client.rb b/app/controllers/concerns/requires_whitelisted_monitoring_client.rb
index 426f224d26b..f47ead2f0da 100644
--- a/app/controllers/concerns/requires_whitelisted_monitoring_client.rb
+++ b/app/controllers/concerns/requires_whitelisted_monitoring_client.rb
@@ -14,6 +14,10 @@ module RequiresWhitelistedMonitoringClient
end
def client_ip_whitelisted?
+ # Always allow developers to access http://localhost:3000/-/metrics for
+ # debugging purposes
+ return true if Rails.env.development? && request.local?
+
ip_whitelist.any? { |e| e.include?(Gitlab::RequestContext.client_ip) }
end
diff --git a/app/controllers/dashboard/projects_controller.rb b/app/controllers/dashboard/projects_controller.rb
index 65d14781d92..d43f5393ecc 100644
--- a/app/controllers/dashboard/projects_controller.rb
+++ b/app/controllers/dashboard/projects_controller.rb
@@ -3,6 +3,7 @@
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
diff --git a/app/controllers/dashboard/todos_controller.rb b/app/controllers/dashboard/todos_controller.rb
index 09cbc052c76..8f6fcb362d2 100644
--- a/app/controllers/dashboard/todos_controller.rb
+++ b/app/controllers/dashboard/todos_controller.rb
@@ -10,6 +10,7 @@ class Dashboard::TodosController < Dashboard::ApplicationController
def index
@sort = params[:sort]
@todos = @todos.page(params[:page])
+ @todos = @todos.with_entity_associations
return if redirect_out_of_range(@todos)
end
diff --git a/app/controllers/groups/clusters_controller.rb b/app/controllers/groups/clusters_controller.rb
index b846fb21266..92602fd8096 100644
--- a/app/controllers/groups/clusters_controller.rb
+++ b/app/controllers/groups/clusters_controller.rb
@@ -4,7 +4,6 @@ class Groups::ClustersController < Clusters::ClustersController
include ControllerWithCrossProjectAccessCheck
prepend_before_action :group
- prepend_before_action :check_group_clusters_feature_flag!
requires_cross_project_access
layout 'group'
@@ -18,12 +17,4 @@ class Groups::ClustersController < Clusters::ClustersController
def group
@group ||= find_routable!(Group, params[:group_id] || params[:id])
end
-
- def check_group_clusters_feature_flag!
- render_404 unless group_clusters_enabled?
- end
-
- def group_clusters_enabled?
- group.group_clusters_enabled?
- end
end
diff --git a/app/controllers/groups_controller.rb b/app/controllers/groups_controller.rb
index e936d771502..797833e3f91 100644
--- a/app/controllers/groups_controller.rb
+++ b/app/controllers/groups_controller.rb
@@ -7,6 +7,10 @@ class GroupsController < Groups::ApplicationController
include PreviewMarkdown
include RecordUserLastActivity
+ before_action do
+ push_frontend_feature_flag(:manual_sorting)
+ end
+
respond_to :html
prepend_before_action(only: [:show, :issues]) { authenticate_sessionless_user!(:rss) }
@@ -197,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 80e4f54bbf4..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
@@ -87,10 +92,4 @@ class Projects::ApplicationController < ApplicationController
def check_issues_available!
return render_404 unless @project.feature_available?(:issues, current_user)
end
-
- def allow_gitaly_ref_name_caching
- ::Gitlab::GitalyClient.allow_ref_name_caching do
- yield
- end
- end
end
diff --git a/app/controllers/projects/boards_controller.rb b/app/controllers/projects/boards_controller.rb
index 95897aaf980..14b02993e6e 100644
--- a/app/controllers/projects/boards_controller.rb
+++ b/app/controllers/projects/boards_controller.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
class Projects::BoardsController < Projects::ApplicationController
- include BoardsActions
+ include MultipleBoardsActions
include IssuableCollections
before_action :check_issues_available!
diff --git a/app/controllers/projects/branches_controller.rb b/app/controllers/projects/branches_controller.rb
index fc708400657..d77f64a84f5 100644
--- a/app/controllers/projects/branches_controller.rb
+++ b/app/controllers/projects/branches_controller.rb
@@ -25,15 +25,6 @@ class Projects::BranchesController < Projects::ApplicationController
@refs_pipelines = @project.ci_pipelines.latest_successful_for_refs(@branches.map(&:name))
@merged_branch_names = repository.merged_branch_names(@branches.map(&:name))
- # n+1: https://gitlab.com/gitlab-org/gitlab-ce/issues/48097
- Gitlab::GitalyClient.allow_n_plus_1_calls do
- @max_commits = @branches.reduce(0) do |memo, branch|
- diverging_commit_counts = repository.diverging_commit_counts(branch)
- [memo, diverging_commit_counts.values_at(:behind, :ahead, :distance)]
- .flatten.compact.max
- end
- end
-
# https://gitlab.com/gitlab-org/gitlab-ce/issues/48097
Gitlab::GitalyClient.allow_n_plus_1_calls do
render
@@ -51,6 +42,19 @@ class Projects::BranchesController < Projects::ApplicationController
@branches = @repository.recent_branches
end
+ def diverging_commit_counts
+ respond_to do |format|
+ format.json do
+ service = Branches::DivergingCommitCountsService.new(repository)
+ branches = BranchesFinder.new(repository, params.permit(names: [])).execute
+
+ Gitlab::GitalyClient.allow_n_plus_1_calls do
+ render json: branches.to_h { |branch| [branch.name, service.call(branch)] }
+ end
+ end
+ end
+ end
+
# rubocop: disable CodeReuse/ActiveRecord
def create
branch_name = strip_tags(sanitize(params[:branch_name]))
@@ -64,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|
@@ -162,4 +167,15 @@ class Projects::BranchesController < Projects::ApplicationController
@branches = Kaminari.paginate_array(@branches).page(params[:page])
end
end
+
+ def confidential_issue_project
+ return unless Feature.enabled?(:create_confidential_merge_request, @project)
+ 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/forks_controller.rb b/app/controllers/projects/forks_controller.rb
index 7a1700a206a..ac1c4bc7fd3 100644
--- a/app/controllers/projects/forks_controller.rb
+++ b/app/controllers/projects/forks_controller.rb
@@ -46,18 +46,14 @@ class Projects::ForksController < Projects::ApplicationController
@forked_project ||= ::Projects::ForkService.new(project, current_user, namespace: namespace).execute
- if @forked_project.saved? && @forked_project.forked?
- if @forked_project.import_in_progress?
- redirect_to project_import_path(@forked_project, continue: continue_params)
- else
- if continue_params
- redirect_to continue_params[:to], notice: continue_params[:notice]
- else
- redirect_to project_path(@forked_project), notice: "The project '#{@forked_project.name}' was successfully forked."
- end
- end
- else
+ if !@forked_project.saved? || !@forked_project.forked?
render :error
+ elsif @forked_project.import_in_progress?
+ redirect_to project_import_path(@forked_project, continue: continue_params)
+ elsif continue_params[:to]
+ redirect_to continue_params[:to], notice: continue_params[:notice]
+ else
+ redirect_to project_path(@forked_project), notice: "The project '#{@forked_project.name}' was successfully forked."
end
end
# rubocop: enable CodeReuse/ActiveRecord
diff --git a/app/controllers/projects/imports_controller.rb b/app/controllers/projects/imports_controller.rb
index afbf9fd7720..da32ab9e2e0 100644
--- a/app/controllers/projects/imports_controller.rb
+++ b/app/controllers/projects/imports_controller.rb
@@ -23,7 +23,7 @@ class Projects::ImportsController < Projects::ApplicationController
def show
if @project.import_finished?
- if continue_params&.key?(:to)
+ if continue_params[:to]
redirect_to continue_params[:to], notice: continue_params[:notice]
else
redirect_to project_path(@project), notice: finished_notice
@@ -31,11 +31,7 @@ class Projects::ImportsController < Projects::ApplicationController
elsif @project.import_failed?
redirect_to new_project_import_path(@project)
else
- if continue_params && continue_params[:notice_now]
- flash.now[:notice] = continue_params[:notice_now]
- end
-
- # Render
+ flash.now[:notice] = continue_params[:notice_now]
end
end
diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb
index b16f3dd9d82..e275b417784 100644
--- a/app/controllers/projects/issues_controller.rb
+++ b/app/controllers/projects/issues_controller.rb
@@ -10,6 +10,10 @@ class Projects::IssuesController < Projects::ApplicationController
include SpammableActions
include RecordUserLastActivity
+ before_action do
+ push_frontend_feature_flag(:manual_sorting)
+ end
+
def issue_except_actions
%i[index calendar new create bulk_update import_csv]
end
@@ -168,6 +172,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 Feature.enabled?(:create_confidential_merge_request, @project)
result = ::MergeRequests::CreateFromIssueService.new(project, current_user, create_params).execute
if result[:status] == :success
diff --git a/app/controllers/projects/jobs_controller.rb b/app/controllers/projects/jobs_controller.rb
index d7c0039b234..02ff6e872c9 100644
--- a/app/controllers/projects/jobs_controller.rb
+++ b/app/controllers/projects/jobs_controller.rb
@@ -103,7 +103,7 @@ class Projects::JobsController < Projects::ApplicationController
@build.cancel
- if continue_params
+ if continue_params[:to]
redirect_to continue_params[:to]
else
redirect_to builds_project_pipeline_path(@project, @build.pipeline.id)
diff --git a/app/controllers/projects/merge_requests/application_controller.rb b/app/controllers/projects/merge_requests/application_controller.rb
index f2a6268b3e9..dcc272aecff 100644
--- a/app/controllers/projects/merge_requests/application_controller.rb
+++ b/app/controllers/projects/merge_requests/application_controller.rb
@@ -51,4 +51,11 @@ class Projects::MergeRequests::ApplicationController < Projects::ApplicationCont
Ci::Pipeline.none
end
end
+
+ def close_merge_request_if_no_source_project
+ return if @merge_request.source_project
+ return unless @merge_request.open?
+
+ @merge_request.close
+ end
end
diff --git a/app/controllers/projects/merge_requests/content_controller.rb b/app/controllers/projects/merge_requests/content_controller.rb
new file mode 100644
index 00000000000..6e026b83ee3
--- /dev/null
+++ b/app/controllers/projects/merge_requests/content_controller.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+class Projects::MergeRequests::ContentController < Projects::MergeRequests::ApplicationController
+ # @merge_request.check_mergeability is not executed here since
+ # widget serializer calls it via mergeable? method
+ # but we might want to call @merge_request.check_mergeability
+ # for other types of serialization
+
+ before_action :close_merge_request_if_no_source_project
+ around_action :allow_gitaly_ref_name_caching
+
+ def widget
+ respond_to do |format|
+ format.json do
+ Gitlab::PollingInterval.set_header(response, interval: 10_000)
+
+ serializer = MergeRequestSerializer.new(current_user: current_user, project: merge_request.project)
+ render json: serializer.represent(merge_request, serializer: 'widget')
+ end
+ end
+ end
+end
diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb
index fc37ce1dbc4..7ee8e0ea8f8 100644
--- a/app/controllers/projects/merge_requests_controller.rb
+++ b/app/controllers/projects/merge_requests_controller.rb
@@ -235,12 +235,6 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
params[:auto_merge_strategy].present? || params[:merge_when_pipeline_succeeds].present?
end
- def close_merge_request_if_no_source_project
- if !@merge_request.source_project && @merge_request.open?
- @merge_request.close
- end
- end
-
private
def ci_environments_status_on_merge_result?
diff --git a/app/controllers/projects/refs_controller.rb b/app/controllers/projects/refs_controller.rb
index b3447812ef2..b4ca9074ca9 100644
--- a/app/controllers/projects/refs_controller.rb
+++ b/app/controllers/projects/refs_controller.rb
@@ -55,6 +55,7 @@ class Projects::RefsController < Projects::ApplicationController
format.html { render_404 }
format.json do
response.headers["More-Logs-Url"] = @more_log_url if summary.more?
+ response.headers["More-Logs-Offset"] = summary.next_offset if summary.more?
render json: @logs
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..330e2d0f8a5 100644
--- a/app/controllers/projects_controller.rb
+++ b/app/controllers/projects_controller.rb
@@ -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/registrations_controller.rb b/app/controllers/registrations_controller.rb
index 07b38371ab9..b2b151bbcf0 100644
--- a/app/controllers/registrations_controller.rb
+++ b/app/controllers/registrations_controller.rb
@@ -3,6 +3,7 @@
class RegistrationsController < Devise::RegistrationsController
include Recaptcha::Verify
include AcceptsPendingInvitations
+ include RecaptchaExperimentHelper
prepend_before_action :check_captcha, only: :create
before_action :whitelist_query_limiting, only: [:destroy]
@@ -15,13 +16,6 @@ class RegistrationsController < Devise::RegistrationsController
end
def create
- # To avoid duplicate form fields on the login page, the registration form
- # names fields using `new_user`, but Devise still wants the params in
- # `user`.
- if params["new_#{resource_name}"].present? && params[resource_name].blank?
- params[resource_name] = params.delete(:"new_#{resource_name}")
- end
-
accept_pending_invitations
super do |new_user|
@@ -74,19 +68,35 @@ class RegistrationsController < Devise::RegistrationsController
end
def after_sign_up_path_for(user)
- Gitlab::AppLogger.info("User Created: username=#{user.username} email=#{user.email} ip=#{request.remote_ip} confirmed:#{user.confirmed?}")
+ Gitlab::AppLogger.info(user_created_message(confirmed: user.confirmed?))
user.confirmed? ? stored_location_for(user) || dashboard_projects_path : users_almost_there_path
end
def after_inactive_sign_up_path_for(resource)
- Gitlab::AppLogger.info("User Created: username=#{resource.username} email=#{resource.email} ip=#{request.remote_ip} confirmed:false")
+ Gitlab::AppLogger.info(user_created_message)
users_almost_there_path
end
private
+ def user_created_message(confirmed: false)
+ "User Created: username=#{resource.username} email=#{resource.email} ip=#{request.remote_ip} confirmed:#{confirmed}"
+ end
+
+ def ensure_correct_params!
+ # To avoid duplicate form fields on the login page, the registration form
+ # names fields using `new_user`, but Devise still wants the params in
+ # `user`.
+ if params["new_#{resource_name}"].present? && params[resource_name].blank?
+ params[resource_name] = params.delete(:"new_#{resource_name}")
+ end
+ end
+
def check_captcha
- return unless Feature.enabled?(:registrations_recaptcha, default_enabled: true)
+ ensure_correct_params!
+
+ return unless Feature.enabled?(:registrations_recaptcha, default_enabled: true) # reCAPTCHA on the UI will still display however
+ return unless show_recaptcha_sign_up?
return unless Gitlab::Recaptcha.load_configurations!
return if verify_recaptcha
diff --git a/app/controllers/search_controller.rb b/app/controllers/search_controller.rb
index a80ab3bcd28..8c674be58c5 100644
--- a/app/controllers/search_controller.rb
+++ b/app/controllers/search_controller.rb
@@ -5,6 +5,8 @@ class SearchController < ApplicationController
include SearchHelper
include RendersCommits
+ around_action :allow_gitaly_ref_name_caching
+
skip_before_action :authenticate_user!
requires_cross_project_access if: -> do
search_term_present = params[:search].present? || params[:term].present?
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/autocomplete/acts_as_taggable_on/tags_finder.rb b/app/finders/autocomplete/acts_as_taggable_on/tags_finder.rb
index f38c187799c..78a17312e26 100644
--- a/app/finders/autocomplete/acts_as_taggable_on/tags_finder.rb
+++ b/app/finders/autocomplete/acts_as_taggable_on/tags_finder.rb
@@ -22,8 +22,7 @@ module Autocomplete
end
def filter_by_name(tags)
- return tags unless search
- return tags.none if search.empty?
+ return tags unless search.present?
if search.length >= Gitlab::SQL::Pattern::MIN_CHARS_FOR_PARTIAL_MATCHING
tags.named_like(search)
diff --git a/app/finders/boards/visits_finder.rb b/app/finders/boards/visits_finder.rb
new file mode 100644
index 00000000000..d17a27f72dc
--- /dev/null
+++ b/app/finders/boards/visits_finder.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+module Boards
+ class VisitsFinder
+ attr_accessor :params, :current_user, :parent
+
+ def initialize(parent, current_user)
+ @current_user = current_user
+ @parent = parent
+ end
+
+ def execute(count = nil)
+ return unless current_user
+
+ recent_visit_model.latest(current_user, parent, count: count)
+ end
+
+ alias_method :latest, :execute
+
+ private
+
+ def recent_visit_model
+ parent.is_a?(Group) ? BoardGroupRecentVisit : BoardProjectRecentVisit
+ end
+ end
+end
diff --git a/app/finders/branches_finder.rb b/app/finders/branches_finder.rb
index 45d5591e81b..b462c8053fa 100644
--- a/app/finders/branches_finder.rb
+++ b/app/finders/branches_finder.rb
@@ -9,6 +9,7 @@ class BranchesFinder
def execute
branches = repository.branches_sorted_by(sort)
branches = by_search(branches)
+ branches = by_names(branches)
branches
end
@@ -16,6 +17,10 @@ class BranchesFinder
attr_reader :repository, :params
+ def names
+ @params[:names].presence
+ end
+
def search
@params[:search].presence
end
@@ -59,4 +64,13 @@ class BranchesFinder
def find_exact_match_index(matches, term)
matches.index { |branch| branch.name.casecmp(term) == 0 }
end
+
+ def by_names(branches)
+ return branches unless names
+
+ branch_names = names.to_set
+ branches.filter do |branch|
+ branch_names.include?(branch.name)
+ end
+ end
end
diff --git a/app/graphql/mutations/award_emojis/add.rb b/app/graphql/mutations/award_emojis/add.rb
new file mode 100644
index 00000000000..8e050dd6d29
--- /dev/null
+++ b/app/graphql/mutations/award_emojis/add.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+module Mutations
+ module AwardEmojis
+ class Add < Base
+ graphql_name 'AddAwardEmoji'
+
+ def resolve(args)
+ awardable = authorized_find!(id: args[:awardable_id])
+
+ check_object_is_awardable!(awardable)
+
+ # TODO this will be handled by AwardEmoji::AddService
+ # See https://gitlab.com/gitlab-org/gitlab-ce/issues/63372 and
+ # https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/29782
+ award = awardable.create_award_emoji(args[:name], current_user)
+
+ {
+ award_emoji: (award if award.persisted?),
+ errors: errors_on_object(award)
+ }
+ end
+ end
+ end
+end
diff --git a/app/graphql/mutations/award_emojis/base.rb b/app/graphql/mutations/award_emojis/base.rb
new file mode 100644
index 00000000000..d868db84f9d
--- /dev/null
+++ b/app/graphql/mutations/award_emojis/base.rb
@@ -0,0 +1,41 @@
+# frozen_string_literal: true
+
+module Mutations
+ module AwardEmojis
+ class Base < BaseMutation
+ include Gitlab::Graphql::Authorize::AuthorizeResource
+
+ authorize :award_emoji
+
+ argument :awardable_id,
+ GraphQL::ID_TYPE,
+ required: true,
+ description: 'The global id of the awardable resource'
+
+ argument :name,
+ GraphQL::STRING_TYPE,
+ required: true,
+ description: copy_field_description(Types::AwardEmojis::AwardEmojiType, :name)
+
+ field :award_emoji,
+ Types::AwardEmojis::AwardEmojiType,
+ null: true,
+ description: 'The award emoji after mutation'
+
+ private
+
+ def find_object(id:)
+ GitlabSchema.object_from_id(id)
+ end
+
+ # Called by mutations methods after performing an authorization check
+ # of an awardable object.
+ def check_object_is_awardable!(object)
+ unless object.is_a?(Awardable) && object.emoji_awardable?
+ raise Gitlab::Graphql::Errors::ResourceNotAvailable,
+ 'Cannot award emoji to this resource'
+ end
+ end
+ end
+ end
+end
diff --git a/app/graphql/mutations/award_emojis/remove.rb b/app/graphql/mutations/award_emojis/remove.rb
new file mode 100644
index 00000000000..3ba85e445b8
--- /dev/null
+++ b/app/graphql/mutations/award_emojis/remove.rb
@@ -0,0 +1,33 @@
+# frozen_string_literal: true
+
+module Mutations
+ module AwardEmojis
+ class Remove < Base
+ graphql_name 'RemoveAwardEmoji'
+
+ def resolve(args)
+ awardable = authorized_find!(id: args[:awardable_id])
+
+ check_object_is_awardable!(awardable)
+
+ # TODO this check can be removed once AwardEmoji services are available.
+ # See https://gitlab.com/gitlab-org/gitlab-ce/issues/63372 and
+ # https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/29782
+ unless awardable.awarded_emoji?(args[:name], current_user)
+ raise Gitlab::Graphql::Errors::ResourceNotAvailable,
+ 'You have not awarded emoji of type name to the awardable'
+ end
+
+ # TODO this will be handled by AwardEmoji::DestroyService
+ # See https://gitlab.com/gitlab-org/gitlab-ce/issues/63372 and
+ # https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/29782
+ awardable.remove_award_emoji(args[:name], current_user)
+
+ {
+ # Mutation response is always a `nil` award_emoji
+ errors: []
+ }
+ end
+ end
+ end
+end
diff --git a/app/graphql/mutations/award_emojis/toggle.rb b/app/graphql/mutations/award_emojis/toggle.rb
new file mode 100644
index 00000000000..c03902e8035
--- /dev/null
+++ b/app/graphql/mutations/award_emojis/toggle.rb
@@ -0,0 +1,40 @@
+# frozen_string_literal: true
+
+module Mutations
+ module AwardEmojis
+ class Toggle < Base
+ graphql_name 'ToggleAwardEmoji'
+
+ field :toggledOn,
+ GraphQL::BOOLEAN_TYPE,
+ null: false,
+ description: 'True when the emoji was awarded, false when it was removed'
+
+ def resolve(args)
+ awardable = authorized_find!(id: args[:awardable_id])
+
+ check_object_is_awardable!(awardable)
+
+ # TODO this will be handled by AwardEmoji::ToggleService
+ # See https://gitlab.com/gitlab-org/gitlab-ce/issues/63372 and
+ # https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/29782
+ award = awardable.toggle_award_emoji(args[:name], current_user)
+
+ # Destroy returns a collection :(
+ award = award.first if award.is_a?(Array)
+
+ errors = errors_on_object(award)
+
+ toggled_on = awardable.awarded_emoji?(args[:name], current_user)
+
+ {
+ # For consistency with the AwardEmojis::Remove mutation, only return
+ # the AwardEmoji if it was created and not destroyed
+ award_emoji: (award if toggled_on),
+ errors: errors,
+ toggled_on: toggled_on
+ }
+ end
+ end
+ end
+end
diff --git a/app/graphql/mutations/base_mutation.rb b/app/graphql/mutations/base_mutation.rb
index eb03dfe1624..08d2a1f18a3 100644
--- a/app/graphql/mutations/base_mutation.rb
+++ b/app/graphql/mutations/base_mutation.rb
@@ -2,6 +2,8 @@
module Mutations
class BaseMutation < GraphQL::Schema::RelayClassicMutation
+ prepend Gitlab::Graphql::CopyFieldDescription
+
field :errors, [GraphQL::STRING_TYPE],
null: false,
description: "Reasons why the mutation failed."
@@ -9,5 +11,10 @@ module Mutations
def current_user
context[:current_user]
end
+
+ # Returns Array of errors on an ActiveRecord object
+ def errors_on_object(record)
+ record.errors.full_messages
+ end
end
end
diff --git a/app/graphql/types/award_emojis/award_emoji_type.rb b/app/graphql/types/award_emojis/award_emoji_type.rb
new file mode 100644
index 00000000000..8daf699a112
--- /dev/null
+++ b/app/graphql/types/award_emojis/award_emoji_type.rb
@@ -0,0 +1,46 @@
+# frozen_string_literal: true
+
+module Types
+ module AwardEmojis
+ class AwardEmojiType < BaseObject
+ graphql_name 'AwardEmoji'
+
+ authorize :read_emoji
+
+ present_using AwardEmojiPresenter
+
+ field :name,
+ GraphQL::STRING_TYPE,
+ null: false,
+ description: 'The emoji name'
+
+ field :description,
+ GraphQL::STRING_TYPE,
+ null: false,
+ description: 'The emoji description'
+
+ field :unicode,
+ GraphQL::STRING_TYPE,
+ null: false,
+ description: 'The emoji in unicode'
+
+ field :emoji,
+ GraphQL::STRING_TYPE,
+ null: false,
+ description: 'The emoji as an icon'
+
+ field :unicode_version,
+ GraphQL::STRING_TYPE,
+ null: false,
+ description: 'The unicode version for this emoji'
+
+ field :user,
+ Types::UserType,
+ null: false,
+ description: 'The user who awarded the emoji',
+ resolve: -> (award_emoji, _args, _context) {
+ Gitlab::Graphql::Loaders::BatchModelLoader.new(User, award_emoji.user_id).find
+ }
+ end
+ end
+end
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/commit_type.rb b/app/graphql/types/commit_type.rb
new file mode 100644
index 00000000000..d73dd73affd
--- /dev/null
+++ b/app/graphql/types/commit_type.rb
@@ -0,0 +1,30 @@
+# frozen_string_literal: true
+
+module Types
+ class CommitType < BaseObject
+ graphql_name 'Commit'
+
+ authorize :download_code
+
+ present_using CommitPresenter
+
+ field :id, type: GraphQL::ID_TYPE, null: false
+ field :sha, type: GraphQL::STRING_TYPE, null: false
+ field :title, type: GraphQL::STRING_TYPE, null: true
+ field :description, type: GraphQL::STRING_TYPE, null: true
+ field :message, type: GraphQL::STRING_TYPE, null: true
+ field :authored_date, type: Types::TimeType, null: true
+ field :web_url, type: GraphQL::STRING_TYPE, null: false
+
+ # models/commit lazy loads the author by email
+ field :author, type: Types::UserType, null: true
+
+ field :latest_pipeline,
+ type: Types::Ci::PipelineType,
+ null: true,
+ description: "Latest pipeline for this commit",
+ resolve: -> (obj, ctx, args) do
+ Gitlab::Graphql::Loaders::PipelineForShaLoader.new(obj.project, obj.sha).find_last
+ end
+ 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/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 2b4ef299296..6ef1d816b7c 100644
--- a/app/graphql/types/mutation_type.rb
+++ b/app/graphql/types/mutation_type.rb
@@ -6,6 +6,9 @@ module Types
graphql_name "Mutation"
+ mount_mutation Mutations::AwardEmojis::Add
+ mount_mutation Mutations::AwardEmojis::Remove
+ mount_mutation Mutations::AwardEmojis::Toggle
mount_mutation Mutations::MergeRequests::SetWip
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/project_type.rb b/app/graphql/types/project_type.rb
index ac957eafafc..c25688ab043 100644
--- a/app/graphql/types/project_type.rb
+++ b/app/graphql/types/project_type.rb
@@ -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/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 1ee93ed9542..b947713074e 100644
--- a/app/graphql/types/tree/tree_type.rb
+++ b/app/graphql/types/tree/tree_type.rb
@@ -1,9 +1,16 @@
# 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
+ tree.repository.last_commit_for_path(tree.sha, tree.path)
+ end
+
field :trees, Types::Tree::TreeEntryType.connection_type, null: false, resolve: -> (obj, args, ctx) do
Gitlab::Graphql::Representation::TreeEntry.decorate(obj.trees, obj.repository)
end
@@ -13,6 +20,7 @@ module Types
field :blobs, Types::Tree::BlobType.connection_type, null: false, 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 4469118f065..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][]'
@@ -165,8 +165,6 @@ module ApplicationSettingsHelper
:authorized_keys_enabled,
:auto_devops_enabled,
:auto_devops_domain,
- :clientside_sentry_dsn,
- :clientside_sentry_enabled,
:container_registry_token_expire_delay,
:default_artifacts_expire_in,
:default_branch_protection,
@@ -189,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,
@@ -235,8 +235,6 @@ module ApplicationSettingsHelper
:restricted_visibility_levels,
:rsa_key_restriction,
:send_user_confirmation_email,
- :sentry_dsn,
- :sentry_enabled,
:session_expire_delay,
:shared_runners_enabled,
:shared_runners_text,
@@ -253,6 +251,7 @@ module ApplicationSettingsHelper
:throttle_unauthenticated_enabled,
:throttle_unauthenticated_period_in_seconds,
:throttle_unauthenticated_requests_per_period,
+ :time_tracking_limit_to_hours,
:two_factor_grace_period,
:unique_ips_limit_enabled,
:unique_ips_limit_per_user,
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/boards_helper.rb b/app/helpers/boards_helper.rb
index 1640f4fc93f..8ef68018d23 100644
--- a/app/helpers/boards_helper.rb
+++ b/app/helpers/boards_helper.rb
@@ -14,7 +14,9 @@ module BoardsHelper
issue_link_base: build_issue_link_base,
root_path: root_path,
bulk_update_path: @bulk_issues_path,
- default_avatar: image_path(default_avatar)
+ default_avatar: image_path(default_avatar),
+ time_tracking_limit_to_hours: Gitlab::CurrentSettings.time_tracking_limit_to_hours.to_s,
+ recent_boards_endpoint: recent_boards_path
}
end
@@ -86,6 +88,18 @@ module BoardsHelper
end
def boards_link_text
- s_("IssueBoards|Board")
+ if current_board_parent.multiple_issue_boards_available?
+ s_("IssueBoards|Boards")
+ else
+ s_("IssueBoards|Board")
+ end
+ end
+
+ def recent_boards_path
+ recent_project_boards_path(@project) if current_board_parent.is_a?(Project)
+ end
+
+ def current_board_json
+ board.to_json
end
end
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/groups_helper.rb b/app/helpers/groups_helper.rb
index a3f53ca8dd6..5aed7e313e6 100644
--- a/app/helpers/groups_helper.rb
+++ b/app/helpers/groups_helper.rb
@@ -142,7 +142,7 @@ module GroupsHelper
can?(current_user, "read_group_#{resource}".to_sym, @group)
end
- if can?(current_user, :read_cluster, @group) && @group.group_clusters_enabled?
+ if can?(current_user, :read_cluster, @group)
links << :kubernetes
end
diff --git a/app/helpers/issuables_helper.rb b/app/helpers/issuables_helper.rb
index aa53c649b2a..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
@@ -430,7 +430,8 @@ module IssuablesHelper
editable: issuable.dig(:current_user, :can_edit),
currentUser: issuable[:current_user],
rootPath: root_path,
- fullPath: issuable[:project_full_path]
+ fullPath: issuable[:project_full_path],
+ timeTrackingLimitToHours: Gitlab::CurrentSettings.time_tracking_limit_to_hours
}
end
diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb
index 59332c0b100..dfadcfc33b2 100644
--- a/app/helpers/issues_helper.rb
+++ b/app/helpers/issues_helper.rb
@@ -5,6 +5,7 @@ module IssuesHelper
classes = ["issue"]
classes << "closed" if issue.closed?
classes << "today" if issue.today?
+ classes << "user-can-drag" if @sort == 'relative_position'
classes.join(' ')
end
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/recaptcha_experiment_helper.rb b/app/helpers/recaptcha_experiment_helper.rb
new file mode 100644
index 00000000000..d2eb9ac54f6
--- /dev/null
+++ b/app/helpers/recaptcha_experiment_helper.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+module RecaptchaExperimentHelper
+ def show_recaptcha_sign_up?
+ !!Gitlab::Recaptcha.enabled?
+ end
+end
diff --git a/app/helpers/search_helper.rb b/app/helpers/search_helper.rb
index dfa34ad7020..f5c4686a3bf 100644
--- a/app/helpers/search_helper.rb
+++ b/app/helpers/search_helper.rb
@@ -169,18 +169,17 @@ module SearchHelper
autocomplete: 'off'
}
+ opts[:data]['runner-tags-endpoint'] = tag_list_admin_runners_path
+
if @project.present?
opts[:data]['project-id'] = @project.id
- opts[:data]['base-endpoint'] = project_path(@project)
opts[:data]['labels-endpoint'] = project_labels_path(@project)
opts[:data]['milestones-endpoint'] = project_milestones_path(@project)
elsif @group.present?
opts[:data]['group-id'] = @group.id
- opts[:data]['base-endpoint'] = group_canonical_path(@group)
opts[:data]['labels-endpoint'] = group_labels_path(@group)
opts[:data]['milestones-endpoint'] = group_milestones_path(@group)
else
- opts[:data]['base-endpoint'] = root_dashboard_path
opts[:data]['labels-endpoint'] = dashboard_labels_path
opts[:data]['milestones-endpoint'] = dashboard_milestones_path
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/todos_helper.rb b/app/helpers/todos_helper.rb
index 6bd78336ed3..645160077f5 100644
--- a/app/helpers/todos_helper.rb
+++ b/app/helpers/todos_helper.rb
@@ -170,7 +170,7 @@ module TodosHelper
end
def todo_group_options
- groups = current_user.authorized_groups.map do |group|
+ groups = current_user.authorized_groups.with_route.map do |group|
{ id: group.id, text: group.full_name }
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 bbe2d2e8fd4..8e558487c1c 100644
--- a/app/models/application_setting.rb
+++ b/app/models/application_setting.rb
@@ -23,13 +23,12 @@ 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
+ ignore_column :sentry_dsn
+ ignore_column :clientside_sentry_enabled
+ ignore_column :clientside_sentry_dsn
cache_markdown_field :sign_in_text
cache_markdown_field :help_page_text
@@ -75,14 +74,6 @@ class ApplicationSetting < ApplicationRecord
presence: true,
if: :recaptcha_enabled
- validates :sentry_dsn,
- presence: true,
- if: :sentry_enabled
-
- validates :clientside_sentry_dsn,
- presence: true,
- if: :clientside_sentry_enabled
-
validates :akismet_api_key,
presence: true,
if: :akismet_enabled
@@ -264,7 +255,6 @@ class ApplicationSetting < ApplicationRecord
encode: true
before_validation :ensure_uuid!
- before_validation :strip_sentry_values
before_save :ensure_runners_registration_token
before_save :ensure_health_check_access_token
@@ -282,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/application_setting_implementation.rb b/app/models/application_setting_implementation.rb
index 904d650ef96..df4caed175d 100644
--- a/app/models/application_setting_implementation.rb
+++ b/app/models/application_setting_implementation.rb
@@ -82,6 +82,7 @@ module ApplicationSettingImplementation
throttle_unauthenticated_enabled: false,
throttle_unauthenticated_period_in_seconds: 3600,
throttle_unauthenticated_requests_per_period: 3600,
+ time_tracking_limit_to_hours: false,
two_factor_grace_period: 48,
unique_ips_limit_enabled: false,
unique_ips_limit_per_user: 10,
@@ -179,27 +180,6 @@ module ApplicationSettingImplementation
super(levels&.map { |level| Gitlab::VisibilityLevel.level_value(level) })
end
- def strip_sentry_values
- sentry_dsn.strip! if sentry_dsn.present?
- clientside_sentry_dsn.strip! if clientside_sentry_dsn.present?
- end
-
- def sentry_enabled
- Gitlab.config.sentry.enabled || read_attribute(:sentry_enabled)
- end
-
- def sentry_dsn
- Gitlab.config.sentry.dsn || read_attribute(:sentry_dsn)
- end
-
- def clientside_sentry_enabled
- Gitlab.config.sentry.enabled || read_attribute(:clientside_sentry_enabled)
- end
-
- def clientside_sentry_dsn
- Gitlab.config.sentry.clientside_dsn || read_attribute(:clientside_sentry_dsn)
- end
-
def performance_bar_allowed_group
Group.find_by_id(performance_bar_allowed_group_id)
end
diff --git a/app/models/board.rb b/app/models/board.rb
index e08db764f65..50b6ca9b70f 100644
--- a/app/models/board.rb
+++ b/app/models/board.rb
@@ -4,11 +4,14 @@ class Board < ApplicationRecord
belongs_to :group
belongs_to :project
- has_many :lists, -> { order(:list_type, :position) }, dependent: :delete_all # rubocop:disable Cop/ActiveRecordDependent
+ has_many :lists, -> { ordered }, dependent: :delete_all # rubocop:disable Cop/ActiveRecordDependent
+ has_many :destroyable_lists, -> { destroyable.ordered }, class_name: "List"
validates :project, presence: true, if: :project_needed?
validates :group, presence: true, unless: :project
+ scope :with_associations, -> { preload(:destroyable_lists) }
+
def project_needed?
!group
end
diff --git a/app/models/broadcast_message.rb b/app/models/broadcast_message.rb
index 0fd8dca70b4..da4584228ce 100644
--- a/app/models/broadcast_message.rb
+++ b/app/models/broadcast_message.rb
@@ -45,7 +45,7 @@ class BroadcastMessage < ApplicationRecord
end
def self.cache_expires_in
- nil
+ 2.weeks
end
def active?
diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb
index 3727a9861aa..fd5aa216174 100644
--- a/app/models/ci/pipeline.rb
+++ b/app/models/ci/pipeline.rb
@@ -295,6 +295,11 @@ module Ci
end
end
+ def self.latest_for_shas(shas)
+ max_id_per_sha = for_sha(shas).group(:sha).select("max(id)")
+ where(id: max_id_per_sha)
+ end
+
def self.latest_successful_ids_per_project
success.group(:project_id).select('max(id) as id')
end
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/applications/runner.rb b/app/models/clusters/applications/runner.rb
index db7fd8524c2..f0256ff4d41 100644
--- a/app/models/clusters/applications/runner.rb
+++ b/app/models/clusters/applications/runner.rb
@@ -3,7 +3,7 @@
module Clusters
module Applications
class Runner < ApplicationRecord
- VERSION = '0.5.2'.freeze
+ VERSION = '0.6.0'.freeze
self.table_name = 'clusters_applications_runners'
diff --git a/app/models/clusters/instance.rb b/app/models/clusters/instance.rb
index d8a888d53ba..f21dbdf7f26 100644
--- a/app/models/clusters/instance.rb
+++ b/app/models/clusters/instance.rb
@@ -9,9 +9,5 @@ module Clusters
def feature_available?(feature)
::Feature.enabled?(feature, default_enabled: true)
end
-
- def self.enabled?
- ::Feature.enabled?(:instance_clusters, default_enabled: true)
- end
end
end
diff --git a/app/models/clusters/platforms/kubernetes.rb b/app/models/clusters/platforms/kubernetes.rb
index 5afb193cf86..9296c28776b 100644
--- a/app/models/clusters/platforms/kubernetes.rb
+++ b/app/models/clusters/platforms/kubernetes.rb
@@ -4,7 +4,6 @@ module Clusters
module Platforms
class Kubernetes < ApplicationRecord
include Gitlab::Kubernetes
- include ReactiveCaching
include EnumWithNil
include AfterCommitQueue
@@ -46,8 +45,6 @@ module Clusters
validate :prevent_modification, on: :update
- after_save :clear_reactive_cache!
-
alias_attribute :ca_pem, :ca_cert
delegate :enabled?, to: :cluster, allow_nil: true
@@ -96,27 +93,16 @@ module Clusters
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, cluster.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
+ def calculate_reactive_cache_for(environment)
return unless enabled?
- # We may want to cache extra things in the future
- { pods: read_pods }
+ { pods: read_pods(environment.deployment_namespace) }
+ end
+
+ def terminals(environment, data)
+ pods = filter_by_project_environment(data[:pods], environment.project.full_path_slug, environment.slug)
+ terminals = pods.flat_map { |pod| terminals_for_pod(api_url, environment.deployment_namespace, pod) }.compact
+ terminals.each { |terminal| add_terminal_auth(terminal, terminal_auth) }
end
def kubeclient
@@ -133,6 +119,12 @@ module Clusters
ca_pem: ca_pem)
end
+ def read_pods(namespace)
+ kubeclient.get_pods(namespace: namespace).as_json
+ rescue Kubeclient::ResourceNotFoundError
+ []
+ end
+
def build_kube_client!
raise "Incomplete settings" unless api_url
@@ -148,19 +140,6 @@ module Clusters
)
end
- # Returns a hash of all pods in the namespace
- def read_pods
- # TODO: The project lookup here should be moved (to environment?),
- # which will enable reading pods from the correct namespace for group
- # and instance clusters.
- # This will be done in https://gitlab.com/gitlab-org/gitlab-ce/issues/61156
- return [] unless cluster.project_type?
-
- kubeclient.get_pods(namespace: cluster.kubernetes_namespace_for(cluster.first_project)).as_json
- rescue Kubeclient::ResourceNotFoundError
- []
- end
-
def kubeclient_ssl_options
opts = { verify_ssl: OpenSSL::SSL::VERIFY_PEER }
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/deployable.rb b/app/models/concerns/deployable.rb
index bc12b06b5af..957b72f3721 100644
--- a/app/models/concerns/deployable.rb
+++ b/app/models/concerns/deployable.rb
@@ -18,6 +18,7 @@ module Deployable
return unless environment.persisted?
create_deployment!(
+ cluster_id: environment.deployment_platform&.cluster_id,
project_id: environment.project_id,
environment: environment,
ref: ref,
diff --git a/app/models/concerns/deployment_platform.rb b/app/models/concerns/deployment_platform.rb
index 1bd8a799f0d..5a358ae2ef6 100644
--- a/app/models/concerns/deployment_platform.rb
+++ b/app/models/concerns/deployment_platform.rb
@@ -13,8 +13,8 @@ module DeploymentPlatform
def find_deployment_platform(environment)
find_cluster_platform_kubernetes(environment: environment) ||
- find_group_cluster_platform_kubernetes_with_feature_guard(environment: environment) ||
- find_instance_cluster_platform_kubernetes_with_feature_guard(environment: environment)
+ find_group_cluster_platform_kubernetes(environment: environment) ||
+ find_instance_cluster_platform_kubernetes(environment: environment)
end
# EE would override this and utilize environment argument
@@ -23,24 +23,12 @@ module DeploymentPlatform
.last&.platform_kubernetes
end
- def find_group_cluster_platform_kubernetes_with_feature_guard(environment: nil)
- return unless group_clusters_enabled?
-
- find_group_cluster_platform_kubernetes(environment: environment)
- end
-
# EE would override this and utilize environment argument
def find_group_cluster_platform_kubernetes(environment: nil)
Clusters::Cluster.enabled.default_environment.ancestor_clusters_for_clusterable(self)
.first&.platform_kubernetes
end
- def find_instance_cluster_platform_kubernetes_with_feature_guard(environment: nil)
- return unless Clusters::Instance.enabled?
-
- find_instance_cluster_platform_kubernetes(environment: environment)
- end
-
# EE would override this and utilize environment argument
def find_instance_cluster_platform_kubernetes(environment: nil)
Clusters::Instance.new.clusters.enabled.default_environment
diff --git a/app/models/concerns/issuable.rb b/app/models/concerns/issuable.rb
index 127430cc68f..299e413321d 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
diff --git a/app/models/concerns/relative_positioning.rb b/app/models/concerns/relative_positioning.rb
index 46d2c345758..22b6b1d720c 100644
--- a/app/models/concerns/relative_positioning.rb
+++ b/app/models/concerns/relative_positioning.rb
@@ -25,7 +25,7 @@ module RelativePositioning
relative_position = position_between(max_relative_position, MAX_POSITION)
object.relative_position = relative_position
max_relative_position = relative_position
- object.save
+ object.save(touch: false)
end
end
end
@@ -159,7 +159,7 @@ module RelativePositioning
def save_positionable_neighbours
return unless @positionable_neighbours
- status = @positionable_neighbours.all?(&:save)
+ status = @positionable_neighbours.all? { |issue| issue.save(touch: false) }
@positionable_neighbours = nil
status
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 ee6e830d3ec..a8f5642f726 100644
--- a/app/models/deployment.rb
+++ b/app/models/deployment.rb
@@ -7,6 +7,7 @@ class Deployment < ApplicationRecord
belongs_to :project, required: true
belongs_to :environment, required: true
+ belongs_to :cluster, class_name: 'Clusters::Cluster', optional: true
belongs_to :user
belongs_to :deployable, polymorphic: true # rubocop:disable Cop/PolymorphicAssociations
@@ -84,12 +85,9 @@ class Deployment < ApplicationRecord
Commit.truncate_sha(sha)
end
- def cluster
- platform = project.deployment_platform(environment: environment.name)
-
- if platform.present? && platform.respond_to?(:cluster)
- platform.cluster
- end
+ # Deprecated - will be replaced by a persisted cluster_id
+ def deployment_platform_cluster
+ environment.deployment_platform&.cluster
end
def execute_hooks
@@ -199,7 +197,22 @@ class Deployment < ApplicationRecord
private
def prometheus_adapter
- environment.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
diff --git a/app/models/environment.rb b/app/models/environment.rb
index 1f7e8815c8e..b8ee54c1696 100644
--- a/app/models/environment.rb
+++ b/app/models/environment.rb
@@ -2,6 +2,8 @@
class Environment < ApplicationRecord
include Gitlab::Utils::StrongMemoize
+ include ReactiveCaching
+
# Used to generate random suffixes for the slug
LETTERS = ('a'..'z').freeze
NUMBERS = ('0'..'9').freeze
@@ -17,6 +19,7 @@ class Environment < ApplicationRecord
before_validation :generate_slug, if: ->(env) { env.slug.blank? }
before_save :set_environment_type
+ after_save :clear_reactive_cache!
validates :name,
presence: true,
@@ -159,7 +162,21 @@ class Environment < ApplicationRecord
end
def terminals
- deployment_platform.terminals(self) if has_terminals?
+ with_reactive_cache do |data|
+ deployment_platform.terminals(self, data)
+ end
+ end
+
+ def calculate_reactive_cache
+ return unless has_terminals? && !project.pending_delete?
+
+ deployment_platform.calculate_reactive_cache_for(self)
+ end
+
+ def deployment_namespace
+ strong_memoize(:kubernetes_namespace) do
+ deployment_platform&.kubernetes_namespace_for(project)
+ end
end
def has_metrics?
diff --git a/app/models/group.rb b/app/models/group.rb
index dbec211935d..8e89c7ecfb1 100644
--- a/app/models/group.rb
+++ b/app/models/group.rb
@@ -410,10 +410,6 @@ class Group < Namespace
ensure_runners_token!
end
- def group_clusters_enabled?
- Feature.enabled?(:group_clusters, root_ancestor, default_enabled: true)
- end
-
def project_creation_level
super || ::Gitlab::CurrentSettings.default_project_creation
end
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/list.rb b/app/models/list.rb
index 17b1a8510cf..d28a9bda82d 100644
--- a/app/models/list.rb
+++ b/app/models/list.rb
@@ -16,6 +16,7 @@ class List < ApplicationRecord
scope :destroyable, -> { where(list_type: list_types.slice(*destroyable_types).values) }
scope :movable, -> { where(list_type: list_types.slice(*movable_types).values) }
scope :preload_associations, -> { preload(:board, :label) }
+ scope :ordered, -> { order(:list_type, :position) }
class << self
def destroyable_types
diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb
index df2dc9c49eb..8391d526d18 100644
--- a/app/models/merge_request.rb
+++ b/app/models/merge_request.rb
@@ -1030,9 +1030,9 @@ class MergeRequest < ApplicationRecord
def mergeable_ci_state?
return true unless project.only_allow_merge_if_pipeline_succeeds?
- return true unless head_pipeline
+ return false unless actual_head_pipeline
- actual_head_pipeline&.success? || actual_head_pipeline&.skipped?
+ actual_head_pipeline.success? || actual_head_pipeline.skipped?
end
def environments_for(current_user)
@@ -1353,6 +1353,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 3c270c7396a..af50293a179 100644
--- a/app/models/namespace.rb
+++ b/app/models/namespace.rb
@@ -35,6 +35,8 @@ class Namespace < ApplicationRecord
belongs_to :parent, class_name: "Namespace"
has_many :children, class_name: "Namespace", foreign_key: :parent_id
has_one :chat_team, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
+ has_one :root_storage_statistics, class_name: 'Namespace::RootStorageStatistics'
+ has_one :aggregation_schedule, class_name: 'Namespace::AggregationSchedule'
validates :owner, presence: true, unless: ->(n) { n.type == "Group" }
validates :name,
@@ -248,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?
@@ -289,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
new file mode 100644
index 00000000000..355593597c6
--- /dev/null
+++ b/app/models/namespace/aggregation_schedule.rb
@@ -0,0 +1,47 @@
+# 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
+end
diff --git a/app/models/namespace/root_storage_statistics.rb b/app/models/namespace/root_storage_statistics.rb
new file mode 100644
index 00000000000..56c430013ee
--- /dev/null
+++ b/app/models/namespace/root_storage_statistics.rb
@@ -0,0 +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/note.rb b/app/models/note.rb
index b55af7d9b5e..4e9ea146485 100644
--- a/app/models/note.rb
+++ b/app/models/note.rb
@@ -452,7 +452,7 @@ class Note < ApplicationRecord
noteable_object&.touch
- # We return the noteable object so we can re-use it in EE for ElasticSearch.
+ # We return the noteable object so we can re-use it in EE for Elasticsearch.
noteable_object
end
diff --git a/app/models/pages_domain.rb b/app/models/pages_domain.rb
index 07195c0bfd3..d6d879c6d89 100644
--- a/app/models/pages_domain.rb
+++ b/app/models/pages_domain.rb
@@ -3,6 +3,7 @@
class PagesDomain < ApplicationRecord
VERIFICATION_KEY = 'gitlab-pages-verification-code'.freeze
VERIFICATION_THRESHOLD = 3.days.freeze
+ SSL_RENEWAL_THRESHOLD = 30.days.freeze
enum certificate_source: { user_provided: 0, gitlab_provided: 1 }, _prefix: :certificate
@@ -41,6 +42,15 @@ class PagesDomain < ApplicationRecord
where(verified_at.eq(nil).or(enabled_until.eq(nil).or(enabled_until.lt(threshold))))
end
+ scope :need_auto_ssl_renewal, -> do
+ expiring = where(certificate_valid_not_after: nil).or(
+ where(arel_table[:certificate_valid_not_after].lt(SSL_RENEWAL_THRESHOLD.from_now)))
+
+ user_provided_or_expiring = certificate_user_provided.or(expiring)
+
+ where(auto_ssl_enabled: true).merge(user_provided_or_expiring)
+ end
+
scope :for_removal, -> { where("remove_at < ?", Time.now) }
def verified?
diff --git a/app/models/postgresql/replication_slot.rb b/app/models/postgresql/replication_slot.rb
index 74ccf23cf69..7a123deb719 100644
--- a/app/models/postgresql/replication_slot.rb
+++ b/app/models/postgresql/replication_slot.rb
@@ -28,7 +28,7 @@ module Postgresql
# We force the use of a transaction here so the query always goes to the
# primary, even when using the EE DB load balancer.
sizes = transaction { pluck(lag_function) }
- too_great = sizes.count { |size| size >= max }
+ too_great = sizes.compact.count { |size| size >= max }
# If too many replicas are falling behind too much, the availability of a
# GitLab instance might suffer. To prevent this from happening we require
diff --git a/app/models/project.rb b/app/models/project.rb
index 351d08eaf63..0f4fba5d0b6 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -306,7 +306,6 @@ class Project < ApplicationRecord
delegate :add_guest, :add_reporter, :add_developer, :add_maintainer, :add_role, to: :team
delegate :add_master, to: :team # @deprecated
delegate :group_runners_enabled, :group_runners_enabled=, :group_runners_enabled?, to: :ci_cd_settings
- delegate :group_clusters_enabled?, to: :group, allow_nil: true
delegate :root_ancestor, to: :namespace, allow_nil: true
delegate :last_pipeline, to: :commit, allow_nil: true
delegate :external_dashboard_url, to: :metrics_setting, allow_nil: true, prefix: true
@@ -1446,11 +1445,6 @@ class Project < ApplicationRecord
end
def in_fork_network_of?(other_project)
- # TODO: Remove this in a next release when all fork_networks are populated
- # This makes sure all MergeRequests remain valid while the projects don't
- # have a fork_network yet.
- return true if forked_from?(other_project)
-
return false if fork_network.nil? || other_project.fork_network.nil?
fork_network == other_project.fork_network
@@ -1949,9 +1943,8 @@ class Project < ApplicationRecord
end
end
- # Overridden on EE module
def multiple_issue_boards_available?
- false
+ true
end
def full_path_before_last_save
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/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 7b4832b84a8..a3b89b2543a 100644
--- a/app/models/project_services/jira_service.rb
+++ b/app/models/project_services/jira_service.rb
@@ -14,17 +14,17 @@ class JiraService < IssueTrackerService
format: { with: Gitlab::Regex.jira_transition_id_regex, message: s_("JiraService|transition ids can have only numbers which can be split with , or ;") },
allow_blank: true
- # 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,
+ # 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
alias_method :project_url, :url
# When these are false GitLab does not create cross reference
- # comments on JIRA except when an issue gets transitioned.
+ # comments on Jira except when an issue gets transitioned.
def self.supported_events
%w(commit merge_request)
end
@@ -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']
}
@@ -69,25 +68,17 @@ class JiraService < IssueTrackerService
end
def help
- "You need to configure JIRA before enabling this service. For more details
+ "You need to configure Jira before enabling this service. For more details
read the
- [JIRA service documentation](#{help_page_url('user/project/integrations/jira')})."
+ [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
@@ -97,7 +88,7 @@ class JiraService < IssueTrackerService
def fields
[
{ type: 'text', name: 'url', title: s_('JiraService|Web URL'), placeholder: 'https://jira.example.com', required: true },
- { type: 'text', name: 'api_url', title: s_('JiraService|JIRA API URL'), placeholder: s_('JiraService|If different from Web URL') },
+ { type: 'text', name: 'api_url', title: s_('JiraService|Jira API URL'), placeholder: s_('JiraService|If different from Web URL') },
{ type: 'text', name: 'username', title: s_('JiraService|Username or Email'), placeholder: s_('JiraService|Use a username for server version and an email for cloud version'), required: true },
{ type: 'password', name: 'password', title: s_('JiraService|Password or API token'), placeholder: s_('JiraService|Use a password for server version and an API token for cloud version'), required: true },
{ type: 'text', name: 'jira_issue_transition_id', title: s_('JiraService|Transition ID(s)'), placeholder: s_('JiraService|Use , or ; to separate multiple transition IDs') }
@@ -130,7 +121,7 @@ class JiraService < IssueTrackerService
commit_url = build_entity_url(:commit, commit_id)
- # Depending on the JIRA project's workflow, a comment during transition
+ # Depending on the Jira project's workflow, a comment during transition
# may or may not be allowed. Refresh the issue after transition and check
# if it is closed, so we don't have one comment for every commit.
issue = jira_request { client.Issue.find(issue.key) } if transition_issue(issue)
@@ -177,7 +168,7 @@ class JiraService < IssueTrackerService
{ success: success, result: result }
end
- # JIRA does not need test data.
+ # Jira does not need test data.
# We are requesting the project that belongs to the project key.
def test_data(user = nil, project = nil)
nil
@@ -313,7 +304,7 @@ class JiraService < IssueTrackerService
name == "project_snippet" ? "snippet" : name
end
- # Handle errors when doing JIRA API calls
+ # Handle errors when doing Jira API calls
def jira_request
yield
@@ -339,9 +330,9 @@ class JiraService < IssueTrackerService
def self.event_description(event)
case event
when "merge_request", "merge_request_events"
- s_("JiraService|JIRA comments will be created when an issue gets referenced in a merge request.")
+ s_("JiraService|Jira comments will be created when an issue gets referenced in a merge request.")
when "commit", "commit_events"
- s_("JiraService|JIRA comments will be created when an issue gets referenced in a commit.")
+ s_("JiraService|Jira comments will be created when an issue gets referenced in a commit.")
end
end
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/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 e05d3dd58ac..d087a5a7bbd 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
@@ -282,46 +281,6 @@ class Repository
ref_exists?(keep_around_ref_name(sha))
end
- def diverging_commit_counts(branch)
- return diverging_commit_counts_without_max(branch) if Feature.enabled?('gitaly_count_diverging_commits_no_max')
-
- ## TODO: deprecate the below code after 12.0
- @root_ref_hash ||= raw_repository.commit(root_ref).id
- cache.fetch(:"diverging_commit_counts_#{branch.name}") do
- # Rugged seems to throw a `ReferenceError` when given branch_names rather
- # than SHA-1 hashes
- branch_sha = branch.dereferenced_target.sha
-
- number_commits_behind, number_commits_ahead =
- raw_repository.diverging_commit_count(
- @root_ref_hash,
- branch_sha,
- max_count: MAX_DIVERGING_COUNT)
-
- if number_commits_behind + number_commits_ahead >= MAX_DIVERGING_COUNT
- { distance: 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(root_ref).id
- cache.fetch(:"diverging_commit_counts_without_max_#{branch.name}") do
- # Rugged seems to throw a `ReferenceError` when given branch_names rather
- # than SHA-1 hashes
- branch_sha = branch.dereferenced_target.sha
-
- number_commits_behind, number_commits_ahead =
- raw_repository.diverging_commit_count(
- @root_ref_hash,
- branch_sha)
-
- { behind: number_commits_behind, ahead: number_commits_ahead }
- end
- end
-
def archive_metadata(ref, storage_path, format = "tar.gz", append_sha:, path: nil)
raw_repository.archive_metadata(
ref,
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/snippet.rb b/app/models/snippet.rb
index f4fdac2558c..00931457344 100644
--- a/app/models/snippet.rb
+++ b/app/models/snippet.rb
@@ -194,6 +194,10 @@ class Snippet < ApplicationRecord
'snippet'
end
+ def to_ability_name
+ model_name.singular
+ end
+
class << self
# Searches for snippets with a matching title or file name.
#
diff --git a/app/models/todo.rb b/app/models/todo.rb
index f1fc5e599eb..240c91da5b6 100644
--- a/app/models/todo.rb
+++ b/app/models/todo.rb
@@ -60,7 +60,7 @@ class Todo < ApplicationRecord
scope :for_type, -> (type) { where(target_type: type) }
scope :for_target, -> (id) { where(target_id: id) }
scope :for_commit, -> (id) { where(commit_id: id) }
- scope :with_api_entity_associations, -> { preload(:target, :author, :note, group: :route, project: [:route, { namespace: :route }]) }
+ scope :with_entity_associations, -> { preload(:target, :author, :note, group: :route, project: [:route, { namespace: :route }]) }
scope :joins_issue_and_assignees, -> { left_joins(issue: :assignees) }
state_machine :state, initial: :pending do
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/award_emoji_policy.rb b/app/policies/award_emoji_policy.rb
new file mode 100644
index 00000000000..21e382e24b3
--- /dev/null
+++ b/app/policies/award_emoji_policy.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+class AwardEmojiPolicy < BasePolicy
+ delegate { @subject.awardable if DeclarativePolicy.has_policy?(@subject.awardable) }
+
+ condition(:can_read_awardable) do
+ can?(:"read_#{@subject.awardable.to_ability_name}")
+ end
+
+ rule { can_read_awardable }.enable :read_emoji
+end
diff --git a/app/policies/clusters/instance_policy.rb b/app/policies/clusters/instance_policy.rb
index e1045c85e6d..f72096e8fc6 100644
--- a/app/policies/clusters/instance_policy.rb
+++ b/app/policies/clusters/instance_policy.rb
@@ -6,9 +6,8 @@ module Clusters
condition(:has_clusters, scope: :subject) { clusterable_has_clusters? }
condition(:can_have_multiple_clusters) { multiple_clusters_available? }
- condition(:instance_clusters_enabled) { Instance.enabled? }
- rule { admin & instance_clusters_enabled }.policy do
+ rule { admin }.policy do
enable :read_cluster
enable :add_cluster
enable :create_cluster
diff --git a/app/policies/project_policy.rb b/app/policies/project_policy.rb
index 08bfe5d14ee..3c9ffbb2065 100644
--- a/app/policies/project_policy.rb
+++ b/app/policies/project_policy.rb
@@ -196,6 +196,7 @@ class ProjectPolicy < BasePolicy
rule { guest & can?(:read_container_image) }.enable :build_read_container_image
rule { can?(:reporter_access) }.policy do
+ enable :admin_board
enable :download_code
enable :read_statistics
enable :download_wiki_code
@@ -240,6 +241,7 @@ class ProjectPolicy < BasePolicy
rule { can?(:developer_access) & can?(:create_issue) }.enable :import_issues
rule { can?(:developer_access) }.policy do
+ enable :admin_board
enable :admin_merge_request
enable :admin_milestone
enable :update_merge_request
@@ -266,6 +268,7 @@ class ProjectPolicy < BasePolicy
end
rule { can?(:maintainer_access) }.policy do
+ enable :admin_board
enable :push_to_delete_protected_branch
enable :update_project_snippet
enable :update_environment
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/presenters/award_emoji_presenter.rb b/app/presenters/award_emoji_presenter.rb
new file mode 100644
index 00000000000..98713855d35
--- /dev/null
+++ b/app/presenters/award_emoji_presenter.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+class AwardEmojiPresenter < Gitlab::View::Presenter::Delegated
+ presents :award_emoji
+
+ def description
+ as_emoji['description']
+ end
+
+ def unicode
+ as_emoji['unicode']
+ end
+
+ def emoji
+ as_emoji['moji']
+ end
+
+ def unicode_version
+ Gitlab::Emoji.emoji_unicode_version(award_emoji.name)
+ end
+
+ private
+
+ def as_emoji
+ @emoji ||= Gitlab::Emoji.emojis[award_emoji.name] || {}
+ end
+end
diff --git a/app/presenters/commit_presenter.rb b/app/presenters/commit_presenter.rb
index 05adbe1d4f5..fc9853733c1 100644
--- a/app/presenters/commit_presenter.rb
+++ b/app/presenters/commit_presenter.rb
@@ -1,6 +1,8 @@
# frozen_string_literal: true
-class CommitPresenter < Gitlab::View::Presenter::Simple
+class CommitPresenter < Gitlab::View::Presenter::Delegated
+ include GlobalID::Identification
+
presents :commit
def status_for(ref)
@@ -10,4 +12,8 @@ class CommitPresenter < Gitlab::View::Presenter::Simple
def any_pipelines?
can?(current_user, :read_pipeline, commit.project) && commit.pipelines.any?
end
+
+ def web_url
+ Gitlab::UrlBuilder.new(commit).url
+ end
end
diff --git a/app/serializers/board_simple_entity.rb b/app/serializers/board_simple_entity.rb
index f297d993e27..029d3808e75 100644
--- a/app/serializers/board_simple_entity.rb
+++ b/app/serializers/board_simple_entity.rb
@@ -2,4 +2,5 @@
class BoardSimpleEntity < Grape::Entity
expose :id
+ expose :name
end
diff --git a/app/serializers/merge_request_widget_entity.rb b/app/serializers/merge_request_widget_entity.rb
index 43aced598a9..fd2673fa0cc 100644
--- a/app/serializers/merge_request_widget_entity.rb
+++ b/app/serializers/merge_request_widget_entity.rb
@@ -217,8 +217,12 @@ class MergeRequestWidgetEntity < IssuableEntity
project_merge_request_path(merge_request.project, merge_request, format: :diff)
end
- expose :status_path do |merge_request|
- project_merge_request_path(merge_request.target_project, merge_request, format: :json)
+ expose :merge_request_basic_path do |merge_request|
+ project_merge_request_path(merge_request.target_project, merge_request, serializer: :basic, format: :json)
+ end
+
+ expose :merge_request_widget_path do |merge_request|
+ widget_project_json_merge_request_path(merge_request.target_project, merge_request, format: :json)
end
expose :ci_environments_status_path do |merge_request|
diff --git a/app/services/boards/create_service.rb b/app/services/boards/create_service.rb
index 1b796cef3e2..dd9358913fd 100644
--- a/app/services/boards/create_service.rb
+++ b/app/services/boards/create_service.rb
@@ -9,7 +9,7 @@ module Boards
private
def can_create_board?
- parent.boards.empty?
+ parent.boards.empty? || parent.multiple_issue_boards_available?
end
def create_board!
diff --git a/app/services/boards/destroy_service.rb b/app/services/boards/destroy_service.rb
new file mode 100644
index 00000000000..ea0c1394aa3
--- /dev/null
+++ b/app/services/boards/destroy_service.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+module Boards
+ class DestroyService < Boards::BaseService
+ def execute(board)
+ return false if parent.boards.size == 1
+
+ board.destroy
+ end
+ end
+end
diff --git a/app/services/boards/update_service.rb b/app/services/boards/update_service.rb
new file mode 100644
index 00000000000..88aced01ccd
--- /dev/null
+++ b/app/services/boards/update_service.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+module Boards
+ class UpdateService < Boards::BaseService
+ def execute(board)
+ board.update(params)
+ end
+ end
+end
diff --git a/app/services/boards/visits/latest_service.rb b/app/services/boards/visits/latest_service.rb
deleted file mode 100644
index d13e25b4f12..00000000000
--- a/app/services/boards/visits/latest_service.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-# frozen_string_literal: true
-
-module Boards
- module Visits
- class LatestService < Boards::BaseService
- def execute
- return unless current_user
-
- recent_visit_model.latest(current_user, parent, count: params[:count])
- end
-
- private
-
- def recent_visit_model
- parent.is_a?(Group) ? BoardGroupRecentVisit : BoardProjectRecentVisit
- end
- end
- end
-end
diff --git a/app/services/branches/diverging_commit_counts_service.rb b/app/services/branches/diverging_commit_counts_service.rb
new file mode 100644
index 00000000000..a3404caf2d7
--- /dev/null
+++ b/app/services/branches/diverging_commit_counts_service.rb
@@ -0,0 +1,32 @@
+# frozen_string_literal: true
+
+module Branches
+ class DivergingCommitCountsService
+ def initialize(repository)
+ @repository = repository
+ @cache = Gitlab::RepositoryCache.new(repository)
+ end
+
+ def call(branch)
+ diverging_commit_counts(branch)
+ end
+
+ private
+
+ attr_reader :repository, :cache
+
+ delegate :raw_repository, to: :repository
+
+ def diverging_commit_counts(branch)
+ @root_ref_hash ||= raw_repository.commit(repository.root_ref).id
+ cache.fetch(:"diverging_commit_counts_#{branch.name}") do
+ number_commits_behind, number_commits_ahead =
+ raw_repository.diverging_commit_count(
+ @root_ref_hash,
+ branch.dereferenced_target.sha)
+
+ { behind: number_commits_behind, ahead: number_commits_ahead }
+ end
+ 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/issuable_base_service.rb b/app/services/issuable_base_service.rb
index 26132f1824a..02de080e0ba 100644
--- a/app/services/issuable_base_service.rb
+++ b/app/services/issuable_base_service.rb
@@ -205,7 +205,7 @@ class IssuableBaseService < BaseService
end
if issuable.changed? || params.present?
- issuable.assign_attributes(params.merge(updated_by: current_user))
+ issuable.assign_attributes(params)
if has_title_or_description_changed?(issuable)
issuable.assign_attributes(last_edited_at: Time.now, last_edited_by: current_user)
@@ -213,11 +213,16 @@ class IssuableBaseService < BaseService
before_update(issuable)
+ # Do not touch when saving the issuable if only changes position within a list. We should call
+ # this method at this point to capture all possible changes.
+ should_touch = update_timestamp?(issuable)
+
+ issuable.updated_by = current_user if should_touch
# We have to perform this check before saving the issuable as Rails resets
# the changed fields upon calling #save.
update_project_counters = issuable.project && update_project_counter_caches?(issuable)
- if issuable.with_transaction_returning_status { issuable.save }
+ if issuable.with_transaction_returning_status { issuable.save(touch: should_touch) }
# We do not touch as it will affect a update on updated_at field
ActiveRecord::Base.no_touching do
Issuable::CommonSystemNotesService.new(project, current_user).execute(issuable, old_labels: old_associations[:labels])
@@ -402,4 +407,8 @@ class IssuableBaseService < BaseService
def ensure_milestone_available(issuable)
issuable.milestone_id = nil unless issuable.milestone_available?
end
+
+ def update_timestamp?(issuable)
+ issuable.changes.keys != ["relative_position"]
+ end
end
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/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/pages_domains/obtain_lets_encrypt_certificate_service.rb b/app/services/pages_domains/obtain_lets_encrypt_certificate_service.rb
index 3413a9e4612..58f795e639e 100644
--- a/app/services/pages_domains/obtain_lets_encrypt_certificate_service.rb
+++ b/app/services/pages_domains/obtain_lets_encrypt_certificate_service.rb
@@ -2,6 +2,14 @@
module PagesDomains
class ObtainLetsEncryptCertificateService
+ # time for processing validation requests for acme challenges
+ # 5-15 seconds is usually enough
+ CHALLENGE_PROCESSING_DELAY = 1.minute.freeze
+
+ # time LetsEncrypt ACME server needs to generate the certificate
+ # no particular SLA, usually takes 10-15 seconds
+ CERTIFICATE_PROCESSING_DELAY = 1.minute.freeze
+
attr_reader :pages_domain
def initialize(pages_domain)
@@ -14,6 +22,7 @@ module PagesDomains
unless acme_order
::PagesDomains::CreateAcmeOrderService.new(pages_domain).execute
+ PagesDomainSslRenewalWorker.perform_in(CHALLENGE_PROCESSING_DELAY, pages_domain.id)
return
end
@@ -23,6 +32,7 @@ module PagesDomains
case api_order.status
when 'ready'
api_order.request_certificate(private_key: acme_order.private_key, domain: pages_domain.domain)
+ PagesDomainSslRenewalWorker.perform_in(CERTIFICATE_PROCESSING_DELAY, pages_domain.id)
when 'valid'
save_certificate(acme_order.private_key, api_order)
acme_order.destroy!
diff --git a/app/services/projects/propagate_service_template.rb b/app/services/projects/propagate_service_template.rb
index a2f36d2bd1b..a25c985585b 100644
--- a/app/services/projects/propagate_service_template.rb
+++ b/app/services/projects/propagate_service_template.rb
@@ -24,7 +24,7 @@ module Projects
def propagate_projects_with_template
loop do
- batch = project_ids_batch
+ batch = Project.uncached { project_ids_batch }
bulk_create_from_template(batch) unless batch.empty?
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..237ddbcf2c2 100644
--- a/app/services/system_note_service.rb
+++ b/app/services/system_note_service.rb
@@ -249,7 +249,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
@@ -404,8 +404,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 +414,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/services/users/update_service.rb b/app/services/users/update_service.rb
index 15c13a452ad..8f52e9cb23f 100644
--- a/app/services/users/update_service.rb
+++ b/app/services/users/update_service.rb
@@ -63,12 +63,20 @@ module Users
def assign_identity
return unless identity_params.present?
- identity = user.identities.find_or_create_by(provider: identity_params[:provider]) # rubocop: disable CodeReuse/ActiveRecord
+ identity = user.identities.find_or_create_by(provider_params) # rubocop: disable CodeReuse/ActiveRecord
identity.update(identity_params)
end
def identity_attributes
[:provider, :extern_uid]
end
+
+ def provider_attributes
+ [:provider]
+ end
+
+ def provider_params
+ identity_params.slice(*provider_attributes)
+ end
end
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/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/_localization.html.haml b/app/views/admin/application_settings/_localization.html.haml
index bb4d1fa1241..e01c123d1db 100644
--- a/app/views/admin/application_settings/_localization.html.haml
+++ b/app/views/admin/application_settings/_localization.html.haml
@@ -8,4 +8,11 @@
.form-text.text-muted
= _('Default first day of the week in calendars and date pickers.')
+ .form-group
+ = f.label :time_tracking, _('Time tracking'), class: 'label-bold'
+ .form-check
+ = f.check_box :time_tracking_limit_to_hours, class: 'form-check-input'
+ = f.label :time_tracking_limit_to_hours, class: 'form-check-label' do
+ = _('Limit display of time tracking units to hours.')
+
= f.submit _('Save changes'), class: "btn btn-success"
diff --git a/app/views/admin/application_settings/_logging.html.haml b/app/views/admin/application_settings/_logging.html.haml
deleted file mode 100644
index d57066bba01..00000000000
--- a/app/views/admin/application_settings/_logging.html.haml
+++ /dev/null
@@ -1,38 +0,0 @@
-= form_for @application_setting, url: reporting_admin_application_settings_path(anchor: 'js-logging-settings'), html: { class: 'fieldset-form' } do |f|
- = form_errors(@application_setting)
-
- %p
- %strong
- NOTE:
- These settings will be removed from the UI in a GitLab 12.0 release and made available within gitlab.yml.
- In addition, you will be able to define a Sentry Environment to differentiate between multiple deployments. For example, development, staging, and production.
-
- %fieldset
- .form-group
- .form-check
- = f.check_box :sentry_enabled, class: 'form-check-input'
- = f.label :sentry_enabled, class: 'form-check-label' do
- Enable Sentry
- .form-text.text-muted
- %p This setting requires a restart to take effect.
- Sentry is an error reporting and logging tool which is currently not shipped with GitLab, get it here:
- %a{ href: 'https://getsentry.com', target: '_blank', rel: 'noopener noreferrer' } https://getsentry.com
-
- .form-group
- = f.label :sentry_dsn, 'Sentry DSN', class: 'label-bold'
- = f.text_field :sentry_dsn, class: 'form-control'
-
- .form-group
- .form-check
- = f.check_box :clientside_sentry_enabled, class: 'form-check-input'
- = f.label :clientside_sentry_enabled, class: 'form-check-label' do
- Enable Clientside Sentry
- .form-text.text-muted
- Sentry can also be used for reporting and logging clientside exceptions.
- %a{ href: 'https://sentry.io/for/javascript/', target: '_blank', rel: 'noopener noreferrer' } https://sentry.io/for/javascript/
-
- .form-group
- = f.label :clientside_sentry_dsn, 'Clientside Sentry DSN', class: 'label-bold'
- = f.text_field :clientside_sentry_dsn, class: 'form-control'
-
- = f.submit 'Save changes', class: "btn btn-success"
diff --git a/app/views/admin/application_settings/_spam.html.haml b/app/views/admin/application_settings/_spam.html.haml
index a34fc15acb1..d24e46b2815 100644
--- a/app/views/admin/application_settings/_spam.html.haml
+++ b/app/views/admin/application_settings/_spam.html.haml
@@ -7,7 +7,10 @@
= f.check_box :recaptcha_enabled, class: 'form-check-input'
= f.label :recaptcha_enabled, class: 'form-check-label' do
Enable reCAPTCHA
- %span.form-text.text-muted#recaptcha_help_block Helps prevent bots from creating accounts
+ - recaptcha_v2_link_url = 'https://developers.google.com/recaptcha/docs/versions'
+ - recaptcha_v2_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: recaptcha_v2_link_url }
+ %span.form-text.text-muted#recaptcha_help_block
+ = _('Helps prevent bots from creating accounts. We currently only support %{recaptcha_v2_link_start}reCAPTCHA v2%{recaptcha_v2_link_end}').html_safe % { recaptcha_v2_link_start: recaptcha_v2_link_start, recaptcha_v2_link_end: '</a>'.html_safe }
.form-group
= f.label :recaptcha_site_key, 'reCAPTCHA Site Key', class: 'label-bold'
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/application_settings/reporting.html.haml b/app/views/admin/application_settings/reporting.html.haml
index 1c2d9ccdb2d..46e3d1c4570 100644
--- a/app/views/admin/application_settings/reporting.html.haml
+++ b/app/views/admin/application_settings/reporting.html.haml
@@ -23,14 +23,3 @@
= _('Set notification email for abuse reports.')
.settings-content
= render 'abuse'
-
-%section.settings.as-logging.no-animate#js-logging-settings{ class: ('expanded' if expanded_by_default?) }
- .settings-header
- %h4
- = _('Error Reporting and Logging')
- %button.btn.btn-default.js-settings-toggle{ type: 'button' }
- = expanded_by_default? ? _('Collapse') : _('Expand')
- %p
- = _('Enable Sentry for error reporting and logging.')
- .settings-content
- = render 'logging'
diff --git a/app/views/admin/runners/index.html.haml b/app/views/admin/runners/index.html.haml
index 2e23b748edb..5129f5d193b 100644
--- a/app/views/admin/runners/index.html.haml
+++ b/app/views/admin/runners/index.html.haml
@@ -58,7 +58,7 @@
.scroll-container
%ul.tokens-container.list-unstyled
%li.input-token
- %input.form-control.filtered-search{ { id: 'filtered-search-runners', placeholder: _('Search or filter results...') } }
+ %input.form-control.filtered-search{ search_filter_input_options('runners') }
#js-dropdown-hint.filtered-search-input-dropdown-menu.dropdown-menu.hint-dropdown
%ul{ data: { dropdown: true } }
%li.filter-dropdown-item{ data: { action: 'submit' } }
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/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/devise/shared/_signup_box.html.haml b/app/views/devise/shared/_signup_box.html.haml
index eae3ee6339f..034273558bb 100644
--- a/app/views/devise/shared/_signup_box.html.haml
+++ b/app/views/devise/shared/_signup_box.html.haml
@@ -33,7 +33,7 @@
= accept_terms_label.html_safe
= render_if_exists 'devise/shared/email_opted_in', f: f
%div
- - if Gitlab::Recaptcha.enabled?
+ - if show_recaptcha_sign_up?
= recaptcha_tags
.submit-container
= f.submit _("Register"), class: "btn-register btn qa-new-user-register-button"
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/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/_head.html.haml b/app/views/layouts/_head.html.haml
index 7535aee83a3..20b844f9fd8 100644
--- a/app/views/layouts/_head.html.haml
+++ b/app/views/layouts/_head.html.haml
@@ -46,7 +46,7 @@
= yield :library_javascripts
= javascript_include_tag locale_path unless I18n.locale == :en
- = webpack_bundle_tag "raven" if Gitlab::CurrentSettings.clientside_sentry_enabled
+ = webpack_bundle_tag "raven" if Gitlab.config.sentry.enabled
- if content_for?(:page_specific_javascripts)
= yield :page_specific_javascripts
diff --git a/app/views/layouts/fullscreen.html.haml b/app/views/layouts/fullscreen.html.haml
index e29f646ed4f..fa04b5be9f2 100644
--- a/app/views/layouts/fullscreen.html.haml
+++ b/app/views/layouts/fullscreen.html.haml
@@ -10,5 +10,5 @@
= render "layouts/broadcast"
= yield :flash_message
= render "layouts/flash"
- .content-wrapper{ id: "content-body", class: "d-flex flex-column align-items-stretch" }
+ .content-wrapper{ id: "content-body", class: "d-flex flex-column align-items-stretch mt-0" }
= yield
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/personal_access_tokens/index.html.haml b/app/views/profiles/personal_access_tokens/index.html.haml
index 4c18398e3dc..65ef9690062 100644
--- a/app/views/profiles/personal_access_tokens/index.html.haml
+++ b/app/views/profiles/personal_access_tokens/index.html.haml
@@ -1,5 +1,5 @@
-- breadcrumb_title "Access Tokens"
-- page_title "Personal Access Tokens"
+- breadcrumb_title s_('AccessTokens|Access Tokens')
+- page_title s_('AccessTokens|Personal Access Tokens')
- @content_class = "limit-container-width" unless fluid_layout
.row.prepend-top-default
@@ -7,10 +7,10 @@
%h4.prepend-top-0
= page_title
%p
- You can generate a personal access token for each application you use that needs access to the GitLab API.
+ = s_('AccessTokens|You can generate a personal access token for each application you use that needs access to the GitLab API.')
%p
- You can also use personal access tokens to authenticate against Git over HTTP.
- They are the only accepted password when you have Two-Factor Authentication (2FA) enabled.
+ = s_('AccessTokens|You can also use personal access tokens to authenticate against Git over HTTP.')
+ = s_('AccessTokens|They are the only accepted password when you have Two-Factor Authentication (2FA) enabled.')
.col-lg-8
- if @new_personal_access_token
@@ -24,35 +24,33 @@
.row.prepend-top-default
.col-lg-4.profile-settings-sidebar
%h4.prepend-top-0
- Feed token
+ = s_('AccessTokens|Feed token')
%p
- Your feed token is used to authenticate you when your RSS reader loads a personalized RSS feed or when your calendar application loads a personalized calendar, and is included in those feed URLs.
+ = s_('AccessTokens|Your feed token is used to authenticate you when your RSS reader loads a personalized RSS feed or when your calendar application loads a personalized calendar, and is included in those feed URLs.')
%p
- It cannot be used to access any other data.
+ = s_('AccessTokens|It cannot be used to access any other data.')
.col-lg-8.feed-token-reset
- = label_tag :feed_token, 'Feed token', class: "label-bold"
+ = label_tag :feed_token, s_('AccessTokens|Feed token'), class: "label-bold"
= text_field_tag :feed_token, current_user.feed_token, class: 'form-control', readonly: true, onclick: 'this.select()'
%p.form-text.text-muted
- Keep this token secret. Anyone who gets ahold of it can read activity and issue RSS feeds or your calendar feed as if they were you.
- You should
- = link_to 'reset it', [:reset, :feed_token, :profile], method: :put, data: { confirm: 'Are you sure? Any RSS or calendar URLs currently in use will stop working.' }
- if that ever happens.
+ - reset_link = link_to s_('AccessTokens|reset it'), [:reset, :feed_token, :profile], method: :put, data: { confirm: s_('AccessTokens|Are you sure? Any RSS or calendar URLs currently in use will stop working.') }
+ - reset_message = s_('AccessTokens|Keep this token secret. Anyone who gets ahold of it can read activity and issue RSS feeds or your calendar feed as if they were you. You should %{link_reset_it} if that ever happens.') % { link_reset_it: reset_link }
+ = reset_message.html_safe
- if incoming_email_token_enabled?
%hr
.row.prepend-top-default
.col-lg-4.profile-settings-sidebar
%h4.prepend-top-0
- Incoming email token
+ = s_('AccessTokens|Incoming email token')
%p
- Your incoming email token is used to authenticate you when you create a new issue by email, and is included in your personal project-specific email addresses.
+ = s_('AccessTokens|Your incoming email token is used to authenticate you when you create a new issue by email, and is included in your personal project-specific email addresses.')
%p
- It cannot be used to access any other data.
+ = s_('AccessTokens|It cannot be used to access any other data.')
.col-lg-8.incoming-email-token-reset
- = label_tag :incoming_email_token, 'Incoming email token', class: "label-bold"
+ = label_tag :incoming_email_token, s_('AccessTokens|Incoming email token'), class: "label-bold"
= text_field_tag :incoming_email_token, current_user.incoming_email_token, class: 'form-control', readonly: true, onclick: 'this.select()'
%p.form-text.text-muted
- Keep this token secret. Anyone who gets ahold of it can create issues as if they were you.
- You should
- = link_to 'reset it', [:reset, :incoming_email_token, :profile], method: :put, data: { confirm: 'Are you sure? Any issue email addresses currently in use will stop working.' }
- if that ever happens.
+ - reset_link = link_to s_('AccessTokens|reset it'), [:reset, :incoming_email_token, :profile], method: :put, data: { confirm: s_('AccessTokens|Are you sure? Any issue email addresses currently in use will stop working.') }
+ - reset_message = s_('AccessTokens|Keep this token secret. Anyone who gets ahold of it can create issues as if they were you. You should %{link_reset_it} if that ever happens.') % { link_reset_it: reset_link }
+ = reset_message.html_safe
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/_files.html.haml b/app/views/projects/_files.html.haml
index 2b0c3985755..6763513f9ae 100644
--- a/app/views/projects/_files.html.haml
+++ b/app/views/projects/_files.html.haml
@@ -9,7 +9,9 @@
.nav-block
= render 'projects/tree/tree_header', tree: @tree
- - if commit
+ - if vue_file_list_enabled?
+ #js-last-commit
+ - elsif commit
= render 'shared/commit_well', commit: commit, ref: ref, project: project
- if is_project_overview
diff --git a/app/views/projects/_merge_request_settings_description_text.html.haml b/app/views/projects/_merge_request_settings_description_text.html.haml
new file mode 100644
index 00000000000..42964c900b3
--- /dev/null
+++ b/app/views/projects/_merge_request_settings_description_text.html.haml
@@ -0,0 +1 @@
+%p= s_('ProjectSettings|Choose your merge method, merge options, and merge checks.')
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 3638334d61c..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 = @repository.diverging_commit_counts(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 c15b84d0aac..3403564992e 100644
--- a/app/views/projects/edit.html.haml
+++ b/app/views/projects/edit.html.haml
@@ -27,7 +27,7 @@
.settings-header
%h4.settings-title.js-settings-toggle.js-settings-toggle-trigger-only= _('Merge requests')
%button.btn.btn-default.js-settings-toggle{ type: 'button' }= expanded ? _('Collapse') : _('Expand')
- %p= _('Choose your merge method, options, checks, and set up a default merge request description template.')
+ = render_if_exists 'projects/merge_request_settings_description_text'
.settings-content
= render_if_exists 'shared/promotions/promote_mr_features'
@@ -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/environments/show.html.haml b/app/views/projects/environments/show.html.haml
index d59b2d4fb01..c13a47b0b09 100644
--- a/app/views/projects/environments/show.html.haml
+++ b/app/views/projects/environments/show.html.haml
@@ -31,21 +31,19 @@
= button_to stop_project_environment_path(@project, @environment), class: 'btn btn-danger has-tooltip', method: :post do
= s_('Environments|Stop environment')
- .row.top-area.adjust
- .col-md-7
- %h3.page-title= @environment.name
- .col-md-5
- .nav-controls
- = render 'projects/environments/terminal_button', environment: @environment
- = render 'projects/environments/external_url', environment: @environment
- = render 'projects/environments/metrics_button', environment: @environment
- - if can?(current_user, :update_environment, @environment)
- = link_to _('Edit'), edit_project_environment_path(@project, @environment), class: 'btn'
- - if can?(current_user, :stop_environment, @environment)
- = button_tag class: 'btn btn-danger', type: 'button', data: { toggle: 'modal',
- target: '#stop-environment-modal' } do
- = sprite_icon('stop')
- = s_('Environments|Stop')
+ .top-area
+ %h3.page-title= @environment.name
+ .nav-controls.ml-auto.my-2
+ = render 'projects/environments/terminal_button', environment: @environment
+ = render 'projects/environments/external_url', environment: @environment
+ = render 'projects/environments/metrics_button', environment: @environment
+ - if can?(current_user, :update_environment, @environment)
+ = link_to _('Edit'), edit_project_environment_path(@project, @environment), class: 'btn'
+ - if can?(current_user, :stop_environment, @environment)
+ = button_tag class: 'btn btn-danger', type: 'button', data: { toggle: 'modal',
+ target: '#stop-environment-modal' } do
+ = sprite_icon('stop')
+ = s_('Environments|Stop')
.environments-container
- if @deployments.blank?
diff --git a/app/views/projects/issues/_issues.html.haml b/app/views/projects/issues/_issues.html.haml
index 6f7713124ac..7d539c9d749 100644
--- a/app/views/projects/issues/_issues.html.haml
+++ b/app/views/projects/issues/_issues.html.haml
@@ -1,6 +1,6 @@
- empty_state_path = local_assigns.fetch(:empty_state_path, 'shared/empty_states/issues')
-%ul.content-list.issues-list.issuable-list
+%ul.content-list.issues-list.issuable-list{ class: ("manual-ordering" if @sort == 'relative_position') }
= render partial: "projects/issues/issue", collection: @issues
- if @issues.blank?
= render empty_state_path
diff --git a/app/views/projects/new.html.haml b/app/views/projects/new.html.haml
index d7e16dbd40c..1cfe302fdc7 100644
--- a/app/views/projects/new.html.haml
+++ b/app/views/projects/new.html.haml
@@ -46,11 +46,11 @@
= render_if_exists 'projects/new_ci_cd_only_project_tab', active_tab: active_tab
.tab-content.gitlab-tab-content
- .tab-pane{ id: 'blank-project-pane', class: active_when(active_tab == 'blank'), role: 'tabpanel' }
+ .tab-pane.js-toggle-container{ id: 'blank-project-pane', class: active_when(active_tab == 'blank'), role: 'tabpanel' }
= form_for @project, html: { class: 'new_project' } do |f|
= render 'new_project_fields', f: f, project_name_id: "blank-project-name"
- #create-from-template-pane.tab-pane.px-0.pb-0{ class: active_when(active_tab == 'template'), role: 'tabpanel' }
+ #create-from-template-pane.tab-pane.js-toggle-container.px-0.pb-0{ class: active_when(active_tab == 'template'), role: 'tabpanel' }
.card-slim.m-4.p-4
%div
- contributing_templates_url = 'https://gitlab.com/gitlab-org/project-templates/contributing'
diff --git a/app/views/projects/notes/_actions.html.haml b/app/views/projects/notes/_actions.html.haml
index 044adb75bea..407de590efb 100644
--- a/app/views/projects/notes/_actions.html.haml
+++ b/app/views/projects/notes/_actions.html.haml
@@ -39,7 +39,7 @@
- if can?(current_user, :award_emoji, note)
- if note.emoji_awardable?
.note-actions-item
- = button_tag title: 'Add reaction', class: "note-action-button note-emoji-button js-add-award js-note-emoji} has-tooltip btn btn-transparent", data: { position: 'right', container: 'body' } do
+ = button_tag title: 'Add reaction', class: "note-action-button note-emoji-button js-add-award js-note-emoji has-tooltip btn btn-transparent", data: { position: 'right', container: 'body' } do
= icon('spinner spin')
%span{ class: 'link-highlight award-control-icon-neutral' }= sprite_icon('slight-smile')
%span{ class: 'link-highlight award-control-icon-positive' }= sprite_icon('smiley')
diff --git a/app/views/projects/pages_domains/_form.html.haml b/app/views/projects/pages_domains/_form.html.haml
index e7edb93f05b..5b657966909 100644
--- a/app/views/projects/pages_domains/_form.html.haml
+++ b/app/views/projects/pages_domains/_form.html.haml
@@ -11,7 +11,7 @@
- if Gitlab.config.pages.external_https
- - auto_ssl_available = ::Gitlab::LetsEncrypt::Client.new.enabled?
+ - auto_ssl_available = ::Gitlab::LetsEncrypt.enabled?(@domain)
- auto_ssl_enabled = @domain.auto_ssl_enabled?
- auto_ssl_available_and_enabled = auto_ssl_available && auto_ssl_enabled
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/projects/tree/_tree_header.html.haml b/app/views/projects/tree/_tree_header.html.haml
index ea6349f2f57..1d0bc588c9c 100644
--- a/app/views/projects/tree/_tree_header.html.haml
+++ b/app/views/projects/tree/_tree_header.html.haml
@@ -76,6 +76,7 @@
#{ _('New tag') }
.tree-controls
+ = render_if_exists 'projects/tree/lock_link'
= link_to s_('Commits|History'), project_commits_path(@project, @id), class: 'btn'
= render 'projects/find_file_link'
diff --git a/app/views/search/_category.html.haml b/app/views/search/_category.html.haml
index df408e5fb60..ee7d89a9bd8 100644
--- a/app/views/search/_category.html.haml
+++ b/app/views/search/_category.html.haml
@@ -87,4 +87,5 @@
= _("Milestones")
%span.badge.badge-pill
= limited_count(@search_results.limited_milestones_count)
+ = render_if_exists 'search/category_elasticsearch'
= users
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/_issues.html.haml b/app/views/shared/_issues.html.haml
index 987a5d4f13f..a21dcabb485 100644
--- a/app/views/shared/_issues.html.haml
+++ b/app/views/shared/_issues.html.haml
@@ -1,6 +1,6 @@
- if @issues.to_a.any?
.card.card-small.card-without-border
- %ul.content-list.issues-list.issuable-list
+ %ul.content-list.issues-list.issuable-list{ class: ("manual-ordering" if @sort == 'relative_position'), data: { group_full_path: @group&.full_path } }
= render partial: 'projects/issues/issue', collection: @issues
= paginate @issues, theme: "gitlab"
- else
diff --git a/app/views/shared/_personal_access_tokens_created_container.html.haml b/app/views/shared/_personal_access_tokens_created_container.html.haml
index a8d3de66418..42989b145a2 100644
--- a/app/views/shared/_personal_access_tokens_created_container.html.haml
+++ b/app/views/shared/_personal_access_tokens_created_container.html.haml
@@ -1,5 +1,5 @@
-- container_title = local_assigns.fetch(:container_title, 'Your New Personal Access Token')
-- clipboard_button_title = local_assigns.fetch(:clipboard_button_title, 'Copy personal access token to clipboard')
+- container_title = local_assigns.fetch(:container_title, _('Your New Personal Access Token'))
+- clipboard_button_title = local_assigns.fetch(:clipboard_button_title, _('Copy personal access token to clipboard'))
.created-personal-access-token-container
%h5.prepend-top-0
@@ -9,6 +9,7 @@
= text_field_tag 'created-personal-access-token', new_token_value, readonly: true, class: "qa-created-personal-access-token form-control js-select-on-focus", 'aria-describedby' => "created-token-help-block"
%span.input-group-append
= clipboard_button(text: new_token_value, title: clipboard_button_title, placement: "left", class: "input-group-text btn-default btn-clipboard")
- %span#created-token-help-block.form-text.text-muted.text-danger Make sure you save it - you won't be able to access it again.
+ %span#created-token-help-block.form-text.text-muted.text-danger
+ = _("Make sure you save it - you won't be able to access it again.")
%hr
diff --git a/app/views/shared/_personal_access_tokens_form.html.haml b/app/views/shared/_personal_access_tokens_form.html.haml
index 0891b3459ec..1d96feda3b0 100644
--- a/app/views/shared/_personal_access_tokens_form.html.haml
+++ b/app/views/shared/_personal_access_tokens_form.html.haml
@@ -1,9 +1,9 @@
-- type = impersonation ? "impersonation" : "personal access"
+- type = impersonation ? s_('Profiles|impersonation') : s_('Profiles|personal access')
%h5.prepend-top-0
- Add a #{type} token
+ = _('Add a %{type} token') % { type: type }
%p.profile-settings-content
- Pick a name for the application, and we'll give you a unique #{type} token.
+ = _("Pick a name for the application, and we'll give you a unique %{type} token.") % { type: type }
= form_for token, url: path, method: :post, html: { class: 'js-requires-input' } do |f|
@@ -11,19 +11,19 @@
.row
.form-group.col-md-6
- = f.label :name, class: 'label-bold'
+ = f.label :name, _('Name'), class: 'label-bold'
= f.text_field :name, class: "form-control qa-personal-access-token-name-field", required: true
.row
.form-group.col-md-6
- = f.label :expires_at, class: 'label-bold'
+ = f.label :expires_at, _('Expires at'), class: 'label-bold'
.input-icon-wrapper
= f.text_field :expires_at, class: "datepicker form-control", placeholder: 'YYYY-MM-DD'
= icon('calendar', { class: 'input-icon-right' })
.form-group
- = f.label :scopes, class: 'label-bold'
+ = f.label :scopes, _('Scopes'), class: 'label-bold'
= render 'shared/tokens/scopes_form', prefix: 'personal_access_token', token: token, scopes: scopes
.prepend-top-default
- = f.submit "Create #{type} token", class: "btn btn-success qa-create-token-button"
+ = f.submit _('Create %{type} token') % { type: type }, class: "btn btn-success qa-create-token-button"
diff --git a/app/views/shared/_personal_access_tokens_table.html.haml b/app/views/shared/_personal_access_tokens_table.html.haml
index 49f3aae0f98..823117f37ca 100644
--- a/app/views/shared/_personal_access_tokens_table.html.haml
+++ b/app/views/shared/_personal_access_tokens_table.html.haml
@@ -1,20 +1,21 @@
-- type = impersonation ? "Impersonation" : "Personal Access"
+- type = impersonation ? s_('Profiles|Impersonation') : s_('Profiles|Personal Access')
%hr
-%h5 Active #{type} Tokens (#{active_tokens.length})
+%h5
+ = _('Active %{type} Tokens (%{token_length})') % { type: type, token_length: active_tokens.length }
- if impersonation
%p.profile-settings-content
- To see all the user's personal access tokens you must impersonate them first.
+ = _("To see all the user's personal access tokens you must impersonate them first.")
- if active_tokens.present?
.table-responsive
%table.table.active-tokens
%thead
%tr
- %th Name
- %th Created
- %th Expires
- %th Scopes
+ %th= _('Name')
+ %th= s_('AccessTokens|Created')
+ %th= _('Expires')
+ %th= _('Scopes')
%th
%tbody
- active_tokens.each do |token|
@@ -26,10 +27,10 @@
%span{ class: ('text-warning' if token.expires_soon?) }
In #{distance_of_time_in_words_to_now(token.expires_at)}
- else
- %span.token-never-expires-label Never
- %td= token.scopes.present? ? token.scopes.join(", ") : "<no scopes selected>"
+ %span.token-never-expires-label= _('Never')
+ %td= token.scopes.present? ? token.scopes.join(", ") : _('<no scopes selected>')
- path = impersonation ? revoke_admin_user_impersonation_token_path(token.user, token) : revoke_profile_personal_access_token_path(token)
- %td= link_to "Revoke", path, method: :put, class: "btn btn-danger float-right qa-revoke-button", data: { confirm: "Are you sure you want to revoke this #{type} Token? This action cannot be undone." }
+ %td= link_to _('Revoke'), path, method: :put, class: "btn btn-danger float-right qa-revoke-button", data: { confirm: _('Are you sure you want to revoke this %{type} Token? This action cannot be undone.') % { type: type } }
- else
.settings-message.text-center
- This user has no active #{type} Tokens.
+ = _('This user has no active %{type} Tokens.') % { type: type }
diff --git a/app/views/shared/boards/components/_board.html.haml b/app/views/shared/boards/components/_board.html.haml
index f9cfcabc015..6c0613605eb 100644
--- a/app/views/shared/boards/components/_board.html.haml
+++ b/app/views/shared/boards/components/_board.html.haml
@@ -1,52 +1,62 @@
.board.d-inline-block.h-100.px-2.align-top.ws-normal{ ":class" => '{ "is-draggable": !list.preset, "is-expandable": list.isExpandable, "is-collapsed": !list.isExpanded, "board-type-assignee": list.type === "assignee" }',
":data-id" => "list.id" }
.board-inner.d-flex.flex-column.position-relative.h-100.rounded
- %header.board-header{ ":class" => '{ "has-border": list.label && list.label.color, "position-relative": list.isExpanded, "position-absolute position-top-0 position-left-0 w-100 h-100": !list.isExpanded }', ":style" => "{ borderTopColor: (list.label && list.label.color ? list.label.color : null) }", "@click" => "toggleExpanded($event)" }
- %h3.board-title.m-0.d-flex.align-items-center.py-2.px-3.js-board-handle{ ":class" => '{ "user-can-drag": (!disabled && !list.preset), "p-0 border-bottom-0 justify-content-center": !list.isExpanded }' }
- %i.fa.fa-fw.board-title-expandable-toggle{ "v-if": "list.isExpandable",
- ":class": "{ \"fa-caret-down\": list.isExpanded, \"fa-caret-right\": !list.isExpanded }",
- "aria-hidden": "true" }
+ %header.board-header{ ":class" => '{ "has-border": list.label && list.label.color, "position-relative": list.isExpanded, "position-absolute position-top-0 position-left-0 w-100 h-100": !list.isExpanded }', ":style" => "{ borderTopColor: (list.label && list.label.color ? list.label.color : null) }" }
+ %h3.board-title.m-0.d-flex.js-board-handle{ ":class" => '{ "user-can-drag": (!disabled && !list.preset), "border-bottom-0": !list.isExpanded }' }
+
+ .board-title-caret.no-drag{ "v-if": "list.isExpandable",
+ "aria-hidden": "true",
+ ":aria-label": "caretTooltip",
+ ":title": "caretTooltip",
+ "v-tooltip": "",
+ data: { placement: "bottom" },
+ "@click": "toggleExpanded" }
+ %i.fa.fa-fw{ ":class": '{ "fa-caret-right": list.isExpanded, "fa-caret-down": !list.isExpanded }' }
= render_if_exists "shared/boards/components/list_milestone"
%a.user-avatar-link.js-no-trigger{ "v-if": "list.type === \"assignee\"", ":href": "list.assignee.path" }
-# haml-lint:disable AltText
%img.avatar.s20.has-tooltip{ height: "20", width: "20", ":src": "list.assignee.avatar", ":alt": "list.assignee.name" }
- %span.board-title-text.has-tooltip.block-truncated{ "v-if": "list.type !== \"label\"",
- ":title" => '((list.label && list.label.description) || list.title || "")', data: { container: "body" } }
- {{ list.title }}
+ .board-title-text
+ %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\"",
- ":title" => '(list.assignee && list.assignee.username || "")' }
- @{{ list.assignee.username }}
+ %span.board-title-sub-text.prepend-left-5.has-tooltip{ "v-if": "list.type === \"assignee\"",
+ ":title" => '(list.assignee && list.assignee.username || "")' }
+ @{{ list.assignee.username }}
- %span.has-tooltip{ "v-if": "list.type === \"label\"",
- ":title" => '(list.label ? list.label.description : "")',
- data: { container: "body", placement: "bottom" },
- class: "badge color-label title board-title-text",
- ":style" => "{ backgroundColor: (list.label && list.label.color ? list.label.color : null), color: (list.label && list.label.textColor ? list.label.textColor : \"#2e2e2e\") }" }
- {{ list.title }}
+ %span.has-tooltip.badge.color-label.title{ "v-if": "list.type === \"label\"",
+ ":title" => '(list.label ? list.label.description : "")',
+ data: { container: "body", placement: "bottom" },
+ ":style" => "{ backgroundColor: (list.label && list.label.color ? list.label.color : null), color: (list.label && list.label.textColor ? list.label.textColor : \"#2e2e2e\") }" }
+ {{ list.title }}
- if can?(current_user, :admin_list, current_board_parent)
%board-delete{ "inline-template" => true,
":list" => "list",
"v-if" => "!list.preset && list.id" }
- %button.board-delete.p-0.border-0.has-tooltip.float-right{ type: "button", title: _("Delete list"), ":class": "{ 'd-none': !list.isExpanded }", "aria-label" => _("Delete list"), data: { placement: "bottom" }, "@click.stop" => "deleteBoard" }
+ %button.board-delete.no-drag.p-0.border-0.has-tooltip.float-right{ type: "button", title: _("Delete list"), ":class": "{ 'd-none': !list.isExpanded }", "aria-label" => _("Delete list"), data: { placement: "bottom" }, "@click.stop" => "deleteBoard" }
= icon("trash")
- .issue-count-badge.text-secondary{ "v-if" => 'list.type !== "blank" && list.type !== "promotion"', ":title": "counterTooltip", ":class": "{ 'd-none': !list.isExpanded }", "v-tooltip": true, data: { placement: "top" } }
- %span.issue-count-badge-count
- %icon.mr-1{ name: "issues" }
- {{ list.issuesSize }}
- = render_if_exists "shared/boards/components/list_weight"
- %button.issue-count-badge-add-button.btn.btn-sm.btn-default.ml-1.has-tooltip.js-no-trigger-collapse{ type: "button",
+ .issue-count-badge.no-drag.text-secondary{ "v-if" => 'list.type !== "blank" && list.type !== "promotion"', ":title": "counterTooltip", "v-tooltip": true, data: { placement: "top" } }
+ %span.d-inline-flex
+ %span.issue-count-badge-count
+ %icon.mr-1{ name: "issues" }
+ {{ list.issuesSize }}
+ = render_if_exists "shared/boards/components/list_weight"
+
+ %button.issue-count-badge-add-button.no-drag.btn.btn-sm.btn-default.ml-1.has-tooltip{ type: "button",
"@click" => "showNewIssueForm",
"v-if" => "isNewIssueShown",
":class": "{ 'd-none': !list.isExpanded }",
"aria-label" => _("New issue"),
"title" => _("New issue"),
data: { placement: "top", container: "body" } }
- = icon("plus", class: "js-no-trigger-collapse")
+ = icon("plus")
%board-list{ "v-if" => 'list.type !== "blank" && list.type !== "promotion"',
":list" => "list",
diff --git a/app/views/shared/boards/components/sidebar/_time_tracker.html.haml b/app/views/shared/boards/components/sidebar/_time_tracker.html.haml
index b76d44c5907..43081499920 100644
--- a/app/views/shared/boards/components/sidebar/_time_tracker.html.haml
+++ b/app/views/shared/boards/components/sidebar/_time_tracker.html.haml
@@ -3,4 +3,5 @@
":time-spent" => "issue.timeSpent || 0",
":human-time-estimate" => "issue.humanTimeEstimate",
":human-time-spent" => "issue.humanTimeSpent",
+ ":limit-to-hours" => "timeTrackingLimitToHours",
"root-path" => "#{root_url}" }
diff --git a/app/views/shared/issuable/_form.html.haml b/app/views/shared/issuable/_form.html.haml
index c6a391ae563..1bd56e064d5 100644
--- a/app/views/shared/issuable/_form.html.haml
+++ b/app/views/shared/issuable/_form.html.haml
@@ -48,13 +48,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/_sort_dropdown.html.haml b/app/views/shared/issuable/_sort_dropdown.html.haml
index 1dd97bc4ed1..403e001bfe8 100644
--- a/app/views/shared/issuable/_sort_dropdown.html.haml
+++ b/app/views/shared/issuable/_sort_dropdown.html.haml
@@ -1,6 +1,7 @@
- sort_value = @sort
- sort_title = issuable_sort_option_title(sort_value)
- viewing_issues = controller.controller_name == 'issues' || controller.action_name == 'issues'
+- manual_sorting = viewing_issues && controller.controller_name != 'dashboard' && Feature.enabled?(:manual_sorting)
.dropdown.inline.prepend-left-10.issue-sort-dropdown
.btn-group{ role: 'group' }
@@ -17,6 +18,6 @@
= sortable_item(sort_title_due_date, page_filter_path(sort: sort_value_due_date), sort_title) if viewing_issues
= sortable_item(sort_title_popularity, page_filter_path(sort: sort_value_popularity), sort_title)
= sortable_item(sort_title_label_priority, page_filter_path(sort: sort_value_label_priority), sort_title)
- = sortable_item(sort_title_relative_position, page_filter_path(sort: sort_value_relative_position), sort_title) if viewing_issues && Feature.enabled?(:manual_sorting)
+ = sortable_item(sort_title_relative_position, page_filter_path(sort: sort_value_relative_position), sort_title) if manual_sorting
= render_if_exists('shared/ee/issuable/sort_dropdown', viewing_issues: viewing_issues, sort_title: sort_title)
= issuable_sort_direction_button(sort_value)
diff --git a/app/views/shared/milestones/_sidebar.html.haml b/app/views/shared/milestones/_sidebar.html.haml
index b24075c7849..ced6af50501 100644
--- a/app/views/shared/milestones/_sidebar.html.haml
+++ b/app/views/shared/milestones/_sidebar.html.haml
@@ -93,7 +93,11 @@
= milestone.issues_visible_to_user(current_user).closed.count
.block
- #issuable-time-tracker{ data: { time_estimate: @milestone.total_issue_time_estimate, time_spent: @milestone.total_issue_time_spent, human_time_estimate: @milestone.human_total_issue_time_estimate, human_time_spent: @milestone.human_total_issue_time_spent } }
+ #issuable-time-tracker{ data: { time_estimate: @milestone.total_issue_time_estimate,
+ time_spent: @milestone.total_issue_time_spent,
+ human_time_estimate: @milestone.human_total_issue_time_estimate,
+ human_time_spent: @milestone.human_total_issue_time_spent,
+ limit_to_hours: Gitlab::CurrentSettings.time_tracking_limit_to_hours.to_s } }
// Fallback while content is loading
.title.hide-collapsed
= _('Time tracking')
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/views/shared/projects/_list.html.haml b/app/views/shared/projects/_list.html.haml
index 13847cd9be1..576ec3e1782 100644
--- a/app/views/shared/projects/_list.html.haml
+++ b/app/views/shared/projects/_list.html.haml
@@ -28,7 +28,7 @@
.js-projects-list-holder
- if any_projects?(projects)
- - load_pipeline_status(projects)
+ - load_pipeline_status(projects) if pipeline_status
%ul.projects-list{ class: css_classes }
- projects.each_with_index do |project, i|
- css_class = (i >= projects_limit) || project.pending_delete? ? 'hide' : nil
diff --git a/app/views/shared/tokens/_scopes_list.html.haml b/app/views/shared/tokens/_scopes_list.html.haml
index f99e905e95c..428861485b4 100644
--- a/app/views/shared/tokens/_scopes_list.html.haml
+++ b/app/views/shared/tokens/_scopes_list.html.haml
@@ -4,7 +4,7 @@
%tr
%td
- Scopes
+ = _('Scopes')
%td
%ul.scopes-list.append-bottom-0
- token.scopes.each do |scope|
diff --git a/app/workers/all_queues.yml b/app/workers/all_queues.yml
index fd0cc5fb24e..3d34bfc05c7 100644
--- a/app/workers/all_queues.yml
+++ b/app/workers/all_queues.yml
@@ -9,6 +9,7 @@
- cronjob:import_export_project_cleanup
- cronjob:pages_domain_verification_cron
- cronjob:pages_domain_removal_cron
+- cronjob:pages_domain_ssl_renewal_cron
- cronjob:pipeline_schedule
- cronjob:prune_old_events
- cronjob:remove_expired_group_links
@@ -25,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
@@ -100,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
@@ -133,6 +138,7 @@
- new_note
- pages
- pages_domain_verification
+- pages_domain_ssl_renewal
- plugin
- post_receive
- process_commit
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/pages_domain_ssl_renewal_cron_worker.rb b/app/workers/pages_domain_ssl_renewal_cron_worker.rb
new file mode 100644
index 00000000000..40c34d29970
--- /dev/null
+++ b/app/workers/pages_domain_ssl_renewal_cron_worker.rb
@@ -0,0 +1,14 @@
+# frozen_string_literal: true
+
+class PagesDomainSslRenewalCronWorker
+ include ApplicationWorker
+ include CronjobQueue
+
+ def perform
+ PagesDomain.need_auto_ssl_renewal.find_each do |domain|
+ next unless ::Gitlab::LetsEncrypt.enabled?(domain)
+
+ PagesDomainSslRenewalWorker.perform_async(domain.id)
+ end
+ end
+end
diff --git a/app/workers/pages_domain_ssl_renewal_worker.rb b/app/workers/pages_domain_ssl_renewal_worker.rb
new file mode 100644
index 00000000000..b32458ca777
--- /dev/null
+++ b/app/workers/pages_domain_ssl_renewal_worker.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+class PagesDomainSslRenewalWorker
+ include ApplicationWorker
+
+ def perform(domain_id)
+ domain = PagesDomain.find_by_id(domain_id)
+ return unless domain&.enabled?
+ return unless ::Gitlab::LetsEncrypt.enabled?(domain)
+
+ ::PagesDomains::ObtainLetsEncryptCertificateService.new(domain).execute
+ end
+end
diff --git a/changelogs/unreleased/11039-moved-code-difference-from-EE-to-CE.yml b/changelogs/unreleased/11039-moved-code-difference-from-EE-to-CE.yml
new file mode 100644
index 00000000000..10c5eed9556
--- /dev/null
+++ b/changelogs/unreleased/11039-moved-code-difference-from-EE-to-CE.yml
@@ -0,0 +1,5 @@
+---
+title: "Moved EE/CE code differences for file `app/views/search/_category.html.haml` into CE"
+merge_request: 28755
+author: Michel Engelen
+type: other
diff --git a/changelogs/unreleased/11888-regression-deploy-correlation-markers-on-monitoring-graphs-not-clickable.yml b/changelogs/unreleased/11888-regression-deploy-correlation-markers-on-monitoring-graphs-not-clickable.yml
new file mode 100644
index 00000000000..606abe818b4
--- /dev/null
+++ b/changelogs/unreleased/11888-regression-deploy-correlation-markers-on-monitoring-graphs-not-clickable.yml
@@ -0,0 +1,5 @@
+---
+title: Turn commit sha in monitor charts popover to link
+merge_request: 29914
+author:
+type: fixed
diff --git a/changelogs/unreleased/30355-use-hours-only-for-time-tracking.yml b/changelogs/unreleased/30355-use-hours-only-for-time-tracking.yml
new file mode 100644
index 00000000000..b0252f9e81b
--- /dev/null
+++ b/changelogs/unreleased/30355-use-hours-only-for-time-tracking.yml
@@ -0,0 +1,5 @@
+---
+title: Add option to limit time tracking units to hours
+merge_request: 29469
+author: Jon Kolb
+type: added
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/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/44949-do-not-update-updated_at-on-an-issue-when-reordering-it.yml b/changelogs/unreleased/44949-do-not-update-updated_at-on-an-issue-when-reordering-it.yml
new file mode 100644
index 00000000000..efc6af7845c
--- /dev/null
+++ b/changelogs/unreleased/44949-do-not-update-updated_at-on-an-issue-when-reordering-it.yml
@@ -0,0 +1,5 @@
+---
+title: Will not update issue timestamps when changing positions in a list
+merge_request: 29677
+author:
+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/45120-fix-ide-editor-to-update-size-on-show-change.yml b/changelogs/unreleased/45120-fix-ide-editor-to-update-size-on-show-change.yml
new file mode 100644
index 00000000000..592612c2615
--- /dev/null
+++ b/changelogs/unreleased/45120-fix-ide-editor-to-update-size-on-show-change.yml
@@ -0,0 +1,5 @@
+---
+title: Fix IDE editor not showing when switching back from preview
+merge_request: 30135
+author:
+type: fixed
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/50834-change-http-status-code-when-repository-disabled.yml b/changelogs/unreleased/50834-change-http-status-code-when-repository-disabled.yml
new file mode 100644
index 00000000000..b51079d5c74
--- /dev/null
+++ b/changelogs/unreleased/50834-change-http-status-code-when-repository-disabled.yml
@@ -0,0 +1,5 @@
+---
+title: "Changed HTTP Status Code for disabled repository on /branches and /commits to 404"
+merge_request: 29585
+author: Sam Battalio
+type: changed
diff --git a/changelogs/unreleased/51952-forking-via-webide.yml b/changelogs/unreleased/51952-forking-via-webide.yml
new file mode 100644
index 00000000000..4497c6b6ca4
--- /dev/null
+++ b/changelogs/unreleased/51952-forking-via-webide.yml
@@ -0,0 +1,5 @@
+---
+title: Resolve "500 error when forking via the web IDE button"
+merge_request: 29909
+author:
+type: fixed
diff --git a/changelogs/unreleased/53811-issue-boards-to-core-projects-backend-ce.yml b/changelogs/unreleased/53811-issue-boards-to-core-projects-backend-ce.yml
new file mode 100644
index 00000000000..d8fbd7ec362
--- /dev/null
+++ b/changelogs/unreleased/53811-issue-boards-to-core-projects-backend-ce.yml
@@ -0,0 +1,5 @@
+---
+title: Move Multiple Issue Boards for Projects to Core
+merge_request:
+author:
+type: added
diff --git a/changelogs/unreleased/54595-incorrect-reaction-emoji-placement-in-discussion.yml b/changelogs/unreleased/54595-incorrect-reaction-emoji-placement-in-discussion.yml
new file mode 100644
index 00000000000..639eefb50cb
--- /dev/null
+++ b/changelogs/unreleased/54595-incorrect-reaction-emoji-placement-in-discussion.yml
@@ -0,0 +1,5 @@
+---
+title: Fix incorrect emoji placement in commit diff discussion
+merge_request: 29445
+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/58689-regroup-jump-button-in-discussion.yml b/changelogs/unreleased/58689-regroup-jump-button-in-discussion.yml
new file mode 100644
index 00000000000..bf6f314f0ce
--- /dev/null
+++ b/changelogs/unreleased/58689-regroup-jump-button-in-discussion.yml
@@ -0,0 +1,6 @@
+---
+title: Improve discussion reply buttons layout and how jump to next discussion button
+ appears
+merge_request: 29779
+author:
+type: changed
diff --git a/changelogs/unreleased/58802-rename-webide.yml b/changelogs/unreleased/58802-rename-webide.yml
new file mode 100644
index 00000000000..40471d967ce
--- /dev/null
+++ b/changelogs/unreleased/58802-rename-webide.yml
@@ -0,0 +1,5 @@
+---
+title: Re-name files in Web IDE in a more natural way
+merge_request: 29948
+author:
+type: changed
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/59702-fix-notification-flags-for-ms-teams.yml b/changelogs/unreleased/59702-fix-notification-flags-for-ms-teams.yml
deleted file mode 100644
index 14a8da95ed9..00000000000
--- a/changelogs/unreleased/59702-fix-notification-flags-for-ms-teams.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fix missing API notification flags for Microsoft Teams
-merge_request: 29824
-author: Seiji Suenaga
-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/60860-keep-empty-folders-in-tree.yml b/changelogs/unreleased/60860-keep-empty-folders-in-tree.yml
new file mode 100644
index 00000000000..237d0fd6aef
--- /dev/null
+++ b/changelogs/unreleased/60860-keep-empty-folders-in-tree.yml
@@ -0,0 +1,5 @@
+---
+title: Keep the empty folders in the tree
+merge_request: 29196
+author:
+type: fixed
diff --git a/changelogs/unreleased/60879-fix-reports-timing-out.yml b/changelogs/unreleased/60879-fix-reports-timing-out.yml
new file mode 100644
index 00000000000..845162fe10f
--- /dev/null
+++ b/changelogs/unreleased/60879-fix-reports-timing-out.yml
@@ -0,0 +1,5 @@
+---
+title: Fix reports jobs timing out because of cache
+merge_request: 29780
+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/61156-instance-level-cluster-pod-terminal-access.yml b/changelogs/unreleased/61156-instance-level-cluster-pod-terminal-access.yml
new file mode 100644
index 00000000000..0b8d301352b
--- /dev/null
+++ b/changelogs/unreleased/61156-instance-level-cluster-pod-terminal-access.yml
@@ -0,0 +1,5 @@
+---
+title: Enable terminals for instance and group clusters
+merge_request: 28613
+author:
+type: added
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/62826-graphql-emoji-mutations.yml b/changelogs/unreleased/62826-graphql-emoji-mutations.yml
new file mode 100644
index 00000000000..0c0aaedf844
--- /dev/null
+++ b/changelogs/unreleased/62826-graphql-emoji-mutations.yml
@@ -0,0 +1,5 @@
+---
+title: GraphQL mutations for add, remove and toggle emoji
+merge_request: 29919
+author:
+type: added
diff --git a/changelogs/unreleased/62938-wcag-aa-edited-text-color.yml b/changelogs/unreleased/62938-wcag-aa-edited-text-color.yml
new file mode 100644
index 00000000000..6652e495869
--- /dev/null
+++ b/changelogs/unreleased/62938-wcag-aa-edited-text-color.yml
@@ -0,0 +1,5 @@
+---
+title: Use darker gray color for system note metadata and edited text
+merge_request: 30054
+author:
+type: other
diff --git a/changelogs/unreleased/62968-environment-details-header-border-misaligned.yml b/changelogs/unreleased/62968-environment-details-header-border-misaligned.yml
new file mode 100644
index 00000000000..749fe6a9cb0
--- /dev/null
+++ b/changelogs/unreleased/62968-environment-details-header-border-misaligned.yml
@@ -0,0 +1,5 @@
+---
+title: Resolve Environment details header border misaligned
+merge_request: 30011
+author:
+type: fixed
diff --git a/changelogs/unreleased/63200-reply-button-broken.yml b/changelogs/unreleased/63200-reply-button-broken.yml
new file mode 100644
index 00000000000..11f81dbd925
--- /dev/null
+++ b/changelogs/unreleased/63200-reply-button-broken.yml
@@ -0,0 +1,5 @@
+---
+title: Fix unresponsive reply button in discussions
+merge_request: 29936
+author:
+type: fixed
diff --git a/changelogs/unreleased/63247-add-conf-toast-and-link.yml b/changelogs/unreleased/63247-add-conf-toast-and-link.yml
new file mode 100644
index 00000000000..915cc20dcc8
--- /dev/null
+++ b/changelogs/unreleased/63247-add-conf-toast-and-link.yml
@@ -0,0 +1,5 @@
+---
+title: Include a link back to the MR for Visual Review feedback form
+merge_request: 29719
+author:
+type: changed
diff --git a/changelogs/unreleased/63479-jira-capitalization.yml b/changelogs/unreleased/63479-jira-capitalization.yml
new file mode 100644
index 00000000000..a4cc32beba6
--- /dev/null
+++ b/changelogs/unreleased/63479-jira-capitalization.yml
@@ -0,0 +1,5 @@
+---
+title: Replace 'JIRA' with 'Jira'
+merge_request: 29849
+author: Takuya Noguchi
+type: other
diff --git a/changelogs/unreleased/63513-ensure-gitlab-jsoncache-includes-the-gitlab-version-in-the-cache-key.yml b/changelogs/unreleased/63513-ensure-gitlab-jsoncache-includes-the-gitlab-version-in-the-cache-key.yml
deleted file mode 100644
index b5715902630..00000000000
--- a/changelogs/unreleased/63513-ensure-gitlab-jsoncache-includes-the-gitlab-version-in-the-cache-key.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Include the GitLab version in the cache key for Gitlab::JsonCache
-merge_request: 29938
-author:
-type: fixed
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/63656-runner-tags-search-dropdown-is-empty.yml b/changelogs/unreleased/63656-runner-tags-search-dropdown-is-empty.yml
new file mode 100644
index 00000000000..08c415f4a1c
--- /dev/null
+++ b/changelogs/unreleased/63656-runner-tags-search-dropdown-is-empty.yml
@@ -0,0 +1,5 @@
+---
+title: Fix runner tags search dropdown being empty when there are tags
+merge_request: 29985
+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/add-clusters-to-deployment.yml b/changelogs/unreleased/add-clusters-to-deployment.yml
new file mode 100644
index 00000000000..c85bd3635cc
--- /dev/null
+++ b/changelogs/unreleased/add-clusters-to-deployment.yml
@@ -0,0 +1,5 @@
+---
+title: Persist the cluster a deployment was deployed to
+merge_request: 29960
+author:
+type: fixed
diff --git a/changelogs/unreleased/add-metrics-dashboard-permission-check.yml b/changelogs/unreleased/add-metrics-dashboard-permission-check.yml
new file mode 100644
index 00000000000..0ea2c4c8e41
--- /dev/null
+++ b/changelogs/unreleased/add-metrics-dashboard-permission-check.yml
@@ -0,0 +1,5 @@
+---
+title: Add permission check to metrics dashboards endpoint
+merge_request: 30017
+author:
+type: added
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/always-allow-prometheus-access-in-dev.yml b/changelogs/unreleased/always-allow-prometheus-access-in-dev.yml
new file mode 100644
index 00000000000..acd944ea684
--- /dev/null
+++ b/changelogs/unreleased/always-allow-prometheus-access-in-dev.yml
@@ -0,0 +1,5 @@
+---
+title: Always allow access to health endpoints from localhost in dev
+merge_request: 29930
+author:
+type: other
diff --git a/changelogs/unreleased/always-display-environment-selector.yml b/changelogs/unreleased/always-display-environment-selector.yml
new file mode 100644
index 00000000000..7a55e8f3e5d
--- /dev/null
+++ b/changelogs/unreleased/always-display-environment-selector.yml
@@ -0,0 +1,5 @@
+---
+title: Fix broken environment selector and always display it on monitoring dashboard
+merge_request: 29705
+author:
+type: fixed
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/bug-63162-duplicate_path_in_links.yml b/changelogs/unreleased/bug-63162-duplicate_path_in_links.yml
deleted file mode 100644
index d3f246492fb..00000000000
--- a/changelogs/unreleased/bug-63162-duplicate_path_in_links.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fixed 'diff version changes' link not working
-merge_request: 29825
-author:
-type: fixed
diff --git a/changelogs/unreleased/ce-11098-update-merge-request-settings-description-text.yml b/changelogs/unreleased/ce-11098-update-merge-request-settings-description-text.yml
new file mode 100644
index 00000000000..9f6a2040095
--- /dev/null
+++ b/changelogs/unreleased/ce-11098-update-merge-request-settings-description-text.yml
@@ -0,0 +1,5 @@
+---
+title: Update merge requests section description text on project settings page
+merge_request: 27838
+author:
+type: changed \ No newline at end of file
diff --git a/changelogs/unreleased/check-min-schema-migrate.yml b/changelogs/unreleased/check-min-schema-migrate.yml
new file mode 100644
index 00000000000..d0f4ae1f5d7
--- /dev/null
+++ b/changelogs/unreleased/check-min-schema-migrate.yml
@@ -0,0 +1,5 @@
+---
+title: Added a min schema version check to db:migrate
+merge_request: 29882
+author:
+type: added
diff --git a/changelogs/unreleased/dohtaset.yml b/changelogs/unreleased/dohtaset.yml
new file mode 100644
index 00000000000..5b917bd06d8
--- /dev/null
+++ b/changelogs/unreleased/dohtaset.yml
@@ -0,0 +1,5 @@
+---
+title: Fix charts on Cluster health page
+merge_request: 30073
+author:
+type: fixed
diff --git a/changelogs/unreleased/dz-remove-deprecated-user-routes.yml b/changelogs/unreleased/dz-remove-deprecated-user-routes.yml
new file mode 100644
index 00000000000..92c2e39dd20
--- /dev/null
+++ b/changelogs/unreleased/dz-remove-deprecated-user-routes.yml
@@ -0,0 +1,5 @@
+---
+title: Remove depreated /u/:username routing
+merge_request: 30044
+author:
+type: removed
diff --git a/changelogs/unreleased/fe-issue-reorder.yml b/changelogs/unreleased/fe-issue-reorder.yml
new file mode 100644
index 00000000000..aca334b6149
--- /dev/null
+++ b/changelogs/unreleased/fe-issue-reorder.yml
@@ -0,0 +1,5 @@
+---
+title: Bring Manual Ordering on Issue List
+merge_request: 29410
+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-jupyter-git-v3.yml b/changelogs/unreleased/fix-jupyter-git-v3.yml
new file mode 100644
index 00000000000..8aaaaf249fb
--- /dev/null
+++ b/changelogs/unreleased/fix-jupyter-git-v3.yml
@@ -0,0 +1,5 @@
+---
+title: Fix Jupyter-Git integration
+merge_request: 30020
+author: Amit Rathi
+type: fixed
diff --git a/changelogs/unreleased/fix-labels-in-hooks.yml b/changelogs/unreleased/fix-labels-in-hooks.yml
deleted file mode 100644
index c0904a860c5..00000000000
--- a/changelogs/unreleased/fix-labels-in-hooks.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fix label serialization in issue and note hooks
-merge_request: 29850
-author:
-type: fixed
diff --git a/changelogs/unreleased/fix-notes-emails-with-group-settings.yml b/changelogs/unreleased/fix-notes-emails-with-group-settings.yml
deleted file mode 100644
index 77dae8418a8..00000000000
--- a/changelogs/unreleased/fix-notes-emails-with-group-settings.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fix comment emails not respecting group-level notification email
-merge_request:
-author:
-type: fixed
diff --git a/changelogs/unreleased/gitaly-version-v1.49.0.yml b/changelogs/unreleased/gitaly-version-v1.49.0.yml
new file mode 100644
index 00000000000..8795bab0209
--- /dev/null
+++ b/changelogs/unreleased/gitaly-version-v1.49.0.yml
@@ -0,0 +1,5 @@
+---
+title: Upgrade to Gitaly v1.49.0
+merge_request: 29990
+author:
+type: changed
diff --git a/changelogs/unreleased/graphql-tree-last-commit.yml b/changelogs/unreleased/graphql-tree-last-commit.yml
new file mode 100644
index 00000000000..5104ca6687e
--- /dev/null
+++ b/changelogs/unreleased/graphql-tree-last-commit.yml
@@ -0,0 +1,5 @@
+---
+title: Added commit type to tree GraphQL response
+merge_request: 29412
+author:
+type: added
diff --git a/changelogs/unreleased/id-extract-widget-into-different-request.yml b/changelogs/unreleased/id-extract-widget-into-different-request.yml
new file mode 100644
index 00000000000..3b9f5fdd6bd
--- /dev/null
+++ b/changelogs/unreleased/id-extract-widget-into-different-request.yml
@@ -0,0 +1,5 @@
+---
+title: Add a separate endpoint for fetching MRs serialized as widgets
+merge_request: 29979
+author:
+type: performance
diff --git a/changelogs/unreleased/id-stale-branches.yml b/changelogs/unreleased/id-stale-branches.yml
new file mode 100644
index 00000000000..2f35c5a12c9
--- /dev/null
+++ b/changelogs/unreleased/id-stale-branches.yml
@@ -0,0 +1,5 @@
+---
+title: Add endpoint for fetching diverging commit counts
+merge_request: 29802
+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/mh-collapsible-boards.yml b/changelogs/unreleased/mh-collapsible-boards.yml
new file mode 100644
index 00000000000..b69d6e81cc4
--- /dev/null
+++ b/changelogs/unreleased/mh-collapsible-boards.yml
@@ -0,0 +1,5 @@
+---
+title: Labeled issue boards can now collapse
+merge_request: 29955
+author:
+type: added
diff --git a/changelogs/unreleased/mh-colon-autocomplete.yml b/changelogs/unreleased/mh-colon-autocomplete.yml
new file mode 100644
index 00000000000..8b169c22588
--- /dev/null
+++ b/changelogs/unreleased/mh-colon-autocomplete.yml
@@ -0,0 +1,5 @@
+---
+title: Allow auto-completing scoped labels
+merge_request: 29749
+author:
+type: added
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/po-raw-changes-encoding.yml b/changelogs/unreleased/po-raw-changes-encoding.yml
new file mode 100644
index 00000000000..051d18f50c7
--- /dev/null
+++ b/changelogs/unreleased/po-raw-changes-encoding.yml
@@ -0,0 +1,5 @@
+---
+title: Expect bytes from Gitaly RPC GetRawChanges
+merge_request: 28164
+author:
+type: fixed
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/refactor-sentry.yml b/changelogs/unreleased/refactor-sentry.yml
new file mode 100644
index 00000000000..25c5534fae0
--- /dev/null
+++ b/changelogs/unreleased/refactor-sentry.yml
@@ -0,0 +1,5 @@
+---
+title: Remove Sentry from application settings
+merge_request: 28447
+author: Roger Meier
+type: added
diff --git a/changelogs/unreleased/remove_group_and_instance_clusters_feature_flag.yml b/changelogs/unreleased/remove_group_and_instance_clusters_feature_flag.yml
new file mode 100644
index 00000000000..fcc6c564345
--- /dev/null
+++ b/changelogs/unreleased/remove_group_and_instance_clusters_feature_flag.yml
@@ -0,0 +1,5 @@
+---
+title: Remove group and instance clusters feature flag
+merge_request: 30124
+author:
+type: changed
diff --git a/changelogs/unreleased/require-pipeline-when-enabling-only-allow-merge-if-pipeline-succeeds.yml b/changelogs/unreleased/require-pipeline-when-enabling-only-allow-merge-if-pipeline-succeeds.yml
new file mode 100644
index 00000000000..c105287532b
--- /dev/null
+++ b/changelogs/unreleased/require-pipeline-when-enabling-only-allow-merge-if-pipeline-succeeds.yml
@@ -0,0 +1,5 @@
+---
+title: Enforce presence of pipeline when "Pipeline must succeed" project setting is enabled
+merge_request: 29926
+author:
+type: fixed
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/set-higher-ttl-for-trace-write.yml b/changelogs/unreleased/set-higher-ttl-for-trace-write.yml
new file mode 100644
index 00000000000..9f17172100c
--- /dev/null
+++ b/changelogs/unreleased/set-higher-ttl-for-trace-write.yml
@@ -0,0 +1,5 @@
+---
+title: Set higher TTL for write lock of trace to prevent concurrent archiving
+merge_request: 30064
+author:
+type: fixed
diff --git a/changelogs/unreleased/sh-add-force-random-password-user-api.yml b/changelogs/unreleased/sh-add-force-random-password-user-api.yml
new file mode 100644
index 00000000000..29f36978a0f
--- /dev/null
+++ b/changelogs/unreleased/sh-add-force-random-password-user-api.yml
@@ -0,0 +1,5 @@
+---
+title: Add support for creating random passwords in user creation API
+merge_request: 30138
+author:
+type: changed
diff --git a/changelogs/unreleased/sh-add-gitaly-ref-caching-search-controller.yml b/changelogs/unreleased/sh-add-gitaly-ref-caching-search-controller.yml
new file mode 100644
index 00000000000..d4be28e9883
--- /dev/null
+++ b/changelogs/unreleased/sh-add-gitaly-ref-caching-search-controller.yml
@@ -0,0 +1,5 @@
+---
+title: Enable Gitaly ref caching for SearchController
+merge_request: 30105
+author:
+type: performance
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-avoid-loading-pipeline-status.yml b/changelogs/unreleased/sh-avoid-loading-pipeline-status.yml
new file mode 100644
index 00000000000..2dead948786
--- /dev/null
+++ b/changelogs/unreleased/sh-avoid-loading-pipeline-status.yml
@@ -0,0 +1,5 @@
+---
+title: Avoid loading pipeline status in search results
+merge_request: 30111
+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-cache-negative-entries-find-commit.yml b/changelogs/unreleased/sh-cache-negative-entries-find-commit.yml
new file mode 100644
index 00000000000..98eb13ee620
--- /dev/null
+++ b/changelogs/unreleased/sh-cache-negative-entries-find-commit.yml
@@ -0,0 +1,5 @@
+---
+title: Allow caching of negative FindCommit matches
+merge_request: 29952
+author:
+type: performance
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-handle-nil-replication-lag.yml b/changelogs/unreleased/sh-handle-nil-replication-lag.yml
new file mode 100644
index 00000000000..5638d7e79e3
--- /dev/null
+++ b/changelogs/unreleased/sh-handle-nil-replication-lag.yml
@@ -0,0 +1,5 @@
+---
+title: Fix background migrations failing with unused replication slot
+merge_request: 30042
+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-omit-issues-links-on-poll.yml b/changelogs/unreleased/sh-omit-issues-links-on-poll.yml
deleted file mode 100644
index 21e51d3534f..00000000000
--- a/changelogs/unreleased/sh-omit-issues-links-on-poll.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Omit issues links in merge request entity API response
-merge_request: 29917
-author:
-type: performance
diff --git a/changelogs/unreleased/sh-optimize-todos-controller.yml b/changelogs/unreleased/sh-optimize-todos-controller.yml
new file mode 100644
index 00000000000..181ddd1b3bc
--- /dev/null
+++ b/changelogs/unreleased/sh-optimize-todos-controller.yml
@@ -0,0 +1,5 @@
+---
+title: Eliminate N+1 queries in Dashboard::TodosController
+merge_request: 29954
+author:
+type: performance
diff --git a/changelogs/unreleased/sh-service-template-bug.yml b/changelogs/unreleased/sh-service-template-bug.yml
new file mode 100644
index 00000000000..1ea5ac84f26
--- /dev/null
+++ b/changelogs/unreleased/sh-service-template-bug.yml
@@ -0,0 +1,5 @@
+---
+title: Disable Rails SQL query cache when applying service templates
+merge_request: 30060
+author:
+type: fixed
diff --git a/changelogs/unreleased/sh-support-subnets-ip-rate-limiter.yml b/changelogs/unreleased/sh-support-subnets-ip-rate-limiter.yml
new file mode 100644
index 00000000000..3e78c58c764
--- /dev/null
+++ b/changelogs/unreleased/sh-support-subnets-ip-rate-limiter.yml
@@ -0,0 +1,5 @@
+---
+title: Support CIDR notation in IP rate limiter
+merge_request: 30146
+author:
+type: changed
diff --git a/changelogs/unreleased/sh-update-mermaid.yml b/changelogs/unreleased/sh-update-mermaid.yml
new file mode 100644
index 00000000000..9a7726cf716
--- /dev/null
+++ b/changelogs/unreleased/sh-update-mermaid.yml
@@ -0,0 +1,5 @@
+---
+title: Update Mermaid to 8.1.0
+merge_request: 30036
+author:
+type: fixed
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/small-s-in-elasticsearch-in-code.yml b/changelogs/unreleased/small-s-in-elasticsearch-in-code.yml
new file mode 100644
index 00000000000..20d7a822cde
--- /dev/null
+++ b/changelogs/unreleased/small-s-in-elasticsearch-in-code.yml
@@ -0,0 +1,5 @@
+---
+title: Fix typo in code comments about Elasticsearch
+merge_request: 30163
+author: Takuya Noguchi
+type: other
diff --git a/changelogs/unreleased/small-s-in-elasticsearch.yml b/changelogs/unreleased/small-s-in-elasticsearch.yml
new file mode 100644
index 00000000000..7cab5c37125
--- /dev/null
+++ b/changelogs/unreleased/small-s-in-elasticsearch.yml
@@ -0,0 +1,5 @@
+---
+title: Fix typo in docs about Elasticsearch
+merge_request: 30162
+author: Takuya Noguchi
+type: other
diff --git a/changelogs/unreleased/support-jsonb-default-value.yml b/changelogs/unreleased/support-jsonb-default-value.yml
new file mode 100644
index 00000000000..d46156276f9
--- /dev/null
+++ b/changelogs/unreleased/support-jsonb-default-value.yml
@@ -0,0 +1,5 @@
+---
+title: Support jsonb default in add_column_with_default migration helper
+merge_request: 29871
+author:
+type: other
diff --git a/changelogs/unreleased/tc-rake-orphan-artifacts.yml b/changelogs/unreleased/tc-rake-orphan-artifacts.yml
new file mode 100644
index 00000000000..7081bee640a
--- /dev/null
+++ b/changelogs/unreleased/tc-rake-orphan-artifacts.yml
@@ -0,0 +1,5 @@
+---
+title: Add rake task to clean orphan artifact files
+merge_request: 29681
+author:
+type: added
diff --git a/changelogs/unreleased/transaction-metrics.yml b/changelogs/unreleased/transaction-metrics.yml
new file mode 100644
index 00000000000..8b6e9c7d9d1
--- /dev/null
+++ b/changelogs/unreleased/transaction-metrics.yml
@@ -0,0 +1,5 @@
+---
+title: Adds metrics to measure cost of expensive operations
+merge_request: 29928
+author:
+type: other
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-gitlab-runner-helm-chart-to-0-6-0.yml b/changelogs/unreleased/update-gitlab-runner-helm-chart-to-0-6-0.yml
new file mode 100644
index 00000000000..6719fa94b19
--- /dev/null
+++ b/changelogs/unreleased/update-gitlab-runner-helm-chart-to-0-6-0.yml
@@ -0,0 +1,5 @@
+---
+title: Update GitLab Runner Helm Chart to 0.6.0
+merge_request: 29982
+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-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/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/gitlab.yml.example b/config/gitlab.yml.example
index dddc5ec3540..c82d9b5ceef 100644
--- a/config/gitlab.yml.example
+++ b/config/gitlab.yml.example
@@ -1078,7 +1078,7 @@ test:
issues_url: "http://redmine/:project_id/:issues_tracker_id/:id"
new_issue_url: "http://redmine/projects/:issues_tracker_id/issues/new"
jira:
- title: "JIRA"
+ title: "Jira"
url: https://sample_company.atlassian.net
project_key: PROJECT
diff --git a/config/initializers/0_inflections.rb b/config/initializers/0_inflections.rb
index 1ad9ddca877..4d1f4917275 100644
--- a/config/initializers/0_inflections.rb
+++ b/config/initializers/0_inflections.rb
@@ -14,6 +14,14 @@ ActiveSupport::Inflector.inflections do |inflect|
award_emoji
project_statistics
system_note_metadata
+ event_log
project_auto_devops
+ project_registry
+ file_registry
+ job_artifact_registry
+ vulnerability_feedback
+ vulnerabilities_feedback
+ group_view
)
+ inflect.acronym 'EE'
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 6cca7a3b75f..bf187e9a282 100644
--- a/config/initializers/1_settings.rb
+++ b/config/initializers/1_settings.rb
@@ -5,6 +5,13 @@ require_relative '../object_store_settings'
Settings['ldap'] ||= Settingslogic.new({})
Settings.ldap['enabled'] = false if Settings.ldap['enabled'].nil?
+Gitlab.ee do
+ Settings.ldap['sync_time'] = 3600 if Settings.ldap['sync_time'].nil?
+ Settings.ldap['schedule_sync_daily'] = 1 if Settings.ldap['schedule_sync_daily'].nil?
+ Settings.ldap['schedule_sync_hour'] = 1 if Settings.ldap['schedule_sync_hour'].nil?
+ Settings.ldap['schedule_sync_minute'] = 30 if Settings.ldap['schedule_sync_minute'].nil?
+end
+
# backwards compatibility, we only have one host
if Settings.ldap['enabled'] || Rails.env.test?
if Settings.ldap['host'].present?
@@ -23,11 +30,14 @@ if Settings.ldap['enabled'] || Rails.env.test?
server['timeout'] ||= 10.seconds
server['block_auto_created_users'] = false if server['block_auto_created_users'].nil?
server['allow_username_or_email_login'] = false if server['allow_username_or_email_login'].nil?
+ server['smartcard_auth'] = false unless %w[optional required].include?(server['smartcard_auth'])
server['active_directory'] = true if server['active_directory'].nil?
server['attributes'] = {} if server['attributes'].nil?
server['lowercase_usernames'] = false if server['lowercase_usernames'].nil?
server['provider_name'] ||= "ldap#{key}".downcase
server['provider_class'] = OmniAuth::Utils.camelize(server['provider_name'])
+ server['external_groups'] = [] if server['external_groups'].nil?
+ server['sync_ssh_keys'] = 'sshPublicKey' if server['sync_ssh_keys'].to_s == 'true'
# For backwards compatibility
server['encryption'] ||= server['method']
@@ -62,6 +72,12 @@ if Settings.ldap['enabled'] || Rails.env.test?
end
end
+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?
+end
+
Settings['omniauth'] ||= Settingslogic.new({})
Settings.omniauth['enabled'] = true if Settings.omniauth['enabled'].nil?
Settings.omniauth['auto_sign_in_with_provider'] = false if Settings.omniauth['auto_sign_in_with_provider'].nil?
@@ -136,6 +152,7 @@ Settings['issues_tracker'] ||= {}
#
Settings['gitlab'] ||= Settingslogic.new({})
Settings.gitlab['default_project_creation'] ||= ::Gitlab::Access::DEVELOPER_MAINTAINER_PROJECT_ACCESS
+Settings.gitlab['default_project_deletion_protection'] ||= false
Settings.gitlab['default_projects_limit'] ||= 100000
Settings.gitlab['default_branch_protection'] ||= 2
Settings.gitlab['default_can_create_group'] = true if Settings.gitlab['default_can_create_group'].nil?
@@ -186,6 +203,21 @@ Settings.gitlab['no_todos_messages'] ||= YAML.load_file(Rails.root.join('config'
Settings.gitlab['impersonation_enabled'] ||= true if Settings.gitlab['impersonation_enabled'].nil?
Settings.gitlab['usage_ping_enabled'] = true if Settings.gitlab['usage_ping_enabled'].nil?
+Gitlab.ee do
+ Settings.gitlab['mirror_max_delay'] ||= 300
+ Settings.gitlab['mirror_max_capacity'] ||= 30
+ Settings.gitlab['mirror_capacity_threshold'] ||= 15
+end
+
+#
+# Elasticseacrh
+#
+Gitlab.ee do
+ Settings['elasticsearch'] ||= Settingslogic.new({})
+ Settings.elasticsearch['enabled'] = false if Settings.elasticsearch['enabled'].nil?
+ Settings.elasticsearch['url'] = ENV['ELASTIC_URL'] || "http://localhost:9200"
+end
+
#
# CI
#
@@ -255,6 +287,15 @@ Settings.pages['admin'] ||= Settingslogic.new({})
Settings.pages.admin['certificate'] ||= ''
#
+# Geo
+#
+Gitlab.ee do
+ Settings['geo'] ||= Settingslogic.new({})
+ # For backwards compatibility, default to gitlab_url and if so, ensure it ends with "/"
+ Settings.geo['node_name'] = Settings.geo['node_name'].presence || Settings.gitlab['url'].chomp('/').concat('/')
+end
+
+#
# External merge request diffs
#
Settings['external_diffs'] ||= Settingslogic.new({})
@@ -281,6 +322,32 @@ Settings.uploads['object_store'] = ObjectStoreSettings.parse(Settings.uploads['o
Settings.uploads['object_store']['remote_directory'] ||= 'uploads'
#
+# Packages
+#
+Gitlab.ee do
+ Settings['packages'] ||= Settingslogic.new({})
+ Settings.packages['enabled'] = true if Settings.packages['enabled'].nil?
+ Settings.packages['storage_path'] = Settings.absolute(Settings.packages['storage_path'] || File.join(Settings.shared['path'], "packages"))
+ Settings.packages['object_store'] = ObjectStoreSettings.parse(Settings.packages['object_store'])
+end
+
+#
+# Dependency Proxy
+#
+Gitlab.ee do
+ Settings['dependency_proxy'] ||= Settingslogic.new({})
+ Settings.dependency_proxy['enabled'] = true if Settings.dependency_proxy['enabled'].nil?
+ Settings.dependency_proxy['storage_path'] = Settings.absolute(Settings.dependency_proxy['storage_path'] || File.join(Settings.shared['path'], "dependency_proxy"))
+ Settings.dependency_proxy['object_store'] = ObjectStoreSettings.parse(Settings.dependency_proxy['object_store'])
+
+ # For first iteration dependency proxy uses Rails server to download blobs.
+ # To ensure acceptable performance we only allow feature to be used with
+ # multithreaded web-server Puma. This will be removed once download logic is moved
+ # to GitLab workhorse
+ Settings.dependency_proxy['enabled'] = false unless defined?(::Puma)
+end
+
+#
# Mattermost
#
Settings['mattermost'] ||= Settingslogic.new({})
@@ -341,7 +408,6 @@ Settings.cron_jobs['remove_expired_group_links_worker']['job_class'] = 'RemoveEx
Settings.cron_jobs['prune_old_events_worker'] ||= Settingslogic.new({})
Settings.cron_jobs['prune_old_events_worker']['cron'] ||= '0 */6 * * *'
Settings.cron_jobs['prune_old_events_worker']['job_class'] = 'PruneOldEventsWorker'
-
Settings.cron_jobs['trending_projects_worker'] ||= Settingslogic.new({})
Settings.cron_jobs['trending_projects_worker']['cron'] = '0 1 * * *'
Settings.cron_jobs['trending_projects_worker']['job_class'] = 'TrendingProjectsWorker'
@@ -354,30 +420,72 @@ Settings.cron_jobs['stuck_import_jobs_worker']['job_class'] = 'StuckImportJobsWo
Settings.cron_jobs['gitlab_usage_ping_worker'] ||= Settingslogic.new({})
Settings.cron_jobs['gitlab_usage_ping_worker']['cron'] ||= Settings.__send__(:cron_for_usage_ping)
Settings.cron_jobs['gitlab_usage_ping_worker']['job_class'] = 'GitlabUsagePingWorker'
-
Settings.cron_jobs['stuck_merge_jobs_worker'] ||= Settingslogic.new({})
Settings.cron_jobs['stuck_merge_jobs_worker']['cron'] ||= '0 */2 * * *'
Settings.cron_jobs['stuck_merge_jobs_worker']['job_class'] = 'StuckMergeJobsWorker'
-
Settings.cron_jobs['pages_domain_verification_cron_worker'] ||= Settingslogic.new({})
Settings.cron_jobs['pages_domain_verification_cron_worker']['cron'] ||= '*/15 * * * *'
Settings.cron_jobs['pages_domain_verification_cron_worker']['job_class'] = 'PagesDomainVerificationCronWorker'
-
Settings.cron_jobs['pages_domain_removal_cron_worker'] ||= Settingslogic.new({})
Settings.cron_jobs['pages_domain_removal_cron_worker']['cron'] ||= '47 0 * * *'
Settings.cron_jobs['pages_domain_removal_cron_worker']['job_class'] = 'PagesDomainRemovalCronWorker'
-
+Settings.cron_jobs['pages_domain_ssl_renewal_cron_worker'] ||= Settingslogic.new({})
+Settings.cron_jobs['pages_domain_ssl_renewal_cron_worker']['cron'] ||= '*/10 * * * *'
+Settings.cron_jobs['pages_domain_ssl_renewal_cron_worker']['job_class'] = 'PagesDomainSslRenewalCronWorker'
Settings.cron_jobs['issue_due_scheduler_worker'] ||= Settingslogic.new({})
Settings.cron_jobs['issue_due_scheduler_worker']['cron'] ||= '50 00 * * *'
Settings.cron_jobs['issue_due_scheduler_worker']['job_class'] = 'IssueDueSchedulerWorker'
-
Settings.cron_jobs['prune_web_hook_logs_worker'] ||= Settingslogic.new({})
Settings.cron_jobs['prune_web_hook_logs_worker']['cron'] ||= '0 */1 * * *'
Settings.cron_jobs['prune_web_hook_logs_worker']['job_class'] = 'PruneWebHookLogsWorker'
-
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({})
+ Settings.cron_jobs['clear_shared_runners_minutes_worker']['cron'] ||= '0 0 1 * *'
+ Settings.cron_jobs['clear_shared_runners_minutes_worker']['job_class'] = 'ClearSharedRunnersMinutesWorker'
+ Settings.cron_jobs['geo_file_download_dispatch_worker'] ||= Settingslogic.new({})
+ Settings.cron_jobs['geo_file_download_dispatch_worker']['cron'] ||= '*/1 * * * *'
+ Settings.cron_jobs['geo_file_download_dispatch_worker']['job_class'] ||= 'Geo::FileDownloadDispatchWorker'
+ Settings.cron_jobs['geo_metrics_update_worker'] ||= Settingslogic.new({})
+ Settings.cron_jobs['geo_metrics_update_worker']['cron'] ||= '*/1 * * * *'
+ Settings.cron_jobs['geo_metrics_update_worker']['job_class'] ||= 'Geo::MetricsUpdateWorker'
+ Settings.cron_jobs['geo_migrated_local_files_clean_up_worker'] ||= Settingslogic.new({})
+ Settings.cron_jobs['geo_migrated_local_files_clean_up_worker']['cron'] ||= '15 */6 * * *'
+ Settings.cron_jobs['geo_migrated_local_files_clean_up_worker']['job_class'] ||= 'Geo::MigratedLocalFilesCleanUpWorker'
+ Settings.cron_jobs['geo_prune_event_log_worker'] ||= Settingslogic.new({})
+ Settings.cron_jobs['geo_prune_event_log_worker']['cron'] ||= '*/5 * * * *'
+ Settings.cron_jobs['geo_prune_event_log_worker']['job_class'] ||= 'Geo::PruneEventLogWorker'
+ Settings.cron_jobs['geo_repository_sync_worker'] ||= Settingslogic.new({})
+ Settings.cron_jobs['geo_repository_sync_worker']['cron'] ||= '*/1 * * * *'
+ Settings.cron_jobs['geo_repository_sync_worker']['job_class'] ||= 'Geo::RepositorySyncWorker'
+ Settings.cron_jobs['geo_repository_verification_primary_batch_worker'] ||= Settingslogic.new({})
+ Settings.cron_jobs['geo_repository_verification_primary_batch_worker']['cron'] ||= '*/1 * * * *'
+ Settings.cron_jobs['geo_repository_verification_primary_batch_worker']['job_class'] ||= 'Geo::RepositoryVerification::Primary::BatchWorker'
+ Settings.cron_jobs['geo_repository_verification_secondary_scheduler_worker'] ||= Settingslogic.new({})
+ Settings.cron_jobs['geo_repository_verification_secondary_scheduler_worker']['cron'] ||= '*/1 * * * *'
+ Settings.cron_jobs['geo_repository_verification_secondary_scheduler_worker']['job_class'] ||= 'Geo::RepositoryVerification::Secondary::SchedulerWorker'
+ Settings.cron_jobs['historical_data_worker'] ||= Settingslogic.new({})
+ Settings.cron_jobs['historical_data_worker']['cron'] ||= '0 12 * * *'
+ Settings.cron_jobs['historical_data_worker']['job_class'] = 'HistoricalDataWorker'
+ Settings.cron_jobs['ldap_group_sync_worker'] ||= Settingslogic.new({})
+ Settings.cron_jobs['ldap_group_sync_worker']['cron'] ||= '0 * * * *'
+ Settings.cron_jobs['ldap_group_sync_worker']['job_class'] = 'LdapAllGroupsSyncWorker'
+ Settings.cron_jobs['ldap_sync_worker'] ||= Settingslogic.new({})
+ Settings.cron_jobs['ldap_sync_worker']['cron'] ||= '30 1 * * *'
+ Settings.cron_jobs['ldap_sync_worker']['job_class'] = 'LdapSyncWorker'
+ Settings.cron_jobs['pseudonymizer_worker'] ||= Settingslogic.new({})
+ Settings.cron_jobs['pseudonymizer_worker']['cron'] ||= '0 23 * * *'
+ Settings.cron_jobs['pseudonymizer_worker']['job_class'] ||= 'PseudonymizerWorker'
+ Settings.cron_jobs['update_max_seats_used_for_gitlab_com_subscriptions_worker'] ||= Settingslogic.new({})
+ Settings.cron_jobs['update_max_seats_used_for_gitlab_com_subscriptions_worker']['cron'] ||= '0 12 * * *'
+ Settings.cron_jobs['update_max_seats_used_for_gitlab_com_subscriptions_worker']['job_class'] = 'UpdateMaxSeatsUsedForGitlabComSubscriptionsWorker'
+end
#
# Sidekiq
@@ -458,6 +566,16 @@ Settings.backup['upload']['encryption_key'] ||= ENV['GITLAB_BACKUP_ENCRYPTION_KE
Settings.backup['upload']['storage_class'] ||= nil
#
+# Pseudonymizer
+#
+Gitlab.ee do
+ Settings['pseudonymizer'] ||= Settingslogic.new({})
+ Settings.pseudonymizer['manifest'] = Settings.absolute(Settings.pseudonymizer['manifest'] || Rails.root.join("config/pseudonymizer.yml"))
+ Settings.pseudonymizer['upload'] ||= Settingslogic.new({ 'remote_directory' => nil, 'connection' => nil })
+ # Settings.pseudonymizer['upload']['multipart_chunk_size'] ||= 104857600
+end
+
+#
# Git
#
Settings['git'] ||= Settingslogic.new({})
@@ -470,6 +588,23 @@ Settings['satellites'] ||= Settingslogic.new({})
Settings.satellites['path'] = Settings.absolute(Settings.satellites['path'] || "tmp/repo_satellites/")
#
+# Kerberos
+#
+Gitlab.ee do
+ Settings['kerberos'] ||= Settingslogic.new({})
+ Settings.kerberos['enabled'] = false if Settings.kerberos['enabled'].nil?
+ Settings.kerberos['keytab'] = nil if Settings.kerberos['keytab'].blank? # nil means use default keytab
+ Settings.kerberos['service_principal_name'] = nil if Settings.kerberos['service_principal_name'].blank? # nil means any SPN in keytab
+ Settings.kerberos['use_dedicated_port'] = false if Settings.kerberos['use_dedicated_port'].nil?
+ Settings.kerberos['https'] = Settings.gitlab.https if Settings.kerberos['https'].nil?
+ Settings.kerberos['port'] ||= Settings.kerberos.https ? 8443 : 8088
+
+ if Settings.kerberos['enabled'] && !Settings.omniauth.providers.map(&:name).include?('kerberos_spnego')
+ Settings.omniauth.providers << Settingslogic.new({ 'name' => 'kerberos_spnego' })
+ end
+end
+
+#
# Extra customization
#
Settings['extra'] ||= 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/forbid_sidekiq_in_transactions.rb b/config/initializers/forbid_sidekiq_in_transactions.rb
index deb94d7dbce..a69f1ba090e 100644
--- a/config/initializers/forbid_sidekiq_in_transactions.rb
+++ b/config/initializers/forbid_sidekiq_in_transactions.rb
@@ -17,7 +17,7 @@ module Sidekiq
module NoEnqueueingFromTransactions
%i(perform_async perform_at perform_in).each do |name|
define_method(name) do |*args|
- if !Sidekiq::Worker.skip_transaction_check && AfterCommitQueue.inside_transaction?
+ if !Sidekiq::Worker.skip_transaction_check && Gitlab::Database.inside_transaction?
begin
raise Sidekiq::Worker::EnqueueFromTransactionError, <<~MSG
`#{self}.#{name}` cannot be called inside a transaction as this can lead to
diff --git a/config/initializers/jira.rb b/config/initializers/jira.rb
index 05f784a6a2a..664f9c87808 100644
--- a/config/initializers/jira.rb
+++ b/config/initializers/jira.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-# Changes JIRA DVCS user agent requests in order to be successfully handled
+# Changes Jira DVCS user agent requests in order to be successfully handled
# by our API.
#
# Gitlab::Jira::Middleware is only defined on EE
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..338e968cc6c 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 req.env['rack.attack.matched'] != 'throttle_unauthenticated'
+ 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/sentry.rb b/config/initializers/sentry.rb
index e5589ce0ad1..fcc6bfa5c92 100644
--- a/config/initializers/sentry.rb
+++ b/config/initializers/sentry.rb
@@ -3,18 +3,11 @@
require 'gitlab/current_settings'
def configure_sentry
- # allow it to fail: it may do so when create_from_defaults is executed before migrations are actually done
- begin
- sentry_enabled = Gitlab::CurrentSettings.current_application_settings.sentry_enabled
- rescue
- sentry_enabled = false
- end
-
- if sentry_enabled
+ if Gitlab::Sentry.enabled?
Raven.configure do |config|
- config.dsn = Gitlab::CurrentSettings.current_application_settings.sentry_dsn
+ config.dsn = Gitlab.config.sentry.dsn
config.release = Gitlab.revision
- config.current_environment = Gitlab.config.sentry.environment.presence
+ config.current_environment = Gitlab.config.sentry.environment
# Sanitize fields based on those sanitized from Rails.
config.sanitize_fields = Rails.application.config.filter_parameters.map(&:to_s)
diff --git a/config/initializers/transaction_metrics.rb b/config/initializers/transaction_metrics.rb
new file mode 100644
index 00000000000..0175d487e66
--- /dev/null
+++ b/config/initializers/transaction_metrics.rb
@@ -0,0 +1,3 @@
+# frozen_string_literal: true
+
+Gitlab::Database.install_monkey_patches
diff --git a/config/routes.rb b/config/routes.rb
index cb90a0134c4..a42fc037227 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -27,10 +27,16 @@ Rails.application.routes.draw do
authorizations: 'oauth/authorizations'
end
- # This is here so we can "reserve" the path for the Jira integration in GitLab EE
- # Having a non-existent controller here does not affect the scope in any way since all possible routes
- # get a 404 proc returned. It is written in this way to minimize merge conflicts with EE
+ # This prefixless path is required because Jira gets confused if we set it up with a path
+ # More information: https://gitlab.com/gitlab-org/gitlab-ee/issues/6752
scope path: '/login/oauth', controller: 'oauth/jira/authorizations', as: :oauth_jira do
+ Gitlab.ee do
+ get :authorize, action: :new
+ get :callback
+ post :access_token
+ end
+
+ # This helps minimize merge conflicts with CE for this scope block
match '*all', via: [:get, :post], to: proc { [404, {}, ['']] }
end
@@ -45,6 +51,10 @@ Rails.application.routes.draw do
get '/autocomplete/award_emojis' => 'autocomplete#award_emojis'
get '/autocomplete/merge_request_target_branches' => 'autocomplete#merge_request_target_branches'
+ Gitlab.ee do
+ get '/autocomplete/project_groups' => 'autocomplete#project_groups'
+ end
+
# Search
get 'search' => 'search#show'
get 'search/autocomplete' => 'search#autocomplete', as: :search_autocomplete
@@ -73,6 +83,11 @@ Rails.application.routes.draw do
end
resources :issues, module: :boards, only: [:index, :update]
+
+ Gitlab.ee do
+ resources :users, module: :boards, only: [:index]
+ resources :milestones, module: :boards, only: [:index]
+ end
end
get 'acme-challenge/' => 'acme_challenges#show'
@@ -86,6 +101,11 @@ Rails.application.routes.draw do
draw :operations
draw :instance_statistics
+ Gitlab.ee do
+ draw :smartcard
+ draw :jira_connect
+ end
+
if ENV['GITLAB_ENABLE_CHAOS_ENDPOINTS']
get '/chaos/leakmem' => 'chaos#leakmem'
get '/chaos/cpuspin' => 'chaos#cpuspin'
@@ -102,6 +122,10 @@ Rails.application.routes.draw do
end
member do
+ Gitlab.ee do
+ get :metrics, format: :json
+ end
+
scope :applications do
post '/:application', to: 'clusters/applications#create', as: :install_applications
patch '/:application', to: 'clusters/applications#update', as: :update_applications
diff --git a/config/routes/api.rb b/config/routes/api.rb
index 3719b7d3a1e..3ba9176d943 100644
--- a/config/routes/api.rb
+++ b/config/routes/api.rb
@@ -3,5 +3,5 @@ constraints(::Constraints::FeatureConstrainer.new(:graphql, default_enabled: tru
mount GraphiQL::Rails::Engine, at: '/-/graphql-explorer', graphql_path: '/api/graphql'
end
-API::API.logger Rails.logger
-mount API::API => '/'
+::API::API.logger Rails.logger
+mount ::API::API => '/'
diff --git a/config/routes/profile.rb b/config/routes/profile.rb
index 0e213b0b989..83a2b33514b 100644
--- a/config/routes/profile.rb
+++ b/config/routes/profile.rb
@@ -40,6 +40,15 @@ resource :profile, only: [:show, :update] do
put :resend_confirmation_instructions
end
end
+
+ Gitlab.ee do
+ resource :slack, only: [:edit] do
+ member do
+ get :slack_link
+ end
+ end
+ end
+
resources :chat_names, only: [:index, :new, :create, :destroy] do
collection do
delete :deny
@@ -63,5 +72,10 @@ resource :profile, only: [:show, :update] do
end
resources :u2f_registrations, only: [:destroy]
+
+ Gitlab.ee do
+ resources :pipeline_quota, only: [:index]
+ resources :billings, only: [:index]
+ end
end
end
diff --git a/config/routes/project.rb b/config/routes/project.rb
index 0e8e089c78a..c202463dadb 100644
--- a/config/routes/project.rb
+++ b/config/routes/project.rb
@@ -79,12 +79,22 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
resource :operations, only: [:show, :update]
resource :integrations, only: [:show]
+ Gitlab.ee do
+ resource :slack, only: [:destroy, :edit, :update] do
+ get :slack_auth
+ end
+ end
+
resource :repository, only: [:show], controller: :repository do
post :create_deploy_token, path: 'deploy_token/create'
post :cleanup
end
end
+ Gitlab.ee do
+ resources :feature_flags
+ end
+
resources :autocomplete_sources, only: [] do
collection do
get 'members'
@@ -155,7 +165,11 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
end
end
- resources :boards, only: [:index, :show], constraints: { id: /\d+/ }
+ resources :boards, only: [:index, :show, :create, :update, :destroy], constraints: { id: /\d+/ } do
+ collection do
+ get :recent
+ end
+ end
resources :releases, only: [:index]
resources :forks, only: [:index, :new, :create]
resources :group_links, only: [:index, :create, :update, :destroy], constraints: { id: /\d+/ }
@@ -168,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
@@ -199,8 +216,18 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
resource :mattermost, only: [:new, :create]
namespace :prometheus do
- resources :metrics, constraints: { id: %r{[^\/]+} }, only: [] do
+ resources :metrics, constraints: { id: %r{[^\/]+} }, only: [:index, :new, :create, :edit, :update, :destroy] do
get :active_common, on: :collection
+
+ Gitlab.ee do
+ post :validate_query, on: :collection
+ end
+ end
+
+ Gitlab.ee do
+ resources :alerts, constraints: { id: /\d+/ }, only: [:index, :create, :show, :update, :destroy] do
+ post :notify, on: :collection
+ end
end
end
@@ -212,6 +239,15 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
get :pipeline_status
get :ci_environments_status
post :toggle_subscription
+
+ Gitlab.ee do
+ get :approvals
+ post :approvals, action: :approve
+ delete :approvals, action: :unapprove
+
+ post :rebase
+ end
+
post :remove_wip
post :assign_related_issues
get :discussions, format: :json
@@ -228,6 +264,7 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
get :commits
get :pipelines
get :diffs, to: 'merge_requests/diffs#show'
+ get :widget, to: 'merge_requests/content#widget'
end
get :diff_for_path, controller: 'merge_requests/diffs'
@@ -244,6 +281,21 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
post :bulk_update
end
+ Gitlab.ee do
+ resources :approvers, only: :destroy
+ delete 'approvers', to: 'approvers#destroy_via_user_id', as: :approver_via_user_id
+ resources :approver_groups, only: :destroy
+
+ scope module: :merge_requests do
+ resources :drafts, only: [:index, :update, :create, :destroy] do
+ collection do
+ post :publish
+ delete :discard
+ end
+ end
+ end
+ end
+
resources :discussions, only: [:show], constraints: { id: /\h{40}/ } do
member do
post :resolve
@@ -274,6 +326,17 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
end
end
+ Gitlab.ee do
+ resources :path_locks, only: [:index, :destroy] do
+ collection do
+ post :toggle
+ end
+ end
+
+ get '/service_desk' => 'service_desk#show', as: :service_desk
+ put '/service_desk' => 'service_desk#update', as: :service_desk_refresh
+ end
+
resource :variables, only: [:show, :update]
resources :triggers, only: [:index, :create, :edit, :update, :destroy] do
@@ -289,6 +352,10 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
end
end
+ Gitlab.ee do
+ resources :push_rules, constraints: { id: /\d+/ }, only: [:update]
+ end
+
resources :pipelines, only: [:index, :new, :create, :show] do
collection do
resource :pipelines_settings, path: 'settings', only: [:show, :update]
@@ -303,6 +370,11 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
get :builds
get :failures
get :status
+
+ Gitlab.ee do
+ get :security
+ get :licenses
+ end
end
member do
@@ -331,6 +403,10 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
get '/terminal.ws/authorize', to: 'environments#terminal_websocket_authorize', constraints: { format: nil }
get '/prometheus/api/v1/*proxy_path', to: 'environments/prometheus_api#proxy', as: :prometheus_api
+
+ Gitlab.ee do
+ get :logs
+ end
end
collection do
@@ -347,6 +423,14 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
end
end
+ Gitlab.ee do
+ resources :protected_environments, only: [:create, :update, :destroy], constraints: { id: /\d+/ } do
+ collection do
+ get 'search'
+ end
+ end
+ end
+
resource :cycle_analytics, only: [:show]
namespace :cycle_analytics do
@@ -399,6 +483,14 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
end
end
+ Gitlab.ee do
+ namespace :security do
+ resource :dashboard, only: [:show], controller: :dashboard
+ end
+
+ resources :vulnerability_feedback, only: [:index, :create, :update, :destroy], constraints: { id: /\d+/ }
+ end
+
get :issues, to: 'issues#calendar', constraints: lambda { |req| req.format == :ics }
resources :issues, concerns: :awardable, constraints: { id: /\d+/ } do
@@ -417,6 +509,15 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
collection do
post :bulk_update
post :import_csv
+
+ Gitlab.ee do
+ post :export_csv
+ get :service_desk
+ end
+ end
+
+ Gitlab.ee do
+ resources :issue_links, only: [:index, :create, :destroy], as: 'links', path: 'links'
end
end
@@ -451,6 +552,11 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
end
end
+ Gitlab.ee do
+ resources :approvers, only: :destroy
+ resources :approver_groups, only: :destroy
+ end
+
resources :runner_projects, only: [:create, :destroy]
resources :badges, only: [:index] do
collection do
@@ -465,6 +571,10 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
end
end
+ Gitlab.ee do
+ resources :audit_events, only: [:index]
+ end
+
resources :error_tracking, only: [:index], controller: :error_tracking do
collection do
post :list_projects
@@ -475,6 +585,10 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
# its preferable to keep it below all other project routes
draw :wiki
draw :repository
+
+ Gitlab.ee do
+ resources :managed_licenses, only: [:index, :show, :new, :create, :edit, :update, :destroy]
+ end
end
resources(:projects,
diff --git a/config/routes/repository.rb b/config/routes/repository.rb
index b96315bfe8b..b89e1c7f9af 100644
--- a/config/routes/repository.rb
+++ b/config/routes/repository.rb
@@ -52,13 +52,16 @@ scope format: false do
end
get '/branches/:state', to: 'branches#index', as: :branches_filtered, constraints: { state: /active|stale|all/ }
- resources :branches, only: [:index, :new, :create, :destroy]
+ resources :branches, only: [:index, :new, :create, :destroy] do
+ get :diverging_commit_counts, on: :collection
+ end
+
delete :merged_branches, controller: 'branches', action: :destroy_all_merged
resources :tags, only: [:index, :show, :new, :create, :destroy] do
resource :release, controller: 'tags/releases', only: [:edit, :update]
end
- resources :protected_branches, only: [:index, :show, :create, :update, :destroy]
+ resources :protected_branches, only: [:index, :show, :create, :update, :destroy, :patch], constraints: { id: Gitlab::PathRegex.git_reference_regex }
resources :protected_tags, only: [:index, :show, :create, :update, :destroy]
end
diff --git a/config/routes/snippets.rb b/config/routes/snippets.rb
index 81bc890d86b..ba6da3ac57e 100644
--- a/config/routes/snippets.rb
+++ b/config/routes/snippets.rb
@@ -17,5 +17,5 @@ resources :snippets, concerns: :awardable do
end
end
-get '/s/:username', to: redirect('u/%{username}/snippets'),
+get '/s/:username', to: redirect('users/%{username}/snippets'),
constraints: { username: /[a-zA-Z.0-9_\-]+(?<!\.atom)/ }
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/routes/user.rb b/config/routes/user.rb
index e0ae264e2c0..80f266aa8f9 100644
--- a/config/routes/user.rb
+++ b/config/routes/user.rb
@@ -1,3 +1,8 @@
+Gitlab.ee do
+ get 'unsubscribes/:email', to: 'unsubscribes#show', as: :unsubscribe
+ post 'unsubscribes/:email', to: 'unsubscribes#create'
+end
+
# Allows individual providers to be directed to a chosen controller
# Call from inside devise_scope
def override_omniauth(provider, controller, path_prefix = '/users/auth')
@@ -25,6 +30,17 @@ devise_for :users, controllers: { omniauth_callbacks: :omniauth_callbacks,
devise_scope :user do
get '/users/auth/:provider/omniauth_error' => 'omniauth_callbacks#omniauth_error', as: :omniauth_error
get '/users/almost_there' => 'confirmations#almost_there'
+
+ Gitlab.ee do
+ get '/users/auth/kerberos_spnego/negotiate' => 'omniauth_kerberos_spnego#negotiate'
+ end
+end
+
+scope '-/users', module: :users do
+ resources :terms, only: [:index] do
+ post :accept, on: :member
+ post :decline, on: :member
+ end
end
scope '-/users', module: :users do
@@ -48,15 +64,6 @@ scope(constraints: { username: Gitlab::PathRegex.root_namespace_route_regex }) d
get :activity
get '/', to: redirect('%{username}'), as: nil
end
-
- # Compatibility with old routing
- # TODO (dzaporozhets): remove in 10.0
- get '/u/:username', to: redirect('%{username}')
- # TODO (dzaporozhets): remove in 9.0
- get '/u/:username/groups', to: redirect('users/%{username}/groups')
- get '/u/:username/projects', to: redirect('users/%{username}/projects')
- get '/u/:username/snippets', to: redirect('users/%{username}/snippets')
- get '/u/:username/contributed', to: redirect('users/%{username}/contributed')
end
constraints(::Constraints::UserUrlConstrainer.new) do
diff --git a/config/sidekiq_queues.yml b/config/sidekiq_queues.yml
index 4fda9d69077..80791795390 100644
--- a/config/sidekiq_queues.yml
+++ b/config/sidekiq_queues.yml
@@ -72,6 +72,7 @@
- [project_rollback_hashed_storage, 1]
- [hashed_storage, 1]
- [pages_domain_verification, 1]
+ - [pages_domain_ssl_renewal, 1]
- [object_storage_upload, 1]
- [object_storage, 1]
- [plugin, 1]
@@ -93,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/danger/only_documentation/Dangerfile b/danger/only_documentation/Dangerfile
new file mode 100644
index 00000000000..8e4564f22b6
--- /dev/null
+++ b/danger/only_documentation/Dangerfile
@@ -0,0 +1,24 @@
+# rubocop:disable Style/SignalException
+# frozen_string_literal: true
+
+has_only_docs_changes = helper.all_changed_files.all? { |file| file.start_with?('doc/') }
+is_docs_only_branch = gitlab.branch_for_head =~ /(^docs[\/-].*|.*-docs$)/
+
+if is_docs_only_branch && !has_only_docs_changes
+ fail "It seems like your branch name has a `docs` prefix or suffix. "\
+ "The CI won't run the full pipeline, but you also have changed non-docs files. "\
+ "Please recreate this MR with a new branch name."
+end
+
+if has_only_docs_changes && !is_docs_only_branch
+ markdown(<<~MARKDOWN)
+
+ ## Documentation only changes
+
+ Hey! Seems your merge request contains only docs changes.
+ Tired of waiting 2 hours for the pipeline to finish?
+ Next time, prepend `docs-` to [your branch name](https://docs.gitlab.com/ee/development/documentation/#branch-naming)
+ and the pipeline will finish before you say GitLab (x300)!
+
+ MARKDOWN
+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/20190402150158_backport_enterprise_schema.rb b/db/migrate/20190402150158_backport_enterprise_schema.rb
index 610a8808383..8762cc53ed7 100644
--- a/db/migrate/20190402150158_backport_enterprise_schema.rb
+++ b/db/migrate/20190402150158_backport_enterprise_schema.rb
@@ -117,6 +117,8 @@ class BackportEnterpriseSchema < ActiveRecord::Migration[5.0]
end
def up
+ check_schema!
+
create_missing_tables
update_appearances
@@ -868,6 +870,52 @@ class BackportEnterpriseSchema < ActiveRecord::Migration[5.0]
remove_column_if_exists(:geo_nodes, :internal_url)
end
+ # Some users may have upgraded to EE at some point but downgraded to
+ # CE v11.11.3. As a result, their EE tables may not be in the right
+ # state. Here we check for these such cases and attempt to guide the
+ # user into recovering from this state by upgrading to v11.11.3 EE
+ # before installing v12.0.0 CE.
+ def check_schema!
+ # The following cases will fail later when this migration attempts
+ # to add a foreign key for non-existent columns.
+ columns_to_check = [
+ [:epics, :parent_id], # Added in GitLab 11.7
+ [:geo_event_log, :cache_invalidation_event_id], # Added in GitLab 11.4
+ [:vulnerability_feedback, :merge_request_id] # Added in GitLab 11.9
+ ].freeze
+
+ columns_to_check.each do |table, column|
+ check_ee_columns!(table, column)
+ end
+ end
+
+ def check_ee_columns!(table, column)
+ return unless table_exists?(table)
+ return if column_exists?(table, column)
+
+ raise_ee_migration_error!(table, column)
+ end
+
+ def raise_ee_migration_error!(table, column)
+ message = "Your database is missing the '#{column}' column from the '#{table}' table that is present for GitLab EE."
+
+ message +=
+ if ::Gitlab.ee?
+ "\nUpgrade your GitLab instance to 11.11.3 EE first!"
+ else
+ <<~MSG
+
+ Even though it looks like you're running a CE installation, it appears
+ you may have installed GitLab EE at some point. To migrate to GitLab 12.0:
+
+ 1. Install GitLab 11.11.3 EE
+ 2. Install GitLab 12.0.x CE
+ MSG
+ end
+
+ raise Exception.new(message)
+ end
+
def create_missing_tables
create_table_if_not_exists "approval_merge_request_rule_sources", id: :bigserial do |t|
t.bigint "approval_merge_request_rule_id", null: false
diff --git a/db/migrate/20190513174947_enable_create_incident_issues_by_default.rb b/db/migrate/20190513174947_enable_create_incident_issues_by_default.rb
new file mode 100644
index 00000000000..ecd466627fe
--- /dev/null
+++ b/db/migrate/20190513174947_enable_create_incident_issues_by_default.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+class EnableCreateIncidentIssuesByDefault < ActiveRecord::Migration[5.1]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ def change
+ change_default_for :create_issue, from: false, to: true
+ change_default_for :send_email, from: true, to: false
+ end
+
+ private
+
+ def change_default_for(column, from:, to:)
+ change_column_default :project_incident_management_settings,
+ column, from: from, to: to
+ end
+end
diff --git a/db/migrate/20190531153110_create_namespace_root_storage_statistics.rb b/db/migrate/20190531153110_create_namespace_root_storage_statistics.rb
new file mode 100644
index 00000000000..702560d05cc
--- /dev/null
+++ b/db/migrate/20190531153110_create_namespace_root_storage_statistics.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+class CreateNamespaceRootStorageStatistics < ActiveRecord::Migration[5.1]
+ DOWNTIME = false
+
+ def change
+ create_table :namespace_root_storage_statistics, id: false, primary_key: :namespace_id do |t|
+ t.integer :namespace_id, null: false, primary_key: true
+ t.datetime_with_timezone :updated_at, null: false
+
+ t.bigint :repository_size, null: false, default: 0
+ t.bigint :lfs_objects_size, null: false, default: 0
+ t.bigint :wiki_size, null: false, default: 0
+ t.bigint :build_artifacts_size, null: false, default: 0
+ t.bigint :storage_size, null: false, default: 0
+ t.bigint :packages_size, null: false, default: 0
+
+ t.index :namespace_id, unique: true
+ t.foreign_key :namespaces, column: :namespace_id, on_delete: :cascade
+ end
+ end
+end
diff --git a/db/migrate/20190605184422_create_namespace_aggregation_schedules.rb b/db/migrate/20190605184422_create_namespace_aggregation_schedules.rb
new file mode 100644
index 00000000000..5e8cb616cc1
--- /dev/null
+++ b/db/migrate/20190605184422_create_namespace_aggregation_schedules.rb
@@ -0,0 +1,14 @@
+# frozen_string_literal: true
+
+class CreateNamespaceAggregationSchedules < ActiveRecord::Migration[5.1]
+ DOWNTIME = false
+
+ def change
+ create_table :namespace_aggregation_schedules, id: false, primary_key: :namespace_id do |t|
+ t.integer :namespace_id, null: false, primary_key: true
+
+ t.index :namespace_id, unique: true
+ t.foreign_key :namespaces, column: :namespace_id, on_delete: :cascade
+ end
+ end
+end
diff --git a/db/migrate/20190607145325_add_pages_domains_ssl_renew_index.rb b/db/migrate/20190607145325_add_pages_domains_ssl_renew_index.rb
new file mode 100644
index 00000000000..7167accbf1e
--- /dev/null
+++ b/db/migrate/20190607145325_add_pages_domains_ssl_renew_index.rb
@@ -0,0 +1,25 @@
+# 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 AddPagesDomainsSslRenewIndex < ActiveRecord::Migration[5.1]
+ include Gitlab::Database::MigrationHelpers
+
+ # Set this constant to true if this migration requires downtime.
+ DOWNTIME = false
+
+ INDEX_NAME = 'index_pages_domains_need_auto_ssl_renewal'
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_index(:pages_domains, [:certificate_source, :certificate_valid_not_after],
+ where: "auto_ssl_enabled = #{::Gitlab::Database.true_value}", name: INDEX_NAME)
+ end
+
+ def down
+ remove_concurrent_index(:pages_domains, [:certificate_source, :certificate_valid_not_after],
+ where: "auto_ssl_enabled = #{::Gitlab::Database.true_value}", name: INDEX_NAME)
+ end
+end
diff --git a/db/migrate/20190611090827_add_time_tracking_limit_to_hours_to_application_settings.rb b/db/migrate/20190611090827_add_time_tracking_limit_to_hours_to_application_settings.rb
new file mode 100644
index 00000000000..a5f8925c1db
--- /dev/null
+++ b/db/migrate/20190611090827_add_time_tracking_limit_to_hours_to_application_settings.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+# See http://doc.gitlab.com/ce/development/migration_style_guide.html
+# for more information on how to write migrations for GitLab.
+
+class AddTimeTrackingLimitToHoursToApplicationSettings < ActiveRecord::Migration[5.1]
+ 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, :time_tracking_limit_to_hours, :boolean, default: false, allow_null: false
+ end
+
+ def down
+ remove_column :application_settings, :time_tracking_limit_to_hours
+ 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/20190613073003_create_project_aliases.rb b/db/migrate/20190613073003_create_project_aliases.rb
new file mode 100644
index 00000000000..5a2c2ba0cf2
--- /dev/null
+++ b/db/migrate/20190613073003_create_project_aliases.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+class CreateProjectAliases < ActiveRecord::Migration[5.1]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ def change
+ create_table :project_aliases do |t|
+ t.references :project, null: false, index: true, foreign_key: { on_delete: :cascade }, type: :integer
+ t.string :name, null: false, index: { unique: true }
+
+ t.timestamps_with_timezone null: false
+ end
+ 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/20190623212503_add_cluster_id_to_deployments.rb b/db/migrate/20190623212503_add_cluster_id_to_deployments.rb
new file mode 100644
index 00000000000..cd0c4191568
--- /dev/null
+++ b/db/migrate/20190623212503_add_cluster_id_to_deployments.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+class AddClusterIdToDeployments < ActiveRecord::Migration[5.1]
+ DOWNTIME = false
+
+ def change
+ add_column :deployments, :cluster_id, :integer
+ 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/20190627051902_add_cluster_id_index_fk_to_deployments.rb b/db/migrate/20190627051902_add_cluster_id_index_fk_to_deployments.rb
new file mode 100644
index 00000000000..f41e5c80269
--- /dev/null
+++ b/db/migrate/20190627051902_add_cluster_id_index_fk_to_deployments.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+class AddClusterIdIndexFkToDeployments < ActiveRecord::Migration[5.1]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_index :deployments, :cluster_id
+
+ add_concurrent_foreign_key :deployments, :clusters, column: :cluster_id, on_delete: :nullify
+ end
+
+ def down
+ remove_foreign_key :deployments, :clusters
+
+ remove_concurrent_index :deployments, :cluster_id
+ 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/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/post_migrate/20190625184066_remove_sentry_from_application_settings.rb b/db/post_migrate/20190625184066_remove_sentry_from_application_settings.rb
new file mode 100644
index 00000000000..427df343193
--- /dev/null
+++ b/db/post_migrate/20190625184066_remove_sentry_from_application_settings.rb
@@ -0,0 +1,38 @@
+# 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 RemoveSentryFromApplicationSettings < ActiveRecord::Migration[5.0]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ SENTRY_ENABLED_COLUMNS = [
+ :sentry_enabled,
+ :clientside_sentry_enabled
+ ].freeze
+
+ SENTRY_DSN_COLUMNS = [
+ :sentry_dsn,
+ :clientside_sentry_dsn
+ ].freeze
+
+ disable_ddl_transaction!
+
+ def up
+ (SENTRY_ENABLED_COLUMNS + SENTRY_DSN_COLUMNS).each do |column|
+ remove_column(:application_settings, column) if column_exists?(:application_settings, column)
+ end
+ end
+
+ def down
+ SENTRY_ENABLED_COLUMNS.each do |column|
+ add_column_with_default(:application_settings, column, :boolean, default: false, allow_null: false) unless column_exists?(:application_settings, column)
+ end
+
+ SENTRY_DSN_COLUMNS.each do |column|
+ add_column(:application_settings, column, :string) unless column_exists?(:application_settings, column)
+ end
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index f6cf2ee07e3..4bcc8b5f1d7 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: 20190620112608) do
+ActiveRecord::Schema.define(version: 20190628185004) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -93,8 +93,6 @@ ActiveRecord::Schema.define(version: 20190620112608) do
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
@@ -135,8 +133,6 @@ ActiveRecord::Schema.define(version: 20190620112608) do
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: true, null: false
t.boolean "help_page_hide_commercial_content", default: false
t.string "help_page_support_url"
@@ -197,6 +193,7 @@ ActiveRecord::Schema.define(version: 20190620112608) 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
@@ -229,6 +226,8 @@ ActiveRecord::Schema.define(version: 20190620112608) do
t.integer "custom_project_templates_group_id"
t.boolean "elasticsearch_limit_indexing", default: false, null: false
t.string "geo_node_allowed_ips", default: "0.0.0.0/0, ::/0"
+ t.boolean "time_tracking_limit_to_hours", default: false, null: false
+ t.string "grafana_url", default: "/-/grafana", null: false
t.index ["custom_project_templates_group_id"], name: "index_application_settings_on_custom_project_templates_group_id", using: :btree
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
@@ -1050,6 +1049,7 @@ ActiveRecord::Schema.define(version: 20190620112608) 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
@@ -1069,6 +1069,8 @@ ActiveRecord::Schema.define(version: 20190620112608) do
t.string "on_stop"
t.integer "status", limit: 2, null: false
t.datetime_with_timezone "finished_at"
+ t.integer "cluster_id"
+ t.index ["cluster_id"], name: "index_deployments_on_cluster_id", using: :btree
t.index ["created_at"], name: "index_deployments_on_created_at", using: :btree
t.index ["deployable_type", "deployable_id"], name: "index_deployments_on_deployable_type_and_deployable_id", using: :btree
t.index ["environment_id", "id"], name: "index_deployments_on_environment_id_and_id", using: :btree
@@ -2054,6 +2056,21 @@ ActiveRecord::Schema.define(version: 20190620112608) do
t.index ["title"], name: "index_milestones_on_title_trigram", using: :gin, opclasses: {"title"=>"gin_trgm_ops"}
end
+ create_table "namespace_aggregation_schedules", primary_key: "namespace_id", id: :integer, default: nil, force: :cascade do |t|
+ t.index ["namespace_id"], name: "index_namespace_aggregation_schedules_on_namespace_id", unique: true, using: :btree
+ end
+
+ create_table "namespace_root_storage_statistics", primary_key: "namespace_id", id: :integer, default: nil, force: :cascade do |t|
+ t.datetime_with_timezone "updated_at", null: false
+ t.bigint "repository_size", default: 0, null: false
+ t.bigint "lfs_objects_size", default: 0, null: false
+ t.bigint "wiki_size", default: 0, null: false
+ t.bigint "build_artifacts_size", default: 0, null: false
+ t.bigint "storage_size", default: 0, null: false
+ t.bigint "packages_size", default: 0, null: false
+ t.index ["namespace_id"], name: "index_namespace_root_storage_statistics_on_namespace_id", unique: true, using: :btree
+ end
+
create_table "namespace_statistics", id: :serial, force: :cascade do |t|
t.integer "namespace_id", null: false
t.integer "shared_runners_seconds", default: 0, null: false
@@ -2249,6 +2266,7 @@ ActiveRecord::Schema.define(version: 20190620112608) 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
@@ -2334,6 +2352,7 @@ ActiveRecord::Schema.define(version: 20190620112608) do
t.datetime_with_timezone "certificate_valid_not_before"
t.datetime_with_timezone "certificate_valid_not_after"
t.integer "certificate_source", limit: 2, default: 0, null: false
+ t.index ["certificate_source", "certificate_valid_not_after"], name: "index_pages_domains_need_auto_ssl_renewal", where: "(auto_ssl_enabled = true)", using: :btree
t.index ["domain"], name: "index_pages_domains_on_domain", unique: true, using: :btree
t.index ["project_id", "enabled_until"], name: "index_pages_domains_on_project_id_and_enabled_until", using: :btree
t.index ["project_id"], name: "index_pages_domains_on_project_id", using: :btree
@@ -2399,6 +2418,15 @@ ActiveRecord::Schema.define(version: 20190620112608) do
t.string "encrypted_token_iv", null: false
end
+ create_table "project_aliases", force: :cascade do |t|
+ t.integer "project_id", null: false
+ t.string "name", null: false
+ t.datetime_with_timezone "created_at", null: false
+ t.datetime_with_timezone "updated_at", null: false
+ t.index ["name"], name: "index_project_aliases_on_name", unique: true, using: :btree
+ t.index ["project_id"], name: "index_project_aliases_on_project_id", using: :btree
+ end
+
create_table "project_authorizations", id: false, force: :cascade do |t|
t.integer "user_id", null: false
t.integer "project_id", null: false
@@ -2501,9 +2529,9 @@ ActiveRecord::Schema.define(version: 20190620112608) do
t.index ["project_id"], name: "index_project_import_data_on_project_id", using: :btree
end
- create_table "project_incident_management_settings", primary_key: "project_id", id: :integer, default: nil, force: :cascade do |t|
- t.boolean "create_issue", default: false, null: false
- t.boolean "send_email", default: true, null: false
+ create_table "project_incident_management_settings", primary_key: "project_id", id: :serial, force: :cascade do |t|
+ t.boolean "create_issue", default: true, null: false
+ t.boolean "send_email", default: false, null: false
t.text "issue_template_key"
end
@@ -2876,6 +2904,7 @@ ActiveRecord::Schema.define(version: 20190620112608) 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
@@ -3004,6 +3033,7 @@ ActiveRecord::Schema.define(version: 20190620112608) 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
@@ -3637,6 +3667,7 @@ ActiveRecord::Schema.define(version: 20190620112608) do
add_foreign_key "dependency_proxy_blobs", "namespaces", column: "group_id", name: "fk_db58bbc5d7", on_delete: :cascade
add_foreign_key "dependency_proxy_group_settings", "namespaces", column: "group_id", name: "fk_616ddd680a", on_delete: :cascade
add_foreign_key "deploy_keys_projects", "projects", name: "fk_58a901ca7e", on_delete: :cascade
+ add_foreign_key "deployments", "clusters", name: "fk_289bba3222", on_delete: :nullify
add_foreign_key "deployments", "projects", name: "fk_b9a3851b82", on_delete: :cascade
add_foreign_key "design_management_designs", "issues", on_delete: :cascade
add_foreign_key "design_management_designs", "projects", on_delete: :cascade
@@ -3755,6 +3786,8 @@ ActiveRecord::Schema.define(version: 20190620112608) do
add_foreign_key "merge_trains", "users", 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 "namespace_aggregation_schedules", "namespaces", on_delete: :cascade
+ add_foreign_key "namespace_root_storage_statistics", "namespaces", on_delete: :cascade
add_foreign_key "namespace_statistics", "namespaces", on_delete: :cascade
add_foreign_key "namespaces", "namespaces", column: "custom_project_templates_group_id", name: "fk_e7a0b20a6b", on_delete: :nullify
add_foreign_key "namespaces", "plans", name: "fk_fdd12e5b80", on_delete: :nullify
@@ -3778,6 +3811,7 @@ ActiveRecord::Schema.define(version: 20190620112608) do
add_foreign_key "pool_repositories", "projects", column: "source_project_id", on_delete: :nullify
add_foreign_key "pool_repositories", "shards", on_delete: :restrict
add_foreign_key "project_alerting_settings", "projects", on_delete: :cascade
+ add_foreign_key "project_aliases", "projects", on_delete: :cascade
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
diff --git a/doc/README.md b/doc/README.md
index 3863e17c268..489c8117b9d 100644
--- a/doc/README.md
+++ b/doc/README.md
@@ -54,7 +54,7 @@ GitLab provides solutions for [all the stages of the DevOps lifecycle](https://a
![DevOps Stages](img/devops-stages.png)
GitLab is like a top-of-the-line kitchen for making software. As the executive
-chef, you decide what software you want serve. Using your recipe, GitLab handles
+chef, you decide what software you want to serve. Using your recipe, GitLab handles
all the prep work, cooking, and delivery, so you can turn around orders faster
than ever.
@@ -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. |
diff --git a/doc/administration/auth/google_secure_ldap.md b/doc/administration/auth/google_secure_ldap.md
index 760af0cfd1a..c668f19ca7d 100644
--- a/doc/administration/auth/google_secure_ldap.md
+++ b/doc/administration/auth/google_secure_ldap.md
@@ -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> and sign in as a GSuite domain administrator.
1. Go to **Apps > LDAP > Add Client**.
diff --git a/doc/administration/auth/ldap-ee.md b/doc/administration/auth/ldap-ee.md
index 15f093bb62d..b45966fa920 100644
--- a/doc/administration/auth/ldap-ee.md
+++ b/doc/administration/auth/ldap-ee.md
@@ -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 54279897e04..79ac7fe0352 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
@@ -396,21 +394,34 @@ omniauth-ldap.
### Escaping special characters
-If the `user_filter` DN contains special characters. For example, a comma:
+The `user_filter` DN can contain special characters. For example:
-```
-OU=GitLab, Inc,DC=gitlab,DC=com
-```
+- A comma:
-This character needs to be escaped as documented in [RFC 4515](https://tools.ietf.org/search/rfc4515).
+ ```
+ OU=GitLab, Inc,DC=gitlab,DC=com
+ ```
-Due to the way the string is parsed, the special character needs to be converted
-to hex and `\\5C\\` (`5C` = `\` in hex) added before it.
-As an example the above DN would look like
+- Open and close brackets:
-```
-OU=GitLab\\5C\\2C Inc,DC=gitlab,DC=com
-```
+ ```
+ OU=Gitlab (Inc),DC=gitlab,DC=com
+ ```
+
+ These characters must be escaped as documented in
+ [RFC 4515](https://tools.ietf.org/search/rfc4515).
+
+- Escape commas with `\2C`. For example:
+
+ ```
+ OU=GitLab\2C Inc,DC=gitlab,DC=com
+ ```
+
+- Escape open and close brackets with `\28` and `\29`, respectively. For example:
+
+ ```
+ OU=Gitlab \28Inc\29,DC=gitlab,DC=com
+ ```
## Enabling LDAP sign-in for existing GitLab users
diff --git a/doc/administration/auth/oidc.md b/doc/administration/auth/oidc.md
index 00422ec347c..6e48add6930 100644
--- a/doc/administration/auth/oidc.md
+++ b/doc/administration/auth/oidc.md
@@ -144,20 +144,20 @@ for more details:
If you're having trouble, here are some tips:
1. Ensure `discovery` is set to `true`. Setting it to `false` requires
-specifying all the URLs and keys required to make OpenID work.
+ specifying all the URLs and keys required to make OpenID work.
1. Check your system clock to ensure the time is synchronized properly.
1. As mentioned in [the
-documentation](https://github.com/m0n9oose/omniauth_openid_connect),
-make sure `issuer` corresponds to the base URL of the Discovery URL. For
-example, `https://accounts.google.com` is used for the URL
-`https://accounts.google.com/.well-known/openid-configuration`.
+ documentation](https://github.com/m0n9oose/omniauth_openid_connect),
+ make sure `issuer` corresponds to the base URL of the Discovery URL. For
+ example, `https://accounts.google.com` is used for the URL
+ `https://accounts.google.com/.well-known/openid-configuration`.
1. The OpenID Connect client uses HTTP Basic Authentication to send the
-OAuth2 access token. For example, if you are seeing 401 errors upon
-retrieving the `userinfo` endpoint, you may want to check your OpenID
-Web server configuration. For example, for
-[oauth2-server-php](https://github.com/bshaffer/oauth2-server-php), you
-may need to [add a configuration parameter to
-Apache](https://github.com/bshaffer/oauth2-server-php/issues/926#issuecomment-387502778).
+ OAuth2 access token. For example, if you are seeing 401 errors upon
+ retrieving the `userinfo` endpoint, you may want to check your OpenID
+ Web server configuration. For example, for
+ [oauth2-server-php](https://github.com/bshaffer/oauth2-server-php), you
+ may need to [add a configuration parameter to
+ Apache](https://github.com/bshaffer/oauth2-server-php/issues/926#issuecomment-387502778).
diff --git a/doc/administration/container_registry.md b/doc/administration/container_registry.md
index 4d55f2357c1..2e4b4efa0ac 100644
--- a/doc/administration/container_registry.md
+++ b/doc/administration/container_registry.md
@@ -689,6 +689,20 @@ You can add a configuration option for backwards compatibility.
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 7f3be402b84..98404ff2a10 100644
--- a/doc/administration/database_load_balancing.md
+++ b/doc/administration/database_load_balancing.md
@@ -40,16 +40,16 @@ For example, say you have a primary (`db1.gitlab.com`) and two secondaries,
`db2.gitlab.com` and `db3.gitlab.com`. For this setup you will need to have 3
load balancers, one for every host. For example:
-* `primary.gitlab.com` forwards to `db1.gitlab.com`
-* `secondary1.gitlab.com` forwards to `db2.gitlab.com`
-* `secondary2.gitlab.com` forwards to `db3.gitlab.com`
+- `primary.gitlab.com` forwards to `db1.gitlab.com`
+- `secondary1.gitlab.com` forwards to `db2.gitlab.com`
+- `secondary2.gitlab.com` forwards to `db3.gitlab.com`
Now let's say that a failover happens and db2 becomes the new primary. This
means forwarding should now happen as follows:
-* `primary.gitlab.com` forwards to `db2.gitlab.com`
-* `secondary1.gitlab.com` forwards to `db1.gitlab.com`
-* `secondary2.gitlab.com` forwards to `db3.gitlab.com`
+- `primary.gitlab.com` forwards to `db2.gitlab.com`
+- `secondary1.gitlab.com` forwards to `db1.gitlab.com`
+- `secondary2.gitlab.com` forwards to `db3.gitlab.com`
GitLab does not take care of this for you, so you will need to do so yourself.
@@ -209,9 +209,9 @@ without it immediately leading to errors being presented to the users.
The load balancer logs various messages, such as:
-* When a host is marked as offline
-* When a host comes back online
-* When all secondaries are offline
+- When a host is marked as offline
+- When a host comes back online
+- When all secondaries are offline
Each log message contains the tag `[DB-LB]` to make searching/filtering of such
log entries easier. For example:
diff --git a/doc/administration/geo/disaster_recovery/background_verification.md b/doc/administration/geo/disaster_recovery/background_verification.md
index d4c8c2d3624..e19cd9bbfec 100644
--- a/doc/administration/geo/disaster_recovery/background_verification.md
+++ b/doc/administration/geo/disaster_recovery/background_verification.md
@@ -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..9a981b49349 100644
--- a/doc/administration/geo/disaster_recovery/bring_primary_back.md
+++ b/doc/administration/geo/disaster_recovery/bring_primary_back.md
@@ -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..86182b84062 100644
--- a/doc/administration/geo/disaster_recovery/index.md
+++ b/doc/administration/geo/disaster_recovery/index.md
@@ -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..c1a95157f8d 100644
--- a/doc/administration/geo/disaster_recovery/planned_failover.md
+++ b/doc/administration/geo/disaster_recovery/planned_failover.md
@@ -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..dd5e09c0dd7 100644
--- a/doc/administration/geo/replication/configuration.md
+++ b/doc/administration/geo/replication/configuration.md
@@ -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..021ed2d9f3c 100644
--- a/doc/administration/geo/replication/database.md
+++ b/doc/administration/geo/replication/database.md
@@ -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/external_database.md b/doc/administration/geo/replication/external_database.md
index 177ca68613e..452e4f490a6 100644
--- a/doc/administration/geo/replication/external_database.md
+++ b/doc/administration/geo/replication/external_database.md
@@ -4,7 +4,7 @@ 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 dd1af0dbf9c..c527248bc72 100644
--- a/doc/administration/geo/replication/faq.md
+++ b/doc/administration/geo/replication/faq.md
@@ -6,8 +6,8 @@ The requirements are listed [on the index page](index.md#requirements-for-runnin
## How does Geo know which projects to sync?
-On each **secondary** node, there is a read-only replicated copy of the GitLab database.
-A **secondary** node also has a tracking database where it stores which projects have been synced.
+On each **secondary** node, there is a read-only replicated copy of the GitLab database.
+A **secondary** node also has a tracking database where it stores which projects have been synced.
Geo compares the two databases to find projects that are not yet tracked.
At the start, this tracking database is empty, so Geo will start trying to update from every project that it can see in the GitLab database.
@@ -15,19 +15,19 @@ At the start, this tracking database is empty, so Geo will start trying to updat
For each project to sync:
1. Geo will issue a `git fetch geo --mirror` to get the latest information from the **primary** node.
-If there are no changes, the sync will be fast and end quickly. Otherwise, it will pull the latest commits.
+ If there are no changes, the sync will be fast and end quickly. Otherwise, it will pull the latest commits.
1. The **secondary** node will update the tracking database to store the fact that it has synced projects A, B, C, etc.
1. Repeat until all projects are synced.
-When someone pushes a commit to the **primary** node, it generates an event in the GitLab database that the repository has changed.
+When someone pushes a commit to the **primary** node, it generates an event in the GitLab database that the repository has changed.
The **secondary** node sees this event, marks the project in question as dirty, and schedules the project to be resynced.
To ensure that problems with pipelines (for example, syncs failing too many times or jobs being lost) don't permanently stop projects syncing, Geo also periodically checks the tracking database for projects that are marked as dirty. This check happens when
-the number of concurrent syncs falls below `repos_max_capacity` and there are no new projects waiting to be synced.
+the number of concurrent syncs falls below `repos_max_capacity` and there are no new projects waiting to be synced.
-Geo also has a checksum feature which runs a SHA256 sum across all the Git references to the SHA values.
-If the refs don't match between the **primary** node and the **secondary** node, then the **secondary** node will mark that project as dirty and try to resync it.
-So even if we have an outdated tracking database, the validation should activate and find discrepancies in the repository state and resync.
+Geo also has a checksum feature which runs a SHA256 sum across all the Git references to the SHA values.
+If the refs don't match between the **primary** node and the **secondary** node, then the **secondary** node will mark that project as dirty and try to resync it.
+So even if we have an outdated tracking database, the validation should activate and find discrepancies in the repository state and resync.
## Can I use Geo in a disaster recovery situation?
diff --git a/doc/administration/geo/replication/high_availability.md b/doc/administration/geo/replication/high_availability.md
index 921a3ef1c7a..61e18df2480 100644
--- a/doc/administration/geo/replication/high_availability.md
+++ b/doc/administration/geo/replication/high_availability.md
@@ -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']
-
- ##
- ## Disable automatic migrations
- ##
- gitlab_rails['auto_migrate'] = false
- ```
+ ```ruby
+ ##
+ ## Enable the Geo primary role
+ ##
+ roles ['geo_primary_role']
+
+ ##
+ ## Disable automatic migrations
+ ##
+ gitlab_rails['auto_migrate'] = false
+ ```
After making these changes, [reconfigure GitLab][gitlab-reconfigure] so the changes take effect.
@@ -79,9 +79,9 @@ The **primary** database will require modification later, as part of
A **secondary** cluster is similar to any other GitLab HA cluster, with two
major differences:
-* The main PostgreSQL database is a read-only replica of the **primary** node's
+- The main PostgreSQL database is a read-only replica of the **primary** node's
PostgreSQL database.
-* There is also a single PostgreSQL database for the **secondary** cluster,
+- There is also a single PostgreSQL database for the **secondary** cluster,
called the "tracking database", which tracks the synchronization state of
various resources.
@@ -93,9 +93,9 @@ from the normal HA setup.
Configure the following services, again using the non-Geo high availability
documentation:
-* [Configuring Redis for GitLab HA](../../high_availability/redis.md) for high
+- [Configuring Redis for GitLab HA](../../high_availability/redis.md) for high
availability.
-* [NFS](../../high_availability/nfs.md) which will store data that is
+- [NFS](../../high_availability/nfs.md) which will store data that is
synchronized from the **primary** node.
### Step 2: Configure the main read-only replica PostgreSQL database on the **secondary** node
@@ -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
@@ -270,15 +270,15 @@ After making these changes [Reconfigure GitLab][gitlab-reconfigure] so the chang
On the secondary the following GitLab frontend services will be enabled:
-* geo-logcursor
-* gitlab-pages
-* gitlab-workhorse
-* logrotate
-* nginx
-* registry
-* remote-syslog
-* sidekiq
-* unicorn
+- geo-logcursor
+- gitlab-pages
+- gitlab-workhorse
+- logrotate
+- nginx
+- registry
+- remote-syslog
+- sidekiq
+- unicorn
Verify these services by running `sudo gitlab-ctl status` on the frontend
application servers.
diff --git a/doc/administration/geo/replication/index.md b/doc/administration/geo/replication/index.md
index 54377f7ae4e..8e1d1cb46ba 100644
--- a/doc/administration/geo/replication/index.md
+++ b/doc/administration/geo/replication/index.md
@@ -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+
diff --git a/doc/administration/geo/replication/remove_geo_node.md b/doc/administration/geo/replication/remove_geo_node.md
index b190fe7d42d..6bdaad8f783 100644
--- a/doc/administration/geo/replication/remove_geo_node.md
+++ b/doc/administration/geo/replication/remove_geo_node.md
@@ -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/troubleshooting.md b/doc/administration/geo/replication/troubleshooting.md
index 846afd8f5f4..c7c78407084 100644
--- a/doc/administration/geo/replication/troubleshooting.md
+++ b/doc/administration/geo/replication/troubleshooting.md
@@ -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
@@ -331,7 +331,7 @@ There are a few key points to remember:
1. The FDW settings are configured on the Geo **tracking** database.
1. The configured foreign server enables a login to the Geo
-**secondary**, read-only database.
+ **secondary**, read-only database.
By default, the Geo secondary and tracking database are running on the
same host on different ports. That is, 5432 and 5431 respectively.
@@ -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.
+ 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_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
@@ -504,6 +502,15 @@ To resolve this, run the following command:
sudo gitlab-rake geo:db:refresh_foreign_tables
```
+## Expired artifacts
+
+If you notice for some reason there are more artifacts on the Geo
+secondary node than on the Geo primary node, you can use the rake task
+to [cleanup orphan artifact files](../../../raketasks/cleanup.md#remove-orphan-artifact-files).
+
+On a Geo **secondary** node, this command will also clean up all Geo
+registry record related to the orphan files on disk.
+
## Fixing common errors
This section documents common errors reported in the Admin UI and how to fix them.
diff --git a/doc/administration/geo/replication/updating_the_geo_nodes.md b/doc/administration/geo/replication/updating_the_geo_nodes.md
index 933a75c47d8..d56a59f4967 100644
--- a/doc/administration/geo/replication/updating_the_geo_nodes.md
+++ b/doc/administration/geo/replication/updating_the_geo_nodes.md
@@ -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/gitaly/index.md b/doc/administration/gitaly/index.md
index da8f1ee1529..a3cbc4272f0 100644
--- a/doc/administration/gitaly/index.md
+++ b/doc/administration/gitaly/index.md
@@ -48,7 +48,7 @@ used by Omnibus and the GitLab source installation guide.
Starting with GitLab 11.4, Gitaly is able to serve all Git requests without
needed a shared NFS mount for Git repository data.
Between 11.4 and 11.8 the exception was the
-[Elastic Search indexer](https://gitlab.com/gitlab-org/gitlab-elasticsearch-indexer).
+[Elasticsearch indexer](https://gitlab.com/gitlab-org/gitlab-elasticsearch-indexer).
But since 11.8 the indexer uses Gitaly for data access as well. NFS can still
be leveraged for redudancy on block level of the Git data. But only has to
be mounted on the Gitaly server.
@@ -267,7 +267,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).
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/database.md b/doc/administration/high_availability/database.md
index 4db53353218..20bbfdb2603 100644
--- a/doc/administration/high_availability/database.md
+++ b/doc/administration/high_availability/database.md
@@ -83,7 +83,7 @@ deploy the bundled PostgreSQL.
plain text password. These will be necessary when configuring the GitLab
application servers later.
1. [Enable monitoring](#enable-monitoring)
-
+
Advanced configuration options are supported and can be added if
needed.
@@ -204,9 +204,9 @@ Few notes on the service itself:
- The service runs under a system account, by default `gitlab-consul`.
- If you are using a different username, you will have to specify it. We
-will refer to it with `CONSUL_USERNAME`,
+ will refer to it with `CONSUL_USERNAME`,
- There will be a database user created with read only access to the repmgr
-database
+ database
- Passwords will be stored in the following locations:
- `/etc/gitlab/gitlab.rb`: hashed
- `/var/opt/gitlab/pgbouncer/pg_auth`: hashed
diff --git a/doc/administration/high_availability/gitaly.md b/doc/administration/high_availability/gitaly.md
index 90e5f71d835..b7eaa4ce105 100644
--- a/doc/administration/high_availability/gitaly.md
+++ b/doc/administration/high_availability/gitaly.md
@@ -2,13 +2,13 @@
Gitaly does not yet support full high availability. However, Gitaly is quite
stable and is in use on GitLab.com. Scaled and highly available GitLab environments
-should consider using Gitaly on a separate node.
+should consider using Gitaly on a separate node.
-See the [Gitaly HA Epic](https://gitlab.com/groups/gitlab-org/-/epics/289) to
-track plans and progress toward high availability support.
+See the [Gitaly HA Epic](https://gitlab.com/groups/gitlab-org/-/epics/289) to
+track plans and progress toward high availability support.
This document is relevant for [Scaled Architecture](README.md#scalable-architecture-examples)
-environments and [High Availability Architecture](README.md#high-availability-architecture-examples).
+environments and [High Availability Architecture](README.md#high-availability-architecture-examples).
## Running Gitaly on its own server
@@ -24,23 +24,25 @@ Continue configuration of other components by going back to:
> [Introduced](https://gitlab.com/gitlab-org/omnibus-gitlab/issues/3786) in GitLab 12.0.
- 1. Create/edit `/etc/gitlab/gitlab.rb` and add the following configuration:
+1. Make sure to 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. Note they are presented as `Y.Y.Y.Y consul1.gitlab.example.com Z.Z.Z.Z`
- ```ruby
- # Enable service discovery for Prometheus
- consul['enable'] = true
- consul['monitoring_service_discovery'] = true
+1. Create/edit `/etc/gitlab/gitlab.rb` and add the following configuration:
- # Replace placeholders
- # Y.Y.Y.Y consul1.gitlab.example.com Z.Z.Z.Z
- # with the addresses of the Consul server nodes
- consul['configuration'] = {
- retry_join: %w(Y.Y.Y.Y consul1.gitlab.example.com Z.Z.Z.Z),
- }
+ ```ruby
+ # Enable service discovery for Prometheus
+ consul['enable'] = true
+ consul['monitoring_service_discovery'] = true
- # Set the network addresses that the exporters will listen on
- node_exporter['listen_address'] = '0.0.0.0:9100'
- gitaly['prometheus_listen_addr'] = "0.0.0.0:9236"
- ```
+ # Replace placeholders
+ # Y.Y.Y.Y consul1.gitlab.example.com Z.Z.Z.Z
+ # with the addresses of the Consul server nodes
+ consul['configuration'] = {
+ retry_join: %w(Y.Y.Y.Y consul1.gitlab.example.com Z.Z.Z.Z),
+ }
- 1. Run `sudo gitlab-ctl reconfigure` to compile the configuration.
+ # Set the network addresses that the exporters will listen on
+ node_exporter['listen_address'] = '0.0.0.0:9100'
+ gitaly['prometheus_listen_addr'] = "0.0.0.0:9236"
+ ```
+
+1. Run `sudo gitlab-ctl reconfigure` to compile the configuration.
diff --git a/doc/administration/high_availability/gitlab.md b/doc/administration/high_availability/gitlab.md
index 0e655e49922..3045be616a6 100644
--- a/doc/administration/high_availability/gitlab.md
+++ b/doc/administration/high_availability/gitlab.md
@@ -138,6 +138,8 @@ need some extra configuration.
If you enable Monitoring, it must be enabled on **all** GitLab servers.
+1. Make sure to 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. Note they are presented as `Y.Y.Y.Y consul1.gitlab.example.com Z.Z.Z.Z`
+
1. Create/edit `/etc/gitlab/gitlab.rb` and add the following configuration:
```ruby
@@ -158,12 +160,11 @@ If you enable Monitoring, it must be enabled on **all** GitLab servers.
sidekiq['listen_address'] = "0.0.0.0"
unicorn['listen'] = '0.0.0.0'
- # Add the monitoring node's IP address to the monitoring whitelist and allow it to scrape the NGINX metrics
- # Replace placeholder
- # monitoring.gitlab.example.com
- # with the addresses gathered for the monitoring node
- gitlab_rails['monitoring_whitelist'] = ['monitoring.gitlab.example.com']
- nginx['status']['options']['allow'] = ['monitoring.gitlab.example.com']
+ # Add the monitoring node's IP address to the monitoring whitelist and allow it to
+ # scrape the NGINX metrics. Replace placeholder `monitoring.gitlab.example.com` with
+ # the address and/or subnets gathered from the monitoring node(s).
+ gitlab_rails['monitoring_whitelist'] = ['monitoring.gitlab.example.com', '127.0.0.0/8']
+ nginx['status']['options']['allow'] = ['monitoring.gitlab.example.com', '127.0.0.0/8']
```
1. Run `sudo gitlab-ctl reconfigure` to compile the configuration.
diff --git a/doc/administration/high_availability/monitoring_node.md b/doc/administration/high_availability/monitoring_node.md
index d16bf7dc0f0..ef415dde10a 100644
--- a/doc/administration/high_availability/monitoring_node.md
+++ b/doc/administration/high_availability/monitoring_node.md
@@ -16,6 +16,8 @@ Omnibus:
package you want using **steps 1 and 2** from the GitLab downloads page.
- Do not complete any other steps on the download page.
+1. Make sure to 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. Note they are presented as `Y.Y.Y.Y consul1.gitlab.example.com Z.Z.Z.Z`
+
1. Edit `/etc/gitlab/gitlab.rb` and add the contents:
```ruby
diff --git a/doc/administration/high_availability/pgbouncer.md b/doc/administration/high_availability/pgbouncer.md
index 762179cf756..053dae25823 100644
--- a/doc/administration/high_availability/pgbouncer.md
+++ b/doc/administration/high_availability/pgbouncer.md
@@ -62,6 +62,33 @@ See our [HA documentation for PostgreSQL](database.md) for information on runnin
1. At this point, your instance should connect to the database through pgbouncer. If you are having issues, see the [Troubleshooting](#troubleshooting) section
+## Enable Monitoring
+
+> [Introduced](https://gitlab.com/gitlab-org/omnibus-gitlab/issues/3786) in GitLab 12.0.
+
+ If you enable Monitoring, it must be enabled on **all** pgbouncer servers.
+
+ 1. Create/edit `/etc/gitlab/gitlab.rb` and add the following configuration:
+
+ ```ruby
+ # Enable service discovery for Prometheus
+ consul['enable'] = true
+ consul['monitoring_service_discovery'] = true
+
+ # Replace placeholders
+ # Y.Y.Y.Y consul1.gitlab.example.com Z.Z.Z.Z
+ # with the addresses of the Consul server nodes
+ consul['configuration'] = {
+ retry_join: %w(Y.Y.Y.Y consul1.gitlab.example.com Z.Z.Z.Z),
+ }
+
+ # Set the network addresses that the exporters will listen on
+ node_exporter['listen_address'] = '0.0.0.0:9100'
+ pgbouncer_exporter['listen_address'] = '0.0.0.0:9188'
+ ```
+
+ 1. Run `sudo gitlab-ctl reconfigure` to compile the configuration.
+
### Interacting with pgbouncer
#### Administrative console
diff --git a/doc/administration/high_availability/redis.md b/doc/administration/high_availability/redis.md
index f61a8834af3..874525dd836 100644
--- a/doc/administration/high_availability/redis.md
+++ b/doc/administration/high_availability/redis.md
@@ -22,10 +22,10 @@ environments including [Basic Scaling](README.md#basic-scaling) and
### 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.
+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]**
@@ -62,11 +62,11 @@ Omnibus:
pgbouncer_exporter['enable'] = false
gitlab_monitor['enable'] = false
gitaly['enable'] = false
-
+
redis['bind'] = '0.0.0.0'
redis['port'] = '6379'
redis['password'] = 'SECRET_PASSWORD_HERE'
-
+
gitlab_rails['auto_migrate'] = false
```
@@ -74,7 +74,7 @@ Omnibus:
1. Note the Redis node's IP address or hostname, port, and
Redis password. These will be necessary when configuring the GitLab
application servers later.
-1. [Enable Monitoring](#enable-monitoring)
+1. [Enable Monitoring](#enable-monitoring)
Advanced configuration options are supported and can be added if
needed.
@@ -91,10 +91,10 @@ environments including [Horizontal](README.md#horizontal),
### 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.
+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]**
@@ -368,7 +368,7 @@ The prerequisites for a HA Redis setup are the following:
```ruby
# Specify server role as 'redis_master_role'
roles ['redis_master_role']
-
+
# IP address pointing to a local IP that the other machines can reach to.
# You can also set bind to '0.0.0.0' which listen in all interfaces.
# If you really need to bind to an external accessible IP, make
@@ -382,7 +382,6 @@ The prerequisites for a HA Redis setup are the following:
# Set up password authentication for Redis (use the same password in all nodes).
redis['password'] = 'redis-password-goes-here'
```
-
1. Only the primary GitLab application server should handle migrations. To
prevent database migrations from running on upgrade, add the following
@@ -394,9 +393,9 @@ 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/
+> 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/>.
### Step 2. Configuring the slave Redis instances
@@ -412,7 +411,7 @@ The prerequisites for a HA Redis setup are the following:
```ruby
# Specify server role as 'redis_slave_role'
roles ['redis_slave_role']
-
+
# IP address pointing to a local IP that the other machines can reach to.
# You can also set bind to '0.0.0.0' which listen in all interfaces.
# If you really need to bind to an external accessible IP, make
@@ -443,9 +442,9 @@ The prerequisites for a HA Redis setup are the following:
1. [Reconfigure Omnibus GitLab][reconfigure] for the changes to take effect.
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/
+> 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/>.
---
@@ -754,28 +753,30 @@ gitlab_rails['redis_sentinels'] = [
> [Introduced](https://gitlab.com/gitlab-org/omnibus-gitlab/issues/3786) in GitLab 12.0.
- If you enable Monitoring, it must be enabled on **all** Redis servers.
+If you enable Monitoring, it must be enabled on **all** Redis servers.
+
+1. Make sure to 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. Note they are presented as `Y.Y.Y.Y consul1.gitlab.example.com Z.Z.Z.Z`
- 1. Create/edit `/etc/gitlab/gitlab.rb` and add the following configuration:
+1. Create/edit `/etc/gitlab/gitlab.rb` and add the following configuration:
- ```ruby
- # Enable service discovery for Prometheus
- consul['enable'] = true
- consul['monitoring_service_discovery'] = true
+ ```ruby
+ # Enable service discovery for Prometheus
+ consul['enable'] = true
+ consul['monitoring_service_discovery'] = true
- # Replace placeholders
- # Y.Y.Y.Y consul1.gitlab.example.com Z.Z.Z.Z
- # with the addresses of the Consul server nodes
- consul['configuration'] = {
- retry_join: %w(Y.Y.Y.Y consul1.gitlab.example.com Z.Z.Z.Z),
- }
+ # Replace placeholders
+ # Y.Y.Y.Y consul1.gitlab.example.com Z.Z.Z.Z
+ # with the addresses of the Consul server nodes
+ consul['configuration'] = {
+ retry_join: %w(Y.Y.Y.Y consul1.gitlab.example.com Z.Z.Z.Z),
+ }
- # Set the network addresses that the exporters will listen on
- node_exporter['listen_address'] = '0.0.0.0:9100'
- redis_exporter['listen_address'] = '0.0.0.0:9121'
- ```
+ # Set the network addresses that the exporters will listen on
+ node_exporter['listen_address'] = '0.0.0.0:9100'
+ redis_exporter['listen_address'] = '0.0.0.0:9121'
+ ```
- 1. Run `sudo gitlab-ctl reconfigure` to compile the configuration.
+1. Run `sudo gitlab-ctl reconfigure` to compile the configuration.
## Advanced configuration
diff --git a/doc/administration/logs.md b/doc/administration/logs.md
index 022c23d02ce..9921ffd8ea0 100644
--- a/doc/administration/logs.md
+++ b/doc/administration/logs.md
@@ -125,7 +125,7 @@ This file lives in `/var/log/gitlab/gitlab-rails/integrations_json.log` for
Omnibus GitLab packages or in `/home/git/gitlab/log/integrations_json.log` for
installations from source.
-It contains information about [integrations](../user/project/integrations/project_services.md) activities such as JIRA, Asana and Irker services. It uses JSON format like the example below:
+It contains information about [integrations](../user/project/integrations/project_services.md) activities such as Jira, Asana and Irker services. It uses JSON format like the example below:
``` json
{"severity":"ERROR","time":"2018-09-06T14:56:20.439Z","service_class":"JiraService","project_id":8,"project_path":"h5bp/html5-boilerplate","message":"Error sending message","client_url":"http://jira.gitlap.com:8080","error":"execution expired"}
diff --git a/doc/administration/monitoring/performance/grafana_configuration.md b/doc/administration/monitoring/performance/grafana_configuration.md
index 187fb2f73a1..51b0d78681d 100644
--- a/doc/administration/monitoring/performance/grafana_configuration.md
+++ b/doc/administration/monitoring/performance/grafana_configuration.md
@@ -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/prometheus/gitlab_metrics.md b/doc/administration/monitoring/prometheus/gitlab_metrics.md
index 84b71ae6f1c..2d9e3f7f18b 100644
--- a/doc/administration/monitoring/prometheus/gitlab_metrics.md
+++ b/doc/administration/monitoring/prometheus/gitlab_metrics.md
@@ -108,7 +108,7 @@ Some basic Ruby runtime metrics are available:
[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 286b99aceb5..7297507f599 100644
--- a/doc/administration/operations/extra_sidekiq_processes.md
+++ b/doc/administration/operations/extra_sidekiq_processes.md
@@ -1,70 +1,132 @@
# Extra Sidekiq processes **[STARTER ONLY]**
-GitLab Enterprise Edition allows one to start an extra set of Sidekiq processes
+NOTE: **Note:**
+The information in this page applies only to Omnibus GitLab.
+
+GitLab Starter allows one to start an extra set of Sidekiq processes
besides the default one. These processes can be used to consume a dedicated set
of queues. This can be used to ensure certain queues always have dedicated
workers, no matter the number of jobs that need to be processed.
-## Starting extra processes via Omnibus GitLab
+## Available Sidekiq queues
-To enable `sidekiq-cluster`, you must apply the `sidekiq_cluster['enable'] = true`
-setting `/etc/gitlab/gitlab.rb`:
+For a list of the existing Sidekiq queues, check the following files:
-```ruby
-sidekiq_cluster['enable'] = true
-```
+- [Queues for both GitLab Community and Enterprise Editions](https://gitlab.com/gitlab-org/gitlab-ee/blob/master/app/workers/all_queues.yml)
+- [Queues for GitLab Enterprise Editions only](https://gitlab.com/gitlab-org/gitlab-ee/blob/master/ee/app/workers/all_queues.yml)
-You will then specify how many additional processes to create via `sidekiq-cluster`
-as well as which queues for them to handle. This is done via the
-`sidekiq_cluster['queue_groups']` setting. This is an array whose items contain
-which queues to process. Each item in the array will equate to one additional
-sidekiq process.
+Each entry in the above files represents a queue on which extra Sidekiq processes
+can be started.
-As an example, to make additional sidekiq processes that process the
-`elastic_indexer` and `mailers` queues, you would apply the following:
+## Starting extra processes
-```ruby
-sidekiq_cluster['queue_groups'] = [
- "elastic_indexer",
- "mailers"
-]
-```
+To start extra Sidekiq processes, you must enable `sidekiq-cluster`:
-To have an additional sidekiq process handle multiple queues, you simply put a
-comma after the first queue name and then put the next queue name:
+1. Edit `/etc/gitlab/gitlab.rb` and add:
-```ruby
-sidekiq_cluster['queue_groups'] = [
- "elastic_indexer,elastic_commit_indexer",
- "mailers"
-]
-```
+ ```ruby
+ sidekiq_cluster['enable'] = true
+ ```
-Keep in mind, all changes must be followed by reconfiguring your GitLab
-application via `sudo gitlab-ctl reconfigure`.
+1. You will then need to specify how many additional processes to create via `sidekiq-cluster`
+ and which queue they should handle via the `sidekiq_cluster['queue_groups']`
+ array setting. Each item in the array equates to one additional Sidekiq
+ process, and values in each item determine the queues it works on.
-### Monitoring
+ For example, the following setting adds additional Sidekiq processes to two
+ queues, one to `elastic_indexer` and one to `mailers`:
-Once the Sidekiq processes are added, you can visit the "Background Jobs"
+ ```ruby
+ sidekiq_cluster['queue_groups'] = [
+ "elastic_indexer",
+ "mailers"
+ ]
+ ```
+
+ To have an additional Sidekiq process handle multiple queues, add multiple
+ queue names to its item delimited by commas. For example:
+
+ ```ruby
+ sidekiq_cluster['queue_groups'] = [
+ "elastic_indexer, elastic_commit_indexer",
+ "mailers"
+ ]
+ ```
+
+1. Save the file and reconfigure GitLab for the changes to take effect:
+
+ ```sh
+ sudo gitlab-ctl reconfigure
+ ```
+
+Once the extra Sidekiq processes are added, you can visit the "Background Jobs"
section under the admin area in GitLab (`/admin/background_jobs`).
-![Extra sidekiq processes](img/sidekiq-cluster.png)
+![Extra Sidekiq processes](img/sidekiq-cluster.png)
-### All queues with exceptions
+## Negating settings
-To have the additional sidekiq processes work on every queue EXCEPT the ones
+To have the additional Sidekiq processes work on every queue **except** the ones
you list:
+1. After you follow the steps for [starting extra processes](#starting-extra-processes),
+ edit `/etc/gitlab/gitlab.rb` and add:
+
+ ```ruby
+ sidekiq_cluster['negate'] = true
+ ```
+
+1. Save the file and reconfigure GitLab for the changes to take effect:
+
+ ```sh
+ sudo gitlab-ctl reconfigure
+ ```
+
+## Ignore all GitHub import queues
+
+When [importing from GitHub](../../user/project/import/github.md), Sidekiq might
+use all of its resources to perform those operations. To set up a separate
+`sidekiq-cluster` process to ignore all GitHub import-related queues:
+
1. Edit `/etc/gitlab/gitlab.rb` and add:
```ruby
+ sidekiq_cluster['enable'] = true
sidekiq_cluster['negate'] = true
+ sidekiq_cluster['queue_groups'] = [
+ "github_import_advance_stage",
+ "github_importer:github_import_import_diff_note",
+ "github_importer:github_import_import_issue",
+ "github_importer:github_import_import_note",
+ "github_importer:github_import_import_lfs_object",
+ "github_importer:github_import_import_pull_request",
+ "github_importer:github_import_refresh_import_jid",
+ "github_importer:github_import_stage_finish_import",
+ "github_importer:github_import_stage_import_base_data",
+ "github_importer:github_import_stage_import_issues_and_diff_notes",
+ "github_importer:github_import_stage_import_notes",
+ "github_importer:github_import_stage_import_lfs_objects",
+ "github_importer:github_import_stage_import_pull_requests",
+ "github_importer:github_import_stage_import_repository"
+ ]
```
-1. Save the file and [reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure) for the changes to take effect.
+1. Save the file and reconfigure GitLab for the changes to take effect:
+ ```sh
+ sudo gitlab-ctl reconfigure
+ ```
-### Limiting concurrency
+## Number of threads
+
+Each process defined under `sidekiq_cluster` starts with a
+number of threads that equals the number of queues, plus one spare thread.
+For example, a process that handles the `process_commit` and `post_receive`
+queues will use three threads in total.
+
+## Limiting concurrency
+
+To limit the concurrency of the Sidekiq processes:
1. Edit `/etc/gitlab/gitlab.rb` and add:
@@ -72,11 +134,22 @@ you list:
sidekiq_cluster['concurrency'] = 25
```
-1. Save the file and [reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure) for the changes to take effect.
+1. Save the file and reconfigure GitLab for the changes to take effect:
-Keep in mind, this normally would not exceed the number of CPU cores available.
+ ```sh
+ sudo gitlab-ctl reconfigure
+ ```
-### Modifying the check interval
+For each queue group, the concurrency factor will be set to `min(number of queues, N)`.
+Setting the value to 0 will disable the limit. Keep in mind this normally would
+not exceed the number of CPU cores available.
+
+Each thread requires a Redis connection, so adding threads may
+increase Redis latency and potentially cause client timeouts. See the [Sidekiq
+documentation about Redis](https://github.com/mperham/sidekiq/wiki/Using-Redis)
+for more details.
+
+## Modifying the check interval
To modify the check interval for the additional Sidekiq processes:
@@ -90,9 +163,14 @@ To modify the check interval for the additional Sidekiq processes:
This tells the additional processes how often to check for enqueued jobs.
-## Starting extra processes via command line
+## Troubleshooting using the CLI
-Starting extra Sidekiq processes can be done using the command
+CAUTION: **Warning:**
+It's recommended to use `/etc/gitlab/gitlab.rb` to configure the Sidekiq processes.
+If you experience a problem, you should contact GitLab support. Use the command
+line at your own risk.
+
+For debugging purposes, you can start extra Sidekiq processes by using the command
`/opt/gitlab/embedded/service/gitlab-rails/ee/bin/sidekiq-cluster`. This command
takes arguments using the following syntax:
@@ -111,29 +189,29 @@ see the relevant section in the
[Sidekiq style guide](../../development/sidekiq_style_guide.md#queue-namespaces).
For example, say you want to start 2 extra processes: one to process the
-"process_commit" queue, and one to process the "post_receive" queue. This can be
+`process_commit` queue, and one to process the `post_receive` queue. This can be
done as follows:
```bash
/opt/gitlab/embedded/service/gitlab-rails/ee/bin/sidekiq-cluster process_commit post_receive
```
-If you instead want to start one process processing both queues you'd use the
+If you instead want to start one process processing both queues, you'd use the
following syntax:
```bash
/opt/gitlab/embedded/service/gitlab-rails/ee/bin/sidekiq-cluster process_commit,post_receive
```
-If you want to have one Sidekiq process process the "process_commit" and
-"post_receive" queues, and one process to process the "gitlab_shell" queue,
+If you want to have one Sidekiq process dealing with the `process_commit` and
+`post_receive` queues, and one process to process the `gitlab_shell` queue,
you'd use the following:
```bash
/opt/gitlab/embedded/service/gitlab-rails/ee/bin/sidekiq-cluster process_commit,post_receive gitlab_shell
```
-### Monitoring
+### Monitoring the `sidekiq-cluster` command
The `sidekiq-cluster` command will not terminate once it has started the desired
amount of Sidekiq processes. Instead, the process will continue running and
@@ -172,24 +250,24 @@ command and not the PID(s) of the started Sidekiq processes.
The Rails environment can be set by passing the `--environment` flag to the
`sidekiq-cluster` command, or by setting `RAILS_ENV` to a non-empty value. The
-default value is "development".
+default value can be found in `/opt/gitlab/etc/gitlab-rails/env/RAILS_ENV`.
-### All queues with exceptions
+### Using negation
You're able to run all queues in `sidekiq_queues.yml` file on a single or
multiple processes with exceptions using the `--negate` flag.
For example, say you want to run a single process for all queues,
-except "process_commit" and "post_receive". You can do so by executing:
+except `process_commit` and `post_receive`:
```bash
-sidekiq-cluster process_commit,post_receive --negate
+/opt/gitlab/embedded/service/gitlab-rails/ee/bin/sidekiq-cluster process_commit,post_receive --negate
```
-For multiple processes of all queues (except "process_commit" and "post_receive"):
+For multiple processes of all queues (except `process_commit` and `post_receive`):
```bash
-sidekiq-cluster process_commit,post_receive process_commit,post_receive --negate
+/opt/gitlab/embedded/service/gitlab-rails/ee/bin/sidekiq-cluster process_commit,post_receive process_commit,post_receive --negate
```
### Limiting concurrency
@@ -201,18 +279,3 @@ the `-m N` option. For example, this would cap the maximum number of threads to
```bash
/opt/gitlab/embedded/service/gitlab-rails/ee/bin/sidekiq-cluster process_commit,post_receive -m 1
```
-
-For each queue group, the concurrency factor will be set to min(number of
-queues, N). Setting the value to 0 will disable the limit.
-
-Note that each thread requires a Redis connection, so adding threads may
-increase Redis latency and potentially cause client timeouts. See the [Sidekiq
-documentation about Redis](https://github.com/mperham/sidekiq/wiki/Using-Redis)
-for more details.
-
-## Number of threads
-
-Each process started using `sidekiq-cluster` (whether it be via command line or
-via the gitlab.rb file) starts with a number of threads that equals the number
-of queues, plus one spare thread. For example, a process that handles the
-"process_commit" and "post_receive" queues will use 3 threads in total.
diff --git a/doc/api/group_boards.md b/doc/api/group_boards.md
index 9b0ac23b41c..a677a9c9a33 100644
--- a/doc/api/group_boards.md
+++ b/doc/api/group_boards.md
@@ -27,7 +27,69 @@ 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. Refer to the table
+above to see what enpoint(s) belong to each tier.
+
+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,
@@ -83,7 +145,16 @@ 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,
@@ -116,6 +187,206 @@ Example response:
}
```
+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,
+ "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
+ }
+ ]
+ }
+```
+
+## 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][ee-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 board lists
Get a list of the board's lists.
@@ -282,3 +553,5 @@ DELETE /groups/:id/boards/:board_id/lists/:list_id
```bash
curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/groups/5/boards/1/lists/1
```
+
+[ee-5954]: https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/5954
diff --git a/doc/api/group_milestones.md b/doc/api/group_milestones.md
index 260eb09cc38..e780a60a416 100644
--- a/doc/api/group_milestones.md
+++ b/doc/api/group_milestones.md
@@ -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..80a2fb8e4d9 100644
--- a/doc/api/groups.md
+++ b/doc/api/groups.md
@@ -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
}
}
]
@@ -375,6 +375,16 @@ 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: **[STARTER]**
+
+```json
+ "shared_runners_minutes_limit": 133,
+ "extra_shared_runners_minutes_limit": 133,
+```
+
When adding the parameter `with_projects=false`, projects will not be returned.
```bash
@@ -412,13 +422,15 @@ 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. |
+| `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
@@ -445,14 +457,18 @@ 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 |
+| `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 +536,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 +568,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/issues.md b/doc/api/issues.md
index 0d96cfa1b21..b29626525da 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,7 +39,7 @@ 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)_ |
@@ -47,6 +47,7 @@ GET /issues?confidential=true
| `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. |
| `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. |
| `iids[]` | Array[integer] | 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` |
@@ -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,7 +189,7 @@ 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`. |
+| `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` |
| `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)_ |
@@ -183,6 +198,7 @@ GET /groups/:id/issues?confidential=true
| `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. |
| `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` |
@@ -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.
@@ -309,7 +339,7 @@ GET /projects/:id/issues?confidential=true
| `iids[]` | Array[integer] | 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)_ |
@@ -317,6 +347,7 @@ GET /projects/:id/issues?confidential=true
| `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. |
| `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` |
@@ -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` | Array[integer] | 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` | 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. |
| `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/jobs.md b/doc/api/jobs.md
index 72973b69117..223bfed91a9 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
diff --git a/doc/api/merge_request_approvals.md b/doc/api/merge_request_approvals.md
index ddac81328b9..49aaac06b46 100644
--- a/doc/api/merge_request_approvals.md
+++ b/doc/api/merge_request_approvals.md
@@ -222,7 +222,7 @@ GET /projects/:id/merge_requests/:merge_request_iid/approvals
"id": 1,
"state": "active",
"avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon",
- "web_url": "http://localhost:3000/u/root"
+ "web_url": "http://localhost:3000/root"
}
}
],
@@ -314,7 +314,7 @@ PUT /projects/:id/merge_requests/:merge_request_iid/approvers
"id": 1,
"state": "active",
"avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon",
- "web_url": "http://localhost:3000/u/root"
+ "web_url": "http://localhost:3000/root"
}
}
],
@@ -387,7 +387,7 @@ does not match, the response code will be `409`.
"id": 1,
"state": "active",
"avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon",
- "web_url": "http://localhost:3000/u/root"
+ "web_url": "http://localhost:3000/root"
}
},
{
@@ -397,7 +397,7 @@ does not match, the response code will be `409`.
"id": 2,
"state": "active",
"avatar_url": "http://www.gravatar.com/avatar/cf7ad14b34162a76d593e3affca2adca?s=80\u0026d=identicon",
- "web_url": "http://localhost:3000/u/ryley"
+ "web_url": "http://localhost:3000/ryley"
}
}
],
diff --git a/doc/api/merge_requests.md b/doc/api/merge_requests.md
index 7b58aa3100e..69db9f97a35 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.
@@ -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,6 +824,7 @@ Parameters:
## Create MR
Creates a new merge request.
+
```
POST /projects/:id/merge_requests
```
@@ -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.)
+2. 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.
@@ -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,7 +1282,19 @@ 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:
+
+```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
@@ -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
@@ -1473,7 +1588,7 @@ Example response when the GitLab issue tracker is used:
]
```
-Example response when an external issue tracker (e.g. JIRA) is used:
+Example response when an external issue tracker (e.g. Jira) is used:
```json
[
@@ -1616,6 +1731,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 +1876,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 +2109,7 @@ Example response:
}]
}
```
+
## Set a time estimate for a merge request
Sets an estimated time of work for this merge request.
@@ -2114,3 +2254,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..e745d0c2e6c 100644
--- a/doc/api/milestones.md
+++ b/doc/api/milestones.md
@@ -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..b354e2b9ab2 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**: 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/notification_settings.md b/doc/api/notification_settings.md
index e21e73c7dac..0342622f384 100644
--- a/doc/api/notification_settings.md
+++ b/doc/api/notification_settings.md
@@ -1,6 +1,6 @@
# Notification settings API
->**Note:** This feature was [introduced][ce-5632] in GitLab 8.12.
+>**Note:** This feature was [introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/5632) in GitLab 8.12.
**Valid notification levels**
@@ -17,22 +17,22 @@ 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 +85,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 +154,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 +184,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/project_aliases.md b/doc/api/project_aliases.md
new file mode 100644
index 00000000000..76343b4cd82
--- /dev/null
+++ b/doc/api/project_aliases.md
@@ -0,0 +1,111 @@
+# 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.
+
+All methods require administrator authorization.
+
+## List all project aliases
+
+Get a list of all project aliases:
+
+```
+GET /project_aliases
+```
+
+```
+curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/project_aliases"
+```
+
+Example response:
+
+```json
+[
+ {
+ "id": 1,
+ "project_id": 1,
+ "name": "gitlab-ce"
+ },
+ {
+ "id": 2,
+ "project_id": 2,
+ "name": "gitlab-ee"
+ }
+]
+```
+
+## Get project alias' details
+
+Get details of a project alias:
+
+```
+GET /project_aliases/:name
+```
+
+| Attribute | Type | Required | Description |
+|-----------|--------|----------|-----------------------|
+| `name` | string | yes | The name of the alias |
+
+```
+curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/project_aliases/gitlab-ee"
+```
+
+Example response:
+
+```json
+{
+ "id": 1,
+ "project_id": 1,
+ "name": "gitlab-ee"
+}
+```
+
+## Create a project alias
+
+Add a new alias for a project. Responds with a 201 when successful,
+400 when there are validation errors (e.g. alias already exists):
+
+```
+POST /project_aliases
+```
+
+| 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 --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:
+
+```json
+{
+ "id": 1,
+ "project_id": 1,
+ "name": "gitlab-ee"
+}
+```
+
+## Delete a project alias
+
+Removes a project aliases. Responds with a 204 when project alias
+exists, 404 when it doesn't:
+
+```
+DELETE /project_aliases/:name
+```
+
+| Attribute | Type | Required | Description |
+|-----------|--------|----------|-----------------------|
+| `name` | string | yes | The name of the alias |
+
+```
+curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/project_aliases/gitlab-ee"
+```
diff --git a/doc/api/project_snippets.md b/doc/api/project_snippets.md
index 0ccb0517e08..2b2e40fb276 100644
--- a/doc/api/project_snippets.md
+++ b/doc/api/project_snippets.md
@@ -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/projects.md b/doc/api/projects.md
index 1d58e390d9e..b8ccf25581e 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**: 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**: 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**: 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
@@ -1548,9 +1610,104 @@ 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+\..*",
+ "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
+}
+```
+
+The following attributes are restricted to certain plans, and will not appear if
+you do not have access to those features:
+
+* `commit_committer_check` only available on **[PREMIUM]**
+
+### 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+\..*` |
+| `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+\..*` |
+| `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 +1729,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 +1775,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..6e41584afef 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/search.md b/doc/api/search.md
index da81c8321c9..abb77ae05dc 100644
--- a/doc/api/search.md
+++ b/doc/api/search.md
@@ -285,7 +285,7 @@ Example response:
### Scope: wiki_blobs **[STARTER]**
-This scope is available only if [Elasticsearch](../integration/elasticsearch.md) is enabled.
+This scope is available only if [Elasticsearch](../integration/elasticsearch.md) is enabled.
```bash
curl --request GET --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/search?scope=wiki_blobs&search=bye
@@ -346,6 +346,7 @@ Example response:
This scope is available only if [Elasticsearch](../integration/elasticsearch.md) is enabled.
Filters are available for this scope:
+
- filename
- path
- extension
@@ -679,6 +680,7 @@ Example response:
This scope is available only if [Elasticsearch](../integration/elasticsearch.md) is enabled.
Filters are available for this scope:
+
- filename
- path
- extension
diff --git a/doc/api/services.md b/doc/api/services.md
index 042fee4a21a..c811d0e84ca 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.
@@ -551,21 +550,21 @@ Get Irker (IRC gateway) service settings for a project.
GET /projects/:id/services/irker
```
-## JIRA
+## Jira
-JIRA issue tracker.
+Jira issue tracker.
-### Get JIRA service settings
+### Get Jira service settings
-Get JIRA service settings for a project.
+Get Jira service settings for a project.
```
GET /projects/:id/services/jira
```
-### Create/Edit JIRA service
+### Create/Edit Jira service
-Set JIRA service for a project.
+Set Jira service for a project.
> Starting with GitLab 8.14, `api_url`, `issues_url`, `new_issue_url` and
> `project_url` are replaced by `url`. If you are using an
@@ -579,18 +578,18 @@ Parameters:
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
-| `url` | string | yes | The URL to the JIRA project which is being linked to this GitLab project. For example, `https://jira.example.com`. |
-| `api_url` | string | no | The base URL to the JIRA instance API. Web URL value will be used if not set. For example, `https://jira-api.example.com`. |
-| `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. |
+| `url` | string | yes | The URL to the Jira project which is being linked to this GitLab project. For example, `https://jira.example.com`. |
+| `api_url` | string | no | The base URL to the Jira instance API. Web URL value will be used if not set. For example, `https://jira-api.example.com`. |
+| `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 ([see screenshot][trans]). 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 |
-### Delete JIRA service
+### Delete Jira service
-Remove all previously JIRA settings from a project.
+Remove all previously Jira settings from a project.
```
DELETE /projects/:id/services/jira
@@ -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 |
@@ -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 c2a1f7feefd..876a5a75590 100644
--- a/doc/api/settings.md
+++ b/doc/api/settings.md
@@ -67,6 +67,14 @@ 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: **[PREMIUM ONLY]**
+
+```json
+ "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 +129,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 +169,12 @@ 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. |
@@ -158,10 +191,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. |
@@ -170,6 +224,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. |
@@ -192,6 +247,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`. |
@@ -203,23 +261,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. |
-| `sentry_dsn` | string | required by: `sentry_enabled` | Sentry Data Source Name. |
-| `sentry_enabled` | boolean | no | (**If enabled, requires:** `sentry_dsn`) Sentry is an error reporting and logging tool which is currently not shipped with GitLab, available at <https://sentry.io>. |
| `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). |
@@ -231,6 +294,7 @@ are listed in the descriptions of the relevant settings.
| `throttle_unauthenticated_enabled` | boolean | no | (**If enabled, requires:** `throttle_unauthenticated_period_in_seconds` and `throttle_unauthenticated_requests_per_period`) Enable unauthenticated request rate limit. Helps reduce request volume (e.g. from crawlers or abusive bots). |
| `throttle_unauthenticated_period_in_seconds` | integer | required by: `throttle_unauthenticated_enabled` | Rate limit period in seconds. |
| `throttle_unauthenticated_requests_per_period` | integer | required by: `throttle_unauthenticated_enabled` | Max requests per period per IP. |
+| `time_tracking_limit_to_hours` | boolean | no | Limit display of time tracking units to hours. Default is `false`. |
| `two_factor_grace_period` | integer | required by: `require_two_factor_authentication` | Amount of time (in hours) that users are allowed to skip forced configuration of two-factor authentication. |
| `unique_ips_limit_enabled` | boolean | no | (**If enabled, requires:** `unique_ips_limit_per_user` and `unique_ips_limit_time_window`) Limit sign in from multiple ips. |
| `unique_ips_limit_per_user` | integer | required by: `unique_ips_limit_enabled` | Maximum number of ips per user. |
@@ -241,3 +305,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 4bc0335ae33..6be097e6364 100644
--- a/doc/api/users.md
+++ b/doc/api/users.md
@@ -147,6 +147,24 @@ 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 +241,8 @@ Parameters:
- `id` (required) - The ID of a user
+Example Responses:
+
```json
{
"id": 1,
@@ -258,9 +278,27 @@ 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.
+Users on GitLab Silver 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}
+ ],
+ ...
}
```
@@ -272,7 +310,14 @@ GET /users/:id?with_custom_attributes=true
## User creation
-Creates a new user. Note only administrators can create new users. Either `password` or `reset_password` should be specified (`reset_password` takes priority). If `reset_password` is `false`, then `password` is required.
+Creates a new user. Note only administrators can create new
+users. Either `password`, `reset_password`, or `force_random_password`
+must be specified. If `reset_password` and `force_random_password` are
+both `false`, then `password` is required.
+
+Note that `force_random_password` and `reset_password` take priority
+over `password`. In addition, `reset_password` and
+`force_random_password` can be used together.
```
POST /users
@@ -293,7 +338,6 @@ Parameters:
- `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
@@ -303,8 +347,8 @@ Parameters:
- `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
+- `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
@@ -340,6 +384,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,
@@ -1262,4 +1308,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/ci/README.md b/doc/ci/README.md
index 1743c38eb46..d851a56ee0e 100644
--- a/doc/ci/README.md
+++ b/doc/ci/README.md
@@ -63,7 +63,7 @@ Once you're familiar with how GitLab CI/CD works, see the
for all the attributes you can set and use.
NOTE: **Note:**
-GitLab CI/CD and [shared runners](runners/README.md#shared-specific-and-group-runners) are enabled in GitLab.com and available for all users, limited only to the [user's pipelines quota](../user/admin_area/settings/continuous_integration.md#extra-shared-runners-pipeline-minutes-quota).
+GitLab CI/CD and [shared runners](runners/README.md#shared-specific-and-group-runners) are enabled in GitLab.com and available for all users, limited only to the [user's pipelines quota](../user/admin_area/settings/continuous_integration.md#extra-shared-runners-pipeline-minutes-quota-free-only).
## Configuration
@@ -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. |
diff --git a/doc/ci/docker/using_docker_build.md b/doc/ci/docker/using_docker_build.md
index b4c4bea6447..efdcaf5a6f5 100644
--- a/doc/ci/docker/using_docker_build.md
+++ b/doc/ci/docker/using_docker_build.md
@@ -205,7 +205,14 @@ An example project using this approach can be found here: <https://gitlab.com/gi
### Use Docker socket binding
-The third approach is to bind-mount `/var/run/docker.sock` into the container so that docker is available in the context of that image.
+The third approach is to bind-mount `/var/run/docker.sock` into the
+container so that Docker is available in the context of that image.
+
+NOTE: **Note:**
+If you bind the Docker socket [when using GitLab Runner 11.11 or
+newer](https://gitlab.com/gitlab-org/gitlab-runner/merge_requests/1261),
+you can no longer use `docker:dind` as a service because volume bindings
+are done to the services as well, making these incompatible.
In order to do that, follow the steps:
diff --git a/doc/ci/docker/using_docker_images.md b/doc/ci/docker/using_docker_images.md
index e4dc289dbdb..e012f4f8595 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,20 @@ 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_LOGIN` with appropriate authentication info.
+
+1. Per-job: To configure one job to access a private registry, add
+ `DOCKER_AUTH_LOGIN` as a job variable.
+1. Per-runner: To configure a Runner so all its jobs can access a
+ private registry, add `DOCKER_AUTH_LOGIN` to the environment in the
+ Runner's configuration.
+
+See below for examples of each.
+
+#### Determining your `DOCKER_AUTH_LOGIN` 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.
@@ -500,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:
+
+ ```bash
+ docker login registry.example.com:5000 --username my_username --password my_password
+ ```
-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:
+ Then copy the content of `~/.docker/config.json`.
- ```bash
- docker login registry.example.com:5000 --username my_username --password my_password
- ```
+ 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
- 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:
+ # 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:
@@ -538,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:
@@ -566,6 +581,37 @@ 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
@@ -574,7 +620,7 @@ Specifying only `registry.example.com` will not work.
To configure credentials store, follow these steps:
1. To use a credentials store, you need an external helper program to interact with a specific keychain or external store.
-Make sure helper program is available in GitLab Runner `$PATH`.
+ Make sure helper program is available in GitLab Runner `$PATH`.
1. Make GitLab Runner use it. There are two ways to accomplish this. Either:
- Create a
@@ -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/examples/test-scala-application.md b/doc/ci/examples/test-scala-application.md
index 0e33a1ba060..bd899240307 100644
--- a/doc/ci/examples/test-scala-application.md
+++ b/doc/ci/examples/test-scala-application.md
@@ -47,10 +47,10 @@ deploy:
In the above configuration:
- The `before_script` installs [SBT](http://www.scala-sbt.org/) and
-displays the version that is being used.
+ 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
-plugin to measure test coverage.
+ - [sbt-scoverage](https://github.com/scoverage/sbt-scoverage) is used as an SBT
+ plugin to measure test coverage.
- The `deploy` stage automatically deploys the project to Heroku using dpl.
You can use other versions of Scala and SBT by defining them in
diff --git a/doc/ci/merge_request_pipelines/index.md b/doc/ci/merge_request_pipelines/index.md
index 5adb7ebd30d..e70ae0bd154 100644
--- a/doc/ci/merge_request_pipelines/index.md
+++ b/doc/ci/merge_request_pipelines/index.md
@@ -1,14 +1,9 @@
---
-type: reference
+type: reference, index
+last_update: 2019-07-03
---
-# Pipelines for merge requests
-
-NOTE: **Note**:
-As of GitLab 11.10, pipelines for merge requests require GitLab Runner 11.9
-or higher due to the [recent refspecs
-changes](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/25504).
-Anything lower will cause the pipeline to fail.
+# Pipelines for Merge Requests
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/15310) in GitLab 11.6.
@@ -23,6 +18,16 @@ for when you are running a pipeline in a merge request. This
could be either adding or removing steps in the pipeline, to make sure that
your pipelines are as efficient as possible.
+## Requirements and limitations
+
+Pipelines for merge requests have the following requirements and limitations:
+
+- As of GitLab 11.10, pipelines for merge requests require GitLab Runner 11.9
+ or higher due to the
+ [recent refspecs changes](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/25504).
+- Pipelines for merge requests are incompatible with
+ [CI/CD for external repositories](../ci_cd_for_external_repos/index.md).
+
## Configuring pipelines for merge requests
To configure pipelines for merge requests, add the `only: merge_requests` parameter to
@@ -73,117 +78,11 @@ when a merge request was created or updated. For example:
## 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.
-
-### 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.
-
-### Pipelines for Merged Result's limitations
-
-- This feature requires [GitLab Runner](https://gitlab.com/gitlab-org/gitlab-runner) 11.9 or newer.
-- This feature requires [Gitaly](https://gitlab.com/gitlab-org/gitaly) 1.21.0 or newer.
-- 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).
-
-## 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).
+Read the [documentation on Pipelines for Merged Results](pipelines_for_merged_results/index.md).
-[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.
+### Merge Trains **[PREMIUM]**
-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.
-
-CAUTION: **Caution:**
-At the moment, 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)
-
-CAUTION: **Warning:**
-This feature requires [Pipelines for merged results](#pipelines-for-merged-results-premium) to be **configured properly**.
-
-### 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
@@ -269,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..3c5088089fa
--- /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..c5ff6f9ebed
--- /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/variables/README.md b/doc/ci/variables/README.md
index c8c92002be2..1b50273eca2 100644
--- a/doc/ci/variables/README.md
+++ b/doc/ci/variables/README.md
@@ -339,7 +339,7 @@ Group-level variables can be added by:
1. Navigating to your group's **Settings > CI/CD** page.
1. Inputing variable types, keys, and values in the **Variables** section.
-Any variables of [subgroups](../../user/group/subgroups/index.md) will be inherited recursively.
+ Any variables of [subgroups](../../user/group/subgroups/index.md) will be inherited recursively.
Once you set them, they will be available for all subsequent pipelines.
diff --git a/doc/ci/variables/predefined_variables.md b/doc/ci/variables/predefined_variables.md
index 4655eec51de..e911e97d3c8 100644
--- a/doc/ci/variables/predefined_variables.md
+++ b/doc/ci/variables/predefined_variables.md
@@ -30,7 +30,7 @@ future GitLab releases.**
| `CI_BUILDS_DIR` | all | 11.10 | Top-level directory where builds are executed. |
| `CI_CONCURRENT_ID` | all | 11.10 | Unique ID of build execution within a single executor. |
| `CI_CONCURRENT_PROJECT_ID` | all | 11.10 | Unique ID of build execution within a single executor and project. |
-| `CI_COMMIT_BEFORE_SHA` | 11.2 | all | The previous latest commit present on a branch before a push request. |
+| `CI_COMMIT_BEFORE_SHA` | 11.2 | all | The previous latest commit present on a branch before a push request. Only populated when there is a merge request associated with the pipeline. |
| `CI_COMMIT_DESCRIPTION` | 10.8 | all | The description of the commit: the message without first line, if the title is shorter than 100 characters; full message in other case. |
| `CI_COMMIT_MESSAGE` | 10.8 | all | The full commit message. |
| `CI_COMMIT_REF_NAME` | 9.0 | all | The branch or tag name for which project is built |
@@ -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/customization/system_header_and_footer_messages.md b/doc/customization/system_header_and_footer_messages.md
index 9d6931c730d..7eee79abc77 100644
--- a/doc/customization/system_header_and_footer_messages.md
+++ b/doc/customization/system_header_and_footer_messages.md
@@ -1,6 +1,7 @@
# 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.
diff --git a/doc/development/README.md b/doc/development/README.md
index af3207671e6..5df6ec5fd56 100644
--- a/doc/development/README.md
+++ b/doc/development/README.md
@@ -108,6 +108,7 @@ description: 'Learn how to contribute to GitLab.'
- [Database Debugging and Troubleshooting](database_debugging.md)
- [Query Count Limits](query_count_limits.md)
- [Database helper modules](database_helpers.md)
+- [Code comments](code_comments.md)
## Integration guides
diff --git a/doc/development/api_graphql_styleguide.md b/doc/development/api_graphql_styleguide.md
index f7f36901fe1..aeddad14995 100644
--- a/doc/development/api_graphql_styleguide.md
+++ b/doc/development/api_graphql_styleguide.md
@@ -198,9 +198,9 @@ abilities as in the Rails app.
If the:
- Currently authenticated user fails the authorization, the authorized
-resource will be returned as `null`.
+ resource will be returned as `null`.
- Resource is part of a collection, the collection will be filtered to
-exclude the objects that the user's authorization checks failed against.
+ exclude the objects that the user's authorization checks failed against.
TIP: **Tip:**
Try to load only what the currently authenticated user is allowed to
@@ -447,7 +447,7 @@ want to validate the abilities for.
Alternatively, we can add a `find_object` method that will load the
object on the mutation. This would allow you to use the
-`authorized_find!` and `authorized_find!` helper methods.
+`authorized_find!` helper method.
When a user is not allowed to perform the action, or an object is not
found, we should raise a
@@ -496,4 +496,4 @@ it 'returns a successful response' do
expect(response).to have_gitlab_http_status(:success)
expect(graphql_mutation_response(:merge_request_set_wip)['errors']).to be_empty
end
-``` \ No newline at end of file
+```
diff --git a/doc/development/architecture.md b/doc/development/architecture.md
index d14a760f972..ee6d00331e3 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.
-->
@@ -93,8 +93,8 @@ graph TB
Prometheus --> Alertmanager
Migrations --> PostgreSQL
Runner -- TCP 443 --> NGINX
- Unicorn -- TCP 9200 --> ElasticSearch
- Sidekiq -- TCP 9200 --> ElasticSearch
+ Unicorn -- TCP 9200 --> Elasticsearch
+ Sidekiq -- TCP 9200 --> Elasticsearch
Sidekiq -- TCP 80, 443 --> Sentry
Unicorn -- TCP 80, 443 --> Sentry
Sidekiq -- UDP 6831 --> Jaeger
@@ -116,10 +116,10 @@ graph TB
### Component legend
-* ✅ - Installed by default
-* ⚙ - Requires additional configuration, or GitLab Managed Apps
-* ⤓ - Manual installation required
-* ❌ - Not supported or no instructions available
+- ✅ - Installed by default
+- ⚙ - Requires additional configuration, or GitLab Managed Apps
+- ⤓ - Manual installation required
+- ❌ - Not supported or no instructions available
Component statuses are linked to configuration documentation for each component.
@@ -158,7 +158,7 @@ Component statuses are linked to configuration documentation for each component.
| [LDAP Authentication](#ldap-authentication) | Authenticate users against centralized LDAP directory | [⤓][ldap-omnibus] | [⤓][ldap-charts] | [⤓][ldap-charts] | [❌](https://about.gitlab.com/pricing/#gitlab-com) | [⤓][gitlab-yml] | [⤓][ldap-gdk] | CE & EE |
| [Outbound email (SMTP)](#outbound-email) | Send email messages to users | [⤓][outbound-email-omnibus] | [⤓][outbound-email-charts] | [⤓][outbound-email-charts] | [✅](../user/gitlab_com/index.md#mail-configuration) | [⤓][gitlab-yml] | [⤓][gitlab-yml] | CE & EE |
| [Inbound email (SMTP)](#inbound-email) | Receive messages to update issues | [⤓][inbound-email-omnibus] | [⤓][inbound-email-charts] | [⤓][inbound-email-charts] | [✅](../user/gitlab_com/index.md#mail-configuration) | [⤓][gitlab-yml] | [⤓][gitlab-yml] | CE & EE |
-| [ElasticSearch](#elasticsearch) | Improved search within GitLab | [⤓][elasticsearch-omnibus] | [⤓][elasticsearch-charts] | [⤓][elasticsearch-charts] | [❌](https://gitlab.com/groups/gitlab-org/-/epics/153) | [⤓][elasticsearch-source] | [⤓][elasticsearch-gdk] | EE Only |
+| [Elasticsearch](#elasticsearch) | Improved search within GitLab | [⤓][elasticsearch-omnibus] | [⤓][elasticsearch-charts] | [⤓][elasticsearch-charts] | [❌](https://gitlab.com/groups/gitlab-org/-/epics/153) | [⤓][elasticsearch-source] | [⤓][elasticsearch-gdk] | EE Only |
| [Sentry integration](#sentry) | Error tracking for deployed apps | [⤓][sentry-integration] | [⤓][sentry-integration] | [⤓][sentry-integration] | [⤓][sentry-integration] | [⤓][sentry-integration] | [⤓][sentry-integration] | CE & EE |
| [Jaeger integration](#jaeger) | Distributed tracing for deployed apps | [⤓][jaeger-integration] | [⤓][jaeger-integration] | [⤓][jaeger-integration] | [⤓][jaeger-integration] | [⤓][jaeger-integration] | [⤓][jaeger-integration] | EE Only |
| [GitLab Managed Apps](#gitlab-managed-apps) | Deploy [Helm](https://docs.helm.sh/), [Ingress](https://kubernetes.io/docs/concepts/services-networking/ingress/), [Cert-Manager](https://docs.cert-manager.io/en/latest/), [Prometheus](https://prometheus.io/docs/introduction/overview/), a [Runner](https://docs.gitlab.com/runner/), [JupyterHub](http://jupyter.org/), [Knative](https://cloud.google.com/knative) to a cluster | [⤓][managed-k8s-apps] | [⤓][managed-k8s-apps] | [⤓][managed-k8s-apps] | [⤓][managed-k8s-apps] | [⤓][managed-k8s-apps] | [⤓][managed-k8s-apps] | CE & EE |
@@ -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
diff --git a/doc/development/chatops_on_gitlabcom.md b/doc/development/chatops_on_gitlabcom.md
index c63ec53414c..a7b402c3fb0 100644
--- a/doc/development/chatops_on_gitlabcom.md
+++ b/doc/development/chatops_on_gitlabcom.md
@@ -1,12 +1,13 @@
# Chatops on GitLab.com
-Chatops on GitLab.com allows GitLabbers to run various automation tasks on GitLab.com using Slack.
+ChatOps on GitLab.com allows GitLab team members to run various automation tasks on GitLab.com using Slack.
## Requesting access
-GitLabbers may need access to Chatops on GitLab.com for administration tasks such as:
+GitLab team-members may need access to Chatops on GitLab.com for administration
+tasks such as:
-- Configuring feature flags on staging.
+- Configuring feature flags.
- Running `EXPLAIN` queries against the GitLab.com production replica.
To request access to Chatops on GitLab.com:
@@ -18,4 +19,4 @@ To request access to Chatops on GitLab.com:
- [Chatops Usage](https://docs.gitlab.com/ee/ci/chatops/README.html)
- [Understanding EXPLAIN plans](understanding_explain_plans.md)
- - [Feature Groups](feature_flags.md#feature-groups)
+ - [Feature Groups](feature_flags/development.md#feature-groups)
diff --git a/doc/development/code_comments.md b/doc/development/code_comments.md
new file mode 100644
index 00000000000..36962eb46d4
--- /dev/null
+++ b/doc/development/code_comments.md
@@ -0,0 +1,14 @@
+# 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
+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:
+
+```rb
+# Deprecated scope until code_owner column has been migrated to rule_type.
+# To be removed with https://gitlab.com/gitlab-org/gitlab-ee/issues/11834.
+scope :code_owner, -> { where(code_owner: true).or(where(rule_type: :code_owner)) }
+```
diff --git a/doc/development/code_review.md b/doc/development/code_review.md
index 29e2aa1a581..6123f9f845a 100644
--- a/doc/development/code_review.md
+++ b/doc/development/code_review.md
@@ -60,6 +60,8 @@ from teams other than your own.
1. If your merge request includes backend changes [^1], it must be
**approved by a [backend maintainer](https://about.gitlab.com/handbook/engineering/projects/#gitlab-ce_maintainers_backend)**.
+ 1. If your merge request includes database migrations or changes to expensive queries [^2], it must be
+ **approved by a [database maintainer](https://about.gitlab.com/handbook/engineering/projects/#gitlab-ce_maintainers_database)**.
1. If your merge request includes frontend changes [^1], it must be
**approved by a [frontend maintainer](https://about.gitlab.com/handbook/engineering/projects/#gitlab-ce_maintainers_frontend)**.
1. If your merge request includes UX changes [^1], it must be
@@ -377,3 +379,4 @@ Largely based on the [thoughtbot code review guide].
[team]: https://about.gitlab.com/team/
[build handbook]: https://about.gitlab.com/handbook/build/handbook/build#how-to-work-with-build
[^1]: Please note that specs other than JavaScript specs are considered backend code.
+[^2]: We encourage you to seek guidance from a database maintainer if your merge request is potentially introducing expensive queries. It is most efficient to comment on the line of code in question with the SQL queries so they can give their advice.
diff --git a/doc/development/contributing/issue_workflow.md b/doc/development/contributing/issue_workflow.md
index 3d36a7bf3b1..f4fa0caeb01 100644
--- a/doc/development/contributing/issue_workflow.md
+++ b/doc/development/contributing/issue_workflow.md
@@ -6,10 +6,13 @@ 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
@@ -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.
@@ -43,6 +45,10 @@ The descriptions on the [labels page][labels-page] explain what falls under each
Subject labels are labels that define what area or feature of GitLab this issue
hits. They are not always necessary, but very convenient.
+Subject labels are now used to infer and apply relevant group and devops stage
+labels. Please apply them whenever possible to facilitate accurate matching.
+Please refer to [this merge request][inferred-labels] for more information.
+
Examples of subject labels are ~wiki, ~ldap, ~api,
~issues, ~"merge requests", ~labels, and ~"Container Registry".
@@ -52,31 +58,37 @@ 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
- ~Growth
- ~Manage
+- ~Memory
- ~Monitor
- ~Plan
-- ~Quality
- ~Release
- ~Secure
-- ~UX
- ~Verify
+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][labels-page] explain what falls under the
responsibility of each team.
@@ -86,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.
@@ -126,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.
@@ -141,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
@@ -186,20 +247,20 @@ There can be multiple facets of the impact. The below is a guideline.
If a bug seems to fall between two severity labels, assign it to the higher-severity label.
-* Example(s) of ~S1
- * Data corruption/loss.
- * Security breach.
- * Unable to create an issue or merge request.
- * Unable to add a comment or discussion to the issue or merge request.
-* Example(s) of ~S2
- * Cannot submit changes through the web IDE but the commandline works.
- * A status widget on the merge request page is not working but information can be seen in the test pipeline page.
-* Example(s) of ~S3
- * Can create merge requests only from the Merge Requests list view, not from an Issue page.
- * Status is not updated in real time and needs a page refresh.
-* Example(s) of ~S4
- * Label colors are incorrect.
- * UI elements are not fully aligned.
+- Example(s) of ~S1
+ - Data corruption/loss.
+ - Security breach.
+ - Unable to create an issue or merge request.
+ - Unable to add a comment or discussion to the issue or merge request.
+- Example(s) of ~S2
+ - Cannot submit changes through the web IDE but the commandline works.
+ - A status widget on the merge request page is not working but information can be seen in the test pipeline page.
+- Example(s) of ~S3
+ - Can create merge requests only from the Merge Requests list view, not from an Issue page.
+ - Status is not updated in real time and needs a page refresh.
+- Example(s) of ~S4
+ - Label colors are incorrect.
+ - UI elements are not fully aligned.
## Label for community contributors
@@ -442,3 +503,4 @@ A recent example of this was the issue for
[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 8a4aa5dfa7f..6064f59ed10 100644
--- a/doc/development/contributing/merge_request_workflow.md
+++ b/doc/development/contributing/merge_request_workflow.md
@@ -126,16 +126,16 @@ When writing commit messages, please follow the guidelines below:
- The commit subject must contain at least 3 words.
- The commit subject should ideally contain up to 50 characters,
-and must not be longer than 72 characters.
+ and must not be longer than 72 characters.
- The commit subject must start with a capital letter.
- The commit subject must not end with a period.
- The commit subject and body must be separated by a blank line.
- The commit body must not contain more than 72 characters per line.
- Commits that change 30 or more lines across at least 3 files must
-describe these changes in the commit body.
+ describe these changes in the commit body.
- The commit subject or body must not contain Emojis.
- Use issues and merge requests' full URLs instead of short references,
-as they are displayed as plain text outside of GitLab.
+ as they are displayed as plain text outside of GitLab.
- The merge request must not contain more than 10 commit messages.
If the guidelines are not met, the MR will not pass the
diff --git a/doc/development/contributing/style_guides.md b/doc/development/contributing/style_guides.md
index f319d00d7fe..87e61a7476f 100644
--- a/doc/development/contributing/style_guides.md
+++ b/doc/development/contributing/style_guides.md
@@ -31,8 +31,8 @@ This is also the style used by linting tools such as
[Return to Contributing documentation](index.md)
-[rss-source]: https://github.com/bbatsov/ruby-style-guide/blob/master/README.md#source-code-layout
-[rss-naming]: https://github.com/bbatsov/ruby-style-guide/blob/master/README.md#naming
+[rss-source]: https://github.com/rubocop-hq/ruby-style-guide/blob/master/README.adoc#source-code-layout
+[rss-naming]: https://github.com/rubocop-hq/ruby-style-guide/blob/master/README.adoc#naming-conventions
[doc-guidelines]: ../documentation/index.md "Documentation guidelines"
[js-styleguide]: ../fe_guide/style_guide_js.md "JavaScript styleguide"
[scss-styleguide]: ../fe_guide/style_guide_scss.md "SCSS styleguide"
diff --git a/doc/development/database_debugging.md b/doc/development/database_debugging.md
index 68d33a9d8e0..de2c5b43411 100644
--- a/doc/development/database_debugging.md
+++ b/doc/development/database_debugging.md
@@ -85,3 +85,21 @@ eric 37709 0.0 0.0 2518640 7524 s006 S Wed11AM 0:00.79 s
$ kill 87304
$ kill 37709
```
+
+### db:migrate `database version is too old to be migrated` error
+
+Users receive this error when `db:migrate` detects that the current schema version
+is older than the `MIN_SCHEMA_VERSION` defined in the `Gitlab::Database` library
+module.
+
+Over time we cleanup/combine old migrations in the codebase, so it is not always
+possible to migrate GitLab from every previous version.
+
+In some cases you may want to bypass this check. For example, if you were on a version
+of GitLab schema later than the `MIN_SCHEMA_VERSION`, and then rolled back the
+to an older migration, from before. In this case, in order to migrate forward again,
+you should set the `SKIP_SCHEMA_VERSION_CHECK` environment variable.
+
+```sh
+bundle exec rake db:migrate SKIP_SCHEMA_VERSION_CHECK=true
+```
diff --git a/doc/development/documentation/index.md b/doc/development/documentation/index.md
index c7fa40af930..418e58b22d5 100644
--- a/doc/development/documentation/index.md
+++ b/doc/development/documentation/index.md
@@ -76,10 +76,10 @@ After a given documentation path is aligned across CE and EE, all merge requests
affecting that path must be submitted to CE, regardless of the content it has.
This means that:
-* For **EE-only docs changes**, you only have to submit a CE MR.
-* For **EE-only features** that touch both the code and the docs, you have to submit
-an EE MR containing all changes, and a CE MR containing only the docs changes
-and without a changelog entry.
+- For **EE-only docs changes**, you only have to submit a CE MR.
+- For **EE-only features** that touch both the code and the docs, you have to submit
+ an EE MR containing all changes, and a CE MR containing only the docs changes
+ and without a changelog entry.
This might seem like a duplicate effort, but it's only for the short term.
A list of the already aligned docs can be found in
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/site_architecture/index.md b/doc/development/documentation/site_architecture/index.md
index ee3a9caf9a0..6dd12b5efa7 100644
--- a/doc/development/documentation/site_architecture/index.md
+++ b/doc/development/documentation/site_architecture/index.md
@@ -11,8 +11,40 @@ and deploy it to <https://docs.gitlab.com>.
While the source of the documentation content is stored in GitLab's respective product
repositories, the source that is used to build the documentation site _from that content_
-is located at <https://gitlab.com/gitlab-com/gitlab-docs>. See the README there for
-detailed information.
+is located at <https://gitlab.com/gitlab-com/gitlab-docs>.
+
+The following diagram illustrates the relationship between the repositories
+from where content is sourced, the `gitlab-docs` project, and the published output.
+
+```mermaid
+ graph LR
+ A[gitlab-ce/doc]
+ B[gitlab-ee/doc]
+ C[gitlab-runner/docs]
+ D[omnibus-gitlab/doc]
+ E[charts/doc]
+ F[gitlab-docs]
+ A --> F
+ B --> F
+ C --> F
+ D --> F
+ E --> F
+ F -- Build pipeline --> G
+ G[docs.gitlab.com]
+ H[/ce/]
+ I[/ee/]
+ J[/runner/]
+ K[/omnibus/]
+ L[/charts/]
+ G --> H
+ G --> I
+ G --> J
+ G --> K
+ G --> L
+```
+
+See the [README there](https://gitlab.com/gitlab-com/gitlab-docs/blob/master/README.md)
+for detailed information.
## Assets
@@ -22,9 +54,9 @@ the GitLab Documentation website.
### Libraries
-- [Bootstrap 3.3 components](https://getbootstrap.com/docs/3.3/components/)
-- [Bootstrap 3.3 JS](https://getbootstrap.com/docs/3.3/javascript/)
-- [jQuery](https://jquery.com/) 3.2.1
+- [Bootstrap 4.3.1 components](https://getbootstrap.com/docs/4.3/components/)
+- [Bootstrap 4.3.1 JS](https://getbootstrap.com/docs/4.3/getting-started/javascript/)
+- [jQuery](https://jquery.com/) 3.3.1
- [Clipboard JS](https://clipboardjs.com/)
- [Font Awesome 4.7.0](https://fontawesome.com/v4.7.0/icons/)
diff --git a/doc/development/documentation/styleguide.md b/doc/development/documentation/styleguide.md
index b8506a72666..6bfedcb1047 100644
--- a/doc/development/documentation/styleguide.md
+++ b/doc/development/documentation/styleguide.md
@@ -76,8 +76,8 @@ and cross-link between any related content.
We employ a **docs-first methodology** to help ensure that the docs remain a complete and trusted resource, and to make communicating about the use of GitLab more efficient.
-* If the answer to a question exists in documentation, share the link to the docs instead of rephrasing the information.
-* When you encounter new information not available in GitLab’s documentation (for example, when working on a support case or testing a feature), your first step should be to create a merge request to add this information to the docs. You can then share the MR in order to communicate this information.
+- If the answer to a question exists in documentation, share the link to the docs instead of rephrasing the information.
+- When you encounter new information not available in GitLab’s documentation (for example, when working on a support case or testing a feature), your first step should be to create a merge request to add this information to the docs. You can then share the MR in order to communicate this information.
New information that would be useful toward the future usage or troubleshooting of GitLab should not be written directly in a forum or other messaging system, but added to a docs MR and then referenced, as described above. Note that among any other doc changes, you can always add a Troubleshooting section to a doc if none exists, or un-comment and use the placeholder Troubleshooting section included as part of our [doc template](structure.md#template-for-new-docs), if present.
@@ -100,6 +100,13 @@ use regular Markdown markup, following the rules in the linked style guide.
Note that Kramdown-specific markup (e.g., `{:.class}`) will not render properly on GitLab instances under [`/help`](index.md#gitlab-help).
+Hard-coded HTML is valid, although it's discouraged to be used while we have `/help`. HTML is permitted as long as:
+
+- There's no equivalent markup in markdown.
+- Advanced tables are necessary.
+- Special styling is required.
+- Reviewed and approved by a technical writer.
+
## Structure
### Organize by topic, not by type
@@ -143,7 +150,8 @@ The table below shows what kind of documentation goes where.
a proper naming would be `import_projects_from_github.md`. The same rule
applies to images.
1. For image files, do not exceed 100KB.
-1. We do not yet support embedded videos. Please link out.
+1. Do not upload video files to the product repositories.
+ [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/`.
@@ -165,13 +173,13 @@ The table below shows what kind of documentation goes where.
`doc/topics/topic-name/subtopic-name/index.md` when subtopics become necessary.
General user- and admin- related documentation, should be placed accordingly.
1. The directories `/workflow/`, `/university/`, and `/articles/` have
-been **deprecated** and the majority their docs have been moved to their correct location
-in small iterations.
+ been **deprecated** and the majority their docs have been moved to their correct location
+ in small iterations.
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
@@ -207,6 +215,7 @@ Do not include the same information in multiple places. [Link to a SSOT instead.
## Text
+- [Write in markdown](#markdown).
- Splitting long lines (preferably up to 100 characters) can make it easier to provide feedback on small chunks of text.
- Insert an empty line for new paragraphs.
- Use sentence case for titles, headings, labels, menu items, and buttons.
@@ -409,11 +418,20 @@ To indicate the steps of navigation through the UI:
## Images
- Place images in a separate directory named `img/` in the same directory where
- the `.md` document that you're working on is located. Always prepend their
- names with the name of the document that they will be included in. For
- example, if there is a document called `twitter.md`, then a valid image name
- could be `twitter_login_screen.png`.
-- Images should have a specific, non-generic name that will differentiate and describe them properly.
+ the `.md` document that you're working on is located.
+- Images should have a specific, non-generic name that will
+ differentiate and describe them properly.
+- Always add to the end of the file name the GitLab release version
+ number corresponding to the release milestone the image was added to,
+ or corresponding to the release the screenshot was taken from, using the
+ format `image_name_vX_Y.png`.
+ ([Introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/61027) in GitLab 12.1.)
+- For example, for a screenshot taken from the pipelines page of
+ GitLab 11.1, a valid name is `pipelines_v11_1.png`. If you're
+ adding an illustration that does not include parts of the UI,
+ add the release number corresponding to the release the image
+ was added to. Example, for an MR added to 11.1's milestone,
+ a valid name for an illustration is `devops_diagram_v11_1.png`.
- Keep all file names in lower case.
- Consider using PNG images instead of JPEG.
- Compress all images with <https://tinypng.com/> or similar tool.
@@ -421,12 +439,12 @@ To indicate the steps of navigation through the UI:
- Images should be used (only when necessary) to _illustrate_ the description
of a process, not to _replace_ it.
- Max image size: 100KB (gifs included).
-- The GitLab docs do not support videos yet.
+- See also how to link and embed [videos](#videos) to illustrate the docs.
Inside the document:
- The Markdown way of using an image inside a document is:
- `![Proper description what the image is about](img/document_image_title.png)`
+ `![Proper description what the image is about](img/document_image_title_vX_Y.png)`
- Always use a proper description for what the image is about. That way, when a
browser fails to show the image, this text will be used as an alternative
description.
@@ -446,6 +464,85 @@ directly to an HTML `img` tag:
<img src="path/to/image.jpg" alt="Alt text (required)" class="image-noshadow">
```
+## Videos
+
+Adding GitLab's existing YouTube video tutorials to the documentation is
+highly encouraged, unless the video is outdated. Videos should not
+replace documentation, but complement or illustrate it. If content in a video is
+fundamental to a feature and its key use cases, but this is not adequately covered in the documentation,
+add this detail to the documentation text or create an issue to review the video and do so.
+
+Do not upload videos to the product repositories. [Link](#link-to-video) or [embed](#embed-videos) them instead.
+
+### Link to video
+
+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
+<i class="fa fa-youtube-play youtube" aria-hidden="true"></i>
+For an overview, see [Video Title](link-to-video).
+```
+
+You can link any up-to-date video that is useful to the GitLab user.
+
+### Embed videos
+
+> [Introduced](https://gitlab.com/gitlab-com/gitlab-docs/merge_requests/472) in GitLab 12.1.
+
+GitLab docs (docs.gitlab.com) support embedded videos.
+
+You can only embed videos from
+[GitLab's official YouTube account](https://www.youtube.com/channel/UCnMGQ8QHMAnVIsI3xJrihhg).
+For videos from other sources, [link](#link-to-video) them instead.
+
+In most cases, it is better to [link to video](#link-to-video) instead,
+because an embed takes up a lot of space on the page and can be distracting
+to readers.
+
+To embed a video, follow the instructions below and make sure
+you have your MR reviewed and approved by a technical writer.
+
+1. Copy the code below and paste it into your markdown file.
+ Leave a blank line above and below it. Do NOT edit the code
+ (don't remove or add any spaces, etc).
+1. On YouTube, visit the video URL you want to display. Copy
+ the regular URL from your browser (`https://www.youtube.com/watch?v=VIDEO-ID`)
+ and replace the video title and link in the line under `<div class="video-fallback">`.
+1. On YouTube, click **Share**, then **Embed**.
+1. Copy the `<iframe>` source (`src`) **URL only**
+ (`https://www.youtube.com/embed/VIDEO-ID`),
+ and paste it, replacing the content of the `src` field in the
+ `iframe` tag.
+
+```html
+leave a blank line here
+<div class="video-fallback">
+ See the video: [Video title](https://www.youtube.com/watch?v=MqL6BMOySIQ).
+</div>
+<figure class="video-container">
+ <iframe src="https://www.youtube.com/embed/MqL6BMOySIQ" frameborder="0" allowfullscreen="true"> </iframe>
+</figure>
+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).
+</div>
+<figure class="video-container">
+ <iframe src="https://www.youtube.com/embed/MqL6BMOySIQ" frameborder="0" allowfullscreen="true"> </iframe>
+</figure>
+
+> Notes:
+>
+> - The `figure` tag is required for semantic SEO and the `video_container`
+class is necessary to make sure the video is responsive and displays
+nicely on different mobile devices.
+> - The `<div class="video-fallback">` is a fallback necessary for GitLab's
+`/help`, as GitLab's markdown processor does not support iframes. It's hidden on the docs site but will be displayed on GitLab's `/help`.
+
## Code blocks
- Always wrap code added to a sentence in inline code blocks (``` ` ```).
@@ -480,7 +577,7 @@ directly to an HTML `img` tag:
## Alert boxes
-Whenever you want to call the attention to a particular sentence,
+Whenever you need to call special attention to particular sentences,
use the following markup for highlighting.
_Note that the alert boxes only work for one paragraph only. Multiple paragraphs,
@@ -488,6 +585,23 @@ lists, headers, etc will not render correctly. For multiple lines, use blockquot
### Note
+Notes catch the eye of most readers, and therefore should be used very sparingly.
+In most cases, content considered for a note should be included:
+
+- As just another sentence in the previous paragraph or the most-relevant paragraph.
+- As its own standalone paragraph.
+- As content under a new subheading that introduces the topic, making it more visible/findable.
+
+#### When to use
+
+Use a note when there is a reason that most or all readers who browse the
+section should see the content. That is, if missed, it’s likely to cause
+major trouble for a minority of users or significant trouble for a majority
+of users.
+
+Weigh the costs of distracting users to whom the content is not relevant against
+the cost of users missing the content if it were not expressed as a note.
+
```md
NOTE: **Note:**
This is something to note.
diff --git a/doc/development/ee_features.md b/doc/development/ee_features.md
index cca52706ddc..6f4a36d4066 100644
--- a/doc/development/ee_features.md
+++ b/doc/development/ee_features.md
@@ -909,11 +909,12 @@ import bundle from 'ee_else_ce/protected_branches/protected_branches_bundle.js';
See the frontend guide [performance section](fe_guide/performance.md) for
information on managing page-specific javascript within EE.
-
## Vue code in `assets/javascript`
+
### script tag
#### Child Component only used in EE
+
To separate Vue template differences we should [async import the components](https://vuejs.org/v2/guide/components-dynamic-async.html#Async-Components).
Doing this allows for us to load the correct component in EE whilst in CE
@@ -937,10 +938,12 @@ export default {
```
#### For JS code that is EE only, like props, computed properties, methods, etc, we will keep the current approach
- - Since we [can't async load a mixin](https://github.com/vuejs/vue-loader/issues/418#issuecomment-254032223) we will use the [`ee_else_ce`](../development/ee_features.md#javascript-code-in-assetsjavascripts) alias we already have for webpack.
+
+- Since we [can't async load a mixin](https://github.com/vuejs/vue-loader/issues/418#issuecomment-254032223) we will use the [`ee_else_ce`](../development/ee_features.md#javascript-code-in-assetsjavascripts) alias we already have for webpack.
- This means all the EE specific props, computed properties, methods, etc that are EE only should be in a mixin in the `ee/` folder and we need to create a CE counterpart of the mixin
##### Example:
+
```javascript
import mixin from 'ee_else_ce/path/mixin';
@@ -955,18 +958,20 @@ import mixin from 'ee_else_ce/path/mixin';
- You can see an MR with an example [here](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/9762)
#### `template` tag
-* **EE Child components**
+
+- **EE Child components**
- Since we are using the async loading to check which component to load, we'd still use the component's name, check [this example](#child-component-only-used-in-ee).
-* **EE extra HTML**
+- **EE extra HTML**
- For the templates that have extra HTML in EE we should move it into a new component and use the `ee_else_ce` dynamic import
### Non Vue Files
+
For regular JS files, the approach is similar.
1. We will keep using the [`ee_else_ce`](../development/ee_features.md#javascript-code-in-assetsjavascripts) helper, this means that EE only code should be inside the `ee/` folder.
- 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:
+ 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:
@@ -996,6 +1001,7 @@ to isolate such ruleset from rest of CE rules (along with adding comment describ
to avoid conflicts during CE to EE merge.
#### Bad
+
```scss
.section-body {
.section-title {
@@ -1011,6 +1017,7 @@ to avoid conflicts during CE to EE merge.
```
#### Good
+
```scss
.section-body {
.section-title {
@@ -1029,7 +1036,14 @@ to avoid conflicts during CE to EE merge.
### Backporting changes from EE to CE
-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.
+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.
+
(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 c8c70fa7216..603a756ff56 100644
--- a/doc/development/elasticsearch.md
+++ b/doc/development/elasticsearch.md
@@ -2,14 +2,14 @@
This area is to maintain a compendium of useful information when working with elasticsearch.
-Information on how to enable ElasticSearch and perform the initial indexing is kept in ../integration/elasticsearch.md#enabling-elasticsearch
+Information on how to enable Elasticsearch and perform the initial indexing is kept in ../integration/elasticsearch.md#enabling-elasticsearch
## Deep Dive
-In June 2019, Mario de la Ossa hosted a [Deep Dive] on GitLab's [ElasticSearch integration] 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 12.0, and while specific details may have changed since then, it should still serve as a good introduction.
+In June 2019, Mario de la Ossa hosted a [Deep Dive] on GitLab's [Elasticsearch integration] 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 12.0, 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
-[ElasticSearch integration]: ../integration/elasticsearch.md
+[Elasticsearch integration]: ../integration/elasticsearch.md
[recording on YouTube]: https://www.youtube.com/watch?v=vrvl-tN2EaA
[Google Slides]: https://docs.google.com/presentation/d/1H-pCzI_LNrgrL5pJAIQgvLX8Ji0-jIKOg1QeJQzChug/edit
[PDF]: https://gitlab.com/gitlab-org/create-stage/uploads/c5aa32b6b07476fa8b597004899ec538/Elasticsearch_Deep_Dive.pdf
@@ -57,27 +57,32 @@ Additionally, if you need large repos or multiple forks for testing, please cons
## How does it work?
-The ElasticSearch integration depends on an external indexer. We ship a [ruby indexer](https://gitlab.com/gitlab-org/gitlab-ee/blob/master/bin/elastic_repo_indexer) by default but are also working on an [indexer written in Go](https://gitlab.com/gitlab-org/gitlab-elasticsearch-indexer). The user must trigger the initial indexing via a rake task, but after this is done GitLab itself will trigger reindexing when required via `after_` callbacks on create, update, and destroy that are inherited from [/ee/app/models/concerns/elastic/application_search.rb](https://gitlab.com/gitlab-org/gitlab-ee/blob/master/ee/app/models/concerns/elastic/application_search.rb).
+The Elasticsearch integration depends on an external indexer. We ship a [ruby indexer](https://gitlab.com/gitlab-org/gitlab-ee/blob/master/bin/elastic_repo_indexer) by default but are also working on an [indexer written in Go](https://gitlab.com/gitlab-org/gitlab-elasticsearch-indexer). The user must trigger the initial indexing via a rake task, but after this is done GitLab itself will trigger reindexing when required via `after_` callbacks on create, update, and destroy that are inherited from [/ee/app/models/concerns/elastic/application_search.rb](https://gitlab.com/gitlab-org/gitlab-ee/blob/master/ee/app/models/concerns/elastic/application_search.rb).
All indexing after the initial one is done via `ElasticIndexerWorker` (sidekiq jobs).
Search queries are generated by the concerns found in [ee/app/models/concerns/elastic](https://gitlab.com/gitlab-org/gitlab-ee/tree/master/ee/app/models/concerns/elastic). These concerns are also in charge of access control, and have been a historic source of security bugs so please pay close attention to them!
## 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
+
#### `path_analyzer`
+
Used when indexing blobs' paths. Uses the `path_tokenizer` and the `lowercase` and `asciifolding` filters.
Please see the `path_tokenizer` explanation below for an example.
#### `sha_analyzer`
+
Used in blobs and commits. Uses the `sha_tokenizer` and the `lowercase` and `asciifolding` filters.
Please see the `sha_tokenizer` explanation later below for an example.
#### `code_analyzer`
+
Used when indexing a blob's filename and content. Uses the `whitespace` tokenizer and the filters: `code`, `edgeNGram_filter`, `lowercase`, and `asciifolding`
The `whitespace` tokenizer was selected in order to have more control over how tokens are split. For example the string `Foo::bar(4)` needs to generate tokens like `Foo` and `bar(4)` in order to be properly searched.
@@ -85,15 +90,19 @@ The `whitespace` tokenizer was selected in order to have more control over how t
Please see the `code` filter for an explanation on how tokens are split.
#### `code_search_analyzer`
+
Not directly used for indexing, but rather used to transform a search input. Uses the `whitespace` tokenizer and the `lowercase` and `asciifolding` filters.
### Tokenizers
+
#### `sha_tokenizer`
+
This is a custom tokenizer that uses the [`edgeNGram` tokenizer](https://www.elastic.co/guide/en/elasticsearch/reference/5.5/analysis-edgengram-tokenizer.html) to allow SHAs to be searcheable by any sub-set of it (minimum of 5 chars).
-example:
+Example:
`240c29dc7e` becomes:
+
- `240c2`
- `240c29`
- `240c29d`
@@ -102,21 +111,26 @@ example:
- `240c29dc7e`
#### `path_tokenizer`
+
This is a custom tokenizer that uses the [`path_hierarchy` tokenizer](https://www.elastic.co/guide/en/elasticsearch/reference/5.5/analysis-pathhierarchy-tokenizer.html) with `reverse: true` in order to allow searches to find paths no matter how much or how little of the path is given as input.
-example:
+Example:
`'/some/path/application.js'` becomes:
+
- `'/some/path/application.js'`
- `'some/path/application.js'`
- `'path/application.js'`
- `'application.js'`
### Filters
+
#### `code`
-Uses a [Pattern Capture token filter](https://www.elastic.co/guide/en/elasticsearch/reference/5.5/analysis-pattern-capture-tokenfilter.html) to split tokens into more easily searched versions of themselves.
+
+Uses a [Pattern Capture token filter](https://www.elastic.co/guide/en/elasticsearch/reference/5.5/analysis-pattern-capture-tokenfilter.html) to split tokens into more easily searched versions of themselves.
Patterns:
+
- `"(\\p{Ll}+|\\p{Lu}\\p{Ll}+|\\p{Lu}+)"`: captures CamelCased and lowedCameCased strings as separate tokens
- `"(\\d+)"`: extracts digits
- `"(?=([\\p{Lu}]+[\\p{L}]+))"`: captures CamelCased strings recursively. Ex: `ThisIsATest` => `[ThisIsATest, IsATest, ATest, Test]`
@@ -126,6 +140,7 @@ Patterns:
- `'\/?([^\/]+)(?=\/|\b)'`: separate path terms `like/this/one`
#### `edgeNGram_filter`
+
Uses an [Edge NGram token filter](https://www.elastic.co/guide/en/elasticsearch/reference/5.5/analysis-edgengram-tokenfilter.html) to allow inputs with only parts of a token to find the token. For example it would turn `glasses` into permutations starting with `gl` and ending with `glasses`, which would allow a search for "`glass`" to find the original token `glasses`
## Gotchas
@@ -140,13 +155,13 @@ Uses an [Edge NGram token filter](https://www.elastic.co/guide/en/elasticsearch/
You might get an error such as
```
-[2018-10-31T15:54:19,762][WARN ][o.e.c.r.a.DiskThresholdMonitor] [pval5Ct]
- flood stage disk watermark [95%] exceeded on
- [pval5Ct7SieH90t5MykM5w][pval5Ct][/usr/local/var/lib/elasticsearch/nodes/0] free: 56.2gb[3%],
+[2018-10-31T15:54:19,762][WARN ][o.e.c.r.a.DiskThresholdMonitor] [pval5Ct]
+ flood stage disk watermark [95%] exceeded on
+ [pval5Ct7SieH90t5MykM5w][pval5Ct][/usr/local/var/lib/elasticsearch/nodes/0] free: 56.2gb[3%],
all indices on this node will be marked read-only
```
-This is because you've exceeded the disk space threshold - it thinks you don't have enough disk space left, based on the default 95% threshold.
+This is because you've exceeded the disk space threshold - it thinks you don't have enough disk space left, based on the default 95% threshold.
In addition, the `read_only_allow_delete` setting will be set to `true`. It will block indexing, `forcemerge`, etc
@@ -158,19 +173,19 @@ Add this to your `elasticsearch.yml` file:
```
# turn off the disk allocator
-cluster.routing.allocation.disk.threshold_enabled: false
+cluster.routing.allocation.disk.threshold_enabled: false
```
_or_
```
# set your own limits
-cluster.routing.allocation.disk.threshold_enabled: true
+cluster.routing.allocation.disk.threshold_enabled: true
cluster.routing.allocation.disk.watermark.flood_stage: 5gb # ES 6.x only
-cluster.routing.allocation.disk.watermark.low: 15gb
+cluster.routing.allocation.disk.watermark.low: 15gb
cluster.routing.allocation.disk.watermark.high: 10gb
```
-Restart ElasticSearch, and the `read_only_allow_delete` will clear on it's own.
+Restart Elasticsearch, and the `read_only_allow_delete` will clear on it's own.
_from "Disk-based Shard Allocation | Elasticsearch Reference" [5.6](https://www.elastic.co/guide/en/elasticsearch/reference/5.6/disk-allocator.html#disk-allocator) and [6.x](https://www.elastic.co/guide/en/elasticsearch/reference/6.x/disk-allocator.html)_
diff --git a/doc/development/fe_guide/accessibility.md b/doc/development/fe_guide/accessibility.md
index df32242a522..64c793cfd64 100644
--- a/doc/development/fe_guide/accessibility.md
+++ b/doc/development/fe_guide/accessibility.md
@@ -5,8 +5,16 @@
[Chrome Accessibility Developer Tools][chrome-accessibility-developer-tools]
are useful for testing for potential accessibility problems in GitLab.
-Accessibility best-practices and more in-depth information is available on
-[the Audit Rules page][audit-rules] for the Chrome Accessibility Developer Tools.
+The [axe][axe-website] browser extension (available for [Firefox][axe-firefox-extension] and [Chrome][axe-chrome-extension]) is
+also a handy tool for running audits and getting feedback on markup, CSS and even potentially problematic color usages.
+
+Accessibility best-practices and more in-depth information are available on
+[the Audit Rules page][audit-rules] for the Chrome Accessibility Developer Tools. The "[awesome a11y][awesome-a11y]" list is also a
+useful compilation of accessibility-related material.
[chrome-accessibility-developer-tools]: https://github.com/GoogleChrome/accessibility-developer-tools
[audit-rules]: https://github.com/GoogleChrome/accessibility-developer-tools/wiki/Audit-Rules
+[axe-website]: https://www.deque.com/axe/
+[axe-firefox-extension]: https://addons.mozilla.org/en-US/firefox/addon/axe-devtools/
+[axe-chrome-extension]: https://chrome.google.com/webstore/detail/axe/lhdoppojpmngadmnindnejefpokejbdd
+[awesome-a11y]: https://github.com/brunopulis/awesome-a11y
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 8c6a73c6824..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,12 +121,13 @@ 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
- Mixing Vue and jQuery is not recommended.
-- If you need to use a specific jQuery plugin in Vue, [create a wrapper around it][https://vuejs.org/v2/examples/select2.html].
+- If you need to use a specific jQuery plugin in Vue, [create a wrapper around it](https://vuejs.org/v2/examples/select2.html).
- It is acceptable for Vue to listen to existing jQuery events using jQuery event listeners.
- It is not recommended to add new jQuery events for Vue to interact with 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.md b/doc/development/feature_flags.md
index 13f0c5cc33e..6bad91d6287 100644
--- a/doc/development/feature_flags.md
+++ b/doc/development/feature_flags.md
@@ -1,127 +1 @@
-# Manage feature flags
-
-Starting from GitLab 9.3 we support feature flags for features in GitLab via
-[Flipper](https://github.com/jnunemaker/flipper/). You should use the `Feature`
-class (defined in `lib/feature.rb`) in your code to get, set and list feature
-flags.
-
-During runtime you can set the values for the gates via the
-[features API](../api/features.md) (accessible to admins only).
-
-## Feature groups
-
-Starting from GitLab 9.4 we support feature groups via
-[Flipper groups](https://github.com/jnunemaker/flipper/blob/v0.10.2/docs/Gates.md#2-group).
-
-Feature groups must be defined statically in `lib/feature.rb` (in the
-`.register_feature_groups` method), but their implementation can obviously be
-dynamic (querying the DB etc.).
-
-Once defined in `lib/feature.rb`, you will be able to activate a
-feature for a given feature group via the [`feature_group` param of the features API](../api/features.md#set-or-create-a-feature)
-
-For GitLab.com, [team members have access to feature flags through Chatops](chatops_on_gitlabcom.md). Only
-percentage gates are supported at this time. Setting a feature to be used 50% of
-the time, you should execute `/chatops run feature set my_feature_flag 50`.
-
-## Feature flags for user applications
-
-This document only covers feature flags used in the development of GitLab
-itself. Feature flags in deployed user applications can be found at
-[Feature Flags](../user/project/operations/feature_flags.md)
-
-## Developing with feature flags
-
-In general, it's better to have a group- or user-based gate, and you should prefer
-it over the use of percentage gates. This would make debugging easier, as you
-filter for example logs and errors based on actors too. Furthermore, this allows
-for enabling for the `gitlab-org` group first, while the rest of the users
-aren't impacted.
-
-```ruby
-# Good
-Feature.enabled?(:feature_flag, project)
-
-# Avoid, if possible
-Feature.enabled?(:feature_flag)
-```
-
-To use feature gates based on actors, the model needs to respond to
-`flipper_id`. For example, to enable for the Foo model:
-
-```ruby
-class Foo < ActiveRecord::Base
- include FeatureGate
-end
-```
-
-Features that are developed and are intended to be merged behind a feature flag
-should not include a changelog entry. The entry should be added in the merge
-request removing the feature flags.
-
-In the rare case that you need the feature flag to be on automatically, use
-`default_enabled: true` when checking:
-
-```ruby
-Feature.enabled?(:feature_flag, project, default_enabled: true)
-```
-
-For more information about rolling out changes using feature flags, refer to the
-[Rolling out changes using feature flags](rolling_out_changes_using_feature_flags.md)
-guide.
-
-### Frontend
-
-For frontend code you can use the method `push_frontend_feature_flag`, which is
-available to all controllers that inherit from `ApplicationController`. Using
-this method you can expose the state of a feature flag as follows:
-
-```ruby
-before_action do
- push_frontend_feature_flag(:vim_bindings)
-end
-
-def index
- # ...
-end
-
-def edit
- # ...
-end
-```
-
-You can then check for the state of the feature flag in JavaScript as follows:
-
-```javascript
-if ( gon.features.vimBindings ) {
- // ...
-}
-```
-
-The name of the feature flag in JavaScript will always be camelCased, meaning
-that checking for `gon.features.vim_bindings` would not work.
-
-### Specs
-
-In the test environment `Feature.enabled?` is stubbed to always respond to `true`,
-so we make sure behavior under feature flag doesn't go untested in some non-specific
-contexts.
-
-Whenever a feature flag is present, make sure to test _both_ states of the
-feature flag.
-
-See the
-[testing guide](testing_guide/best_practices.md#feature-flags-in-tests)
-for information and examples on how to stub feature flags in tests.
-
-## Enabling a feature flag (in development)
-
-In the rails console (`rails c`), enter the following command to enable your feature flag
-
-```ruby
-Feature.enable(:feature_flag_name)
-```
-
-## Enabling a feature flag (in production)
-
-Check how to [roll out changes using feature flags](rolling_out_changes_using_feature_flags.md).
+This document was moved to [another location](feature_flags/index.md).
diff --git a/doc/development/feature_flags/controls.md b/doc/development/feature_flags/controls.md
new file mode 100644
index 00000000000..c67467b7c11
--- /dev/null
+++ b/doc/development/feature_flags/controls.md
@@ -0,0 +1,123 @@
+# Access for enabling a feature flag in production
+
+In order to be able to turn on/off features behind feature flags in any of the
+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).
+
+Once you are added to the project test if your access propagated,
+run:
+
+```
+/chatops run feature --help
+```
+
+## Rolling out changes
+
+When the changes are deployed to the environments it is time to start
+rolling out the feature to our users. The exact procedure of rolling out a
+change is unspecified, as this can vary from change to change. However, in
+general we recommend rolling out changes incrementally, instead of enabling them
+for everybody right away. We also recommend you to _not_ enable a feature
+_before_ the code is being deployed.
+This allows you to separate rolling out a feature from a deploy, making it
+easier to measure the impact of both separately.
+
+GitLab's feature library (using
+[Flipper](https://github.com/jnunemaker/flipper), and covered in the [Feature
+Flags process](process.md) guide) supports rolling out changes to a percentage of
+users. This in turn can be controlled using [GitLab chatops](../../ci/chatops/README.md).
+
+For an up to date list of feature flag commands please see [the source
+code](https://gitlab.com/gitlab-com/chatops/blob/master/lib/chatops/commands/feature.rb).
+Note that all the examples in that file must be preceded by
+`/chatops run`.
+
+If you get an error "Whoops! This action is not allowed. This incident
+will be reported." that means your Slack account is not allowed to
+change feature flags or you do not [have access](#access-for-enabling-a-feature-flag-in-production).
+
+### Enabling feature for staging and dev.gitlab.org
+
+As a first step in a feature rollout, you should enable the feature on <https://staging.gitlab.com>
+and <https://dev.gitlab.org>.
+
+For example, to enable a feature for 25% of all users, run the following in
+Slack:
+
+```
+/chatops run feature set new_navigation_bar 25 --dev
+/chatops run feature set new_navigation_bar 25 --staging
+```
+
+These two environments have different scopes.
+`dev.gitlab.org` is a production CE environment that has internal GitLab Inc.
+traffic and is used for some development and other related work.
+`staging.gitlab.com` has a smaller subset of GitLab.com database and repositories
+and does not have regular traffic. Staging is an EE instance and can give you
+a (very) rough estimate of how your feature will look/behave on GitLab.com.
+Both of these instances are connected to Sentry so make sure you check the projects
+there for any exceptions while testing your feature after enabling the feature flag.
+
+Once you are confident enough that these environments are in a good state with your
+feature enabled, you can roll out the change to GitLab.com.
+
+## Enabling feature for GitLab.com
+
+Similar to above, to enable a feature for 25% of all users, run the following in
+Slack:
+
+```
+/chatops run feature set new_navigation_bar 25
+```
+
+This will enable the feature for GitLab.com, with `new_navigation_bar` being the
+name of the feature.
+
+If you are not certain what percentages to use, simply use the following steps:
+
+1. 25%
+1. 50%
+1. 75%
+1. 100%
+
+Between every step you'll want to wait a little while and monitor the
+appropriate graphs on <https://dashboards.gitlab.net>. The exact time to wait
+may differ. For some features a few minutes is enough, while for others you may
+want to wait several hours or even days. This is entirely up to you, just make
+sure it is clearly communicated to your team, and the Production team if you
+anticipate any potential problems.
+
+Feature gates can also be actor based, for example a feature could first be
+enabled for only the `gitlab-ce` project. The project is passed by supplying a
+`--project` flag:
+
+```
+/chatops run feature set --project=gitlab-org/gitlab-ce some_feature true
+```
+
+For groups the `--group` flag is available:
+
+```
+/chatops run feature set --group=gitlab-org some_feature true
+```
+
+## Cleaning up
+
+Once the change is deemed stable, submit a new merge request to remove the
+feature flag. This ensures the change is available to all users and self-hosted
+instances. Make sure to add the ~"feature flag" label to this merge request so
+release managers are aware the changes are hidden behind a feature flag. If the
+merge request has to be picked into a stable branch, 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.
+
+When a feature gate has been removed from the code base, the value still exists
+in the database.
+This can be removed through ChatOps:
+
+```
+/chatops run feature delete some_feature
+```
diff --git a/doc/development/feature_flags/development.md b/doc/development/feature_flags/development.md
new file mode 100644
index 00000000000..238052529d9
--- /dev/null
+++ b/doc/development/feature_flags/development.md
@@ -0,0 +1,131 @@
+# Developing with feature flags
+
+In general, it's better to have a group- or user-based gate, and you should prefer
+it over the use of percentage gates. This would make debugging easier, as you
+filter for example logs and errors based on actors too. Furthermore, this allows
+for enabling for the `gitlab-org` or `gitlab-com` group first, while the rest of
+the users aren't impacted.
+
+```ruby
+# Good
+Feature.enabled?(:feature_flag, project)
+
+# Avoid, if possible
+Feature.enabled?(:feature_flag)
+```
+
+To use feature gates based on actors, the model needs to respond to
+`flipper_id`. For example, to enable for the Foo model:
+
+```ruby
+class Foo < ActiveRecord::Base
+ include FeatureGate
+end
+```
+
+Features that are developed and are intended to be merged behind a feature flag
+should not include a changelog entry. The entry should be added in the merge
+request removing the feature flags.
+
+In the rare case that you need the feature flag to be on automatically, use
+`default_enabled: true` when checking:
+
+```ruby
+Feature.enabled?(:feature_flag, project, default_enabled: true)
+```
+
+The [`Project#feature_available?`][project-fa],
+[`Namespace#feature_available?`][namespace-fa] (EE), and
+[`License.feature_available?`][license-fa] (EE) methods all implicitly check for
+a feature flag by the same name as the provided argument.
+
+For example if a feature is license-gated, there's no need to add an additional
+explicit feature flag check since the flag will be checked as part of the
+`License.feature_available?` call. Similarly, there's no need to "clean up" a
+feature flag once the feature has reached general availability.
+
+You'd still want to use an explicit `Feature.enabled?` check if your new feature
+isn't gated by a License or Plan.
+
+[project-fa]: https://gitlab.com/gitlab-org/gitlab-ee/blob/4cc1c62918aa4c31750cb21dfb1a6c3492d71080/app/models/project_feature.rb#L63-68
+[namespace-fa]: https://gitlab.com/gitlab-org/gitlab-ee/blob/4cc1c62918aa4c31750cb21dfb1a6c3492d71080/ee/app/models/ee/namespace.rb#L71-85
+[license-fa]: https://gitlab.com/gitlab-org/gitlab-ee/blob/4cc1c62918aa4c31750cb21dfb1a6c3492d71080/ee/app/models/license.rb#L293-300
+
+An important side-effect of the implicit feature flags mentioned above is that
+unless the feature is explicitly disabled or limited to a percentage of users,
+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):
+
+```
+/chatops run feature set some_feature 0
+```
+
+Note that you can do this at any time, even before the merge request using the
+flag has been merged!
+
+## Feature groups
+
+Starting from GitLab 9.4 we support feature groups via
+[Flipper groups](https://github.com/jnunemaker/flipper/blob/v0.10.2/docs/Gates.md#2-group).
+
+Feature groups must be defined statically in `lib/feature.rb` (in the
+`.register_feature_groups` method), but their implementation can obviously be
+dynamic (querying the DB etc.).
+
+Once defined in `lib/feature.rb`, you will be able to activate a
+feature for a given feature group via the [`feature_group` param of the features API](../../api/features.md#set-or-create-a-feature)
+
+### Frontend
+
+For frontend code you can use the method `push_frontend_feature_flag`, which is
+available to all controllers that inherit from `ApplicationController`. Using
+this method you can expose the state of a feature flag as follows:
+
+```ruby
+before_action do
+ push_frontend_feature_flag(:vim_bindings)
+end
+
+def index
+ # ...
+end
+
+def edit
+ # ...
+end
+```
+
+You can then check for the state of the feature flag in JavaScript as follows:
+
+```javascript
+if ( gon.features.vimBindings ) {
+ // ...
+}
+```
+
+The name of the feature flag in JavaScript will always be camelCased, meaning
+that checking for `gon.features.vim_bindings` would not work.
+
+### Specs
+
+In the test environment `Feature.enabled?` is stubbed to always respond to `true`,
+so we make sure behavior under feature flag doesn't go untested in some non-specific
+contexts.
+
+Whenever a feature flag is present, make sure to test _both_ states of the
+feature flag.
+
+See the
+[testing guide](../testing_guide/best_practices.md#feature-flags-in-tests)
+for information and examples on how to stub feature flags in tests.
+
+### Enabling a feature flag (in development)
+
+In the rails console (`rails c`), enter the following command to enable your feature flag
+
+```ruby
+Feature.enable(:feature_flag_name)
+```
diff --git a/doc/development/feature_flags/index.md b/doc/development/feature_flags/index.md
new file mode 100644
index 00000000000..56872f8c075
--- /dev/null
+++ b/doc/development/feature_flags/index.md
@@ -0,0 +1,12 @@
+# Feature flags in development of GitLab
+
+Feature flags can be used to gradually roll out changes, be
+it a new feature, or a performance improvement. By using feature flags, we can
+comfortably measure the impact of our changes, while still being able to easily
+disable those changes, without having to revert an entire release.
+
+Before using feature flags for GitLab's development, read through the following:
+
+- [Process for using features flags](process.md).
+- [Developing with feature flags documentation](development.md).
+- [Controlling feature flags documentation](controls.md).
diff --git a/doc/development/feature_flags/process.md b/doc/development/feature_flags/process.md
new file mode 100644
index 00000000000..28d6080ce87
--- /dev/null
+++ b/doc/development/feature_flags/process.md
@@ -0,0 +1,131 @@
+# Feature flags process
+
+## Feature flags for user applications
+
+This document only covers feature flags used in the development of GitLab
+itself. Feature flags in deployed user applications can be found at
+[Feature Flags feature documentation](../../user/project/operations/feature_flags.md).
+
+## Feature flags in GitLab development
+
+The following highlights should be considered when deciding if feature flags
+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.
+- The person operating with feature flags is responsible for clearly communicating
+ 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.
+
+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
+flag does not have to stick around for a specific amount of time
+(e.g. at least one release), instead they should stick around until the feature
+is deemed stable. Stable means it works on GitLab.com without causing any
+problems, such as outages.
+
+### When to use feature flags
+
+Starting with GitLab 11.4, developers are required to use feature flags for
+non-trivial changes. Such changes include:
+
+- New features (e.g. a new merge request widget, epics, etc).
+- Complex performance improvements that may require additional testing in
+ production, such as rewriting complex queries.
+- Invasive changes to the user interface, such as a new navigation bar or the
+ removal of a sidebar.
+- Adding support for importing projects from a third-party service.
+
+In all cases, those working on the changes can best decide if a feature flag is
+necessary. For example, changing the color of a button doesn't need a feature
+flag, while changing the navigation bar definitely needs one. In case you are
+uncertain if a feature flag is necessary, simply ask about this in the merge
+request, and those reviewing the changes will likely provide you with an answer.
+
+When using a feature flag for UI elements, make sure to _also_ use a feature
+flag for the underlying backend code, if there is any. This ensures there is
+absolutely no way to use the feature until it is enabled.
+
+### Including a feature behind feature flag in the final release
+
+In order to build a final release and present the feature for self-hosted
+users, the feature flag should be at least defaulted to **on**. If the feature
+is deemed stable and there is confidence that removing the feature flag is safe,
+consider removing the feature flag altogether. Take into consideration that such
+action can make the feature available on GitLab.com shortly after the change to
+the feature flag is merged.
+
+Changing the default state or removing the feature flag has to be done before
+the 22nd of the month, _at least_ 2 working days before, in order for the change
+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.
+- 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.
+
+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
+the changes are deemed problematic, too invasive, or there simply isn't enough
+time to properly measure how the changes behave on GitLab.com.
+
+### The cost of feature flags
+
+When reading the above, one might be tempted to think this procedure is going to
+add a lot of work. Fortunately, this is not the case, and we'll show why. For
+this example we'll specify the cost of the work to do as a number, ranging from
+0 to infinity. The greater the number, the more expensive the work is. The cost
+does _not_ translate to time, it's just a way of measuring complexity of one
+change relative to another.
+
+Let's say we are building a new feature, and we have determined that the cost of
+this is 10. We have also determined that the cost of adding a feature flag check
+in a variety of places is 1. If we do not use feature flags, and our feature
+works as intended, our total cost is 10. This however is the best case scenario.
+Optimizing for the best case scenario is guaranteed to lead to trouble, whereas
+optimizing for the worst case scenario is almost always better.
+
+To illustrate this, let's say our feature causes an outage, and there's no
+immediate way to resolve it. This means we'd have to take the following steps to
+resolve the outage:
+
+1. Revert the release.
+1. Perform any cleanups that might be necessary, depending on the changes that
+ were made.
+1. Revert the commit, ensuring the "master" branch remains stable. This is
+ especially necessary if solving the problem can take days or even weeks.
+1. Pick the revert commit into the appropriate stable branches, ensuring we
+ don't block any future releases until the problem is resolved.
+
+As history has shown, these steps are time consuming, complex, often involve
+many developers, and worst of all: our users will have a bad experience using
+GitLab.com until the problem is resolved.
+
+Now let's say that all of this has an associated cost of 10. This means that in
+the worst case scenario, which we should optimize for, our total cost is now 20.
+
+If we had used a feature flag, things would have been very different. We don't
+need to revert a release, and because feature flags are disabled by default we
+don't need to revert and pick any Git commits. In fact, all we have to do is
+disable the feature, and in the worst case, perform cleanup. Let's say that
+the cost of this is 2. In this case, our best case cost is 11: 10 to build the
+feature, and 1 to add the feature flag. The worst case cost is now 13: 10 to
+build the feature, 1 to add the feature flag, and 2 to disable and clean up.
+
+Here we can see that in the best case scenario the work necessary is only a tiny
+bit more compared to not using a feature flag. Meanwhile, the process of
+reverting our changes has been made significantly and reliably cheaper.
+
+In other words, feature flags do not slow down the development process. Instead,
+they speed up the process as managing incidents now becomes _much_ easier. Once
+continuous deployments are easier to perform, the time to iterate on a feature
+is reduced even further, as you no longer need to wait weeks before your changes
+are available on GitLab.com.
diff --git a/doc/development/geo.md b/doc/development/geo.md
index 6e59fab34c7..a10f13b069f 100644
--- a/doc/development/geo.md
+++ b/doc/development/geo.md
@@ -14,10 +14,10 @@ Geo handles replication for different components:
- [Database](#database-replication): includes the entire application, except cache and jobs.
- [Git repositories](#repository-replication): includes both projects and wikis.
- [Uploaded blobs](#uploads-replication): includes anything from images attached on issues
-to raw logs and assets from CI.
+ to raw logs and assets from CI.
With the exception of the Database replication, on a *secondary* node, everything is coordinated
-by the [Geo Log Cursor](#geo-log-cursor).
+by the [Geo Log Cursor](#geo-log-cursor).
### Geo Log Cursor daemon
@@ -31,8 +31,8 @@ picks the event up and schedules a `Geo::ProjectSyncWorker` job which will
use the `Geo::RepositorySyncService` and `Geo::WikiSyncService` classes
to update the repository and the wiki respectively.
-The Geo Log Cursor daemon can operate in High Availability mode automatically.
-The daemon will try to acquire a lock from time to time and once acquired, it
+The Geo Log Cursor daemon can operate in High Availability mode automatically.
+The daemon will try to acquire a lock from time to time and once acquired, it
will behave as the *active* daemon.
Any additional running daemons on the same node, will be in standby
@@ -164,20 +164,20 @@ The Git Push Proxy exists as a functionality built inside the `gitlab-shell` com
It is active on a **secondary** node only. It allows the user that has cloned a repository
from the secondary node to push to the same URL.
-Git `push` requests directed to a **secondary** node will be sent over to the **primary** node,
+Git `push` requests directed to a **secondary** node will be sent over to the **primary** node,
while `pull` requests will continue to be served by the **secondary** node for maximum efficiency.
HTTPS and SSH requests are handled differently:
- With HTTPS, we will give the user a `HTTP 302 Redirect` pointing to the project on the **primary** node.
-The git client is wise enough to understand that status code and process the redirection.
+ The git client is wise enough to understand that status code and process the redirection.
- With SSH, because there is no equivalent way to perform a redirect, we have to proxy the request.
-This is done inside [`gitlab-shell`](https://gitlab.com/gitlab-org/gitlab-shell), by first translating the request
-to the HTTP protocol, and then proxying it to the **primary** node.
+ This is done inside [`gitlab-shell`](https://gitlab.com/gitlab-org/gitlab-shell), by first translating the request
+ to the HTTP protocol, and then proxying it to the **primary** node.
-The [`gitlab-shell`](https://gitlab.com/gitlab-org/gitlab-shell) daemon knows when to proxy based on the response
-from `/api/v4/allowed`. A special `HTTP 300` status code is returned and we execute a "custom action",
-specified in the response body. The response contains additional data that allows the proxied `push` operation
+The [`gitlab-shell`](https://gitlab.com/gitlab-org/gitlab-shell) daemon knows when to proxy based on the response
+from `/api/v4/allowed`. A special `HTTP 300` status code is returned and we execute a "custom action",
+specified in the response body. The response contains additional data that allows the proxied `push` operation
to happen on the **primary** node.
## Using the Tracking Database
@@ -229,17 +229,17 @@ named `gitlab_secondary`. This configuration exists within the database's user
context only. To access the `gitlab_secondary`, GitLab needs to use the
same database user that had previously been configured.
-The Geo Tracking Database accesses the readonly database replica via FDW as a regular user,
-limited by its own restrictions. The credentials are configured as a
-`USER MAPPING` associated with the `SERVER` mapped previously
+The Geo Tracking Database accesses the readonly database replica via FDW as a regular user,
+limited by its own restrictions. The credentials are configured as a
+`USER MAPPING` associated with the `SERVER` mapped previously
(`gitlab_secondary`).
FDW configuration and credentials definition are managed automatically by the
-Omnibus GitLab `gitlab-ctl reconfigure` command.
+Omnibus GitLab `gitlab-ctl reconfigure` command.
#### Refeshing the Foreign Tables
-Whenever a new Geo node is configured or the database schema changes on the
+Whenever a new Geo node is configured or the database schema changes on the
**primary** node, you must refresh the foreign tables on the **secondary** node
by running the following:
@@ -279,11 +279,11 @@ on the Tracking Database:
SELECT project_registry.*
FROM project_registry
JOIN gitlab_secondary.projects
- ON (project_registry.project_id = gitlab_secondary.projects.id
+ ON (project_registry.project_id = gitlab_secondary.projects.id
AND gitlab_secondary.projects.archived IS FALSE)
```
-At the ActiveRecord level, we have additional Models that represent the
+At the ActiveRecord level, we have additional Models that represent the
foreign tables. They must be mapped in a slightly different way, and they are read-only.
Check the existing FDW models in `ee/app/models/geo/fdw` for reference.
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/gitaly.md b/doc/development/gitaly.md
index a0585fed2fc..5552d5d37b4 100644
--- a/doc/development/gitaly.md
+++ b/doc/development/gitaly.md
@@ -88,12 +88,12 @@ Until GitLab has eliminated most of these inefficiencies or the use of
NFS is discontinued for Git data, Rugged implementations of some of the
most commonly-used RPCs can be enabled via feature flags:
-* `rugged_find_commit`
-* `rugged_get_tree_entries`
-* `rugged_tree_entry`
-* `rugged_commit_is_ancestor`
-* `rugged_commit_tree_entry`
-* `rugged_list_commits_by_oid`
+- `rugged_find_commit`
+- `rugged_get_tree_entries`
+- `rugged_tree_entry`
+- `rugged_commit_is_ancestor`
+- `rugged_commit_tree_entry`
+- `rugged_list_commits_by_oid`
A convenience Rake task can be used to enable or disable these flags
all together. To enable:
diff --git a/doc/development/go_guide/index.md b/doc/development/go_guide/index.md
index 4dad8815fcb..f961a2fc837 100644
--- a/doc/development/go_guide/index.md
+++ b/doc/development/go_guide/index.md
@@ -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)
diff --git a/doc/development/i18n/externalization.md b/doc/development/i18n/externalization.md
index ce310672dad..17462887162 100644
--- a/doc/development/i18n/externalization.md
+++ b/doc/development/i18n/externalization.md
@@ -135,7 +135,7 @@ There is also and alternative method to [translate messages from validation erro
### Interpolation
Placeholders in translated text should match the code style of the respective source file.
-For example use `%{created_at}` in Ruby but `%{createdAt}` in JavaScript.
+For example use `%{created_at}` in Ruby but `%{createdAt}` in JavaScript. Make sure to [avoid splitting sentences when adding links](#avoid-splitting-sentences-when-adding-links).
- In Ruby/HAML:
@@ -267,20 +267,41 @@ should be externalized as follows:
This also applies when using links in between translated sentences, otherwise these texts are not translatable in certain languages.
-Instead of:
+- In Ruby/HAML, instead of:
+
+ ```haml
+ - zones_link = link_to(s_('ClusterIntegration|zones'), 'https://cloud.google.com/compute/docs/regions-zones/regions-zones', target: '_blank', rel: 'noopener noreferrer')
+ = s_('ClusterIntegration|Learn more about %{zones_link}').html_safe % { zones_link: zones_link }
+ ```
+
+ Set the link starting and ending HTML fragments as variables like so:
+
+ ```haml
+ - zones_link_url = 'https://cloud.google.com/compute/docs/regions-zones/regions-zones'
+ - zones_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: zones_link_url }
+ = s_('ClusterIntegration|Learn more about %{zones_link_start}zones%{zones_link_end}').html_safe % { zones_link_start: zones_link_start, zones_link_end: '</a>'.html_safe }
+ ```
-```haml
-- zones_link = link_to(s_('ClusterIntegration|zones'), 'https://cloud.google.com/compute/docs/regions-zones/regions-zones', target: '_blank', rel: 'noopener noreferrer')
-= s_('ClusterIntegration|Learn more about %{zones_link}').html_safe % { zones_link: zones_link }
-```
+- In JavaScript, instead of:
-Set the link starting and ending HTML fragments as variables like so:
+ ```js
+ {{
+ sprintf(s__("ClusterIntegration|Learn more about %{link}"), {
+ link: '<a href="https://cloud.google.com/compute/docs/regions-zones/regions-zones" target="_blank" rel="noopener noreferrer">zones</a>'
+ })
+ }}
+ ```
-```haml
-- zones_link_url = 'https://cloud.google.com/compute/docs/regions-zones/regions-zones'
-- zones_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: zones_link_url }
-= s_('ClusterIntegration|Learn more about %{zones_link_start}zones%{zones_link_end}').html_safe % { zones_link_start: zones_link_start, zones_link_end: '</a>'.html_safe }
-```
+ Set the link starting and ending HTML fragments as variables like so:
+
+ ```js
+ {{
+ sprintf(s__("ClusterIntegration|Learn more about %{linkStart}zones%{linkEnd}"), {
+ linkStart: '<a href="https://cloud.google.com/compute/docs/regions-zones/regions-zones" target="_blank" rel="noopener noreferrer">'
+ linkEnd: '</a>',
+ })
+ }}
+ ```
The reasoning behind this is that in some languages words change depending on context. For example in Japanese は is added to the subject of a sentence and を to the object. This is impossible to translate correctly if we extract individual words from the sentence.
diff --git a/doc/development/new_fe_guide/tips.md b/doc/development/new_fe_guide/tips.md
index 4564f678ec0..879b54bd93c 100644
--- a/doc/development/new_fe_guide/tips.md
+++ b/doc/development/new_fe_guide/tips.md
@@ -10,16 +10,16 @@ yarn clean
## Creating feature flags in development
-The process for creating a feature flag is the same as [enabling a feature flag in development](../feature_flags.md#enabling-a-feature-flag-in-development).
+The process for creating a feature flag is the same as [enabling a feature flag in development](../feature_flags/development.md#enabling-a-feature-flag-in-development).
Your feature flag can now be:
-- [made available to the frontend](../feature_flags.md#frontend) via the `gon`
-- queried in [tests](../feature_flags.md#specs)
-- queried in HAML templates and ruby files via the `Feature.enabled?(:my_shiny_new_feature_flag)` method
+- [Made available to the frontend](../feature_flags/development.md#frontend) via the `gon`
+- Queried in [tests](../feature_flags/development.md#specs)
+- Queried in HAML templates and ruby files via the `Feature.enabled?(:my_shiny_new_feature_flag)` method
### More on feature flags
- [Deleting a feature flag](../../api/features.md#delete-a-feature)
-- [Manage feature flags](../feature_flags.md)
+- [Manage feature flags](../feature_flags/process.md)
- [Feature flags API](../../api/features.md)
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/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/reusing_abstractions.md b/doc/development/reusing_abstractions.md
index 01cedf734fb..59da02ed6fd 100644
--- a/doc/development/reusing_abstractions.md
+++ b/doc/development/reusing_abstractions.md
@@ -127,6 +127,42 @@ Everything in `lib/api`.
Everything that resides in `app/services`.
+#### ServiceResponse
+
+Service classes usually have an `execute` method, which can return a
+`ServiceResponse`. You can use `ServiceResponse.success` and
+`ServiceResponse.error` to return a response in `execute` method.
+
+In a successful case:
+
+``` ruby
+response = ServiceResponse.success(message: 'Branch was deleted')
+
+response.success? # => true
+response.error? # => false
+response.status # => :success
+response.message # => 'Branch was deleted'
+```
+
+In a failed case:
+
+``` ruby
+response = ServiceResponse.error(message: 'Unsupported operation')
+
+response.success? # => false
+response.error? # => true
+response.status # => :error
+response.message # => 'Unsupported operation'
+```
+
+An additional payload can also be attached:
+
+``` ruby
+response = ServiceResponse.success(payload: { issue: issue })
+
+response.payload[:issue] # => issue
+```
+
### Finders
Everything in `app/finders`, typically used for retrieving data from a database.
diff --git a/doc/development/rolling_out_changes_using_feature_flags.md b/doc/development/rolling_out_changes_using_feature_flags.md
index 84028b1b342..6bad91d6287 100644
--- a/doc/development/rolling_out_changes_using_feature_flags.md
+++ b/doc/development/rolling_out_changes_using_feature_flags.md
@@ -1,225 +1 @@
-# Rolling out changes using feature flags
-
-[Feature flags](feature_flags.md) can be used to gradually roll out changes, be
-it a new feature, or a performance improvement. By using feature flags, we can
-comfortably measure the impact of our changes, while still being able to easily
-disable those changes, without having to revert an entire release.
-
-## When to use feature flags
-
-Starting with GitLab 11.4, developers are required to use feature flags for
-non-trivial changes. Such changes include:
-
-- New features (e.g. a new merge request widget, epics, etc).
-- Complex performance improvements that may require additional testing in
- production, such as rewriting complex queries.
-- Invasive changes to the user interface, such as a new navigation bar or the
- removal of a sidebar.
-- Adding support for importing projects from a third-party service.
-
-In all cases, those working on the changes can best decide if a feature flag is
-necessary. For example, changing the color of a button doesn't need a feature
-flag, while changing the navigation bar definitely needs one. In case you are
-uncertain if a feature flag is necessary, simply ask about this in the merge
-request, and those reviewing the changes will likely provide you with an answer.
-
-When using a feature flag for UI elements, make sure to _also_ use a feature
-flag for the underlying backend code, if there is any. This ensures there is
-absolutely no way to use the feature until it is enabled.
-
-## The cost of feature flags
-
-When reading the above, one might be tempted to think this procedure is going to
-add a lot of work. Fortunately, this is not the case, and we'll show why. For
-this example we'll specify the cost of the work to do as a number, ranging from
-0 to infinity. The greater the number, the more expensive the work is. The cost
-does _not_ translate to time, it's just a way of measuring complexity of one
-change relative to another.
-
-Let's say we are building a new feature, and we have determined that the cost of
-this is 10. We have also determined that the cost of adding a feature flag check
-in a variety of places is 1. If we do not use feature flags, and our feature
-works as intended, our total cost is 10. This however is the best case scenario.
-Optimising for the best case scenario is guaranteed to lead to trouble, whereas
-optimising for the worst case scenario is almost always better.
-
-To illustrate this, let's say our feature causes an outage, and there's no
-immediate way to resolve it. This means we'd have to take the following steps to
-resolve the outage:
-
-1. Revert the release.
-1. Perform any cleanups that might be necessary, depending on the changes that
- were made.
-1. Revert the commit, ensuring the "master" branch remains stable. This is
- especially necessary if solving the problem can take days or even weeks.
-1. Pick the revert commit into the appropriate stable branches, ensuring we
- don't block any future releases until the problem is resolved.
-
-As history has shown, these steps are time consuming, complex, often involve
-many developers, and worst of all: our users will have a bad experience using
-GitLab.com until the problem is resolved.
-
-Now let's say that all of this has an associated cost of 10. This means that in
-the worst case scenario, which we should optimise for, our total cost is now 20.
-
-If we had used a feature flag, things would have been very different. We don't
-need to revert a release, and because feature flags are disabled by default we
-don't need to revert and pick any Git commits. In fact, all we have to do is
-disable the feature, and in the worst case, perform cleanup. Let's say that
-the cost of this is 2. In this case, our best case cost is 11: 10 to build the
-feature, and 1 to add the feature flag. The worst case cost is now 13: 10 to
-build the feature, 1 to add the feature flag, and 2 to disable and clean up.
-
-Here we can see that in the best case scenario the work necessary is only a tiny
-bit more compared to not using a feature flag. Meanwhile, the process of
-reverting our changes has been made significantly and reliably cheaper.
-
-In other words, feature flags do not slow down the development process. Instead,
-they speed up the process as managing incidents now becomes _much_ easier. Once
-continuous deployments are easier to perform, the time to iterate on a feature
-is reduced even further, as you no longer need to wait weeks before your changes
-are available on GitLab.com.
-
-## Rolling out changes
-
-The procedure of using feature flags is straightforward, and similar to not
-using them. You add the necessary tests (make sure to test both the on and off
-states of your feature flag(s)), make sure they all pass, have the code
-reviewed, etc. You then submit your merge request, and add the ~"feature flag"
-label. This label is used to signal to release managers that your changes are
-hidden behind a feature flag and that it is safe to pick the MR into a stable
-branch, without the need for an exception request.
-
-When the changes are deployed it is time to start rolling out the feature to our
-users. The exact procedure of rolling out a change is unspecified, as this can
-vary from change to change. However, in general we recommend rolling out changes
-incrementally, instead of enabling them for everybody right away. We also
-recommend you to _not_ enable a feature _before_ the code is being deployed.
-This allows you to separate rolling out a feature from a deploy, making it
-easier to measure the impact of both separately.
-
-GitLab's feature library (using
-[Flipper](https://github.com/jnunemaker/flipper), and covered in the [Feature
-Flags](feature_flags.md) guide) supports rolling out changes to a percentage of
-users. This in turn can be controlled using [GitLab
-chatops](../ci/chatops/README.md).
-
-For an up to date list of feature flag commands please see [the source
-code](https://gitlab.com/gitlab-com/chatops/blob/master/lib/chatops/commands/feature.rb).
-Note that all the examples in that file must be preceded by
-`/chatops run`.
-
-If you get an error "Whoops! This action is not allowed. This incident
-will be reported." that means your Slack account is not allowed to
-change feature flags. To test if you are allowed to do anything at all,
-run:
-
-```
-/chatops run feature --help
-```
-
-For example, to enable a feature for 25% of all users, run the following in
-Slack:
-
-```
-/chatops run feature set new_navigation_bar 25
-```
-
-This will enable the feature for GitLab.com, with `new_navigation_bar` being the
-name of the feature. We can also enable the feature for <https://dev.gitlab.org>
-or <https://staging.gitlab.com>:
-
-```
-/chatops run feature set new_navigation_bar 25 --dev
-/chatops run feature set new_navigation_bar 25 --staging
-```
-
-If you are not certain what percentages to use, simply use the following steps:
-
-1. 25%
-1. 50%
-1. 75%
-1. 100%
-
-Between every step you'll want to wait a little while and monitor the
-appropriate graphs on <https://dashboards.gitlab.net>. The exact time to wait
-may differ. For some features a few minutes is enough, while for others you may
-want to wait several hours or even days. This is entirely up to you, just make
-sure it is clearly communicated to your team, and the Production team if you
-anticipate any potential problems.
-
-Feature gates can also be actor based, for example a feature could first be
-enabled for only the `gitlab-ce` project. The project is passed by supplying a
-`--project` flag:
-
-```
-/chatops run feature set --project=gitlab-org/gitlab-ce some_feature true
-```
-
-For groups the `--group` flag is available:
-
-```
-/chatops run feature set --group=gitlab-org some_feature true
-```
-
-Once a change is deemed stable, submit a new merge request to remove the
-feature flag. This ensures the change is available to all users and self-hosted
-instances. Make sure to add the ~"feature flag" label to this merge request so
-release managers are aware the changes are hidden behind a feature flag. If the
-merge request has to be picked into a stable branch (e.g. after the 7th), make
-sure to also add the appropriate "Pick into X" label (e.g. "Pick into 11.4").
-
-One might be tempted to think this will delay the release of a feature by at
-least one month (= one release). This is not the case. A feature flag does not
-have to stick around for a specific amount of time (e.g. at least one release),
-instead they should stick around until the feature is deemed stable. Stable
-means it works on GitLab.com without causing any problems, such as outages. In
-most cases this will translate to a feature (with a feature flag) being shipped
-in RC1, followed by the feature flag being removed in RC2. This in turn means
-the feature will be stable by the time we publish a stable package around the
-22nd of the month.
-
-## Implicit feature flags
-
-The [`Project#feature_available?`][project-fa],
-[`Namespace#feature_available?`][namespace-fa] (EE), and
-[`License.feature_available?`][license-fa] (EE) methods all implicitly check for
-a feature flag by the same name as the provided argument.
-
-For example if a feature is license-gated, there's no need to add an additional
-explicit feature flag check since the flag will be checked as part of the
-`License.feature_available?` call. Similarly, there's no need to "clean up" a
-feature flag once the feature has reached general availability.
-
-You'd still want to use an explicit `Feature.enabled?` check if your new feature
-isn't gated by a License or Plan.
-
-[project-fa]: https://gitlab.com/gitlab-org/gitlab-ee/blob/4cc1c62918aa4c31750cb21dfb1a6c3492d71080/app/models/project_feature.rb#L63-68
-[namespace-fa]: https://gitlab.com/gitlab-org/gitlab-ee/blob/4cc1c62918aa4c31750cb21dfb1a6c3492d71080/ee/app/models/ee/namespace.rb#L71-85
-[license-fa]: https://gitlab.com/gitlab-org/gitlab-ee/blob/4cc1c62918aa4c31750cb21dfb1a6c3492d71080/ee/app/models/license.rb#L293-300
-
-### Undefined feature flags default to "on"
-
-An important side-effect of the [implicit feature flags](#implicit-feature-flags)
-mentioned above is that unless the feature is explicitly disabled or limited to a
-percentage of users, 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:
-
-```
-/chatops run feature set some_feature 0
-```
-
-Note that you can do this at any time, even before the merge request using the
-flag has been merged!
-
-### Cleaning up
-
-When a feature gate has been removed from the code base, the value still exists
-in the database. This can be removed through ChatOps:
-
-```
-/chatops run feature delete some_feature
-```
+This document was moved to [another location](feature_flags/index.md).
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/end_to_end/dynamic_element_validation.md b/doc/development/testing_guide/end_to_end/dynamic_element_validation.md
index f7b3ca8bc89..aec0a3ede5a 100644
--- a/doc/development/testing_guide/end_to_end/dynamic_element_validation.md
+++ b/doc/development/testing_guide/end_to_end/dynamic_element_validation.md
@@ -5,8 +5,8 @@ We devised a solution to solve common test automation problems such as the dread
Other problems that dynamic element validations solve are...
- When we perform an action with the mouse, we expect something to occur.
-- When our test is navigating to (or from) a page, we ensure that we are on the page we expect before
-test continuation.
+- When our test is navigating to (or from) a page, we ensure that we are on the page we expect before
+ test continuation.
## How it works
@@ -19,7 +19,7 @@ We interpret user actions on the page to have some sort of effect. These actions
When a page is navigated to, there are elements that will always appear on the page unconditionally.
-Dynamic element validation is instituted when using
+Dynamic element validation is instituted when using
```ruby
Runtime::Browser.visit(:gitlab, Some::Page)
@@ -27,7 +27,7 @@ Runtime::Browser.visit(:gitlab, Some::Page)
### Clicks
-When we perform a click within our tests, we expect something to occur. That something could be a component to now
+When we perform a click within our tests, we expect something to occur. That something could be a component to now
appear on the webpage, or the test to navigate away from the page entirely.
Dynamic element validation is instituted when using
@@ -71,7 +71,7 @@ class MyPage < Page::Base
element :another_element, required: true
element :conditional_element
end
-
+
def open_layer
click_element :my_element, Layer::MyLayer
end
@@ -95,7 +95,7 @@ execute_stuff
```
will invoke GitLab QA to scan `MyPage` for `my_element` and `another_element` to be on the page before continuing to
-`execute_stuff`
+`execute_stuff`
### Clicking
diff --git a/doc/development/testing_guide/end_to_end/page_objects.md b/doc/development/testing_guide/end_to_end/page_objects.md
index 73e1fd862c1..05cb03eb4bd 100644
--- a/doc/development/testing_guide/end_to_end/page_objects.md
+++ b/doc/development/testing_guide/end_to_end/page_objects.md
@@ -82,7 +82,7 @@ module Page
end
# ...
- end
+ end
end
end
```
@@ -134,7 +134,7 @@ for each element defined.
In our case, `qa-login-field`, `qa-password-field` and `qa-sign-in-button`
-**app/views/my/view.html.haml**
+**app/views/my/view.html.haml**
```haml
= f.text_field :login, class: "form-control top qa-login-field", autofocus: "autofocus", autocapitalize: "off", autocorrect: "off", required: true, title: "This field is required."
@@ -146,7 +146,7 @@ Things to note:
- The CSS class must be `kebab-cased` (separated with hyphens "`-`")
- If the element appears on the page unconditionally, add `required: true` to the element. See
-[Dynamic element validation](dynamic_element_validation.md)
+ [Dynamic element validation](dynamic_element_validation.md)
## Running the test locally
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 f96c85be1ba..041bdf716b3 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
@@ -242,7 +242,7 @@ module QA
issue = Resource::Issue.fabricate_via_api! do |issue|
issue.title = 'Issue to test the scoped labels'
- issue.labels = @initial_label
+ issue.labels = [@initial_label]
end
[@new_label_same_scope, @new_label_different_scope].each do |label|
@@ -365,6 +365,14 @@ Add the following `attribute :id` and `attribute :labels` right above the [`attr
> We add the attributes above the existing attribute to keep them alphabetically organized.
+Then, let's initialize an instance variable for labels to allow an empty array as default value when such information is not passed during the resource fabrication, since this optional. [Between the attributes and the `fabricate!` method](https://gitlab.com/gitlab-org/gitlab-ee/blob/1a1f1408728f19b2aa15887cd20bddab7e70c8bd/qa/qa/resource/issue.rb#L18), add the following:
+
+```ruby
+def initialize
+ @labels = []
+end
+```
+
Next, add the following code right below the [`fabricate!`](https://gitlab.com/gitlab-org/gitlab-ee/blob/d3584e80b4236acdf393d815d604801573af72cc/qa/qa/resource/issue.rb#L27) method.
```ruby
@@ -378,7 +386,7 @@ end
def api_post_body
{
- labels: [labels],
+ labels: labels,
title: title
}
end
diff --git a/doc/development/testing_guide/frontend_testing.md b/doc/development/testing_guide/frontend_testing.md
index 4c9d1684c00..28ebb6f0f64 100644
--- a/doc/development/testing_guide/frontend_testing.md
+++ b/doc/development/testing_guide/frontend_testing.md
@@ -27,14 +27,30 @@ we need to solve before being able to use Jest for all our needs.
### Differences to Karma
- Jest runs in a Node.js environment, not in a browser. Support for running Jest tests in a browser [is planned](https://gitlab.com/gitlab-org/gitlab-ce/issues/58205).
-- Because Jest runs in a Node.js environment, it uses [jsdom](https://github.com/jsdom/jsdom) by default.
+- Because Jest runs in a Node.js environment, it uses [jsdom](https://github.com/jsdom/jsdom) by default. See also its [limitations](#limitations-of-jsdom) below.
+- Jest does not have access to Webpack loaders or aliases.
+ The aliases used by Jest are defined in its [own config](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/jest.config.js).
- All calls to `setTimeout` and `setInterval` are mocked away. See also [Jest Timer Mocks](https://jestjs.io/docs/en/timer-mocks).
- `rewire` is not required because Jest supports mocking modules. See also [Manual Mocks](https://jestjs.io/docs/en/manual-mocks).
+- No [context object](https://jasmine.github.io/tutorials/your_first_suite#section-The_%3Ccode%3Ethis%3C/code%3E_keyword) is passed to tests in Jest.
+ This means sharing `this.something` between `beforeEach()` and `it()` for example does not work.
+ Instead you should declare shared variables in the context that they are needed (via `const` / `let`).
- The following will cause tests to fail in Jest:
- Unmocked requests.
- Unhandled Promise rejections.
- Calls to `console.warn`, including warnings from libraries like Vue.
+### Limitations of jsdom
+
+As mentioned [above](#differences-to-karma), Jest uses jsdom instead of a browser for running tests.
+This comes with a number of limitations, namely:
+
+- [No scrolling support](https://github.com/jsdom/jsdom/blob/15.1.1/lib/jsdom/browser/Window.js#L623-L625)
+- [No element sizes or positions](https://github.com/jsdom/jsdom/blob/15.1.1/lib/jsdom/living/nodes/Element-impl.js#L334-L371)
+- [No layout engine](https://github.com/jsdom/jsdom/issues/1322) in general
+
+See also the issue for [support running Jest tests in browsers](https://gitlab.com/gitlab-org/gitlab-ce/issues/58205).
+
### Debugging Jest tests
Running `yarn jest-debug` will run Jest in debug mode, allowing you to debug/inspect as described in the [Jest docs](https://jestjs.io/docs/en/troubleshooting#tests-are-failing-and-you-don-t-know-why).
diff --git a/doc/development/testing_guide/review_apps.md b/doc/development/testing_guide/review_apps.md
index 63b7b97c32f..ae40d628717 100644
--- a/doc/development/testing_guide/review_apps.md
+++ b/doc/development/testing_guide/review_apps.md
@@ -257,7 +257,7 @@ find a way to limit it to only us.**
## Other resources
-* [Review Apps integration for CE/EE (presentation)](https://docs.google.com/presentation/d/1QPLr6FO4LduROU8pQIPkX1yfGvD13GEJIBOenqoKxR8/edit?usp=sharing)
+- [Review Apps integration for CE/EE (presentation)](https://docs.google.com/presentation/d/1QPLr6FO4LduROU8pQIPkX1yfGvD13GEJIBOenqoKxR8/edit?usp=sharing)
[charts-1068]: https://gitlab.com/charts/gitlab/issues/1068
[gitlab-pipeline]: https://gitlab.com/gitlab-org/gitlab-ce/pipelines/44362587
diff --git a/doc/gitlab-basics/command-line-commands.md b/doc/gitlab-basics/command-line-commands.md
index 1cf883679d7..b7e6844f43a 100644
--- a/doc/gitlab-basics/command-line-commands.md
+++ b/doc/gitlab-basics/command-line-commands.md
@@ -29,7 +29,9 @@ git clone PASTE HTTPS OR SSH HERE
A clone of the project will be created in your computer.
->**Note:** If you clone your project via a URL that contains special characters, make sure that characters are URL-encoded.
+NOTE: **Note:**
+If you clone your project via a URL that contains special characters, make sure
+that characters are URL-encoded.
### Go into a project directory to work in it
@@ -86,12 +88,18 @@ cat README.md
### Remove a file
+DANGER: **Danger:**
+This will permanently delete the file.
+
```
rm NAME-OF-FILE
```
### Remove a directory and all of its contents
+DANGER: **Danger:**
+This will permanently delete the directory and all of its contents.
+
```
rm -r NAME-OF-DIRECTORY
```
@@ -113,9 +121,13 @@ history
You will be asked for an administrator’s password.
```
-sudo
+sudo COMMAND
```
+CAUTION: **Caution:**
+Be careful of the commands you run with `sudo`. Certain commands may cause
+damage to your data and system.
+
### Show which directory I am in
```
diff --git a/doc/install/installation.md b/doc/install/installation.md
index 4c1021d097f..70e5ab28931 100644
--- a/doc/install/installation.md
+++ b/doc/install/installation.md
@@ -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:
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 18981c43464..45d07ec5d11 100644
--- a/doc/install/openshift_and_gitlab/index.md
+++ b/doc/install/openshift_and_gitlab/index.md
@@ -145,12 +145,12 @@ Login successful.
You have access to the following projects and can switch between them with 'oc project <projectname>':
- * cockpit
- * default (current)
- * delete
- * openshift
- * openshift-infra
- * sample
+- cockpit
+- default (current)
+- delete
+- openshift
+- openshift-infra
+- sample
Using project "default".
```
diff --git a/doc/install/requirements.md b/doc/install/requirements.md
index 92122fca7dd..68c1bcbc801 100644
--- a/doc/install/requirements.md
+++ b/doc/install/requirements.md
@@ -9,7 +9,7 @@ as the hardware requirements that are needed to install and use GitLab.
## Operating Systems
-### Supported Unix distributions
+### Supported Linux distributions
- Ubuntu
- Debian
@@ -21,7 +21,7 @@ as the hardware requirements that are needed to install and use GitLab.
For the installations options, see [the main installation page](README.md).
-### Unsupported Unix distributions
+### Unsupported Linux distributions and Unix-like operating systems
- Arch Linux
- Fedora
@@ -29,13 +29,13 @@ For the installations options, see [the main installation page](README.md).
- Gentoo
- macOS
-On the above unsupported distributions is still possible to install GitLab yourself.
+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.
-### Non-Unix operating systems such as Windows
+### Microsoft Windows
-GitLab is developed for Unix operating systems.
-It does **not** run on Windows, and we have no plans to support it in the near future. For the latest development status view this [issue](https://gitlab.com/gitlab-org/gitlab-ce/issues/46567).
+GitLab is developed for Linux-based operating systems.
+It does **not** run on Microsoft Windows, and we have no plans to support it in the near future. For the latest development status view this [issue](https://gitlab.com/gitlab-org/gitlab-ce/issues/46567).
Please consider using a virtual machine to run GitLab.
## Ruby versions
diff --git a/doc/integration/README.md b/doc/integration/README.md
index f74da97119a..135952a1b08 100644
--- a/doc/integration/README.md
+++ b/doc/integration/README.md
@@ -13,10 +13,10 @@ See the documentation below for details on how to configure these services.
- [Auth0 OmniAuth](auth0.md) Enable the Auth0 OmniAuth provider
- [Bitbucket](bitbucket.md) Import projects from Bitbucket.org and login to your GitLab instance with your Bitbucket.org account
- [CAS](cas.md) Configure GitLab to sign in using CAS
-- [External issue tracker](external-issue-tracker.md) Redmine, JIRA, etc.
+- [External issue tracker](external-issue-tracker.md) Redmine, Jira, etc.
- [Gmail actions buttons](gmail_action_buttons_for_gitlab.md) Adds GitLab actions to messages
- [Jenkins](jenkins.md) Integrate with the Jenkins CI
-- [JIRA](../user/project/integrations/jira.md) Integrate with the JIRA issue tracker
+- [Jira](../user/project/integrations/jira.md) Integrate with the Jira issue tracker
- [Kerberos](kerberos.md) Integrate with Kerberos
- [LDAP](ldap.md) Set up sign in via LDAP
- [OAuth2 provider](oauth_provider.md) OAuth2 application creation
diff --git a/doc/integration/elasticsearch.md b/doc/integration/elasticsearch.md
index a2f38a2fcdf..877330b8c44 100644
--- a/doc/integration/elasticsearch.md
+++ b/doc/integration/elasticsearch.md
@@ -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 elastic search servers and now I can't find anything**
+- **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 5950737b964..e6496ae3a2e 100644
--- a/doc/integration/jenkins.md
+++ b/doc/integration/jenkins.md
@@ -25,22 +25,22 @@ and [Migrating from Jenkins to GitLab](https://www.youtube.com/watch?v=RlEVGOpYF
## Use cases
- Suppose you are new to GitLab, and want to keep using Jenkins until you prepare
-your projects to build with [GitLab CI/CD](../ci/README.md). You set up the
-integration between GitLab and Jenkins, then you migrate to GitLab CI later. While
-you organize yourself and your team to onboard GitLab, you keep your pipelines
-running with Jenkins, but view the results in your project's repository in GitLab.
+ your projects to build with [GitLab CI/CD](../ci/README.md). You set up the
+ integration between GitLab and Jenkins, then you migrate to GitLab CI later. While
+ you organize yourself and your team to onboard GitLab, you keep your pipelines
+ running with Jenkins, but view the results in your project's repository in GitLab.
- Your team uses [Jenkins Plugins](https://plugins.jenkins.io/) for other proceedings,
-therefore, you opt for keep using Jenkins to build your apps. Show the results of your
-pipelines directly in GitLab.
+ therefore, you opt for keep using Jenkins to build your apps. Show the results of your
+ pipelines directly in GitLab.
For a real use case, read the blog post [Continuous integration: From Jenkins to GitLab using Docker](https://about.gitlab.com/2017/07/27/docker-my-precious/).
## Requirements
-* [Jenkins GitLab Plugin](https://wiki.jenkins.io/display/JENKINS/GitLab+Plugin)
-* [Jenkins Git Plugin](https://wiki.jenkins.io/display/JENKINS/Git+Plugin)
-* Git clone access for Jenkins from the GitLab repository
-* GitLab API access to report build status
+- [Jenkins GitLab Plugin](https://wiki.jenkins.io/display/JENKINS/GitLab+Plugin)
+- [Jenkins Git Plugin](https://wiki.jenkins.io/display/JENKINS/Git+Plugin)
+- Git clone access for Jenkins from the GitLab repository
+- GitLab API access to report build status
## Configure GitLab users
@@ -65,7 +65,7 @@ Go to Manage Jenkins -> Configure System and scroll down to the 'GitLab' section
Enter the GitLab server URL in the 'GitLab host URL' field and paste the API token
copied earlier in the 'API Token' field.
-For more information, see GitLab Plugin documentation about
+For more information, see GitLab Plugin documentation about
[Jenkins-to-GitLab authentication](https://github.com/jenkinsci/gitlab-plugin#jenkins-to-gitlab-authentication)
![Jenkins GitLab plugin configuration](img/jenkins_gitlab_plugin_config.png)
@@ -76,8 +76,8 @@ Follow the GitLab Plugin documentation about [Jenkins Job Configuration](https:/
NOTE: **Note:**
Be sure to include the steps about [Build status configuration](https://github.com/jenkinsci/gitlab-plugin#build-status-configuration).
-The 'Publish build status to GitLab' post-build step is required to view
-Jenkins build status in GitLab Merge Requests.
+The 'Publish build status to GitLab' post-build step is required to view
+Jenkins build status in GitLab Merge Requests.
## Configure a GitLab project
@@ -114,21 +114,21 @@ and storing build status for Commits and Merge Requests.
All steps are implemented using AJAX requests on the merge request page.
1. In order to display the build status in a merge request you must create a project service in GitLab.
-2. Your project service will do a (JSON) query to a URL of the CI tool with the SHA1 of the commit.
-3. The project service builds this URL and payload based on project service settings and knowledge of the CI tool.
-4. The response is parsed to give a response in GitLab (success/failed/pending).
+1. Your project service will do a (JSON) query to a URL of the CI tool with the SHA1 of the commit.
+1. The project service builds this URL and payload based on project service settings and knowledge of the CI tool.
+1. The response is parsed to give a response in GitLab (success/failed/pending).
## Troubleshooting
### Error in merge requests - "Could not connect to the CI server"
This integration relies on Jenkins reporting the build status back to GitLab via
-the [Commit Status API](../api/commits.md#commit-status).
+the [Commit Status API](../api/commits.md#commit-status).
The error 'Could not connect to the CI server' usually means that GitLab did not
receive a build status update via the API. Either Jenkins was not properly
-configured or there was an error reporting the status via the API.
+configured or there was an error reporting the status via the API.
1. [Configure the Jenkins server](#configure-the-jenkins-server) for GitLab API access
-2. [Configure a Jenkins project](#configure-a-jenkins-project), including the
- 'Publish build status to GitLab' post-build action.
+1. [Configure a Jenkins project](#configure-a-jenkins-project), including the
+ 'Publish build status to GitLab' post-build action.
diff --git a/doc/integration/jenkins_deprecated.md b/doc/integration/jenkins_deprecated.md
index 8001c5dbd83..eae705c9637 100644
--- a/doc/integration/jenkins_deprecated.md
+++ b/doc/integration/jenkins_deprecated.md
@@ -8,13 +8,13 @@ Please use documentation for the new [Jenkins CI service](jenkins.md).
Integration includes:
-* Trigger Jenkins build after push to repo
-* Show build status on Merge Request page
+- Trigger Jenkins build after push to repo
+- Show build status on Merge Request page
Requirements:
-* [Jenkins GitLab Hook plugin](https://wiki.jenkins.io/display/JENKINS/GitLab+Hook+Plugin)
-* git clone access for Jenkins from GitLab repo (via ssh key)
+- [Jenkins GitLab Hook plugin](https://wiki.jenkins.io/display/JENKINS/GitLab+Hook+Plugin)
+- git clone access for Jenkins from GitLab repo (via ssh key)
## Jenkins
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 b2d626a0a74..2142f5a5f69 100644
--- a/doc/push_rules/push_rules.md
+++ b/doc/push_rules/push_rules.md
@@ -26,11 +26,11 @@ Every push rule could have its own use case, but let's consider some examples.
Let's assume you have the following requirements for your workflow:
-- every commit should reference a JIRA issue, for example: `Refactored css. Fixes JIRA-123.`
+- every commit should reference a Jira issue, for example: `Refactored css. Fixes JIRA-123.`
- users should not be able to remove git tags with `git push`
All you need to do is write a simple regular expression that requires the mention
-of a JIRA issue in the commit message, like `JIRA\-\d+`.
+of a Jira issue in the commit message, like `JIRA\-\d+`.
Now when a user tries to push a commit with a message `Bugfix`, their push will
be declined. Only pushing commits with messages like `Bugfix according to JIRA-123`
diff --git a/doc/raketasks/backup_restore.md b/doc/raketasks/backup_restore.md
index c7aa22b11f8..092b4375208 100644
--- a/doc/raketasks/backup_restore.md
+++ b/doc/raketasks/backup_restore.md
@@ -18,16 +18,16 @@ installed on your system.
If you installed GitLab:
-- Using the Omnibus package, you're all set.
-- From source, make sure `rsync` is installed:
+- Using the Omnibus package, you're all set.
+- From source, make sure `rsync` is installed:
- ```sh
- # Debian/Ubuntu
- sudo apt-get install rsync
+ ```sh
+ # Debian/Ubuntu
+ sudo apt-get install rsync
- # RHEL/CentOS
- sudo yum install rsync
- ```
+ # RHEL/CentOS
+ sudo yum install rsync
+ ```
### Tar
@@ -269,17 +269,17 @@ For Omnibus GitLab packages:
1. Add the following to `/etc/gitlab/gitlab.rb`:
- ```ruby
- gitlab_rails['backup_upload_connection'] = {
- 'provider' => 'AWS',
- 'region' => 'eu-west-1',
- 'aws_access_key_id' => 'AKIAKIAKI',
- 'aws_secret_access_key' => 'secret123'
- # If using an IAM Profile, don't configure aws_access_key_id & aws_secret_access_key
- # 'use_iam_profile' => true
- }
- gitlab_rails['backup_upload_remote_directory'] = 'my.s3.bucket'
- ```
+ ```ruby
+ gitlab_rails['backup_upload_connection'] = {
+ 'provider' => 'AWS',
+ 'region' => 'eu-west-1',
+ 'aws_access_key_id' => 'AKIAKIAKI',
+ 'aws_secret_access_key' => 'secret123'
+ # If using an IAM Profile, don't configure aws_access_key_id & aws_secret_access_key
+ # 'use_iam_profile' => true
+ }
+ gitlab_rails['backup_upload_remote_directory'] = 'my.s3.bucket'
+ ```
1. [Reconfigure GitLab] for the changes to take effect
@@ -289,16 +289,16 @@ This example can be used for a bucket in Amsterdam (AMS3).
1. Add the following to `/etc/gitlab/gitlab.rb`:
- ```ruby
- gitlab_rails['backup_upload_connection'] = {
- 'provider' => 'AWS',
- 'region' => 'ams3',
- 'aws_access_key_id' => 'AKIAKIAKI',
- 'aws_secret_access_key' => 'secret123',
- 'endpoint' => 'https://ams3.digitaloceanspaces.com'
- }
- gitlab_rails['backup_upload_remote_directory'] = 'my.s3.bucket'
- ```
+ ```ruby
+ gitlab_rails['backup_upload_connection'] = {
+ 'provider' => 'AWS',
+ 'region' => 'ams3',
+ 'aws_access_key_id' => 'AKIAKIAKI',
+ 'aws_secret_access_key' => 'secret123',
+ 'endpoint' => 'https://ams3.digitaloceanspaces.com'
+ }
+ gitlab_rails['backup_upload_remote_directory'] = 'my.s3.bucket'
+ ```
1. [Reconfigure GitLab] for the changes to take effect
@@ -321,31 +321,31 @@ For installations from source:
1. Edit `home/git/gitlab/config/gitlab.yml`:
- ```yaml
- backup:
- # snip
- upload:
- # Fog storage connection settings, see http://fog.io/storage/ .
- connection:
- provider: AWS
- region: eu-west-1
- aws_access_key_id: AKIAKIAKI
- aws_secret_access_key: 'secret123'
- # If using an IAM Profile, leave aws_access_key_id & aws_secret_access_key empty
- # ie. aws_access_key_id: ''
- # use_iam_profile: 'true'
- # The remote 'directory' to store your backups. For S3, this would be the bucket name.
- remote_directory: 'my.s3.bucket'
- # Turns on AWS Server-Side Encryption with Amazon S3-Managed Keys for backups, this is optional
- # encryption: 'AES256'
- # Turns on AWS Server-Side Encryption with Amazon Customer-Provided Encryption Keys for backups, this is optional
- # This should be set to the base64-encoded encryption key for Amazon S3 to use to encrypt or decrypt your data.
- # 'encryption' must also be set in order for this to have any effect.
- # To avoid storing the key on disk, the key can also be specified via the `GITLAB_BACKUP_ENCRYPTION_KEY` environment variable.
- # encryption_key: '<base64 key>'
- # Specifies Amazon S3 storage class to use for backups, this is optional
- # storage_class: 'STANDARD'
- ```
+ ```yaml
+ backup:
+ # snip
+ upload:
+ # Fog storage connection settings, see http://fog.io/storage/ .
+ connection:
+ provider: AWS
+ region: eu-west-1
+ aws_access_key_id: AKIAKIAKI
+ aws_secret_access_key: 'secret123'
+ # If using an IAM Profile, leave aws_access_key_id & aws_secret_access_key empty
+ # ie. aws_access_key_id: ''
+ # use_iam_profile: 'true'
+ # The remote 'directory' to store your backups. For S3, this would be the bucket name.
+ remote_directory: 'my.s3.bucket'
+ # Turns on AWS Server-Side Encryption with Amazon S3-Managed Keys for backups, this is optional
+ # encryption: 'AES256'
+ # Turns on AWS Server-Side Encryption with Amazon Customer-Provided Encryption Keys for backups, this is optional
+ # This should be set to the base64-encoded encryption key for Amazon S3 to use to encrypt or decrypt your data.
+ # 'encryption' must also be set in order for this to have any effect.
+ # To avoid storing the key on disk, the key can also be specified via the `GITLAB_BACKUP_ENCRYPTION_KEY` environment variable.
+ # encryption_key: '<base64 key>'
+ # Specifies Amazon S3 storage class to use for backups, this is optional
+ # storage_class: 'STANDARD'
+ ```
1. [Restart GitLab] for the changes to take effect
@@ -417,14 +417,14 @@ For Omnibus GitLab packages:
1. Edit `/etc/gitlab/gitlab.rb`:
- ```ruby
- gitlab_rails['backup_upload_connection'] = {
- 'provider' => 'Google',
- 'google_storage_access_key_id' => 'Access Key',
- 'google_storage_secret_access_key' => 'Secret'
- }
- gitlab_rails['backup_upload_remote_directory'] = 'my.google.bucket'
- ```
+ ```ruby
+ gitlab_rails['backup_upload_connection'] = {
+ 'provider' => 'Google',
+ 'google_storage_access_key_id' => 'Access Key',
+ 'google_storage_secret_access_key' => 'Secret'
+ }
+ gitlab_rails['backup_upload_remote_directory'] = 'my.google.bucket'
+ ```
1. [Reconfigure GitLab] for the changes to take effect
@@ -434,15 +434,15 @@ For installations from source:
1. Edit `home/git/gitlab/config/gitlab.yml`:
- ```yaml
- backup:
- upload:
- connection:
- provider: 'Google'
- google_storage_access_key_id: 'Access Key'
- google_storage_secret_access_key: 'Secret'
- remote_directory: 'my.google.bucket'
- ```
+ ```yaml
+ backup:
+ upload:
+ connection:
+ provider: 'Google'
+ google_storage_access_key_id: 'Access Key'
+ google_storage_secret_access_key: 'Secret'
+ remote_directory: 'my.google.bucket'
+ ```
1. [Restart GitLab] for the changes to take effect
@@ -477,16 +477,16 @@ For Omnibus GitLab packages:
1. Edit `/etc/gitlab/gitlab.rb`:
- ```ruby
- gitlab_rails['backup_upload_connection'] = {
- :provider => 'Local',
- :local_root => '/mnt/backups'
- }
+ ```ruby
+ gitlab_rails['backup_upload_connection'] = {
+ :provider => 'Local',
+ :local_root => '/mnt/backups'
+ }
- # The directory inside the mounted folder to copy backups to
- # Use '.' to store them in the root directory
- gitlab_rails['backup_upload_remote_directory'] = 'gitlab_backups'
- ```
+ # The directory inside the mounted folder to copy backups to
+ # Use '.' to store them in the root directory
+ gitlab_rails['backup_upload_remote_directory'] = 'gitlab_backups'
+ ```
1. [Reconfigure GitLab] for the changes to take effect.
@@ -496,17 +496,17 @@ For installations from source:
1. Edit `home/git/gitlab/config/gitlab.yml`:
- ```yaml
- backup:
- upload:
- # Fog storage connection settings, see http://fog.io/storage/ .
- connection:
- provider: Local
- local_root: '/mnt/backups'
- # The directory inside the mounted folder to copy backups to
- # Use '.' to store them in the root directory
- remote_directory: 'gitlab_backups'
- ```
+ ```yaml
+ backup:
+ upload:
+ # Fog storage connection settings, see http://fog.io/storage/ .
+ connection:
+ provider: Local
+ local_root: '/mnt/backups'
+ # The directory inside the mounted folder to copy backups to
+ # Use '.' to store them in the root directory
+ remote_directory: 'gitlab_backups'
+ ```
1. [Restart GitLab] for the changes to take effect.
@@ -521,9 +521,9 @@ For Omnibus GitLab packages:
1. Edit `/etc/gitlab/gitlab.rb`:
- ```ruby
- gitlab_rails['backup_archive_permissions'] = 0644 # Makes the backup archives world-readable
- ```
+ ```ruby
+ gitlab_rails['backup_archive_permissions'] = 0644 # Makes the backup archives world-readable
+ ```
1. [Reconfigure GitLab] for the changes to take effect.
@@ -533,10 +533,10 @@ For installations from source:
1. Edit `/home/git/gitlab/config/gitlab.yml`:
- ```yaml
- backup:
- archive_permissions: 0644 # Makes the backup archives world-readable
- ```
+ ```yaml
+ backup:
+ archive_permissions: 0644 # Makes the backup archives world-readable
+ ```
1. [Restart GitLab] for the changes to take effect.
@@ -550,10 +550,10 @@ For Omnibus GitLab packages:
1. Edit `/etc/gitlab/gitlab.rb`:
- ```ruby
- ## Limit backup lifetime to 7 days - 604800 seconds
- gitlab_rails['backup_keep_time'] = 604800
- ```
+ ```ruby
+ ## Limit backup lifetime to 7 days - 604800 seconds
+ gitlab_rails['backup_keep_time'] = 604800
+ ```
1. [Reconfigure GitLab] for the changes to take effect.
@@ -586,11 +586,11 @@ For installations from source:
1. Edit `home/git/gitlab/config/gitlab.yml`:
- ```yaml
- backup:
- ## Limit backup lifetime to 7 days - 604800 seconds
- keep_time: 604800
- ```
+ ```yaml
+ backup:
+ ## Limit backup lifetime to 7 days - 604800 seconds
+ keep_time: 604800
+ ```
1. [Restart GitLab] for the changes to take effect.
@@ -840,13 +840,13 @@ columns containing sensitive information. If the key is lost, GitLab will be
unable to decrypt those columns. This will break a wide range of functionality,
including (but not restricted to):
-* [CI/CD variables](../ci/variables/README.md)
-* [Kubernetes / GCP integration](../user/project/clusters/index.md)
-* [Custom Pages domains](../user/project/pages/getting_started_part_three.md)
-* [Project error tracking](../user/project/operations/error_tracking.md)
-* [Runner authentication](../ci/runners/README.md)
-* [Project mirroring](../workflow/repository_mirroring.md)
-* [Web hooks](../user/project/integrations/webhooks.md)
+- [CI/CD variables](../ci/variables/README.md)
+- [Kubernetes / GCP integration](../user/project/clusters/index.md)
+- [Custom Pages domains](../user/project/pages/getting_started_part_three.md)
+- [Project error tracking](../user/project/operations/error_tracking.md)
+- [Runner authentication](../ci/runners/README.md)
+- [Project mirroring](../workflow/repository_mirroring.md)
+- [Web hooks](../user/project/integrations/webhooks.md)
In cases like CI/CD variables and Runner authentication, you might
experience some unexpected behavior such as:
@@ -865,72 +865,71 @@ backup beforehand.
#### Reset CI/CD variables
-1. Enter the DB console:
+1. Enter the DB console:
- For Omnibus GitLab packages:
+ For Omnibus GitLab packages:
- ```sh
- sudo gitlab-rails dbconsole
- ```
+ ```sh
+ sudo gitlab-rails dbconsole
+ ```
- For installations from source:
+ For installations from source:
- ```sh
- sudo -u git -H bundle exec rails dbconsole RAILS_ENV=production
- ```
+ ```sh
+ sudo -u git -H bundle exec rails dbconsole RAILS_ENV=production
+ ```
-1. Check the `ci_group_variables` and `ci_variables` tables:
+1. Check the `ci_group_variables` and `ci_variables` tables:
- ```sql
- SELECT * FROM public."ci_group_variables";
- SELECT * FROM public."ci_variables";
- ```
+ ```sql
+ SELECT * FROM public."ci_group_variables";
+ SELECT * FROM public."ci_variables";
+ ```
- Those are the variables that you need to delete.
+ Those are the variables that you need to delete.
-1. Drop the table:
+1. Drop the table:
- ```sql
- DELETE FROM ci_group_variables;
- DELETE FROM ci_variables;
- ```
+ ```sql
+ DELETE FROM ci_group_variables;
+ DELETE FROM ci_variables;
+ ```
1. You may need to reconfigure or restart GitLab for the changes to take
effect.
-
#### Reset Runner registration tokens
-1. Enter the DB console:
+1. Enter the DB console:
- For Omnibus GitLab packages:
+ For Omnibus GitLab packages:
- ```sh
- sudo gitlab-rails dbconsole
- ```
+ ```sh
+ sudo gitlab-rails dbconsole
+ ```
- For installations from source:
+ For installations from source:
- ```sh
- sudo -u git -H bundle exec rails dbconsole RAILS_ENV=production
- ```
+ ```sh
+ sudo -u git -H bundle exec rails dbconsole RAILS_ENV=production
+ ```
1. Clear all the tokens for projects, groups, and the whole instance:
- CAUTION: **Caution:**
- The last UPDATE operation will stop the runners being able to pick up
- new jobs. You must register new runners.
-
- ```sql
- -- Clear project tokens
- UPDATE projects SET runners_token = null, runners_token_encrypted = null;
- -- Clear group tokens
- UPDATE namespaces SET runners_token = null, runners_token_encrypted = null;
- -- Clear instance tokens
- UPDATE application_settings SET runners_registration_token_encrypted = null;
- -- Clear runner tokens
- UPDATE ci_runners SET token = null, token_encrypted = null;
- ```
+ CAUTION: **Caution:**
+ The last UPDATE operation will stop the runners being able to pick up
+ new jobs. You must register new runners.
+
+ ```sql
+ -- Clear project tokens
+ UPDATE projects SET runners_token = null, runners_token_encrypted = null;
+ -- Clear group tokens
+ UPDATE namespaces SET runners_token = null, runners_token_encrypted = null;
+ -- Clear instance tokens
+ UPDATE application_settings SET runners_registration_token_encrypted = null;
+ -- Clear runner tokens
+ UPDATE ci_runners SET token = null, token_encrypted = null;
+ ```
A similar strategy can be employed for the remaining features - by removing the
data that cannot be decrypted, GitLab can be brought back into working order,
diff --git a/doc/raketasks/cleanup.md b/doc/raketasks/cleanup.md
index f5c788af578..f880f31c39e 100644
--- a/doc/raketasks/cleanup.md
+++ b/doc/raketasks/cleanup.md
@@ -92,3 +92,48 @@ I, [2018-08-02T10:26:47.598424 #45087] INFO -- : Looking for orphaned remote up
I, [2018-08-02T10:26:47.753131 #45087] INFO -- : Moved to lost and found: @hashed/6b/DSC_6152.JPG -> lost_and_found/@hashed/6b/DSC_6152.JPG
I, [2018-08-02T10:26:47.764356 #45087] INFO -- : Moved to lost and found: @hashed/79/02/7902699be42c8a8e46fbbb4501726517e86b22c56a189f7625a6da49081b2451/711491b29d3eb08837798c4909e2aa4d/DSC00314.jpg -> lost_and_found/@hashed/79/02/7902699be42c8a8e46fbbb4501726517e86b22c56a189f7625a6da49081b2451/711491b29d3eb08837798c4909e2aa4d/DSC00314.jpg
```
+
+## Remove orphan artifact files
+
+When you notice there are more job artifacts files on disk than there
+should be, you can run:
+
+```shell
+gitlab-rake gitlab:cleanup:orphan_job_artifact_files
+```
+
+This command:
+
+- Scans through the entire artifacts folder.
+- Checks which files still have a record in the database.
+- If no database record is found, the file is deleted from disk.
+
+By default, this task does not delete anything but shows what it can
+delete. Run the command with `DRY_RUN=false` if you actually want to
+delete the files:
+
+```shell
+gitlab-rake gitlab:cleanup:orphan_job_artifact_files DRY_RUN=false
+```
+
+You can also limit the number of files to delete with `LIMIT`:
+
+```shell
+gitlab-rake gitlab:cleanup:orphan_job_artifact_files LIMIT=100`
+```
+
+This will only delete up to 100 files from disk. You can use this to
+delete a small set for testing purposes.
+
+If you provide `DEBUG=1`, you'll see the full path of every file that
+is detected as being an orphan.
+
+If `ionice` is installed, the tasks uses it to ensure the command is
+not causing too much load on the disk. You can configure the niceness
+level with `NICENESS`. Below are the valid levels, but consult
+`man 1 ionice` to be sure.
+
+- `0` or `None`
+- `1` or `Realtime`
+- `2` or `Best-effort` (default)
+- `3` or `Idle`
diff --git a/doc/raketasks/web_hooks.md b/doc/raketasks/web_hooks.md
index df3dab118b2..2c6ae0749dd 100644
--- a/doc/raketasks/web_hooks.md
+++ b/doc/raketasks/web_hooks.md
@@ -2,42 +2,54 @@
## Add a webhook for **ALL** projects:
- # omnibus-gitlab
- sudo gitlab-rake gitlab:web_hook:add URL="http://example.com/hook"
- # source installations
- bundle exec rake gitlab:web_hook:add URL="http://example.com/hook" RAILS_ENV=production
+```sh
+# omnibus-gitlab
+sudo gitlab-rake gitlab:web_hook:add URL="http://example.com/hook"
+# source installations
+bundle exec rake gitlab:web_hook:add URL="http://example.com/hook" RAILS_ENV=production
+```
## Add a webhook for projects in a given **NAMESPACE**:
- # omnibus-gitlab
- sudo gitlab-rake gitlab:web_hook:add URL="http://example.com/hook" NAMESPACE=acme
- # source installations
- bundle exec rake gitlab:web_hook:add URL="http://example.com/hook" NAMESPACE=acme RAILS_ENV=production
+```sh
+# omnibus-gitlab
+sudo gitlab-rake gitlab:web_hook:add URL="http://example.com/hook" NAMESPACE=acme
+# source installations
+bundle exec rake gitlab:web_hook:add URL="http://example.com/hook" NAMESPACE=acme RAILS_ENV=production
+```
## Remove a webhook from **ALL** projects using:
- # omnibus-gitlab
- sudo gitlab-rake gitlab:web_hook:rm URL="http://example.com/hook"
- # source installations
- bundle exec rake gitlab:web_hook:rm URL="http://example.com/hook" RAILS_ENV=production
+```sh
+# omnibus-gitlab
+sudo gitlab-rake gitlab:web_hook:rm URL="http://example.com/hook"
+# source installations
+bundle exec rake gitlab:web_hook:rm URL="http://example.com/hook" RAILS_ENV=production
+```
## Remove a webhook from projects in a given **NAMESPACE**:
- # omnibus-gitlab
- sudo gitlab-rake gitlab:web_hook:rm URL="http://example.com/hook" NAMESPACE=acme
- # source installations
- bundle exec rake gitlab:web_hook:rm URL="http://example.com/hook" NAMESPACE=acme RAILS_ENV=production
+```sh
+# omnibus-gitlab
+sudo gitlab-rake gitlab:web_hook:rm URL="http://example.com/hook" NAMESPACE=acme
+# source installations
+bundle exec rake gitlab:web_hook:rm URL="http://example.com/hook" NAMESPACE=acme RAILS_ENV=production
+```
## List **ALL** webhooks:
- # omnibus-gitlab
- sudo gitlab-rake gitlab:web_hook:list
- # source installations
- bundle exec rake gitlab:web_hook:list RAILS_ENV=production
+```sh
+# omnibus-gitlab
+sudo gitlab-rake gitlab:web_hook:list
+# source installations
+bundle exec rake gitlab:web_hook:list RAILS_ENV=production
+```
## List the webhooks from projects in a given **NAMESPACE**:
- # omnibus-gitlab
- sudo gitlab-rake gitlab:web_hook:list NAMESPACE=acme
- # source installations
- bundle exec rake gitlab:web_hook:list NAMESPACE=acme RAILS_ENV=production
+```sh
+# omnibus-gitlab
+sudo gitlab-rake gitlab:web_hook:list NAMESPACE=acme
+# source installations
+bundle exec rake gitlab:web_hook:list NAMESPACE=acme RAILS_ENV=production
+```
diff --git a/doc/security/rack_attack.md b/doc/security/rack_attack.md
index fa4b0d1fb09..8695b5d2194 100644
--- a/doc/security/rack_attack.md
+++ b/doc/security/rack_attack.md
@@ -53,8 +53,9 @@ For more information on how to use these options check out
The following settings can be configured:
- `enabled`: By default this is set to `false`. Set this to `true` to enable Rack Attack.
-- `ip_whitelist`: Whitelist any IPs from being blocked. They must be formatted as strings within a ruby array.
- For example, `["127.0.0.1", "127.0.0.2", "127.0.0.3"]`.
+- `ip_whitelist`: Whitelist any IPs from being blocked. They must be formatted as strings within a Ruby array.
+ CIDR notation is supported in GitLab v12.1 and up.
+ For example, `["127.0.0.1", "127.0.0.2", "127.0.0.3", "192.168.0.1/24"]`.
- `maxretry`: The maximum amount of times a request can be made in the
specified time.
- `findtime`: The maximum amount of time that failed requests can count against an IP
diff --git a/doc/subscriptions/index.md b/doc/subscriptions/index.md
index 37051f6b10f..745a2253e84 100644
--- a/doc/subscriptions/index.md
+++ b/doc/subscriptions/index.md
@@ -14,7 +14,7 @@ Learn how GitLab helps you in the stages of the DevOps lifecycle by learning mor
### Self-managed: Install GitLab
-Take a look at [installing GitLab](https://about.gitlab.com/install/) and our [administrator documentation](../administration/index.md). Then, follow the instructions below under [Your subscription](#your-subscription) to apply your license file.
+Take a look at [installing GitLab](https://about.gitlab.com/install/) and our [administrator documentation](../administration/index.md). Then, follow the instructions below under [Your subscription](#your-subscription) to apply your license file.
### GitLab.com: Create a user and group
@@ -74,11 +74,11 @@ 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
-in your Settings,
-* For groups, this is located under the group's Settings dropdown, under Billing.
+- 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.
-For groups, you can see details of your subscription - including your current
+For groups, you can see details of your subscription - including your current
plan - in the included table:
![Billing table](billing_table.png)
@@ -86,11 +86,11 @@ plan - in the included table:
| Field | Description |
| ------ | ------ |
| Seats in subscription | If this is a paid plan, this represents the number of seats you've paid to support in your group. |
-| Seats currently in use | The number of active seats currently in use. |
-| Max seats used | The highest number of seats you've used. If this exceeds the seats in subscription, you may owe an additional fee for the additional users. |
-| Seats owed | If your max seats used exceeds the seats in your subscription, you'll owe an additional fee for the users you've added. |
-| Subscription start date | The date your subscription started. If this is for a Free plan, this is the date you transitioned off your group's paid plan. |
-| Subscription end date | The date your current subscription will end. This does not apply to Free plans. |
+| Seats currently in use | The number of active seats currently in use. |
+| Max seats used | The highest number of seats you've used. If this exceeds the seats in subscription, you may owe an additional fee for the additional users. |
+| Seats owed | If your max seats used exceeds the seats in your subscription, you'll owe an additional fee for the users you've added. |
+| Subscription start date | The date your subscription started. If this is for a Free plan, this is the date you transitioned off your group's paid plan. |
+| Subscription end date | The date your current subscription will end. This does not apply to Free plans. |
### Subscription changes and your data
diff --git a/doc/topics/application_development_platform/index.md b/doc/topics/application_development_platform/index.md
index e8960a76dd9..8742606479d 100644
--- a/doc/topics/application_development_platform/index.md
+++ b/doc/topics/application_development_platform/index.md
@@ -1,12 +1,21 @@
# Application Development Platform
-The GitLab Application Development Platform refers to the set of GitLab features that can be used by operations teams to
-provide a full development environment to internal software development teams.
+The GitLab Application Development Platform refers to the set of GitLab features used to create, configure, and manage
+a complete software development environment. It provides development, operations, and security teams with a robust feature set aimed at supporting best practices out of the box.
## Overview
-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. It comprises the following high-level elements:
+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
+ 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
+ problems and unintended use.
+
+It is comprised of the following high-level elements:
1. Compute
1. Build, test, and deploy a wide range of applications
diff --git a/doc/topics/autodevops/index.md b/doc/topics/autodevops/index.md
index 702245b22a0..bd788cb138c 100644
--- a/doc/topics/autodevops/index.md
+++ b/doc/topics/autodevops/index.md
@@ -175,8 +175,8 @@ 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`
@@ -662,25 +662,32 @@ to the desired environment. See [Limiting environment scopes of variables](../..
### 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
@@ -723,7 +730,7 @@ also be customized, and you can easily use a [custom buildpack](#custom-buildpac
| `AUTO_DEVOPS_CHART_REPOSITORY_USERNAME` | From Gitlab 11.11, this variable can be used to set a username to connect to the helm repository. Defaults to no credentials. (Also set AUTO_DEVOPS_CHART_REPOSITORY_PASSWORD) |
| `AUTO_DEVOPS_CHART_REPOSITORY_PASSWORD` | From Gitlab 11.11, this variable can be used to set a password to connect to the helm repository. Defaults to no credentials. (Also set AUTO_DEVOPS_CHART_REPOSITORY_USERNAME) |
| `REPLICAS` | The number of replicas to deploy; defaults to 1. |
-| `PRODUCTION_REPLICAS` | The number of replicas to deploy in the production environment. This takes precedence over `REPLICAS`; defaults to 1. |
+| `PRODUCTION_REPLICAS` | The number of replicas to deploy in the production environment. Takes precedence over `REPLICAS` and defaults to 1. For zero downtime upgrades, set to 2 or greater. |
| `CANARY_REPLICAS` | The number of canary replicas to deploy for [Canary Deployments](../../user/project/canary_deployments.md); defaults to 1 |
| `CANARY_PRODUCTION_REPLICAS` | The number of canary replicas to deploy for [Canary Deployments](../../user/project/canary_deployments.md) in the production environment. This takes precedence over `CANARY_REPLICAS`; defaults to 1 |
| `ADDITIONAL_HOSTS` | Fully qualified domain names specified as a comma-separated list that are added to the ingress hosts. |
diff --git a/doc/university/README.md b/doc/university/README.md
index 1d2c0f2068a..9d861460618 100644
--- a/doc/university/README.md
+++ b/doc/university/README.md
@@ -181,7 +181,7 @@ The GitLab University curriculum is composed of GitLab videos, screencasts, pres
### 3.9. Integrations
-1. [How to Integrate JIRA and Jenkins with GitLab - Video](https://gitlabmeetings.webex.com/gitlabmeetings/ldr.php?RCID=44b548147a67ab4d8a62274047146415)
+1. [How to Integrate Jira and Jenkins with GitLab - Video](https://gitlabmeetings.webex.com/gitlabmeetings/ldr.php?RCID=44b548147a67ab4d8a62274047146415)
1. [How to Integrate Jira with GitLab](../user/project/integrations/jira.md)
1. [How to Integrate Jenkins with GitLab](../integration/jenkins.md)
1. [How to Integrate Bamboo with GitLab](../user/project/integrations/bamboo.md)
diff --git a/doc/university/process/README.md b/doc/university/process/README.md
index fdf6224f7f6..b278e02ccd5 100644
--- a/doc/university/process/README.md
+++ b/doc/university/process/README.md
@@ -9,11 +9,11 @@ title: University | Process
# Suggesting improvements
If you would like to teach a class or participate or help in any way please
-submit a merge request and assign it to [Job](https://gitlab.com/u/JobV).
+submit a merge request and assign it to [Job](https://gitlab.com/JobV).
If you have suggestions for additional courses you would like to see,
please submit a merge request to add an upcoming class, assign to
-[Chad](https://gitlab.com/u/chadmalchow) and /cc [Job](https://gitlab.com/u/JobV).
+[Chad](https://gitlab.com/chadmalchow) and /cc [Job](https://gitlab.com/JobV).
## Adding classes
@@ -31,4 +31,4 @@ please submit a merge request to add an upcoming class, assign to
1. Please upload any video recordings to our Youtube channel. We prefer them to
be public, if needed they can be unlisted but if so they should be linked from
this page.
-1. Please create a merge request and assign to [Erica](https://gitlab.com/u/Erica).
+1. Please create a merge request and assign to [Erica](https://gitlab.com/Erica).
diff --git a/doc/university/support/README.md b/doc/university/support/README.md
index 35e65b60768..2c6e52acfde 100644
--- a/doc/university/support/README.md
+++ b/doc/university/support/README.md
@@ -80,7 +80,7 @@ Our integrations add great value to GitLab. User questions often relate to integ
- Learn about our Integrations (specially, not only):
- [LDAP](../../integration/ldap.md)
- - [JIRA](../../project_services/jira.md)
+ - [Jira](../../project_services/jira.md)
- [Jenkins](../../integration/jenkins.md)
- [SAML](../../integration/saml.md)
diff --git a/doc/update/upgrading_from_ce_to_ee.md b/doc/update/upgrading_from_ce_to_ee.md
index 428377adb19..7ae716d2cb3 100644
--- a/doc/update/upgrading_from_ce_to_ee.md
+++ b/doc/update/upgrading_from_ce_to_ee.md
@@ -25,14 +25,14 @@ Branch names use the format `major-minor-stable-ee` for Enterprise Edition, and
`major-minor-stable` for Community Edition. For example, for 11.8.0 you would
use the following branches:
-* Enterprise Edition: `11-8-stable-ee`
-* Community Edition: `11-8-stable`
+- Enterprise Edition: `11-8-stable-ee`
+- Community Edition: `11-8-stable`
### 0. Backup
Make a backup just in case something goes wrong:
-```bash
+```sh
cd /home/git/gitlab
sudo -u git -H bundle exec rake gitlab:backup:create RAILS_ENV=production
```
@@ -42,13 +42,13 @@ privileges to the GitLab user on the database version.
### 1. Stop server
-```bash
+```sh
sudo service gitlab stop
```
### 2. Get the EE code
-```bash
+```sh
cd /home/git/gitlab
sudo -u git -H git remote add -f ee https://gitlab.com/gitlab-org/gitlab-ee.git
sudo -u git -H git checkout EE_BRANCH
@@ -56,7 +56,7 @@ sudo -u git -H git checkout EE_BRANCH
### 3. Install libs, migrations, etc.
-```bash
+```sh
cd /home/git/gitlab
# MySQL installations (note: the line below states '--without postgres')
@@ -80,7 +80,7 @@ document linked above and enable the indexer usage in the GitLab admin settings.
### 5. Start application
-```bash
+```sh
sudo service gitlab start
sudo service nginx restart
```
@@ -89,13 +89,13 @@ sudo service nginx restart
Check if GitLab and its environment are configured correctly:
-```bash
+```sh
sudo -u git -H bundle exec rake gitlab:env:info RAILS_ENV=production
```
To make sure you didn't miss anything run a more thorough check with:
-```bash
+```sh
sudo -u git -H bundle exec rake gitlab:check RAILS_ENV=production
```
@@ -105,14 +105,14 @@ If all items are green, then congratulations upgrade complete!
### 1. Revert the code to the previous version
-```bash
+```sh
cd /home/git/gitlab
sudo -u git -H git checkout CE_BRANCH
```
### 2. Restore from the backup
-```bash
+```sh
cd /home/git/gitlab
sudo -u git -H bundle exec rake gitlab:backup:restore RAILS_ENV=production
```
diff --git a/doc/user/admin_area/index.md b/doc/user/admin_area/index.md
index add5971e01c..d2947ae3371 100644
--- a/doc/user/admin_area/index.md
+++ b/doc/user/admin_area/index.md
@@ -21,7 +21,7 @@ The Admin Area is made up of the following sections:
| Section | Description |
|:------------------------------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| [Overview](#overview-section) | View your GitLab [Dashboard](#admin-dashboard), and administer [projects](#administering-projects), [users](#administering-users), [groups](#administering-groups), [jobs](#administering-jobs), [Runners](#administering-runners), and [Gitaly servers](#administering-gitaly-servers). |
-| Monitoring | View GitLab system information, and information on background jobs, logs, [health checks](monitoring/health_check.md), request profiles, and audit logs. |
+| Monitoring | View GitLab [system information](#system-info), and information on [background jobs](#background-jobs), [logs](#logs), [health checks](monitoring/health_check.md), [requests profiles](#requests-profiles), and [audit logs](#audit-log-premium-only). |
| Messages | Send and manage [broadcast messages](broadcast_messages.md) for your users. |
| 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. |
@@ -186,7 +186,7 @@ the sort order to *Last Contacted* from the dropdown beside the search field.
To search Runners' descriptions:
1. In the **Search or filter results...** field, type the description of the Runner you want to
-find.
+ find.
1. Press Enter.
You can also filter Runners by status, type, and tag. To filter:
@@ -229,3 +229,66 @@ For each Gitaly server, the following details are listed:
| Server version | Gitaly version |
| Git version | Version of Git installed on the Gitaly server |
| Up to date | Indicates if the Gitaly server version is the latest version available. A green dot indicates the server is up to date. |
+
+## Monitoring section
+
+The following topics document the **Monitoring** section of the Admin Area.
+
+### System Info
+
+The **System Info** page provides the following statistics:
+
+| Field | Description |
+| :----------- | :---------- |
+| CPU | Number of CPU cores available |
+| Memory Usage | Memory in use, and total memory available |
+| Disk Usage | Disk space in use, and total disk space available |
+| Uptime | Approximate uptime of the GitLab instance |
+
+These statistics are updated only when you navigate to the **System Info** page, or you refresh the page in your browser.
+
+### Background Jobs
+
+The **Background Jobs** page displays the Sidekiq dashboard. Sidekiq is used by GitLab to
+perform processing in the background.
+
+The Sidekiq dashboard consists of the following elements:
+
+- A tab per jobs' status.
+- A breakdown of background job statistics.
+- A live graph of **Processed** and **Failed** jobs, with a selectable polling interval.
+- An historical graph of **Processed** and **Failed** jobs, with a selectable time span.
+- Redis statistics, including:
+ - Version number
+ - Uptime, measured in days
+ - Number of connections
+ - Current memory usage, measured in MB
+ - Peak memory usage, measured in MB
+
+### Logs
+
+The **Logs** page provides access to the following log files:
+
+| Log file | Contents |
+| :---------------------- | :------- |
+| `application.log` | GitLab user activity |
+| `githost.log` | Failed GitLab interaction with Git repositories |
+| `production.log` | Requests received from Unicorn, and the actions taken to serve those requests |
+| `sidekiq.log` | Background jobs |
+| `repocheck.log` | Repository activity |
+| `integrations_json.log` | Activity between GitLab and integrated systems |
+| `kubernetes.log` | Kubernetes activity |
+
+The contents of these log files can be useful when troubleshooting a problem. Access is available to GitLab admins, without requiring direct access to the log files.
+
+For details of these log files and their contents, see [Log system](../../administration/logs.md).
+
+The content of each log file is listed in chronological order. To minimize performance issues, a maximum 2000 lines of each log file are shown.
+
+### Requests Profiles
+
+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]**
+
+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/monitoring/health_check.md b/doc/user/admin_area/monitoring/health_check.md
index f80d4e9d2aa..35e7b6fb541 100644
--- a/doc/user/admin_area/monitoring/health_check.md
+++ b/doc/user/admin_area/monitoring/health_check.md
@@ -41,42 +41,51 @@ The readiness and liveness probes will provide a report of system health in JSON
```json
{
- "queues_check" : {
- "status" : "ok"
+ "db_check":{
+ "status":"ok"
},
- "redis_check" : {
- "status" : "ok"
+ "redis_check":{
+ "status":"ok"
},
- "shared_state_check" : {
- "status" : "ok"
+ "cache_check":{
+ "status":"ok"
},
- "db_check" : {
- "status" : "ok"
+ "queues_check":{
+ "status":"ok"
},
- "cache_check" : {
- "status" : "ok"
+ "shared_state_check":{
+ "status":"ok"
+ },
+ "gitaly_check":{
+ "status":"ok",
+ "labels":{
+ "shard":"default"
+ }
+ }
}
-}
```
`liveness` probe example output:
```json
{
- "cache_check" : {
- "status" : "ok"
+ "db_check":{
+ "status":"ok"
+ },
+ "redis_check":{
+ "status":"ok"
},
- "db_check" : {
- "status" : "ok"
+ "cache_check":{
+ "status":"ok"
},
- "redis_check" : {
- "status" : "ok"
+ "queues_check":{
+ "status":"ok"
},
- "queues_check" : {
- "status" : "ok"
+ "shared_state_check":{
+ "status":"ok"
},
- "shared_state_check" : {
- "status" : "ok"
+ "gitaly_check":{
+ "status":"ok"
}
}
```
diff --git a/doc/user/admin_area/settings/continuous_integration.md b/doc/user/admin_area/settings/continuous_integration.md
index fde7d1aeaf7..84596ff6a2c 100644
--- a/doc/user/admin_area/settings/continuous_integration.md
+++ b/doc/user/admin_area/settings/continuous_integration.md
@@ -94,14 +94,11 @@ a group in the **Usage Quotas** page available to the group page settings list.
![Group pipelines quota](img/group_pipelines_quota.png)
+## Extra Shared Runners pipeline minutes quota **[FREE ONLY]**
-## Extra Shared Runners pipeline minutes quota
-
-NOTE: **Note:**
-Only available on GitLab.com.
-
-You can purchase additional CI minutes so your pipelines will not be blocked after you have
-used all your CI minutes from your main quota.
+If you're using GitLab.com, you can purchase additional CI minutes so your
+pipelines will not be blocked after you have used all your CI minutes from your
+main quota.
In order to purchase additional minutes, you should follow these steps:
@@ -110,27 +107,27 @@ In order to purchase additional minutes, you should follow these steps:
![Buy additional minutes](img/buy_btn.png)
1. Locate the subscription card that is linked to your group on GitLab.com,
-click on **Buy more CI minutes**, and complete the details about the transaction.
+ click on **Buy more CI minutes**, and complete the details about the transaction.
![Buy additional minutes](img/buy_minutes_card.png)
1. Once we have processed your payment, the extra CI minutes
-will be synced to your Group and you can visualize it from the
-**Group > Settings > Pipelines quota** page:
+ will be synced to your Group and you can visualize it from the
+ **Group > Settings > Pipelines quota** page:
![Additional minutes](img/additional_minutes.png)
Be aware that:
1. If you have purchased extra CI minutes before the purchase of a paid plan,
-we will calculate a pro-rated charge for your paid plan. That means you may
-be charged for less than one year since your subscription was previously
-created with the extra CI minutes.
+ we will calculate a pro-rated charge for your paid plan. That means you may
+ be charged for less than one year since your subscription was previously
+ created with the extra CI minutes.
1. Once the extra CI minutes has been assigned to a Group they cannot be transferred
-to a different Group.
+ to a different Group.
1. If you have some minutes used over your default quota, these minutes will
-be deducted from your Additional Minutes quota immediately after your purchase of additional
-minutes.
+ be deducted from your Additional Minutes quota immediately after your purchase of additional
+ minutes.
## What happens when my CI minutes quota run out
diff --git a/doc/user/admin_area/settings/terms.md b/doc/user/admin_area/settings/terms.md
index a5f8d05f662..a1bce5a6c69 100644
--- a/doc/user/admin_area/settings/terms.md
+++ b/doc/user/admin_area/settings/terms.md
@@ -17,7 +17,7 @@ To enforce acceptance of a Terms of Service and Privacy Policy:
1. Go to **Admin Area > Settings > General**.
1. Expand the **Terms of Service and Privacy Policy** section.
1. Check the **Require all users to accept Terms of Service and Privacy Policy when they access
-GitLab.** checkbox.
+ GitLab.** checkbox.
1. Input the text of the **Terms of Service and Privacy Policy**. Markdown formatting can be used in this input box.
1. Click **Save changes**.
1. When you are presented with the **Terms of Service** statement, click **Accept terms**.
diff --git a/doc/user/application_security/container_scanning/index.md b/doc/user/application_security/container_scanning/index.md
index 4a2fb1d7190..9dfbe326f1d 100644
--- a/doc/user/application_security/container_scanning/index.md
+++ b/doc/user/application_security/container_scanning/index.md
@@ -206,6 +206,11 @@ vulnerabilities in your groups and projects. Read more about the
Once a vulnerability is found, you can interact with it. Read more on how to
[interact with the vulnerabilities](../index.md#interacting-with-the-vulnerabilities).
+## Vulnerabilities database update
+
+For more information about the vulnerabilities database update, check the
+[maintenance table](../index.md#maintenance-and-update-of-the-vulnerabilities-database).
+
## Troubleshooting
### docker: Error response from daemon: failed to copy xattrs
diff --git a/doc/user/application_security/dast/index.md b/doc/user/application_security/dast/index.md
index a722aa88f9d..2283efe3a44 100644
--- a/doc/user/application_security/dast/index.md
+++ b/doc/user/application_security/dast/index.md
@@ -259,3 +259,8 @@ vulnerabilities in your groups and projects. Read more about the
Once a vulnerability is found, you can interact with it. Read more on how to
[interact with the vulnerabilities](../index.md#interacting-with-the-vulnerabilities).
+
+## Vulnerabilities database update
+
+For more information about the vulnerabilities database update, check the
+[maintenance table](../index.md#maintenance-and-update-of-the-vulnerabilities-database).
diff --git a/doc/user/application_security/dependency_scanning/analyzers.md b/doc/user/application_security/dependency_scanning/analyzers.md
new file mode 100644
index 00000000000..937ded287e5
--- /dev/null
+++ b/doc/user/application_security/dependency_scanning/analyzers.md
@@ -0,0 +1,133 @@
+# Dependency Scanning Analyzers **[ULTIMATE]**
+
+Dependency Scanning relies on underlying third party tools that are wrapped into
+what we call "Analyzers". An analyzer is a
+[dedicated project](https://gitlab.com/gitlab-org/security-products/analyzers)
+that wraps a particular tool to:
+
+- Expose its detection logic.
+- Handle its execution.
+- Convert its output to the common format.
+
+This is achieved by implementing the [common API](https://gitlab.com/gitlab-org/security-products/analyzers/common).
+
+Dependency Scanning supports the following official analyzers:
+
+- [`bundler-audit`](https://gitlab.com/gitlab-org/security-products/analyzers/bundler-audit)
+- [`gemnasium`](https://gitlab.com/gitlab-org/security-products/analyzers/gemnasium)
+- [`gemnasium-maven`](https://gitlab.com/gitlab-org/security-products/analyzers/gemnasium-maven)
+- [`gemnasium-python`](https://gitlab.com/gitlab-org/security-products/analyzers/gemnasium-python)
+- [`retire.js`](https://gitlab.com/gitlab-org/security-products/analyzers/retire.js)
+
+The analyzers are published as Docker images that Dependency Scanning will use
+to launch dedicated containers for each analysis.
+
+Dependency Scanning is pre-configured with a set of **default images** that are
+maintained by GitLab, but users can also integrate their own **custom images**.
+
+## Official default analyzers
+
+Any custom change to the official analyzers can be achieved by using an
+[environment variable in your `.gitlab-ci.yml`](index.md#customizing-the-dependency-scanning-settings).
+
+### Using a custom Docker mirror
+
+You can switch to a custom Docker registry that provides the official analyzer
+images under a different prefix. For instance, the following instructs Dependency
+Scanning to pull `my-docker-registry/gl-images/gemnasium`
+instead of `registry.gitlab.com/gitlab-org/security-products/analyzers/gemnasium`.
+In `.gitlab-ci.yml` define:
+
+```yaml
+include:
+ template: Dependency-Scanning.gitlab-ci.yml
+
+variables:
+ DS_ANALYZER_IMAGE_PREFIX: my-docker-registry/gl-images
+```
+
+This configuration requires that your custom registry provides images for all
+the official analyzers.
+
+### Selecting specific analyzers
+
+You can select the official analyzers you want to run. Here's how to enable
+`bundler-audit` and `gemnasium` while disabling all the other default ones.
+In `.gitlab-ci.yml` define:
+
+```yaml
+include:
+ template: Dependency-Scanning.gitlab-ci.yml
+
+variables:
+ DS_DEFAULT_ANALYZERS: "bundler-audit,gemnasium"
+```
+
+`bundler-audit` runs first. When merging the reports, Dependency Scanning will
+remove the duplicates and will keep the `bundler-audit` entries.
+
+### Disabling default analyzers
+
+Setting `DS_DEFAULT_ANALYZERS` to an empty string will disable all the official
+default analyzers. In `.gitlab-ci.yml` define:
+
+```yaml
+include:
+ template: Dependency-Scanning.gitlab-ci.yml
+
+variables:
+ DS_DEFAULT_ANALYZERS: ""
+```
+
+That's needed when one totally relies on [custom analyzers](#custom-analyzers).
+
+## Custom analyzers
+
+You can provide your own analyzers as a comma separated list of Docker images.
+Here's how to add `analyzers/nugget` and `analyzers/perl` to the default images.
+In `.gitlab-ci.yml` define:
+
+```yaml
+include:
+ template: Dependency-Scanning.gitlab-ci.yml
+
+variables:
+ DS_ANALYZER_IMAGES: "my-docker-registry/analyzers/nugget,amy-docker-registry/nalyzers/perl"
+```
+
+The values must be the full path to the container registry images,
+like what you would feed to the `docker pull` command.
+
+NOTE: **Note:**
+This configuration doesn't benefit from the integrated detection step. Dependency
+Scanning has to fetch and spawn each Docker image to establish whether the
+custom analyzer can scan the source code.
+
+## Analyzers data
+
+The following table lists the data available for each official analyzer.
+
+| Property \ Tool | Gemnasium | bundler-audit | Retire.js |
+|---------------------------------------|:------------------:|:------------------:|:------------------:|
+| Severity | 𐄂 | ✓ | ✓ |
+| Title | ✓ | ✓ | ✓ |
+| File | ✓ | ⚠ | ✓ |
+| Start line | 𐄂 | 𐄂 | 𐄂 |
+| End line | 𐄂 | 𐄂 | 𐄂 |
+| External ID (e.g., CVE) | ✓ | ✓ | ⚠ |
+| URLs | ✓ | ✓ | ✓ |
+| Internal doc/explanation | ✓ | 𐄂 | 𐄂 |
+| Solution | ✓ | ✓ | 𐄂 |
+| Confidence | 𐄂 | 𐄂 | 𐄂 |
+| Affected item (e.g. class or package) | ✓ | ✓ | ✓ |
+| Source code extract | 𐄂 | 𐄂 | 𐄂 |
+| Internal ID | ✓ | 𐄂 | 𐄂 |
+| Date | ✓ | 𐄂 | 𐄂 |
+| Credits | ✓ | 𐄂 | 𐄂 |
+
+- ✓ => we have that data
+- ⚠ => we have that data but it's partially reliable, or we need to extract that data from unstructured content
+- 𐄂 => we don't have that data or it would need to develop specific or inefficient/unreliable logic to obtain it.
+
+The values provided by these tools are heterogeneous so they are sometimes
+normalized into common values (e.g., `severity`, `confidence`, etc).
diff --git a/doc/user/application_security/dependency_scanning/index.md b/doc/user/application_security/dependency_scanning/index.md
index a4e5b19bdc7..9145e034dcb 100644
--- a/doc/user/application_security/dependency_scanning/index.md
+++ b/doc/user/application_security/dependency_scanning/index.md
@@ -46,17 +46,33 @@ this is enabled by default.
The following languages and dependency managers are supported.
-| Language (package managers) | Scan tool |
-|-----------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------|
-| JavaScript ([npm](https://www.npmjs.com/), [yarn](https://yarnpkg.com/en/)) | [gemnasium](https://gitlab.com/gitlab-org/security-products/gemnasium/general), [Retire.js](https://retirejs.github.io/retire.js) |
-| Python ([pip](https://pip.pypa.io/en/stable/)) (only `requirements.txt` supported) | [gemnasium](https://gitlab.com/gitlab-org/security-products/gemnasium/general) |
-| Ruby ([gem](https://rubygems.org/)) | [gemnasium](https://gitlab.com/gitlab-org/security-products/gemnasium/general), [bundler-audit](https://github.com/rubysec/bundler-audit) |
-| Java ([Maven](https://maven.apache.org/)) | [gemnasium](https://gitlab.com/gitlab-org/security-products/gemnasium/general) |
-| PHP ([Composer](https://getcomposer.org/)) | [gemnasium](https://gitlab.com/gitlab-org/security-products/gemnasium/general) |
-
-Some scanners require to send a list of project dependencies to GitLab's central
-servers to check for vulnerabilities. To learn more about this or to disable it,
-refer to the [GitLab Dependency Scanning tool documentation](https://gitlab.com/gitlab-org/security-products/dependency-scanning#remote-checks).
+| Language (package managers) | Supported | Scan tool(s) |
+|----------------------------- | --------- | ------------ |
+| JavaScript ([npm](https://www.npmjs.com/), [yarn](https://yarnpkg.com/en/)) | yes | [gemnasium](https://gitlab.com/gitlab-org/security-products/gemnasium), [Retire.js](https://retirejs.github.io/retire.js) |
+| Python ([pip](https://pip.pypa.io/en/stable/)) (only `requirements.txt` supported) | yes | [gemnasium](https://gitlab.com/gitlab-org/security-products/gemnasium) |
+| Ruby ([gem](https://rubygems.org/)) | yes | [gemnasium](https://gitlab.com/gitlab-org/security-products/gemnasium), [bundler-audit](https://github.com/rubysec/bundler-audit) |
+| Java ([Maven](https://maven.apache.org/)) | yes | [gemnasium](https://gitlab.com/gitlab-org/security-products/gemnasium) |
+| PHP ([Composer](https://getcomposer.org/)) | yes | [gemnasium](https://gitlab.com/gitlab-org/security-products/gemnasium) |
+| Python ([poetry](https://poetry.eustace.io/)) | no ([issue](https://gitlab.com/gitlab-org/gitlab-ee/issues/7006 "Support Poetry in Dependency Scanning")) | not available |
+| Python ([Pipfile](https://docs.pipenv.org/en/latest/basics/)) | no ([issue](https://gitlab.com/gitlab-org/gitlab-ee/issues/11756 "Pipfile.lock support for Dependency Scanning"))| not available |
+| Go ([Golang](https://golang.org/)) | no ([issue](https://gitlab.com/gitlab-org/gitlab-ee/issues/7132 "Dependency Scanning for Go")) | not available |
+
+## Remote checks
+
+While some tools pull a local database to check vulnerabilities, some others
+like Gemnasium require sending data to GitLab central servers to analyze them:
+
+1. Gemnasium scans the dependencies of your project locally and sends a list of
+ packages to GitLab central servers.
+1. The servers return the list of known vulnerabilities for all versions of
+ these packages.
+1. The client picks up the relevant vulnerabilities by comparing with the versions
+ of the packages that are used by the project.
+
+The Gemnasium client does **NOT** send the exact package versions your project relies on.
+
+You can disable the remote checks by [using](#customizing-the-dependency-scanning-settings)
+the `DS_DISABLE_REMOTE_CHECKS` environment variable and setting it to `true`.
## Configuring Dependency Scanning
@@ -97,17 +113,10 @@ The report will be saved as a
that you can later download and analyze. Due to implementation limitations, we
always take the latest Dependency Scanning artifact available.
-Some security scanners require to send a list of project dependencies to GitLab
-central servers to check for vulnerabilities. To learn more about this or to
-disable it, check the
-[GitLab Dependency Scanning tool documentation](https://gitlab.com/gitlab-org/security-products/dependency-scanning#remote-checks).
-
#### Customizing the Dependency Scanning settings
-The Dependency Scanning settings can be changed through environment variables by using the
+The Dependency Scanning settings can be changed through [environment variables](#available-variables) by using the
[`variables`](../../../ci/yaml/README.md#variables) parameter in `.gitlab-ci.yml`.
-These variables are documented in the
-[Dependency Scanning tool documentation](https://gitlab.com/gitlab-org/security-products/dependency-scanning#settings).
For example:
@@ -116,7 +125,7 @@ include:
template: Dependency-Scanning.gitlab-ci.yml
variables:
- DEP_SCAN_DISABLE_REMOTE_CHECKS: true
+ DS_DISABLE_REMOTE_CHECKS: true
```
Because template is [evaluated before](../../../ci/yaml/README.md#include) the pipeline
@@ -137,6 +146,24 @@ dependency_scanning:
CI_DEBUG_TRACE: "true"
```
+#### Available variables
+
+Dependency Scanning can be [configured](#customizing-the-dependency-scanning-settings)
+using environment variables.
+
+| Environment variable | Function |
+|-------------------------------- |----------|
+| `DS_ANALYZER_IMAGES` | Comma separated list of custom images. The official default images are still enabled. Read more about [customizing analyzers](analyzers.md). |
+| `DS_ANALYZER_IMAGE_PREFIX` | Override the name of the Docker registry providing the official default images (proxy). Read more about [customizing analyzers](analyzers.md). |
+| `DS_ANALYZER_IMAGE_TAG` | Override the Docker tag of the official default images. Read more about [customizing analyzers](analyzers.md). |
+| `DS_DEFAULT_ANALYZERS` | Override the names of the official default images. Read more about [customizing analyzers](analyzers.md). |
+| `DS_DISABLE_REMOTE_CHECKS` | Do not send any data to GitLab. Used in the [Gemnasium analyzer](#remote-checks). |
+| `DS_PULL_ANALYZER_IMAGES` | Pull the images from the Docker registry (set to `0` to disable). |
+| `DS_EXCLUDED_PATHS` | Exclude vulnerabilities from output based on the paths. A comma-separated list of patterns. Patterns can be globs, file or folder paths. Parent directories will also match patterns. |
+| `DS_DOCKER_CLIENT_NEGOTIATION_TIMEOUT` | Time limit for Docker client negotiation. Timeouts are parsed using Go's [`ParseDuration`](https://golang.org/pkg/time/#ParseDuration). Valid time units are `ns`, `us` (or `µs`), `ms`, `s`, `m`, `h`. For example, `300ms`, `1.5h`, or `2h45m`. |
+| `DS_PULL_ANALYZER_IMAGE_TIMEOUT` | Time limit when pulling the image of an analyzer. Timeouts are parsed using Go's [`ParseDuration`](https://golang.org/pkg/time/#ParseDuration). Valid time units are `ns`, `us` (or `µs`), `ms`, `s`, `m`, `h`. For example, `300ms`, `1.5h`, or `2h45m`. |
+| `DS_RUN_ANALYZER_TIMEOUT` | Time limit when running an analyzer. Timeouts are parsed using Go's [`ParseDuration`](https://golang.org/pkg/time/#ParseDuration). Valid time units are `ns`, `us` (or `µs`), `ms`, `s`, `m`, `h`. For example, `300ms`, `1.5h`, or `2h45m`. |
+
### Manual job definition for GitLab 11.5 and later
For GitLab 11.5 and GitLab Runner 11.5 and later, the following `dependency_scanning`
@@ -171,7 +198,7 @@ dependency_scanning:
dependency_scanning: gl-dependency-scanning-report.json
```
-You can supply many other [settings variables](https://gitlab.com/gitlab-org/security-products/dependency-scanning#settings)
+You can supply many other [settings variables](#available-variables)
via `docker run --env` to customize your job execution.
### Manual job definition for GitLab 11.4 and earlier (deprecated)
@@ -377,6 +404,11 @@ vulnerabilities in your groups and projects. Read more about the
Once a vulnerability is found, you can interact with it. Read more on how to
[interact with the vulnerabilities](../index.md#interacting-with-the-vulnerabilities).
+## Vulnerabilities database update
+
+For more information about the vulnerabilities database update, check the
+[maintenance table](../index.md#maintenance-and-update-of-the-vulnerabilities-database).
+
## Dependency List
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/10075) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 12.0.
@@ -388,6 +420,10 @@ supported by Gemnasium.
To see the generated dependency list, navigate to your project's **Project > Dependency List**.
+## Versioning and release process
+
+Please check the [Release Process documentation](https://gitlab.com/gitlab-org/security-products/release/blob/master/docs/release_process.md).
+
## Contributing to the vulnerability database
You can search the [gemnasium-db](https://gitlab.com/gitlab-org/security-products/gemnasium-db) project
diff --git a/doc/user/application_security/index.md b/doc/user/application_security/index.md
index 679847b76d7..69fa1ec5da6 100644
--- a/doc/user/application_security/index.md
+++ b/doc/user/application_security/index.md
@@ -10,7 +10,7 @@ high-level view on projects and groups, and start remediation processes when nee
GitLab can scan and report any vulnerabilities found in your project.
-| Secure scanning tools | Description |
+| 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. |
@@ -19,6 +19,29 @@ GitLab can scan and report any vulnerabilities found in your project.
| [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
+
+The various scanning tools and the vulnerabilities database are updated regularly.
+
+| Secure scanning tool | Vulnerabilities database updates |
+|:-------------------------------------------------------------|-------------------------------------------|
+| [Container Scanning](container_scanning/index.md) | Uses `clair` underneath and the latest `clair-db` version is used for each job run by running the [`latest` docker image tag](https://gitlab.com/gitlab-org/gitlab-ee/blob/438a0a56dc0882f22bdd82e700554525f552d91b/lib/gitlab/ci/templates/Security/Container-Scanning.gitlab-ci.yml#L37). The `clair-db` database [is updated daily according to the author](https://github.com/arminc/clair-local-scan#clair-server-or-local). |
+| [Dependency Scanning](dependency_scanning/index.md) | Relies on `bundler-audit` (for Rubygems), `retire.js` (for NPM packages) and `gemnasium` (GitLab's own tool for all libraries). `bundler-audit` and `retire.js` both fetch their vulnerabilities data from GitHub repositories, so vulnerabilities added to `ruby-advisory-db` and `retire.js` are immediately available. The tools themselves are updated once per month if there's a new version. The [Gemnasium DB](https://gitlab.com/gitlab-org/security-products/gemnasium-db) is updated at least once a week. |
+| [Dynamic Application Security Testing (DAST)](dast/index.md) | Updated weekly on Sundays. The underlying tool, `zaproxy`, downloads fresh rules at startup. |
+| [Static Application Security Testing (SAST)](sast/index.md) | Relies exclusively on [the tools GitLab is wrapping](sast/index.md#supported-languages-and-frameworks). The underlying analyzers are updated at least once per month if a relevant update is available. The vulnerabilities database is updated by the upstream tools. |
+
+You don't have to update GitLab to benefit from the latest vulnerabilities definitions,
+but you may have to in the future.
+
+The security tools are released as Docker images, and the vendored job definitions
+to enable them are using the `x-y-stable` image tags that get overridden each time a new
+release of the tools is pushed. The Docker images are updated to match the
+previous GitLab releases, so they automatically get the latest versions of the
+scanning tools without the user having to do anything.
+
+This workflow comes with some drawbacks and there's a
+[plan to change this](https://gitlab.com/gitlab-org/gitlab-ee/issues/9725).
+
## Interacting with the vulnerabilities
> Introduced in [GitLab Ultimate](https://about.gitlab.com/pricing) 10.8.
diff --git a/doc/user/application_security/sast/index.md b/doc/user/application_security/sast/index.md
index ec3f7fbde76..9074ac3f4a1 100644
--- a/doc/user/application_security/sast/index.md
+++ b/doc/user/application_security/sast/index.md
@@ -269,7 +269,7 @@ it highlighted:
"url": "https://cwe.mitre.org/data/definitions/330.html"
}
]
- },
+ },
{
"category": "sast",
"message": "Probable insecure usage of temp file/directory.",
@@ -296,7 +296,7 @@ it highlighted:
"url": "https://docs.openstack.org/bandit/latest/plugins/b108_hardcoded_tmp_directory.html"
}
]
- },
+ },
],
"remediations": []
}
@@ -320,7 +320,7 @@ the report JSON unless stated otherwise. Presence of optional fields depends on
| `vulnerabilities[].scanner` | A node that describes the analyzer used to find this vulnerability. |
| `vulnerabilities[].scanner.id` | Id of the scanner as a snake_case string. |
| `vulnerabilities[].scanner.name` | Name of the scanner, for display purposes. |
-| `vulnerabilities[].location` | A node that tells where the vulnerability is located. |
+| `vulnerabilities[].location` | A node that tells where the vulnerability is located. |
| `vulnerabilities[].location.file` | Path to the file where the vulnerability is located. Optional. |
| `vulnerabilities[].location.start_line` | The first line of the code affected by the vulnerability. Optional. |
| `vulnerabilities[].location.end_line` | The last line of the code affected by the vulnerability. Optional. |
@@ -330,7 +330,7 @@ the report JSON unless stated otherwise. Presence of optional fields depends on
| `vulnerabilities[].identifiers[].type` | Type of the identifier. Possible values: common identifier types (among `cve`, `cwe`, `osvdb`, and `usn`) or analyzer-dependent ones (e.g., `bandit_test_id` for [Bandit analyzer](https://wiki.openstack.org/wiki/Security/Projects/Bandit)). |
| `vulnerabilities[].identifiers[].name` | Name of the identifier for display purposes. |
| `vulnerabilities[].identifiers[].value` | Value of the identifier for matching purposes. |
-| `vulnerabilities[].identifiers[].url` | URL to identifier's documentation. Optional. |
+| `vulnerabilities[].identifiers[].url` | URL to identifier's documentation. Optional. |
## Secret detection
@@ -363,3 +363,8 @@ vulnerabilities in your groups and projects. Read more about the
Once a vulnerability is found, you can interact with it. Read more on how to
[interact with the vulnerabilities](../index.md#interacting-with-the-vulnerabilities).
+
+## Vulnerabilities database update
+
+For more information about the vulnerabilities database update, check the
+[maintenance table](../index.md#maintenance-and-update-of-the-vulnerabilities-database).
diff --git a/doc/user/asciidoc.md b/doc/user/asciidoc.md
index a22b285b114..0ed9bf3f518 100644
--- a/doc/user/asciidoc.md
+++ b/doc/user/asciidoc.md
@@ -6,7 +6,7 @@ Consult the [Asciidoctor User Manual](https://asciidoctor.org/docs/user-manual)
## 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/gitlab_com/index.md b/doc/user/gitlab_com/index.md
index 2fb6cec55fa..886fb6e6f55 100644
--- a/doc/user/gitlab_com/index.md
+++ b/doc/user/gitlab_com/index.md
@@ -352,3 +352,13 @@ 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"
+
+## Other admin area settings
+
+This area highlights other noteworthy admin area settings on GitLab.com that differ from default settings. This list is not exhaustive.
+
+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).
diff --git a/doc/user/group/clusters/index.md b/doc/user/group/clusters/index.md
index 26d764fa2cf..8d4ffd93f59 100644
--- a/doc/user/group/clusters/index.md
+++ b/doc/user/group/clusters/index.md
@@ -138,14 +138,6 @@ The result will then be:
- The Staging cluster will be used for the `deploy to staging` job.
- The Production cluster will be used for the `deploy to production` job.
-## Unavailable features
-
-The following features are not currently available for group-level clusters:
-
-1. Terminals (see [related issue](https://gitlab.com/gitlab-org/gitlab-ce/issues/55487)).
-1. Pod logs (see [related issue](https://gitlab.com/gitlab-org/gitlab-ce/issues/55488)).
-1. Deployment boards (see [related issue](https://gitlab.com/gitlab-org/gitlab-ce/issues/55489)).
-
<!-- ## Troubleshooting
Include any troubleshooting steps that you can foresee. If you know beforehand what issues
diff --git a/doc/user/group/contribution_analytics/index.md b/doc/user/group/contribution_analytics/index.md
index 7e6cb24a51e..a555b7723df 100644
--- a/doc/user/group/contribution_analytics/index.md
+++ b/doc/user/group/contribution_analytics/index.md
@@ -21,9 +21,9 @@ page.
## Use cases
- Analyze your team's contributions over a period of time, and offer a bonus for the top
-contributors.
+ contributors.
- Identify opportunities for improvement with group members who may benefit from additional
-support.
+ support.
## Using Contribution Analytics
@@ -54,13 +54,13 @@ Select the desired period from the calendar dropdown.
Contributions per group member are also presented in tabular format. Click a column header to sort the table by that column:
-* Member name
-* Number of pushed events
-* Number of opened issues
-* Number of closed issues
-* Number of opened MRs
-* Number of accepted MRs
-* Number of total contributions
+- Member name
+- Number of pushed events
+- Number of opened issues
+- Number of closed issues
+- Number of opened MRs
+- Number of accepted MRs
+- Number of total contributions
![Contribution analytics contributions table](img/group_stats_table.png)
diff --git a/doc/user/group/epics/index.md b/doc/user/group/epics/index.md
index 2e4106f55e5..f53c1dd95d7 100644
--- a/doc/user/group/epics/index.md
+++ b/doc/user/group/epics/index.md
@@ -202,8 +202,8 @@ You may also consult the [group permissions table][permissions].
## Thread
- Comments: collaborate on that epic by posting comments in its thread.
-These text fields also fully support
-[GitLab Flavored Markdown](../../markdown.md#gitlab-flavored-markdown-gfm).
+ These text fields also fully support
+ [GitLab Flavored Markdown](../../markdown.md#gitlab-flavored-markdown-gfm).
## Comment, or start a discussion
@@ -216,7 +216,7 @@ Once you wrote your comment, you can either:
- You can [award an emoji](../../award_emojis.md) to that epic or its comments.
-## Notifications
+## Notifications
- [Receive notifications](../../../workflow/notifications.md) for epic events.
diff --git a/doc/user/group/index.md b/doc/user/group/index.md
index 4fde45da6c4..7240b8e118b 100644
--- a/doc/user/group/index.md
+++ b/doc/user/group/index.md
@@ -41,12 +41,13 @@ You can create groups for numerous reasons. To name a couple:
- Make it easier to `@mention` all of your team at once in issues and merge requests by creating a group and including the appropriate members.
For example, you could create a group for your company members, and create a [subgroup](subgroups/index.md) for each individual team. Let's say you create a group called `company-team`, and you create subgroups in this group for the individual teams `backend-team`, `frontend-team`, and `production-team`.
- - When you start a new implementation from an issue, you add a comment:
- _"`@company-team`, let's do it! `@company-team/backend-team` you're good to go!"_
- - When your backend team needs help from frontend, they add a comment:
- _"`@company-team/frontend-team` could you help us here please?"_
- - When the frontend team completes their implementation, they comment:
- _"`@company-team/backend-team`, it's done! Let's ship it `@company-team/production-team`!"_
+
+- When you start a new implementation from an issue, you add a comment:
+ _"`@company-team`, let's do it! `@company-team/backend-team` you're good to go!"_
+- When your backend team needs help from frontend, they add a comment:
+ _"`@company-team/frontend-team` could you help us here please?"_
+- When the frontend team completes their implementation, they comment:
+ _"`@company-team/backend-team`, it's done! Let's ship it `@company-team/production-team`!"_
## Namespaces
@@ -217,6 +218,8 @@ Get an overview of the vulnerabilities of all the projects in a group and its su
## Insights **[ULTIMATE]**
+> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/725) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 12.0.
+
Configure the Insights that matter for your groups or projects, allowing users
to explore data such as:
diff --git a/doc/user/group/insights/index.md b/doc/user/group/insights/index.md
index 1aba5d0986b..e6ba47939b3 100644
--- a/doc/user/group/insights/index.md
+++ b/doc/user/group/insights/index.md
@@ -4,8 +4,7 @@ type: reference, howto
# Insights **[ULTIMATE]**
-> Introduced in [GitLab Ultimate](https://about.gitlab.com/pricing/) 11.9 behind the `insights` feature flag.
-> **Generally Available** (GA) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 12.0.
+> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/725) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 12.0.
Configure the Insights that matter for your groups to explore data such as
triage hygiene, issues created/closed per a given period, average time for merge
diff --git a/doc/user/group/saml_sso/scim_setup.md b/doc/user/group/saml_sso/scim_setup.md
index 96cc523f4ec..5aef463d782 100644
--- a/doc/user/group/saml_sso/scim_setup.md
+++ b/doc/user/group/saml_sso/scim_setup.md
@@ -24,27 +24,27 @@ The following identity providers are supported:
## Requirements
-- [Group SSO](index.md) needs to be configured.
+- [Group SSO](index.md) needs to be configured.
- The `scim_group` feature flag must be enabled:
Run the following commands in a Rails console:
-
+
```sh
# Omnibus GitLab
gitlab-rails console
-
+
# Installation from source
cd /home/git/gitlab
sudo -u git -H bin/rails console RAILS_ENV=production
```
-
+
To enable SCIM for a group named `group_name`:
-
+
```ruby
group = Group.find_by_full_path('group_name')
Feature.enable(:group_scim, group)
```
-
+
### GitLab configuration
Once [Single sign-on](index.md) has been configured, we can:
@@ -53,7 +53,7 @@ Once [Single sign-on](index.md) has been configured, we can:
1. Click on the **Generate a SCIM token** button.
1. Save the token and URL so they can be used in the next step.
-![SCIM token configuration](img/scim_token.png)
+![SCIM token configuration](img/scim_token.png)
## SCIM IdP configuration
@@ -63,15 +63,15 @@ In the [Single sign-on](index.md) configuration for the group, make sure
that the **Name identifier value** (NameID) points to a unique identifier, such
as the `user.objectid`. This will match the `extern_uid` used on GitLab.
-The GitLab app in Azure needs to be configured following
+The GitLab app in Azure needs to be configured following
[Azure's SCIM setup](https://docs.microsoft.com/en-us/azure/active-directory/manage-apps/use-scim-to-provision-users-and-groups#getting-started).
Note the following:
- The `Tenant URL` and `secret token` are the ones retrieved in the
-[previous step](#gitlab-configuration).
+ [previous step](#gitlab-configuration).
- Should there be any problems with the availability of GitLab or similar
-errors, the notification email set will get those.
+ errors, the notification email set will get those.
- For mappings, we will only leave `Synchronize Azure Active Directory Users to AppName` enabled.
You can then test the connection clicking on `Test Connection`.
@@ -79,14 +79,14 @@ You can then test the connection clicking on `Test Connection`.
### Synchronize Azure Active Directory users
1. Click on `Synchronize Azure Active Directory Users to AppName`, to configure
-the attribute mapping.
+ the attribute mapping.
1. Select the unique identifier (in the example `objectId`) as the `id` and `externalId`,
-and enable the `Create`, `Update`, and `Delete` actions.
+ and enable the `Create`, `Update`, and `Delete` actions.
1. Map the `userPricipalName` to `emails[type eq "work"].value` and `mailNickname` to
-`userName`.
+ `userName`.
Example configuration:
-
+
![Azure's attribute mapping configuration](img/scim_attribute_mapping.png)
1. Click on **Show advanced options > Edit attribute list for AppName**.
@@ -95,11 +95,11 @@ and enable the `Create`, `Update`, and `Delete` actions.
NOTE: **Note:**
`username` should neither be primary nor required as we don't support
that field on GitLab SCIM yet.
-
+
![Azure's attribute advanced configuration](img/scim_advanced.png)
1. Save all the screens and, in the **Provisioning** step, set
-the `Provisioning Status` to `ON`.
+ the `Provisioning Status` to `ON`.
NOTE: **Note:**
You can control what is actually synced by selecting the `Scope`. For example,
diff --git a/doc/user/img/color_inline_colorchip_render_gfm.png b/doc/user/img/color_inline_colorchip_render_gfm.png
deleted file mode 100644
index 6f93dbeeb10..00000000000
--- a/doc/user/img/color_inline_colorchip_render_gfm.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/img/markdown_inline_diffs_tags_rendered.png b/doc/user/img/markdown_inline_diffs_tags_rendered.png
deleted file mode 100644
index 4279a20b5a0..00000000000
--- a/doc/user/img/markdown_inline_diffs_tags_rendered.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/img/math_inline_sup_render_gfm.png b/doc/user/img/math_inline_sup_render_gfm.png
deleted file mode 100644
index 3ee2abb14df..00000000000
--- a/doc/user/img/math_inline_sup_render_gfm.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/img/task_list_ordered_render_gfm.png b/doc/user/img/task_list_ordered_render_gfm.png
deleted file mode 100644
index 98ec791e958..00000000000
--- a/doc/user/img/task_list_ordered_render_gfm.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/index.md b/doc/user/index.md
index 1fc4e4c43cf..899026a801f 100644
--- a/doc/user/index.md
+++ b/doc/user/index.md
@@ -66,7 +66,7 @@ With GitLab Enterprise Edition, you can also:
- Leverage continuous delivery method with [Canary Deployments](project/canary_deployments.md).
- Scan your code for vulnerabilities and [display them in merge requests](application_security/sast/index.md).
-You can also [integrate](project/integrations/project_services.md) GitLab with numerous third-party applications, such as Mattermost, Microsoft Teams, HipChat, Trello, Slack, Bamboo CI, JIRA, and a lot more.
+You can also [integrate](project/integrations/project_services.md) GitLab with numerous third-party applications, such as Mattermost, Microsoft Teams, HipChat, Trello, Slack, Bamboo CI, Jira, and a lot more.
## Projects
@@ -153,7 +153,7 @@ you have quick access to. You can also gather feedback on them through
## Integrations
[Integrate GitLab](../integration/README.md) with your preferred tool,
-such as Trello, JIRA, etc.
+such as Trello, Jira, etc.
## Webhooks
diff --git a/doc/user/markdown.md b/doc/user/markdown.md
index 31c8093ced7..eaae9964367 100644
--- a/doc/user/markdown.md
+++ b/doc/user/markdown.md
@@ -1,15 +1,20 @@
# GitLab Markdown
-This markdown guide is **valid for GitLab's system markdown entries and files**.
-It is not valid for the [GitLab documentation website](https://docs.gitlab.com)
-nor [GitLab's main website](https://about.gitlab.com), as they both use
-[Kramdown](https://kramdown.gettalong.org) as their markdown engine.
-The documentation website uses an extended Kramdown gem, [GitLab Kramdown](https://gitlab.com/gitlab-org/gitlab_kramdown).
-Consult the [GitLab Kramdown Guide](https://about.gitlab.com/handbook/product/technical-writing/markdown-guide/) for a complete Kramdown reference.
+This markdown guide is **valid only for GitLab's internal markdown rendering system for entries and files**.
+It is **not** valid for the [GitLab documentation website](https://docs.gitlab.com)
+or [GitLab's main website](https://about.gitlab.com), as they both use
+[Kramdown](https://kramdown.gettalong.org) as their markdown engine. The documentation
+website uses an extended Kramdown gem, [GitLab Kramdown](https://gitlab.com/gitlab-org/gitlab_kramdown).
+Consult the [GitLab Kramdown Guide](https://about.gitlab.com/handbook/product/technical-writing/markdown-guide/)
+for a complete Kramdown reference.
+
+NOTE: **Note:** We encourage you to view this document as [rendered by GitLab itself](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/user/markdown.md).
## GitLab Flavored Markdown (GFM)
-GitLab uses "GitLab Flavored Markdown" (GFM). It extends the [CommonMark specification][commonmark-spec] (which is based on standard Markdown) in a few significant ways to add additional useful functionality. It was inspired by [GitHub Flavored Markdown](https://help.github.com/articles/basic-writing-and-formatting-syntax/).
+GitLab uses "GitLab Flavored Markdown" (GFM). It extends the [CommonMark specification](https://spec.commonmark.org/current/)
+(which is based on standard Markdown) in several ways to add additional useful functionality.
+It was inspired by [GitHub Flavored Markdown](https://help.github.com/articles/basic-writing-and-formatting-syntax/).
You can use GFM in the following areas:
@@ -22,35 +27,29 @@ You can use GFM in the following areas:
- Markdown documents inside repositories
- 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 [`github-markup` gem readme](https://github.com/gitlabhq/markup#markups) for more information.
-
-> **Notes:**
->
-> We encourage you to view this document as [rendered by GitLab itself](markdown.md).
->
-> As of 11.1, GitLab uses the [CommonMark Ruby Library][commonmarker] for Markdown
-processing of all new issues, merge requests, comments, and other Markdown content
-in the GitLab system. As of 11.3, wiki pages and Markdown files (`.md`) in the
-repositories are also processed with CommonMark. As of 11.8, the [Redcarpet
-Ruby library][redcarpet] has been removed and all issues/comments, including
-those from pre-11.1, are now processed using [CommonMark Ruby
-Library][commonmarker].
->
-> The documentation website had its [markdown engine migrated from Redcarpet to Kramdown](https://gitlab.com/gitlab-com/gitlab-docs/merge_requests/108)
-in October 2018.
->
-> _Where there are significant differences, we will try to call them out in this document._
+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)
+for more information.
+
+### Transition from Redcarpet to CommonMark
-### Transitioning to CommonMark
+Since 11.1, GitLab uses the [CommonMark Ruby Library](https://github.com/gjtorikian/commonmarker)
+for Markdown processing of all new issues, merge requests, comments, and other Markdown
+content in the GitLab system. Since 11.3, wiki pages and Markdown files (`*.md`) in
+repositories are also processed with CommonMark. As of 11.8, the [Redcarpet Ruby library](https://github.com/vmg/redcarpet)
+has been removed and all issues and comments, including those from pre-11.1, are now processed
+using the [CommonMark Ruby Library](https://github.com/gjtorikian/commonmarker).
-You may have older issues/merge requests or Markdown documents in your
-repository that were written using some of the nuances of RedCarpet's version
+The documentation website had its [markdown engine migrated from Redcarpet to Kramdown](https://gitlab.com/gitlab-com/gitlab-docs/merge_requests/108)
+in October 2018.
+
+You may have older issues, merge requests, or Markdown documents in your
+repository that were written using some of the nuances of GitLab's RedCarpet version
of Markdown. Since CommonMark uses a slightly stricter syntax, these documents
-may now display a little strangely since we've transitioned to CommonMark.
-Numbered lists with nested lists in particular can be displayed incorrectly.
+may now display a little differently since we've transitioned to CommonMark.
-It is usually quite easy to fix. In the case of a nested list such as this:
+It is usually quite easy to fix. For example, numbered lists with nested lists may
+render incorrectly:
```markdown
1. Chocolate
@@ -58,7 +57,14 @@ It is usually quite easy to fix. In the case of a nested list such as this:
- milk
```
-simply add a space to each nested item:
+1. Chocolate
+ - dark
+ - milk
+
+---
+
+Simply add a space to each nested item to align the `-` with the first character of
+the top list item (`C` in this case):
```markdown
1. Chocolate
@@ -66,515 +72,674 @@ simply add a space to each nested item:
- milk
```
-In the documentation below, we try to highlight some of the differences.
+1. Chocolate
+ - dark
+ - milk
+
+NOTE: **Note:** We will flag any significant differences between Redcarpet and CommonMark
+ markdown in this document.
If you have a large volume of Markdown files, it can be tedious to determine
-if they will be displayed correctly or not. You can use the
+if they will display correctly or not. You can use the
[diff_redcarpet_cmark](https://gitlab.com/digitalmoksha/diff_redcarpet_cmark)
-tool (not an officially supported product) to generate a list of files and
+tool (not an officially supported product) to generate a list of files, and the
differences between how RedCarpet and CommonMark render the files. It can give
-you a great idea if anything needs to be changed - many times nothing will need
-to changed.
+an indication if anything needs to be changed - often nothing will need
+to change.
+
+### GFM extends standard markdown
+
+GitLab makes full use of the standard (CommonMark) formatting, but also includes additional
+functionality useful for GitLab users.
+
+It makes use of [new markdown features](#new-GFM-markdown-extensions),
+not found in standard markdown:
+
+- [Color "chips" written in HEX, RGB or HSL](#colors)
+- [Diagrams and flowcharts using Mermaid](#diagrams-and-flowcharts-using-mermaid)
+- [Emoji](#emoji)
+- [Front matter](#front-matter)
+- [Inline diffs](#inline-diff)
+- [Math equations and symbols written in LaTeX](#math)
+- [Special GitLab references](#special-gitlab-references)
+- [Task Lists](#task-lists)
+- [Wiki specific markdown](#wiki-specific-markdown)
+
+It also has [extended markdown features](#standard-markdown-and-extensions-in-gitlab), without
+changing how standard markdown is used:
+
+| Standard markdown | Extended markdown in GitLab |
+| ------------------------------------- | ------------------------- |
+| [blockquotes](#blockquotes) | [multiline blockquotes](#multiline-blockquote) |
+| [code blocks](#code-spans-and-blocks) | [colored code and syntax highlighting](#colored-code-and-syntax-highlighting) |
+| [emphasis](#emphasis) | [multiple underscores in words](#multiple-underscores-in-words-and-mid-word-emphasis)
+| [headers](#headers) | [linkable Header IDs](#header-ids-and-links) |
+| [images](#images) | [embedded videos](#videos) |
+| [linebreaks](#line-breaks) | [more linebreak control](#newlines) |
+| [links](#links) | [automatically linking URLs](#url-auto-linking) |
+
+## New GFM markdown extensions
-### Newlines
+### Colors
-> If this is not rendered correctly, see
-https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/user/markdown.md#newlines
+> 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).
-GFM honors the markdown specification in how [paragraphs and line breaks are handled][commonmark-spec].
+It is possible to have color written in HEX, RGB or HSL format rendered with a color
+indicator.
-A paragraph is simply one or more consecutive lines of text, separated by one or
-more blank lines.
-Line-breaks, or soft returns, are rendered if you end a line with two or more spaces:
+Supported formats (named colors are not supported):
-<!-- (Do *NOT* remove the two ending whitespaces in the following line.) -->
-<!-- (They are needed for the Markdown text to render correctly.) -->
- Roses are red [followed by two or more spaces]
- Violets are blue
+- HEX: `` `#RGB[A]` `` or `` `#RRGGBB[AA]` ``
+- RGB: `` `RGB[A](R, G, B[, A])` ``
+- HSL: `` `HSL[A](H, S, L[, A])` ``
- Sugar is sweet
+Color written inside backticks will be followed by a color "chip":
-<!-- (Do *NOT* remove the two ending whitespaces in the following line.) -->
-<!-- (They are needed for the Markdown text to render correctly.) -->
-Roses are red
-Violets are blue
+```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)`
+```
-Sugar is sweet
+`#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)`
-### Multiple underscores in words
+### Diagrams and flowcharts using Mermaid
-> If this is not rendered correctly, see
-https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/user/markdown.md#multiple-underscores-in-words
+> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/15107) in
+GitLab 10.3.
-It is not reasonable to italicize just _part_ of a word, especially when you're
-dealing with code and names that often appear with multiple underscores.
-Therefore, GFM ignores multiple underscores in words:
+It is possible to generate diagrams and flowcharts from text using [Mermaid](https://mermaidjs.github.io/).
+Visit the official page for more details.
- perform_complicated_task
+In order to generate a diagram or flowchart, you should write your text inside the `mermaid` block:
- do_this_and_do_that_and_another_thing
+~~~
+```mermaid
+graph TD;
+ A-->B;
+ A-->C;
+ B-->D;
+ C-->D;
+```
+~~~
-perform_complicated_task
+```mermaid
+graph TD;
+ A-->B;
+ A-->C;
+ B-->D;
+ C-->D;
+```
-do_this_and_do_that_and_another_thing
+### Emoji
-### URL auto-linking
+> If this is not rendered correctly, [view it in GitLab itself](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/user/markdown.md#emoji).
-> If this is not rendered correctly, see
-https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/user/markdown.md#url-auto-linking
+```md
+Sometimes you want to :monkey: around a bit and add some :star2: to your :speech_balloon:. Well we have a gift for you:
-GFM will autolink almost any URL you copy and paste into your text:
+:zap: You can use emoji anywhere GFM is supported. :v:
- * 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
+You can use it to point out a :bug: or warn about :speak_no_evil: patches. And if someone improves your really :snail: code, send them some :birthday:. People will :heart: you for that.
-* https://www.google.com
-* https://google.com/
-* ftp://ftp.us.debian.org/debian/
-* <a href="smb://foo/bar/baz">smb://foo/bar/baz</a>
-* <a href="irc://irc.freenode.net/gitlab">irc://irc.freenode.net/gitlab</a>
-* http://localhost:3000
+If you are new to this, don't be :fearful:. You can easily join the emoji :family:. All you need to do is to look up one of the supported codes.
-### Multiline blockquote
+Consult the [Emoji Cheat Sheet](https://www.emojicopy.com) for a list of all supported emoji codes. :thumbsup:
+```
-> If this is not rendered correctly, see
-https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/user/markdown.md#multiline-blockquote
+Sometimes you want to <img src="https://gitlab.com/gitlab-org/gitlab-ce/raw/master/app/assets/images/emoji/monkey.png" width="20px" height="20px" style="display:inline;margin:0"> around a bit and add some <img src="https://gitlab.com/gitlab-org/gitlab-ce/raw/master/app/assets/images/emoji/star2.png" width="20px" height="20px" style="display:inline;margin:0"> to your <img src="https://gitlab.com/gitlab-org/gitlab-ce/raw/master/app/assets/images/emoji/speech_balloon.png" width="20px" height="20px" style="display:inline;margin:0">. Well we have a gift for you:
-On top of standard Markdown [blockquotes](#blockquotes), which require prepending `>` to quoted lines,
-GFM supports multiline blockquotes fenced by <code>>>></code>:
+<img src="https://gitlab.com/gitlab-org/gitlab-ce/raw/master/app/assets/images/emoji/zap.png" width="20px" height="20px" style="display:inline;margin:0">You can use emoji anywhere GFM is supported. <img src="https://gitlab.com/gitlab-org/gitlab-ce/raw/master/app/assets/images/emoji/v.png" width="20px" height="20px" style="display:inline;margin:0">
-```
->>>
-If you paste a message from somewhere else
+You can use it to point out a <img src="https://gitlab.com/gitlab-org/gitlab-ce/raw/master/app/assets/images/emoji/bug.png" width="20px" height="20px" style="display:inline;margin:0"> or warn about <img src="https://gitlab.com/gitlab-org/gitlab-ce/raw/master/app/assets/images/emoji/speak_no_evil.png" width="20px" height="20px" style="display:inline;margin:0"> patches. And if someone improves your really <img src="https://gitlab.com/gitlab-org/gitlab-ce/raw/master/app/assets/images/emoji/snail.png" width="20px" height="20px" style="display:inline;margin:0"> code, send them some <img src="https://gitlab.com/gitlab-org/gitlab-ce/raw/master/app/assets/images/emoji/birthday.png" width="20px" height="20px" style="display:inline;margin:0">. People will <img src="https://gitlab.com/gitlab-org/gitlab-ce/raw/master/app/assets/images/emoji/heart.png" width="20px" height="20px" style="display:inline;margin:0"> you for that.
-that
+If you are new to this, don't be <img src="https://gitlab.com/gitlab-org/gitlab-ce/raw/master/app/assets/images/emoji/fearful.png" width="20px" height="20px" style="display:inline;margin:0">. You can easily join the emoji <img src="https://gitlab.com/gitlab-org/gitlab-ce/raw/master/app/assets/images/emoji/family.png" width="20px" height="20px" style="display:inline;margin:0">. All you need to do is to look up one of the supported codes.
-spans
+Consult the [Emoji Cheat Sheet](https://www.webfx.com/tools/emoji-cheat-sheet/) for a list of all supported emoji codes. <img src="https://gitlab.com/gitlab-org/gitlab-ce/raw/master/app/assets/images/emoji/thumbsup.png" width="20px" height="20px" style="display:inline;margin:0">
-multiple lines,
+> **Note:** The emoji example above uses hard-coded images for this documentation. The emoji,
+when rendered within GitLab, may appear different depending on the OS and browser used.
-you can quote that without having to manually prepend `>` to every line!
->>>
-```
+Most emoji are natively supported on macOS, Windows, iOS, Android and will fallback to image-based emoji where there is lack of support.
-<blockquote dir="auto">
-<p>If you paste a message from somewhere else</p>
-<p>that</p>
-<p>spans</p>
-<p>multiple lines,</p>
-<p>you can quote that without having to manually prepend <code>&gt;</code> to every line!</p>
-</blockquote>
+NOTE: **Note:** On Linux, you can download [Noto Color Emoji](https://www.google.com/get/noto/help/emoji/)
+to get full native emoji support. Ubuntu 18.04 (like many modern Linux distros) has
+this font installed by default.
-### Code and syntax highlighting
+### Front matter
-> If this is not rendered correctly, see
-https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/user/markdown.md#code-and-syntax-highlighting
+> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/23331)
+ in GitLab 11.6.
-_GitLab uses the [Rouge Ruby library][rouge] for syntax highlighting. For a
-list of supported languages visit the Rouge website._
+Front matter is metadata included at the beginning of a markdown document, preceding
+its content. This data can be used by static site generators such as [Jekyll](https://jekyllrb.com/docs/front-matter/),
+[Hugo](https://gohugo.io/content-management/front-matter/), and many other applications.
-Blocks of code are either fenced by lines with three back-ticks <code>```</code>,
-or are indented with four spaces. Only the fenced code blocks support syntax
-highlighting:
+When you view a Markdown file rendered by GitLab, any front matter is displayed as-is,
+in a box at the top of the document, before the rendered HTML content. To view an example,
+you can toggle between the source and rendered version of a [GitLab documentation file](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/README.md).
-```
-Inline `code` has `back-ticks around` it.
-```
+In GitLab, front matter is only used in Markdown files and wiki pages, not the other
+places where Markdown formatting is supported. It must be at the very top of the document,
+and must be between delimiters, as explained below.
-Inline `code` has `back-ticks around` it.
+The following delimeters are supported:
-Example:
+- YAML (`---`):
- ```javascript
- var s = "JavaScript syntax highlighting";
- alert(s);
- ```
+ ~~~yaml
+ ---
+ title: About Front Matter
+ example:
+ language: yaml
+ ---
+ ~~~
- ```python
- def function():
- #indenting works just fine in the fenced code block
- s = "Python syntax highlighting"
- print s
- ```
+- TOML (`+++`):
- ```ruby
- require 'redcarpet'
- markdown = Redcarpet.new("Hello World!")
- puts markdown.to_html
- ```
+ ~~~toml
+ +++
+ title = "About Front Matter"
+ [example]
+ language = "toml"
+ +++
+ ~~~
- ```
- No language indicated, so no syntax highlighting.
- s = "There is no highlighting for this."
- But let's throw in a <b>tag</b>.
- ```
+- JSON (`;;;`):
-becomes:
+ ~~~json
+ ;;;
+ {
+ "title": "About Front Matter"
+ "example": {
+ "language": "json"
+ }
+ }
+ ;;;
+ ~~~
-```javascript
-var s = "JavaScript syntax highlighting";
-alert(s);
-```
+Other languages are supported by adding a specifier to any of the existing
+delimiters. For example:
-```python
-def function():
- #indenting works just fine in the fenced code block
- s = "Python syntax highlighting"
- print s
+```php
+---php
+$title = "About Front Matter";
+$example = array(
+ 'language' => "php",
+);
+---
```
-```ruby
-require 'redcarpet'
-markdown = Redcarpet.new("Hello World!")
-puts markdown.to_html
-```
+### Inline diff
-```
-No language indicated, so no syntax highlighting.
-s = "There is no highlighting for this."
-But let's throw in a <b>tag</b>.
-```
+> 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).
-### Inline diff
+With inline diff tags you can display `{+ additions +}` or `[- deletions -]`.
+
+The wrapping tags can be either curly braces or square brackets:
-> If this is not rendered correctly, see
-https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/user/markdown.md#inline-diff
+```markdown
+- {+ addition 1 +}
+- [+ addition 2 +]
+- {- deletion 3 -}
+- [- deletion 4 -]
+```
-With inline diffs tags you can display {+ additions +} or [- deletions -].
+- {+ addition 1 +}
+- [+ addition 2 +]
+- {- deletion 3 -}
+- [- deletion 4 -]
-The wrapping tags can be either curly braces or square brackets.
+---
-Examples:
+However the wrapping tags cannot be mixed:
+```markdown
+- {+ addition +]
+- [+ addition +}
+- {- deletion -]
+- [- deletion -}
```
-- {+ additions +}
-- [+ additions +]
-- {- deletions -}
-- [- deletions -]
-```
-becomes:
+### Math
+
+> If this is not rendered correctly, [view it in GitLab itself](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/user/markdown.md#math).
+
+It is possible to have math written with LaTeX syntax rendered using [KaTeX](https://github.com/Khan/KaTeX).
+
+Math written between dollar signs `$` will be rendered inline with the text. Math written
+inside a [code block](#code-spans-and-blocks) with the language declared as `math`, will be rendered
+on a separate line:
-![inline diffs tags rendered](img/markdown_inline_diffs_tags_rendered.png)
+~~~
+This math is inline $`a^2+b^2=c^2`$.
-However the wrapping tags cannot be mixed as such:
+This is on a separate line
+```math
+a^2+b^2=c^2
```
-- {+ additions +]
-- [+ additions +}
-- {- deletions -]
-- [- deletions -}
+~~~
+
+This math is inline $`a^2+b^2=c^2`$.
+
+This is on a separate line
+
+```math
+a^2+b^2=c^2
```
-### Emoji
+_Be advised that KaTeX only supports a [subset](https://katex.org/docs/supported.html) of LaTeX._
-```md
-Sometimes you want to :monkey: around a bit and add some :star2: to your :speech_balloon:. Well we have a gift for you:
+NOTE: **Note:** This also works for the asciidoctor `:stem: latexmath`. For details see
+the [asciidoctor user manual](http://asciidoctor.org/docs/user-manual/#activating-stem-support).
-:zap: You can use emoji anywhere GFM is supported. :v:
+### Special GitLab references
-You can use it to point out a :bug: or warn about :speak_no_evil: patches. And if someone improves your really :snail: code, send them some :birthday:. People will :heart: you for that.
+GFM recognizes special GitLab related references. For example, you can easily reference
+an issue, a commit, a team member or even the whole team within a project. GFM will turn
+that reference into a link so you can navigate between them easily.
-If you are new to this, don't be :fearful:. You can easily join the emoji :family:. All you need to do is to look up one of the supported codes.
+Additionally, GFM recognizes certain cross-project references, and also has a shorthand
+version to reference other projects from the same namespace.
-Consult the [Emoji Cheat Sheet](https://www.emojicopy.com) for a list of all supported emoji codes. :thumbsup:
+GFM will recognize the following:
-Most emoji are natively supported on macOS, Windows, iOS, Android and will fallback to image-based emoji where there is lack of support.
+| references | input | cross-project reference | shortcut within same namespace |
+| :------------------------------ | :------------------------- | :-------------------------------------- | :----------------------------- |
+| specific user | `@user_name` | | |
+| specific group | `@group_name` | | |
+| entire team | `@all` | | |
+| project | `namespace/project>` | | |
+| 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` | |
+| 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"` |
+| project milestone by ID | `%123` | `namespace/project%123` | `project%123` |
+| one-word milestone by name | `%v1.23` | `namespace/project%v1.23` | `project%v1.23` |
+| multi-word milestone by name | `%"release candidate"` | `namespace/project%"release candidate"` | `project%"release candidate"` |
+| specific commit | `9ba12248` | `namespace/project@9ba12248` | `project@9ba12248` |
+| commit range comparison | `9ba12248...b19a04f5` | `namespace/project@9ba12248...b19a04f5` | `project@9ba12248...b19a04f5` |
+| repository file references | `[README](doc/README)` | | |
+| repository file line references | `[README](doc/README#L13)` | | |
-On Linux, you can download [Noto Color Emoji](https://www.google.com/get/noto/help/emoji/) to get full native emoji support.
+### Task lists
+
+> If this is not rendered correctly, [view it in GitLab itself](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/user/markdown.md#task-lists).
+
+You can add task lists anywhere markdown is supported, but you can only "click" to
+toggle the boxes if they are in issues, merge requests, or comments. In other places
+you must edit the markdown manually to change the status by adding or removing the `x`.
-Ubuntu 18.04 (like many modern Linux distros) has this font installed by default.
+To create a task list, add a specially-formatted Markdown list. You can use either
+unordered or ordered lists:
+
+```markdown
+- [x] Completed task
+- [ ] Incomplete task
+ - [ ] Sub-task 1
+ - [x] Sub-task 2
+ - [ ] Sub-task 3
+1. [x] Completed task
+1. [ ] Incomplete task
+ 1. [ ] Sub-task 1
+ 1. [x] Sub-task 2
```
-Sometimes you want to <img src="https://gitlab.com/gitlab-org/gitlab-ce/raw/master/app/assets/images/emoji/monkey.png" width="20px" height="20px" style="display:inline;margin:0"> around a bit and add some <img src="https://gitlab.com/gitlab-org/gitlab-ce/raw/master/app/assets/images/emoji/star2.png" width="20px" height="20px" style="display:inline;margin:0"> to your <img src="https://gitlab.com/gitlab-org/gitlab-ce/raw/master/app/assets/images/emoji/speech_balloon.png" width="20px" height="20px" style="display:inline;margin:0">. Well we have a gift for you:
+- [x] Completed task
+- [ ] Incomplete task
+ - [ ] Sub-task 1
+ - [x] Sub-task 2
+ - [ ] Sub-task 3
+1. [x] Completed task
+1. [ ] Incomplete task
+ 1. [ ] Sub-task 1
+ 1. [x] Sub-task 2
-<img src="https://gitlab.com/gitlab-org/gitlab-ce/raw/master/app/assets/images/emoji/zap.png" width="20px" height="20px" style="display:inline;margin:0">You can use emoji anywhere GFM is supported. <img src="https://gitlab.com/gitlab-org/gitlab-ce/raw/master/app/assets/images/emoji/v.png" width="20px" height="20px" style="display:inline;margin:0">
+### Wiki-specific Markdown
-You can use it to point out a <img src="https://gitlab.com/gitlab-org/gitlab-ce/raw/master/app/assets/images/emoji/bug.png" width="20px" height="20px" style="display:inline;margin:0"> or warn about <img src="https://gitlab.com/gitlab-org/gitlab-ce/raw/master/app/assets/images/emoji/speak_no_evil.png" width="20px" height="20px" style="display:inline;margin:0"> patches. And if someone improves your really <img src="https://gitlab.com/gitlab-org/gitlab-ce/raw/master/app/assets/images/emoji/snail.png" width="20px" height="20px" style="display:inline;margin:0"> code, send them some <img src="https://gitlab.com/gitlab-org/gitlab-ce/raw/master/app/assets/images/emoji/birthday.png" width="20px" height="20px" style="display:inline;margin:0">. People will <img src="https://gitlab.com/gitlab-org/gitlab-ce/raw/master/app/assets/images/emoji/heart.png" width="20px" height="20px" style="display:inline;margin:0"> you for that.
+The following examples show how links inside wikis behave.
-If you are new to this, don't be <img src="https://gitlab.com/gitlab-org/gitlab-ce/raw/master/app/assets/images/emoji/fearful.png" width="20px" height="20px" style="display:inline;margin:0">. You can easily join the emoji <img src="https://gitlab.com/gitlab-org/gitlab-ce/raw/master/app/assets/images/emoji/family.png" width="20px" height="20px" style="display:inline;margin:0">. All you need to do is to look up one of the supported codes.
+#### Wiki - Direct page link
-Consult the [Emoji Cheat Sheet](https://www.webfx.com/tools/emoji-cheat-sheet/) for a list of all supported emoji codes. <img src="https://gitlab.com/gitlab-org/gitlab-ce/raw/master/app/assets/images/emoji/thumbsup.png" width="20px" height="20px" style="display:inline;margin:0">
+A link which just includes the slug for a page will point to that page,
+_at the base level of the wiki_.
-Most emoji are natively supported on macOS, Windows, iOS, Android and will fallback to image-based emoji where there is lack of support.
+This snippet would link to a `documentation` page at the root of your wiki:
-On Linux, you can download [Noto Color Emoji](https://www.google.com/get/noto/help/emoji/) to get full native emoji support.
+```markdown
+[Link to Documentation](documentation)
+```
-Ubuntu 18.04 (like many modern Linux distros) has this font installed by default.
+#### Wiki - Direct file link
-### Special GitLab references
+Links with a file extension point to that file, _relative to the current page_.
-GFM recognizes special references.
+If the snippet below was placed on a page at `<your_wiki>/documentation/related`,
+it would link to `<your_wiki>/documentation/file.md`:
-You can easily reference e.g. an issue, a commit, a team member or even the whole team within a project.
+```markdown
+[Link to File](file.md)
+```
-GFM will turn that reference into a link so you can navigate between them easily.
+#### Wiki - Hierarchical link
-GFM will recognize the following:
+A link can be constructed relative to the current wiki page using `./<page>`,
+`../<page>`, etc.
-| input | references |
-|:---------------------------|:--------------------------------|
-| `@user_name` | specific user |
-| `@group_name` | specific group |
-| `@all` | entire team |
-| `namespace/project>` | project |
-| `#12345` | issue |
-| `!123` | merge request |
-| `$123` | snippet |
-| `&123` | epic **[ULTIMATE]** |
-| `~123` | label by ID |
-| `~bug` | one-word label by name |
-| `~"feature request"` | multi-word label by name |
-| `%123` | project milestone by ID |
-| `%v1.23` | one-word milestone by name |
-| `%"release candidate"` | multi-word milestone by name |
-| `9ba12248` | specific commit |
-| `9ba12248...b19a04f5` | commit range comparison |
-| `[README](doc/README)` | repository file references |
-| `[README](doc/README#L13)` | repository file line references |
-
-GFM also recognizes certain cross-project references:
-
-| input | references |
-|:----------------------------------------|:------------------------|
-| `namespace/project#123` | issue |
-| `namespace/project!123` | merge request |
-| `namespace/project%123` | project milestone |
-| `namespace/project$123` | snippet |
-| `namespace/project@9ba12248` | specific commit |
-| `group1/subgroup&123` | epic **[ULTIMATE]** |
-| `namespace/project@9ba12248...b19a04f5` | commit range comparison |
-| `namespace/project~"Some label"` | issues with given label |
-
-It also has a shorthand version to reference other projects from the same namespace:
-
-| input | references |
-|:------------------------------|:------------------------|
-| `project#123` | issue |
-| `project!123` | merge request |
-| `project%123` | project milestone |
-| `project$123` | snippet |
-| `project@9ba12248` | specific commit |
-| `project@9ba12248...b19a04f5` | commit range comparison |
-| `project~"Some label"` | issues with given label |
+If this snippet was placed on a page at `<your_wiki>/documentation/main`,
+it would link to `<your_wiki>/documentation/related`:
-### Task lists
+```markdown
+[Link to Related Page](./related)
+```
+
+If this snippet was placed on a page at `<your_wiki>/documentation/related/content`,
+it would link to `<your_wiki>/documentation/main`:
-> If this is not rendered correctly, see
-https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/user/markdown.md#task-lists
+```markdown
+[Link to Related Page](../main)
+```
-You can add task lists to issues, merge requests and comments. To create a task list, add a specially-formatted Markdown list, like so:
+If this snippet was placed on a page at `<your_wiki>/documentation/main`,
+it would link to `<your_wiki>/documentation/related.md`:
+```markdown
+[Link to Related Page](./related.md)
```
-- [x] Completed task
-- [ ] Incomplete task
- - [ ] Sub-task 1
- - [x] Sub-task 2
- - [ ] Sub-task 3
+
+If this snippet was placed on a page at `<your_wiki>/documentation/related/content`,
+it would link to `<your_wiki>/documentation/main.md`:
+
+```markdown
+[Link to Related Page](../main.md)
```
-![alt unordered-check-list-render-gfm](img/unordered_check_list_render_gfm.png)
+#### Wiki - Root link
+
+A link starting with a `/` is relative to the wiki root.
-Tasks formatted as ordered lists are supported as well:
+This snippet links to `<wiki_root>/documentation`:
+```markdown
+[Link to Related Page](/documentation)
```
-1. [x] Completed task
-1. [ ] Incomplete task
- 1. [ ] Sub-task 1
- 1. [x] Sub-task 2
+
+This snippet links to `<wiki_root>/miscellaneous.md`:
+
+```markdown
+[Link to Related Page](/miscellaneous.md)
```
-![alt task-list-ordered-render-gfm](img/task_list_ordered_render_gfm.png)
+## Standard markdown and extensions in GitLab
-Task lists can only be created in descriptions, not in titles. Task item state can be managed by editing the description's Markdown or by toggling the rendered check boxes.
+All standard markdown formatting should work as expected within GitLab. Some standard
+functionality is extended with additional features, without affecting the standard usage.
+If a functionality is extended, the new option will be listed as a sub-section.
-### Videos
+### Blockquotes
-> If this is not rendered correctly, see
-https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/user/markdown.md#videos
+Blockquotes are an easy way to highlight information, such as a side-note. It is generated
+by starting the lines of the blockquote with `>`:
-Image tags with a video extension are automatically converted to a video player.
+```markdown
+> Blockquotes are very handy to emulate reply text.
+> This line is part of the same quote.
-The valid video extensions are `.mp4`, `.m4v`, `.mov`, `.webm`, and `.ogv`.
+Quote break.
- Here's a sample video:
+> This is a very long line that will still be quoted properly when it wraps. Oh boy let's keep writing to make sure this is long enough to actually wrap for everyone. Oh, you can *put* **Markdown** into a blockquote.
+```
- ![Sample Video](img/markdown_video.mp4)
+> Blockquotes are very handy to emulate reply text.
+> This line is part of the same quote.
-Here's a sample video:
+Quote break.
-<div class="video-container">
- <video src="img/markdown_video.mp4" width="400" controls="true" data-setup="{}" data-title="Sample Video"></video>
- <p><a href="img/markdown_video.mp4" target="_blank" rel="noopener noreferrer" title="Download 'Sample Video'">Sample Video</a></p>
-</div>
+> This is a very long line that will still be quoted properly when it wraps. Oh boy let's keep writing to make sure this is long enough to actually wrap for everyone. Oh, you can *put* **Markdown** into a blockquote.
-### Math
+#### Multiline blockquote
-> If this is not rendered correctly, see
-https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/user/markdown.md#math
+> If this is not rendered correctly, [view it in GitLab itself](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/user/markdown.md#multiline-blockquote).
-It is possible to have math written with the LaTeX syntax rendered using [KaTeX][katex].
+GFM extends the standard markdown standard by also supporting multiline blockquotes
+fenced by `>>>`:
-Math written inside ```$``$``` will be rendered inline with the text.
+```
+>>>
+If you paste a message from somewhere else
-Math written inside triple back quotes, with the language declared as `math`, will be rendered on a separate line.
+that spans multiple lines,
-Example:
+you can quote that without having to manually prepend `>` to every line!
+>>>
+```
+
+>>>
+If you paste a message from somewhere else
- This math is inline $`a^2+b^2=c^2`$.
+that spans multiple lines,
- This is on a separate line
- ```math
- a^2+b^2=c^2
- ```
+you can quote that without having to manually prepend `>` to every line!
+>>>
-Becomes:
+### Code spans and blocks
-This math is inline ![alt text](img/math_inline_sup_render_gfm.png).
+You can easily highlight anything that should be viewed as code and not simple text.
-This is on a separate line
+Simple inline code is easily highlighted with single backticks `` ` ``:
-<img src="./img/math_inline_sup_render_gfm.png" >
+```markdown
+Inline `code` has `back-ticks around` it.
+```
-_Be advised that KaTeX only supports a [subset][katex-subset] of LaTeX._
+Inline `code` has `back-ticks around` it.
->**Note:**
-This also works for the asciidoctor `:stem: latexmath`. For details see the [asciidoctor user manual][asciidoctor-manual].
+---
-### Colors
+Similarly, a whole block of code can be fenced with triple backticks ```` ``` ````,
+triple tildes (`~~~`), or indended 4 or more spaces to achieve a similar effect for
+a larger body of code. test.
-> If this is not rendered correctly, see
-https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/user/markdown.md#colors
+~~~
+```
+def function():
+ #indenting works just fine in the fenced code block
+ s = "Python code"
+ print s
+```
-It is possible to have color written in HEX, RGB or HSL format rendered with a color indicator.
+ Using 4 spaces
+ is like using
+ 3-backtick fences.
+~~~
-Color written inside backticks will be followed by a color "chip".
+```
+~~~
+Tildes are OK too.
+~~~
+```
-Examples:
+The three examples above render as:
- `#F00`
- `#F00A`
- `#FF0000`
- `#FF0000AA`
- `RGB(0,255,0)`
- `RGB(0%,100%,0%)`
- `RGBA(0,255,0,0.7)`
- `HSL(540,70%,50%)`
- `HSLA(540,70%,50%,0.7)`
+```
+def function():
+ #indenting works just fine in the fenced code block
+ s = "Python code"
+ print s
+```
-Becomes:
+ Using 4 spaces
+ is like using
+ 3-backtick fences.
-![alt color-inline-colorchip-render-gfm](img/color_inline_colorchip_render_gfm.png)
+~~~
+Tildes are OK too.
+~~~
-#### Supported formats:
+#### Colored code and syntax highlighting
-* HEX: `` `#RGB[A]` `` or `` `#RRGGBB[AA]` ``
-* RGB: `` `RGB[A](R, G, B[, A])` ``
-* HSL: `` `HSL[A](H, S, L[, A])` ``
+> If this is not rendered correctly, [view it in GitLab itself](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/user/markdown.md#colored-code-and-syntax-highlighting).
-### Mermaid
+GitLab uses the [Rouge Ruby library](http://rouge.jneen.net/) for more colorful syntax
+highlighting in code blocks. For a list of supported languages visit the
+[Rouge project wiki](https://github.com/jneen/rouge/wiki/List-of-supported-languages-and-lexers).
+Syntax highlighting is only supported in code blocks, it is not possible to highlight
+code when it is inline.
-> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/15107) in
-GitLab 10.3.
->
-> If this is not rendered correctly, see
-https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/user/markdown.md#mermaid
+Blocks of code are fenced by lines with three back-ticks ```` ``` ```` or three tildes `~~~`, and have
+the language identified at the end of the first fence:
-It is possible to generate diagrams and flowcharts from text using [Mermaid](https://mermaidjs.github.io/).
+~~~
+```javascript
+var s = "JavaScript syntax highlighting";
+alert(s);
+```
-In order to generate a diagram or flowchart, you should write your text inside the `mermaid` block.
+```python
+def function():
+ #indenting works just fine in the fenced code block
+ s = "Python syntax highlighting"
+ print s
+```
-Example:
+```ruby
+require 'redcarpet'
+markdown = Redcarpet.new("Hello World!")
+puts markdown.to_html
+```
- ```mermaid
- graph TD;
- A-->B;
- A-->C;
- B-->D;
- C-->D;
- ```
+```
+No language indicated, so no syntax highlighting.
+s = "There is no highlighting for this."
+But let's throw in a <b>tag</b>.
+```
+~~~
-Becomes:
+The four examples above render as:
-```mermaid
-graph TD;
- A-->B;
- A-->C;
- B-->D;
- C-->D;
+```javascript
+var s = "JavaScript syntax highlighting";
+alert(s);
```
-For details see the [Mermaid official page](https://mermaidjs.github.io/).
+```python
+def function():
+ #indenting works just fine in the fenced code block
+ s = "Python syntax highlighting"
+ print s
+```
-### Front matter
+```ruby
+require 'redcarpet'
+markdown = Redcarpet.new("Hello World!")
+puts markdown.to_html
+```
-> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/23331)
- in GitLab 11.6.
+```
+No language indicated, so no syntax highlighting.
+s = "There is no highlighting for this."
+But let's throw in a <b>tag</b>.
+```
-Front matter is metadata included at the beginning of a markdown document, preceding
-its content. This data can be used by static site generators such as [Jekyll](https://jekyllrb.com/docs/front-matter/) and [Hugo](https://gohugo.io/content-management/front-matter/),
-and many other applications.
+### Emphasis
-In GitLab, front matter is only used in Markdown files and wiki pages, not the other places where Markdown formatting is supported.
-When you view a Markdown file rendered by GitLab, any front matter is displayed as-is, in a box at the top of the document, before the rendered HTML content.
-To view an example, you can toggle between the source and rendered version of a [GitLab documentation file](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/README.md).
+There are multiple ways to emphasize text in markdown. You can italicize, bold, strikethrough,
+as well as combine these emphasis styles together.
-The following delimeters are supported:
+Examples:
-- YAML (`---`):
+```markdown
+Emphasis, aka italics, with *asterisks* or _underscores_.
- ```
- ---
- title: About Front Matter
- example:
- language: yaml
- ---
- ```
+Strong emphasis, aka bold, with double **asterisks** or __underscores__.
-- TOML (`+++`):
+Combined emphasis with **asterisks and _underscores_**.
- ```
- +++
- title = "About Front Matter"
- [example]
- language = "toml"
- +++
- ```
+Strikethrough uses two tildes. ~~Scratch this.~~
+```
-- JSON (`;;;`):
+Emphasis, aka italics, with *asterisks* or _underscores_.
- ```
- ;;;
- {
- "title": "About Front Matter"
- "example": {
- "language": "json"
- }
- }
- ;;;
- ```
+Strong emphasis, aka bold, with double **asterisks** or __underscores__.
-Other languages are supported by adding a specifier to any of the existing
-delimiters. For example:
+Combined emphasis with **asterisks and _underscores_**.
+
+Strikethrough uses two tildes. ~~Scratch this.~~
+
+NOTE: **Note:** Strikethrough is not part of the core Markdown standard, but is part of GFM.
+
+#### Multiple underscores in words and mid-word emphasis
+
+> If this is not rendered correctly, [view it in GitLab itself](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/user/markdown.md#multiple-underscores-in-words).
+It is not usually useful to italicize just _part_ of a word, especially when you're
+dealing with code and names that often appear with multiple underscores. As a result,
+GFM extends the standard markdown standard by ignoring multiple underlines in words,
+to allow better rendering of markdown documents discussing code:
+
+```md
+perform_complicated_task
+
+do_this_and_do_that_and_another_thing
+
+but_emphasis is_desired _here_
```
----php
-$title = "About Front Matter";
-$example = array(
- 'language' => "php",
-);
+
+perform_complicated_task
+
+do_this_and_do_that_and_another_thing
+
+but_emphasis is_desired _here_
+
---
+
+If you wish to emphasize only a part of a word, it can still be done with asterisks:
+
+```md
+perform*complicated*task
+
+do*this*and*do*that*and*another thing
```
-## Standard Markdown
+perform*complicated*task
-### Headers
+do*this*and*do*that*and*another thing
+
+### Footnotes
+
+Footnotes add a link to a note rendered at the end of a markdown file:
+```markdown
+You can add footnotes to your text as follows.[^1]
+
+[^1]: This is my awesome footnote (later in file).
```
+
+You can add footnotes to your text as follows.[^1]
+
+[^1]: This is my awesome footnote (later in file).
+
+### Headers
+
+```markdown
# H1
## H2
### H3
@@ -593,9 +758,11 @@ Alt-H2
#### Header IDs and links
-All Markdown-rendered headers automatically get IDs, which can be linked to, except in comments.
+GFM extends the standard markdown standard so that all Markdown-rendered headers automatically
+get IDs, which can be linked to, except in comments.
-On hover, a link to those IDs becomes visible to make it easier to copy the link to the header to use it somewhere else.
+On hover, a link to those IDs becomes visible to make it easier to copy the link to
+the header to use it somewhere else.
The IDs are generated from the content of the header according to the following rules:
@@ -606,7 +773,7 @@ The IDs are generated from the content of the header according to the following
1. If a header with the same ID has already been generated, a unique
incrementing number is appended, starting at 1.
-For example:
+Example:
```
# This header has spaces in it
@@ -626,216 +793,165 @@ Would generate the following link IDs:
1. `this-header-has-spaces-in-it-2`
1. `this-header-has-3-5-in-it-and-parentheses`
-Note that the Emoji processing happens before the header IDs are generated, so the Emoji is converted to an image which then gets removed from the ID.
+Note that the Emoji processing happens before the header IDs are generated, so the
+Emoji is converted to an image which is then removed from the ID.
-### Emphasis
-
-Examples:
-
-```
-Emphasis, aka italics, with *asterisks* or _underscores_.
-
-Strong emphasis, aka bold, with **asterisks** or __underscores__.
-
-Combined emphasis with **asterisks and _underscores_**.
-
-Strikethrough uses two tildes. ~~Scratch this.~~
-```
-
-Becomes:
-
-Emphasis, aka italics, with *asterisks* or _underscores_.
+### Horizontal Rule
-Strong emphasis, aka bold, with **asterisks** or __underscores__.
+It's very simple to create a horizontal rule, by using three or more hyphens, asterisks,
+or underscores:
-Combined emphasis with **asterisks and _underscores_**.
+```markdown
+Three or more hyphens,
-Strikethrough uses two tildes. ~~Scratch this.~~
+---
-### Lists
+asterisks,
-Examples:
+***
-```
-1. First ordered list item
-2. Another item
- * Unordered sub-list.
-1. Actual numbers don't matter, just that it's a number
- 1. Ordered sub-list
-4. And another item.
+or underscores
-* Unordered list can use asterisks
-- Or minuses
-+ Or pluses
+___
```
-Becomes:
-
-1. First ordered list item
-2. Another item
- * Unordered sub-list.
-1. Actual numbers don't matter, just that it's a number
- 1. Ordered sub-list
-4. And another item.
-
-* Unordered list can use asterisks
-- Or minuses
-+ Or pluses
-
-If a list item contains multiple paragraphs,
-each subsequent paragraph should be indented to the same level as the start of the list item text
+Three or more hyphens,
-Example:
+---
-```
-1. First ordered list item
+asterisks,
- Second paragraph of first item.
-
-2. Another item
-```
+***
-Becomes:
+or underscores
-1. First ordered list item
+___
- Paragraph of first item.
+### Images
-2. Another item
+Examples:
-If the paragraph of the first item is not indented with the proper number of spaces,
-the paragraph will appear outside the list, instead of properly indented under the list item.
+```markdown
+Inline-style (hover to see title text):
-Example:
+![alt text](img/markdown_logo.png "Title Text")
-```
-1. First ordered list item
+Reference-style (hover to see title text):
- Paragraph of first item.
+![alt text1][logo]
-2. Another item
+[logo]: img/markdown_logo.png "Title Text"
```
-Becomes:
+Inline-style (hover to see title text):
-1. First ordered list item
+![alt text](img/markdown_logo.png "Title Text")
- Paragraph of first item.
+Reference-style (hover to see title text):
-2. Another item
-
-### Links
+![alt text][logo]
-There are two ways to create links, inline-style and reference-style.
+[logo]: img/markdown_logo.png "Title Text"
-```markdown
-[I'm an inline-style link](https://www.google.com)
-[I'm a link to a repository file in the same directory](index.md)
-[I am an absolute reference within the repository](/doc/user/index.md)
-[I'm a relative link to the Milestones page](../README.md)
+#### Videos
-[I link to a section on a different markdown page, using a header ID](index.md#overview)
-[I link to a different section on the same page, using the header ID](#header-ids-and-links)
+> If this is not rendered correctly, [view it in GitLab itself](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/user/markdown.md#videos).
-[I'm a reference-style link][Arbitrary case-insensitive reference text]
-[You can use numbers for reference-style link definitions][1]
-Or leave it empty and use the [link text itself][]
+Image tags that link to files with a video extension are automatically converted to
+a video player. The valid video extensions are `.mp4`, `.m4v`, `.mov`, `.webm`, and `.ogv`:
-Some text to show that the reference links can follow later.
+```md
+Here's a sample video:
-[arbitrary case-insensitive reference text]: https://www.mozilla.org
-[1]: http://slashdot.org
-[link text itself]: https://www.reddit.com
+![Sample Video](img/markdown_video.mp4)
```
->**Note:**
-Relative links do not allow referencing project files in a wiki page or wiki
-page in a project file. The reason for this is that, in GitLab, wiki is always
-a separate Git repository. For example, `[I'm a reference-style link](style)`
-will point the link to `wikis/style` when the link is inside of a wiki markdown file.
-
-### Images
+Here's a sample video:
-Examples:
+![Sample Video](img/markdown_video.mp4)
- Here's our logo (hover to see the title text):
+### Inline HTML
- Inline-style:
- ![alt text](img/markdown_logo.png)
+> To see the markdown rendered within HTML in the second example, [view it in GitLab itself](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/user/markdown.md#inline-html).
- Reference-style:
- ![alt text1][logo]
+You can also use raw HTML in your Markdown, and it'll usually work pretty well.
- [logo]: img/markdown_logo.png
+See the documentation for HTML::Pipeline's [SanitizationFilter](http://www.rubydoc.info/gems/html-pipeline/1.11.0/HTML/Pipeline/SanitizationFilter#WHITELIST-constant)
+class for the list of allowed HTML tags and attributes. In addition to the default
+`SanitizationFilter` whitelist, GitLab allows `span`, `abbr`, `details` and `summary` elements.
-Becomes:
+```html
+<dl>
+ <dt>Definition list</dt>
+ <dd>Is something people use sometimes.</dd>
-Here's our logo:
+ <dt>Markdown in HTML</dt>
+ <dd>Does *not* work **very** well. HTML <em>tags</em> will <b>always</b> work.</dd>
+</dl>
+```
-Inline-style:
+<dl>
+ <dt>Definition list</dt>
+ <dd>Is something people use sometimes.</dd>
-![alt text](img/markdown_logo.png)
+ <dt>Markdown in HTML</dt>
+ <dd>Does *not* work **very** well. HTML <em>tags</em> will <b>always</b> work.</dd>
+</dl>
-Reference-style:
+---
-![alt text][logo]
+It is still possible to use markdown inside HTML tags, but only if the lines containing markdown
+are separated into their own lines:
-[logo]: img/markdown_logo.png
+```html
+<dl>
+ <dt>Markdown in HTML</dt>
+ <dd>Does *not* work **very** well. HTML tags will always work.</dd>
-### Blockquotes
+ <dt>Markdown in HTML</dt>
+ <dd>
-Examples:
+ Does *not* work **very** well. HTML tags will always work.
+ </dd>
+</dl>
```
-> Blockquotes are very handy in email to emulate reply text.
-> This line is part of the same quote.
-Quote break.
+<!-- Note: The example below uses HTML to force correct rendering on docs.gitlab.com, markdown will be fine in GitLab -->
-> This is a very long line that will still be quoted properly when it wraps. Oh boy let's keep writing to make sure this is long enough to actually wrap for everyone. Oh, you can *put* **Markdown** into a blockquote.
-```
+<dl>
+ <dt>Markdown in HTML</dt>
+ <dd>Does *not* work **very** well. HTML tags will always work.</dd>
-Becomes:
+ <dt>Markdown in HTML</dt>
+ <dd>
-> Blockquotes are very handy in email to emulate reply text.
-> This line is part of the same quote.
+ Does <em>not</em> work <b>very</b> well. HTML tags will always work.
-Quote break.
+ </dd>
+</dl>
-> This is a very long line that will still be quoted properly when it wraps. Oh boy let's keep writing to make sure this is long enough to actually wrap for everyone. Oh, you can *put* **Markdown** into a blockquote.
+#### Details and Summary
-### Inline HTML
+> To see the markdown rendered within HTML in the second example, [view it in GitLab itself](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/user/markdown.md#details-and-summary).
-You can also use raw HTML in your Markdown, and it'll mostly work pretty well.
+Content can be collapsed using HTML's [`<details>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/details)
+and [`<summary>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/summary)
+tags. This is especially useful for collapsing long logs so they take up less screen space.
-See the documentation for HTML::Pipeline's [SanitizationFilter](http://www.rubydoc.info/gems/html-pipeline/1.11.0/HTML/Pipeline/SanitizationFilter#WHITELIST-constant) class for the list of allowed HTML tags and attributes. In addition to the default `SanitizationFilter` whitelist, GitLab allows `span`, `abbr`, `details` and `summary` elements.
+```html
+<p>
+<details>
+<summary>Click me to collapse/fold.</summary>
-Examples:
+These details <em>will</em> remain <strong>hidden</strong> until expanded.
-```
-<dl>
- <dt>Definition list</dt>
- <dd>Is something people use sometimes.</dd>
+<pre><code>PASTE LOGS HERE</code></pre>
- <dt>Markdown in HTML</dt>
- <dd>Does *not* work **very** well. Use HTML <em>tags</em>.</dd>
-</dl>
+</details>
+</p>
```
-Becomes:
-
-<dl>
- <dt>Definition list</dt>
- <dd>Is something people use sometimes.</dd>
-
- <dt>Markdown in HTML</dt>
- <dd>Does *not* work **very** well. Use HTML <em>tags</em>.</dd>
-</dl>
-
-#### Details and Summary
-
-Content can be collapsed using HTML's [`<details>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/details) and [`<summary>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/summary) tags. This is especially useful for collapsing long logs so they take up less screen space.
-
<p>
<details>
<summary>Click me to collapse/fold.</summary>
@@ -847,7 +963,10 @@ These details <em>will</em> remain <strong>hidden</strong> until expanded.
</details>
</p>
-**Note:** Markdown inside these tags is supported, as long as you have a blank line after the `</summary>` tag and before the `</details>` tag, as shown in the example.
+---
+
+Markdown inside these tags is supported as well, as long as you have a blank line
+after the `</summary>` tag and before the `</details>` tag, as shown in the example:
```html
<details>
@@ -860,232 +979,302 @@ These details _will_ remain **hidden** until expanded.
</details>
```
-### Horizontal Rule
+<!-- Note: The example below uses HTML to force correct rendering on docs.gitlab.com, markdown will be fine in GitLab -->
-Examples:
+<details>
+<summary>Click me to collapse/fold.</summary>
-```
-Three or more...
+These details <em>will</em> remain <b>hidden</b> until expanded.
----
+ PASTE LOGS HERE
-Hyphens
+</details>
-***
+### Line Breaks
-Asterisks
+A line break will be inserted (a new paragraph will start) if the previous text is
+ended with two newlines, i.e. you hit <kbd>Enter</kbd> twice in a row. If you only
+use one newline (hit <kbd>Enter</kbd> once), the next sentence will be part of the
+same paragraph. This is useful if you want to keep long lines from wrapping, and keep
+them easily editable:
-___
+```markdown
+Here's a line for us to start with.
-Underscores
-```
+This longer line is separated from the one above by two newlines, so it will be a *separate paragraph*.
-Becomes:
+This line is also a separate paragraph, but...
+These lines are only separated by single newlines,
+so they *do not break* and just follow the previous lines
+in the *same paragraph*.
+```
-Three or more...
+Here's a line for us to start with.
----
+This longer line is separated from the one above by two newlines, so it will be a *separate paragraph*.
-Hyphens
+This line is also a separate paragraph, but...
+These lines are only separated by single newlines,
+so they *do not break* and just follow the previous lines
+in the *same paragraph*.
-***
+#### Newlines
-Asterisks
+GFM adheres to the markdown specification in how [paragraphs and line breaks are handled](https://spec.commonmark.org/current/).
-___
+A paragraph is simply one or more consecutive lines of text, separated by one or
+more blank lines (i.e. two newlines at the end of the first paragraph), as [explained above](#line-breaks).
-Underscores
+If you need more control over line-breaks or soft returns, you can add a single line-break
+by ending a line with a backslash, or two or more spaces. Two newlines in a row will create a new
+paragraph, with a blank line in between:
-### Line Breaks
+```markdown
+First paragraph.
+Another line in the same paragraph.
+A third line in the same paragraph, but this time ending with two spaces.{space}{space}
+A new line directly under the first paragraph.
+
+Second paragraph.
+Another line, this time ending with a backslash.\
+A new line due to the previous backslash.
+```
-A good way to learn how line breaks work is to experiment and discover -- hit <kbd>Enter</kbd> once (i.e., insert one newline), then hit it twice (i.e., insert two newlines), see what happens. You'll soon learn to get what you want. The "Preview" tab is your friend.
+<!-- (Do *NOT* remove the two ending whitespaces in the third line) -->
+<!-- (They are needed for the Markdown text to render correctly) -->
-Here are some things to try out:
+First paragraph.
+Another line in the same paragraph.
+A third line in the same paragraph, but this time ending with two spaces.
+A new line directly under the first paragraph.
-Examples:
+<!-- (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) -->
-```
-Here's a line for us to start with.
+Second paragraph.
+Another line, this time ending with a backslash.
+A new line due to the previous backslash.
-This line is separated from the one above by two newlines, so it will be a *separate paragraph*.
+### Links
-This line is also a separate paragraph, but...
-This line is only separated by a single newline, so it *does not break* and just follows the previous line in the *same paragraph*.
+There are two ways to create links, inline-style and reference-style:
-This line is also a separate paragraph, and...
-This line is *on its own line*, because the previous line ends with two spaces. (but still in the *same paragraph*)
+```md
+- This is an [inline-style link](https://www.google.com)
+- This is a [link to a repository file in the same directory](index.md)
+- This is a [relative link to a readme one directory higher](../README.md)
+- This is a [link that also has title text](https://www.google.com "This link takes you to Google!")
-spaces.
-```
+Using header ID anchors:
-Becomes:
+- This links to [a section on a different markdown page, using a "#" and the header ID](index.md#overview)
+- This links to [a different section on the same page, using a "#" and the header ID](#header-ids-and-links)
-Here's a line for us to start with.
+Using references:
-This line is separated from the one above by two newlines, so it will be a *separate paragraph*.
+- This is a [reference-style link, see below][Arbitrary case-insensitive reference text]
+- You can [use numbers for reference-style link definitions, see below][1]
+- Or leave it empty and use the [link text itself][], see below.
-This line is also a separate paragraph, but...
-This line is only separated by a single newline, so it *does not break* and just follows the previous line in the *same paragraph*.
+Some text to show that the reference links can follow later.
-This line is also a separate paragraph, and...
-This line is *on its own line*, because the previous line ends with two spaces. (but still in the *same paragraph*)
+[arbitrary case-insensitive reference text]: https://www.mozilla.org
+[1]: http://slashdot.org
+[link text itself]: https://www.reddit.com
+```
-spaces.
+- This is an [inline-style link](https://www.google.com)
+- This is a [link to a repository file in the same directory](index.md)
+- This is a [relative link to a readme one directory higher](../README.md)
+- This is a [link that also has title text](https://www.google.com "This link takes you to Google!")
-### Tables
+Using header ID anchors:
-Tables aren't part of the core Markdown spec, but they are part of GFM.
+- This links to [a section on a different markdown page, using a "#" and the header ID](index.md#overview)
+- This links to [a different section on the same page, using a "#" and the header ID](#header-ids-and-links)
-Example:
+Using references:
-```
-| header 1 | header 2 |
-| -------- | -------- |
-| cell 1 | cell 2 |
-| cell 3 | cell 4 |
-```
+- This is a [reference-style link, see below][Arbitrary case-insensitive reference text]
+- You can [use numbers for reference-style link definitions, see below][1]
+- Or leave it empty and use the [link text itself][], see below.
-Becomes:
+Some text to show that the reference links can follow later.
-| header 1 | header 2 |
-| -------- | -------- |
-| cell 1 | cell 2 |
-| cell 3 | cell 4 |
+[arbitrary case-insensitive reference text]: https://www.mozilla.org
+[1]: http://slashdot.org
+[link text itself]: https://www.reddit.com
-**Note:** The row of dashes between the table header and body must have at least three dashes in each column.
+NOTE: **Note:** Relative links do not allow the referencing of project files in a wiki
+page, or a wiki page in a project file. The reason for this is that a wiki is always
+in a separate Git repository in GitLab. For example, `[I'm a reference-style link](style)`
+will point the link to `wikis/style` only when the link is inside of a wiki markdown file.
-By including colons in the header row, you can align the text within that column.
+#### URL auto-linking
-Example:
+GFM will autolink almost any URL you put into your text:
-```
-| Left Aligned | Centered | Right Aligned | Left Aligned | Centered | Right Aligned |
-| :----------- | :------: | ------------: | :----------- | :------: | ------------: |
-| Cell 1 | Cell 2 | Cell 3 | Cell 4 | Cell 5 | Cell 6 |
-| Cell 7 | Cell 8 | Cell 9 | Cell 10 | Cell 11 | Cell 12 |
+```markdown
+- 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
```
-Becomes:
+- <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>
-| Left Aligned | Centered | Right Aligned | Left Aligned | Centered | Right Aligned |
-| :----------- | :------: | ------------: | :----------- | :------: | ------------: |
-| Cell 1 | Cell 2 | Cell 3 | Cell 4 | Cell 5 | Cell 6 |
-| Cell 7 | Cell 8 | Cell 9 | Cell 10 | Cell 11 | Cell 12 |
+### Lists
-### Footnotes
+Ordered and unordered lists can be easily created. Add the number you want the list
+to start with, like `1. ` (with a space) at the start of each line for ordered lists.
+After the first number, it does not matter what number you use, ordered lists will be
+numbered automatically by vertical order, so repeating `1. ` for all items in the
+same list is common. If you start with a number other than `1. `, it will use that as the first
+number, and count up from there.
-Example:
+Add a `* `, `- ` or `+ ` (with a space) at the start of each line for unordered lists, but
+you should not use a mix of them.
-```
-You can add footnotes to your text as follows.[^2]
-[^2]: This is my awesome footnote.
+Examples:
+
+```md
+1. First ordered list item
+2. Another item
+ - Unordered sub-list.
+1. Actual numbers don't matter, just that it's a number
+ 1. Ordered sub-list
+ 1. Next ordered sub-list item
+4. And another item.
+
+* Unordered lists can use asterisks
+- Or minuses
++ Or pluses
```
-Becomes:
+1. First ordered list item
+2. Another item
+ - Unordered sub-list.
+1. Actual numbers don't matter, just that it's a number
+ 1. Ordered sub-list
+ 1. Next ordered sub-list item
+4. And another item.
-You can add footnotes to your text as follows.[^2]
+* Unordered lists can use asterisks
+- Or minuses
++ Or pluses
-### Superscripts / Subscripts
+---
-CommonMark and GFM currently do not support the superscript syntax ( `x^2` ) that Redcarpet does. You can use the standard HTML syntax for superscripts and subscripts.
+If a list item contains multiple paragraphs, each subsequent paragraph should be indented
+to the same level as the start of the list item text.
-```
-The formula for water is H<sub>2</sub>O
-while the equation for the theory of relativity is E = mc<sup>2</sup>.
-```
+Example:
-The formula for water is H<sub>2</sub>O while the equation for the theory of relativity is E = mc<sup>2</sup>.
+```markdown
+1. First ordered list item
-## Wiki-specific Markdown
+ Second paragraph of first item.
-The following examples show how links inside wikis behave.
+2. Another item
+```
-### Wiki - Direct page link
+1. First ordered list item
-A link which just includes the slug for a page will point to that page,
-_at the base level of the wiki_.
+ Second paragraph of first item.
-This snippet would link to a `documentation` page at the root of your wiki:
+2. Another item
-```markdown
-[Link to Documentation](documentation)
-```
+---
-### Wiki - Direct file link
+If the paragraph of the first item is not indented with the proper number of spaces,
+the paragraph will appear outside the list, instead of properly indented under the list item.
-Links with a file extension point to that file, _relative to the current page_.
+Example:
-If this snippet was placed on a page at `<your_wiki>/documentation/related`,
-it would link to `<your_wiki>/documentation/file.md`:
+```
+1. First ordered list item
-```markdown
-[Link to File](file.md)
+ Paragraph of first item.
+
+2. Another item
```
-### Wiki - Hierarchical link
+1. First ordered list item
-A link can be constructed relative to the current wiki page using `./<page>`,
-`../<page>`, etc.
+ Paragraph of first item.
-- If this snippet was placed on a page at `<your_wiki>/documentation/main`,
- it would link to `<your_wiki>/documentation/related`:
+2. Another item
- ```markdown
- [Link to Related Page](related)
- ```
+### Superscripts / Subscripts
-- If this snippet was placed on a page at `<your_wiki>/documentation/related/content`,
- it would link to `<your_wiki>/documentation/main`:
+CommonMark and GFM currently do not support the superscript syntax ( `x^2` ) that
+Redcarpet does. You can use the standard HTML syntax for superscripts and subscripts:
+
+```html
+The formula for water is H<sub>2</sub>O
+while the equation for the theory of relativity is E = mc<sup>2</sup>.
+```
- ```markdown
- [Link to Related Page](../main)
- ```
+The formula for water is H<sub>2</sub>O
+while the equation for the theory of relativity is E = mc<sup>2</sup>.
-- If this snippet was placed on a page at `<your_wiki>/documentation/main`,
- it would link to `<your_wiki>/documentation/related.md`:
+### Tables
- ```markdown
- [Link to Related Page](related.md)
- ```
+Tables aren't part of the core Markdown spec, but they are part of GFM.
-- If this snippet was placed on a page at `<your_wiki>/documentation/related/content`,
- it would link to `<your_wiki>/documentation/main.md`:
+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,
+ but they can be very long. You can also include HTML `<br>` tags to force newlines if needed.
+ - The cell sizes **don't** have to match each other. They are flexible, but must be separated
+ by pipes (`|`).
+ - You **can** have blank cells.
- ```markdown
- [Link to Related Page](../main.md)
- ```
+Example:
-### Wiki - Root link
+```markdown
+| header 1 | header 2 | header 3 |
+| --- | ------ |----------|
+| cell 1 | cell 2 | cell 3 |
+| cell 4 | cell 5 is longer | cell 6 is much longer than the others, but that's ok. It will eventually wrap the text when the cell is too large for the display size. |
+| cell 7 | | cell <br> 9 |
+```
-A link starting with a `/` is relative to the wiki root.
+| header 1 | header 2 | header 3 |
+| --- | ------ |---------:|
+| cell 1 | cell 2 | cell 3 |
+| cell 4 | cell 5 is longer | cell 6 is much longer than the others, but that's ok. It will eventually wrap the text when the cell is too large for the display size. |
+| cell 7 | | cell <br> 9 |
-- This snippet links to `<wiki_root>/documentation`:
+Additionally, you can choose the alignment of text within columns by adding colons (`:`)
+to the sides of the "dash" lines in the second row. This will affect every cell in the column.
- ```markdown
- [Link to Related Page](/documentation)
- ```
+> Note that the headers are always right aligned [within GitLab itself itself](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/user/markdown.md#tables).
-- This snippet links to `<wiki_root>/miscellaneous.md`:
+```markdown
+| Left Aligned | Centered | Right Aligned | Left Aligned | Centered | Right Aligned |
+| :--- | :---: | ---: | :----------- | :------: | ------------: |
+| Cell 1 | Cell 2 | Cell 3 | Cell 4 | Cell 5 | Cell 6 |
+| Cell 7 | Cell 8 | Cell 9 | Cell 10 | Cell 11 | Cell 12 |
+```
- ```markdown
- [Link to Related Page](/miscellaneous.md)
- ```
+| Left Aligned | Centered | Right Aligned | Left Aligned | Centered | Right Aligned |
+| :--- | :---: | ---: | :----------- | :------: | ------------: |
+| Cell 1 | Cell 2 | Cell 3 | Cell 4 | Cell 5 | Cell 6 |
+| Cell 7 | Cell 8 | Cell 9 | Cell 10 | Cell 11 | Cell 12 |
## References
- This document leveraged heavily from the [Markdown-Cheatsheet](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet).
-- The original [Markdown Syntax Guide](https://daringfireball.net/projects/markdown/syntax) at Daring Fireball is an excellent resource for a detailed explanation of standard markdown.
-- The detailed specification for CommonMark can be found in the [CommonMark Spec][commonmark-spec]
+- The original [Markdown Syntax Guide](https://daringfireball.net/projects/markdown/syntax)
+ at Daring Fireball is an excellent resource for a detailed explanation of standard markdown.
+- The detailed specification for CommonMark can be found in the [CommonMark Spec](https://spec.commonmark.org/current/)
- The [CommonMark Dingus](http://try.commonmark.org) is a handy tool for testing CommonMark syntax.
-
-[^1]: This link will be broken if you see this document from the Help page or docs.gitlab.com
-[^2]: This is my awesome footnote.
-
-[markdown.md]: https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/user/markdown.md
-[rouge]: http://rouge.jneen.net/ "Rouge website"
-[redcarpet]: https://github.com/vmg/redcarpet "Redcarpet website"
-[katex]: https://github.com/Khan/KaTeX "KaTeX website"
-[katex-subset]: https://katex.org/docs/supported.html "Macros supported by KaTeX"
-[asciidoctor-manual]: http://asciidoctor.org/docs/user-manual/#activating-stem-support "Asciidoctor user manual"
-[commonmarker]: https://github.com/gjtorikian/commonmarker
-[commonmark-spec]: https://spec.commonmark.org/current/
diff --git a/doc/user/operations_dashboard/index.md b/doc/user/operations_dashboard/index.md
index 66362f27299..54bf3ff8a40 100644
--- a/doc/user/operations_dashboard/index.md
+++ b/doc/user/operations_dashboard/index.md
@@ -1,9 +1,6 @@
# 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.
+> [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.
The Operations Dashboard provides a summary of each project's operational health,
including pipeline and alert status.
@@ -16,9 +13,9 @@ dashboard icon:
## Adding a project to the dashboard
NOTE: **Note:**
-For GitLab.com, the Operations Dashboard is available for free for public projects.
-If your project is private, the group it belongs to must have a
-[Gold](https://about.gitlab.com/pricing/) plan.
+For GitLab.com, you can add your project to the Operations Dashboard for free if
+your project is public. If your project is private, the group it belongs to must
+have a [Silver](https://about.gitlab.com/pricing/) plan.
To add a project to the dashboard:
diff --git a/doc/user/permissions.md b/doc/user/permissions.md
index 7af3d4a0ac3..33fff0fed74 100644
--- a/doc/user/permissions.md
+++ b/doc/user/permissions.md
@@ -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
@@ -365,3 +365,8 @@ for details about the pipelines security model.
Since GitLab 8.15, LDAP user permissions can now be manually overridden by an admin user.
Read through the documentation on [LDAP users permissions](../administration/auth/how_to_configure_ldap_gitlab_ee/index.html) to learn more.
+
+## Project aliases
+
+Project aliases can only be read, created and deleted by a GitLab administrator.
+Read through the documentation on [Project aliases](../user/project/index.md#project-aliases-premium-only) to learn more.
diff --git a/doc/user/profile/account/img/2fa.png b/doc/user/profile/account/img/2fa.png
deleted file mode 100644
index bb464efa685..00000000000
--- a/doc/user/profile/account/img/2fa.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/profile/account/img/2fa_auth.png b/doc/user/profile/account/img/2fa_auth.png
deleted file mode 100644
index 0caaed10805..00000000000
--- a/doc/user/profile/account/img/2fa_auth.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/profile/account/img/2fa_u2f_authenticate.png b/doc/user/profile/account/img/2fa_u2f_authenticate.png
deleted file mode 100644
index ff2e936764d..00000000000
--- a/doc/user/profile/account/img/2fa_u2f_authenticate.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/profile/account/img/2fa_u2f_register.png b/doc/user/profile/account/img/2fa_u2f_register.png
deleted file mode 100644
index 1cc142aa851..00000000000
--- a/doc/user/profile/account/img/2fa_u2f_register.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/profile/account/two_factor_authentication.md b/doc/user/profile/account/two_factor_authentication.md
index df413a11af0..e3e8c9a0d6d 100644
--- a/doc/user/profile/account/two_factor_authentication.md
+++ b/doc/user/profile/account/two_factor_authentication.md
@@ -10,17 +10,18 @@ is to know your username and password *and* have access to your one time passwor
## Overview
-> **Note:**
-When you enable 2FA, don't forget to back up your recovery codes.
-
-In addition to one time authenticators (TOTP), GitLab supports U2F (universal 2nd factor) devices as
-the second factor of authentication. Once enabled, in addition to supplying your username and
-password to login, you'll be prompted to activate your U2F device (usually by pressing
-a button on it), and it will perform secure authentication on your behalf.
-
-The U2F workflow is [supported by](https://caniuse.com/#search=U2F) Google Chrome, Opera, and Firefox.
-
-We recommend that you set up 2FA with both a [one-time password authenticator](#enable-2fa-via-one-time-password-authenticator) and a [U2F device](#enable-2fa-via-u2f-device), so you can still access your account
+TIP: **Tip:**
+When you enable 2FA, don't forget to back up your [recovery codes](#recovery-codes)!
+
+In addition to time-based one time passwords (TOTP), GitLab supports U2F
+(universal 2nd factor) devices as the second factor of authentication. Once
+enabled, in addition to supplying your username and password to login, you'll
+be prompted to activate your U2F device (usually by pressing a button on it),
+and it will perform secure authentication on your behalf.
+
+It is highly recommended that you set up 2FA with both a
+[one-time password authenticator](#enable-2fa-via-one-time-password-authenticator)
+and a [U2F device](#enable-2fa-via-u2f-device), so you can still access your account
if you lose your U2F device.
## Enabling 2FA
@@ -30,41 +31,52 @@ or a U2F device.
### Enable 2FA via one time password authenticator
-**In GitLab:**
-
-1. Log in to your GitLab account.
-1. Go to your **Profile Settings**.
-1. Go to **Account**.
-1. Click **Enable Two-factor Authentication**.
-
-![Two-factor setup](img/2fa.png)
-
-**On your phone:**
-
-1. Install a compatible application. We recommend [Google Authenticator]
- \(proprietary\) or [FreeOTP] \(open source\).
-1. In the application, add a new entry in one of two ways:
- - Scan the code with your phone's camera to add the entry automatically.
- - Enter the details provided to add the entry manually.
-
-**In GitLab:**
-
-1. Enter the six-digit pin number from the entry on your phone into the **Pin
- code** field.
-1. Click **Submit**.
+To enable 2FA:
+
+1. **In GitLab:**
+ 1. Log in to your GitLab account.
+ 1. Go to your **Profile Settings**.
+ 1. Go to **Account**.
+ 1. Click **Enable Two-factor Authentication**.
+1. **On your device (usually your phone):**
+ 1. Install a compatible application, like:
+ - [Authenticator](https://mattrubin.me/authenticator/): open source app for iOS devices.
+ - [andOTP](https://github.com/andOTP/andOTP): feature rich open source app for Android which supports PGP encrypted backups.
+ - [FreeOTP](https://freeotp.github.io/): open source app for Android.
+ - [Google Authenticator](https://support.google.com/accounts/answer/1066447?hl=en): proprietary app for iOS and Android.
+ 1. In the application, add a new entry in one of two ways:
+ - Scan the code presented in GitLab with your device's camera to add the
+ entry automatically.
+ - Enter the details provided to add the entry manually.
+1. **In GitLab:**
+ 1. Enter the six-digit pin number from the entry on your device into the **Pin
+ code** field.
+ 1. Click **Submit**.
If the pin you entered was correct, you'll see a message indicating that
Two-Factor Authentication has been enabled, and you'll be presented with a list
-of recovery codes.
+of [recovery codes](#recovery-codes). Make sure you download them and keep them
+in a safe place.
### Enable 2FA via U2F device
-> **Notes:**
->
-> - GitLab officially only supports [Yubikey] U2F devices.
-> - Support for U2F devices was added in GitLab 8.8.
+GitLab officially only supports [YubiKey](https://www.yubico.com/products/yubikey-hardware/)
+U2F devices, but users have successfully used [SoloKeys](https://solokeys.com/).
+
+The U2F workflow is [supported by](https://caniuse.com/#search=U2F) the
+following desktop browsers:
-**In GitLab:**
+- Chrome
+- Edge
+- Firefox (disabled by default)
+- Opera
+
+NOTE: **Note:**
+For Firefox, you can enable the FIDO U2F API in
+[about:config](https://support.mozilla.org/en-US/kb/about-config-editor-firefox).
+Search for `security.webauth.u2f` and double click on it to toggle to `true`.
+
+To set up 2FA with a U2F device:
1. Log in to your GitLab account.
1. Go to your **Profile Settings**.
@@ -77,20 +89,21 @@ of recovery codes.
You will see a message indicating that your device was successfully set up.
Click on **Register U2F Device** to complete the process.
-![Two-Factor U2F Setup](img/2fa_u2f_register.png)
+## Recovery codes
-## Recovery Codes
-
-> **Note:**
+NOTE: **Note:**
Recovery codes are not generated for U2F devices.
-Should you ever lose access to your one time password authenticator, you can use one of the ten provided
-backup codes to login to your account. We suggest copying them, printing them, or downloading them using
-the **Download codes** button for storage in a safe place.
-
CAUTION: **Caution:**
Each code can be used only once to log in to your account.
+Immediately after successfully enabling two-factor authentication, you'll be
+prompted to download a set of set recovery codes. Should you ever lose access
+to your one time password authenticator, you can use one of them to log in to
+your account. We suggest copying them, printing them, or downloading them using
+the **Download codes** button for storage in a safe place. If you choose to
+download them, the file will be called **gitlab-recovery-codes.txt**.
+
If you lose the recovery codes or just want to generate new ones, you can do so
[using SSH](#generate-new-recovery-codes-using-ssh).
@@ -100,24 +113,26 @@ Logging in with 2FA enabled is only slightly different than a normal login.
Enter your username and password credentials as you normally would, and you'll
be presented with a second prompt, depending on which type of 2FA you've enabled.
-### Log in via mobile application
-
-Enter the pin from your one time password authenticator's application or a recovery code to log in.
+### Log in via a one-time password
-![Two-Factor Authentication on sign in via OTP](img/2fa_auth.png)
+When asked, enter the pin from your one time password authenticator's application or a
+recovery code to log in.
### Log in via U2F device
-1. Click **Login via U2F Device**.
-1. A light will start blinking on your device. Activate it by pressing its button.
+To log in via a U2F device:
-You will see a message indicating that your device responded to the authentication request.
-Click on **Authenticate via U2F Device** to complete the process.
+1. Click **Login via U2F Device**.
+1. A light will start blinking on your device. Activate it by touching/pressing
+ its button.
-![Two-Factor Authentication on sign in via U2F device](img/2fa_u2f_authenticate.png)
+You will see a message indicating that your device responded to the authentication
+request and you will be automatically logged in.
## Disabling 2FA
+If you ever need to disable 2FA:
+
1. Log in to your GitLab account.
1. Go to your **Profile Settings**.
1. Go to **Account**.
@@ -130,7 +145,8 @@ applications and U2F devices.
When 2FA is enabled, you can no longer use your normal account password to
authenticate with Git over HTTPS on the command line or when using
-[GitLab's API][api], you must use a [personal access token][pat] instead.
+[GitLab's API](../../../api/README.md). You must use a
+[personal access token](../personal_access_tokens.md) instead.
## Recovery options
@@ -149,7 +165,6 @@ codes. If you saved these codes, you can use one of them to sign in.
To use a recovery code, enter your username/email and password on the GitLab
sign-in page. When prompted for a two-factor code, enter the recovery code.
-> **Note:**
Once you use a recovery code, you cannot re-use it. You can still use the other
recovery codes you saved.
@@ -157,13 +172,18 @@ recovery codes you saved.
Users often forget to save their recovery codes when enabling two-factor
authentication. If an SSH key is added to your GitLab account, you can generate
-a new set of recovery codes with SSH.
+a new set of recovery codes with SSH:
-1. Run `ssh git@gitlab.example.com 2fa_recovery_codes`.
-1. You are prompted to confirm that you want to generate new codes. Continuing this process invalidates previously saved codes.
+1. Run:
+
+ ```sh
+ ssh git@gitlab.example.com 2fa_recovery_codes
+ ```
+
+1. You will then be prompted to confirm that you want to generate new codes.
+ Continuing this process invalidates previously saved codes:
```sh
- $ ssh git@gitlab.example.com 2fa_recovery_codes
Are you sure you want to generate new two-factor recovery codes?
Any existing recovery codes you saved will be invalidated. (yes/no)
@@ -191,7 +211,6 @@ a new set of recovery codes with SSH.
When prompted for a two-factor code, enter one of the recovery codes obtained
from the command-line output.
-> **Note:**
After signing in, visit your **Profile settings > Account** immediately to set
up two-factor authentication with a new device.
@@ -219,9 +238,3 @@ Sign in and re-enable two-factor authentication as soon as possible.
- The user logs out and attempts to log in via `first.host.xyz` - U2F authentication succeeds.
- The user logs out and attempts to log in via `second.host.xyz` - U2F authentication fails, because
the U2F key has only been registered on `first.host.xyz`.
-
-[Google Authenticator]: https://support.google.com/accounts/answer/1066447?hl=en
-[FreeOTP]: https://freeotp.github.io/
-[YubiKey]: https://www.yubico.com/products/yubikey-hardware/
-[api]: ../../../api/README.md
-[pat]: ../personal_access_tokens.md
diff --git a/doc/user/project/canary_deployments.md b/doc/user/project/canary_deployments.md
index cce862b0911..9bb282f1b78 100644
--- a/doc/user/project/canary_deployments.md
+++ b/doc/user/project/canary_deployments.md
@@ -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 a0fe97f2b9d..d21455fb5ca 100644
--- a/doc/user/project/clusters/index.md
+++ b/doc/user/project/clusters/index.md
@@ -222,7 +222,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.
@@ -519,8 +519,11 @@ service account of the cluster integration.
### Troubleshooting failed deployment jobs
-GitLab will create a namespace and service account specifically for your
-deployment jobs. This happens immediately before the deployment job starts.
+Before the deployment jobs starts, GitLab creates the following specifically for
+the deployment job:
+
+- A namespace.
+- A service account.
However, sometimes GitLab can not create them. In such instances, your job will fail with the message:
@@ -530,22 +533,20 @@ This job failed because the necessary resources were not successfully created.
To find the cause of this error when creating a namespace and service account, check the [logs](../../../administration/logs.md#kuberneteslog).
-NOTE: **NOTE:**
-As of GitLab 12.1 we require [`cluster-admin`](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#user-facing-roles)
-tokens for all project level clusters unless you unselect the
-[GitLab-managed cluster](#gitlab-managed-clusters) option. If you
-want to manage namespaces and service accounts yourself and don't
-want to provide a `cluster-admin` token to GitLab you must unselect this
-option or you will get the above error.
-
-Common reasons for failure include:
+Reasons for failure include:
-- The token you gave GitLab did not have [`cluster-admin`](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#user-facing-roles)
+- The token you gave GitLab does not have [`cluster-admin`](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#user-facing-roles)
privileges required by GitLab.
- Missing `KUBECONFIG` or `KUBE_TOKEN` variables. To be passed to your job, they must have a matching
[`environment:name`](../../../ci/environments.md#defining-environments). If your job has no
`environment:name` set, it will not be passed the Kubernetes credentials.
+NOTE: **NOTE:**
+Project-level clusters upgraded from GitLab 12.0 or older may be configured
+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]**
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/4701) in [GitLab Ultimate][ee] 10.6.
diff --git a/doc/user/project/clusters/kubernetes_pod_logs.md b/doc/user/project/clusters/kubernetes_pod_logs.md
index 368031070c1..25d8abebf07 100644
--- a/doc/user/project/clusters/kubernetes_pod_logs.md
+++ b/doc/user/project/clusters/kubernetes_pod_logs.md
@@ -12,9 +12,9 @@ By displaying the logs directly in GitLab, developers can avoid having to manage
1. Go to **Operations > Environments** and find the environment which contains the desired pod, like `production`.
1. On the **Environments** page, you should see the status of the environment's pods with [Deploy Boards](../deploy_boards.md).
1. When mousing over the list of pods, a tooltip will appear with the exact pod name and status.
-![Deploy Boards pod list](img/pod_logs_deploy_board.png)
+ ![Deploy Boards pod list](img/pod_logs_deploy_board.png)
1. Click on the desired pod to bring up the logs view, which will contain the last 500 lines for that pod. Support for pods with multiple containers is coming [in a future release](https://gitlab.com/gitlab-org/gitlab-ee/issues/6502).
-![Deploy Boards pod list](img/kubernetes_pod_logs.png)
+ ![Deploy Boards pod list](img/kubernetes_pod_logs.png)
## Requirements
diff --git a/doc/user/project/clusters/serverless/img/function-endpoint.png b/doc/user/project/clusters/serverless/img/function-endpoint.png
new file mode 100644
index 00000000000..f3c7ae7a00d
--- /dev/null
+++ b/doc/user/project/clusters/serverless/img/function-endpoint.png
Binary files differ
diff --git a/doc/user/project/clusters/serverless/index.md b/doc/user/project/clusters/serverless/index.md
index 3be5bfeaddc..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.
@@ -325,3 +370,275 @@ loading or is not available at this time._ It will appear upon the first access
page, but should go away after a few seconds. If the message does not disappear, then it
is possible that GitLab is unable to connect to the Prometheus instance running on the
cluster.
+
+## Enabling TLS for Knative services
+
+By default, a GitLab serverless deployment will be served over `http`. In order to serve over `https` you
+must manually obtain and install TLS certificates.
+
+The simplest way to accomplish this is to
+use [Certbot to manually obtain Let's Encrypt certificates](https://knative.dev/docs/serving/using-a-tls-cert/#using-certbot-to-manually-obtain-let-s-encrypt-certificates). Certbot is a free, open source software tool for automatically using Let’s Encrypt certificates on manually-administrated websites to enable HTTPS.
+
+NOTE: **Note:**
+The instructions below relate to installing and running Certbot on a Linux server and may not work on other operating systems.
+
+1. Install Certbot by running the
+ [`certbot-auto` wrapper script](https://certbot.eff.org/docs/install.html#certbot-auto).
+ On the command line of your server, run the following commands:
+
+ ```sh
+ wget https://dl.eff.org/certbot-auto
+ sudo mv certbot-auto /usr/local/bin/certbot-auto
+ sudo chown root /usr/local/bin/certbot-auto
+ chmod 0755 /usr/local/bin/certbot-auto
+ /usr/local/bin/certbot-auto --help
+ ```
+
+ To check the integrity of the `certbot-auto` script, run:
+
+ ```sh
+ wget -N https://dl.eff.org/certbot-auto.asc
+ gpg2 --keyserver ipv4.pool.sks-keyservers.net --recv-key A2CFB51FA275A7286234E7B24D17C995CD9775F2
+ gpg2 --trusted-key 4D17C995CD9775F2 --verify certbot-auto.asc /usr/local/bin/certbot-auto
+ ```
+
+ The output of the last command should look something like:
+
+ ```sh
+ gpg: Signature made Mon 10 Jun 2019 06:24:40 PM EDT
+ gpg: using RSA key A2CFB51FA275A7286234E7B24D17C995CD9775F2
+ gpg: key 4D17C995CD9775F2 marked as ultimately trusted
+ gpg: checking the trustdb
+ gpg: marginals needed: 3 completes needed: 1 trust model: pgp
+ gpg: depth: 0 valid: 1 signed: 0 trust: 0-, 0q, 0n, 0m, 0f, 1u
+ gpg: next trustdb check due at 2027-11-22
+ gpg: Good signature from "Let's Encrypt Client Team <letsencrypt-client@eff.org>" [ultimate]
+ ```
+
+1. Run the following command to use Certbot to request a certificate
+ using DNS challenge during authorization:
+
+
+ ```sh
+ ./certbot-auto certonly --manual --preferred-challenges dns -d '*.<namespace>.example.com'
+ ```
+
+ Where `<namespace>` is the namespace created by GitLab for your serverless project (composed of `<projectname+id>`) and
+ `example.com` is the domain being used for your project. If you are unsure what the namespace of your project is, navigate
+ to the **Operations > Serverless** page of your project and inspect
+ the endpoint provided for your function/app.
+
+ ![function_endpoint](img/function-endpoint.png)
+
+ In the above image, the namespace for the project is `node-function-11909507` and the domain is `knative.info`, thus
+ certificate request line would look like this:
+
+ ```sh
+ ./certbot-auto certonly --manual --preferred-challenges dns -d '*.node-function-11909507.knative.info'
+ ```
+
+ The Certbot tool walks you through the steps of validating that you own each domain that you specify by creating TXT records in those domains.
+ After this process is complete, the output should look something like this:
+
+ ```sh
+ IMPORTANT NOTES:
+ - Congratulations! Your certificate and chain have been saved at:
+ /etc/letsencrypt/live/namespace.example.com/fullchain.pem
+ Your key file has been saved at:
+ /etc/letsencrypt/live/namespace.example/privkey.pem
+ Your cert will expire on 2019-09-19. To obtain a new or tweaked
+ version of this certificate in the future, simply run certbot-auto
+ again. To non-interactively renew *all* of your certificates, run
+ "certbot-auto renew"
+ -----BEGIN PRIVATE KEY-----
+ - Your account credentials have been saved in your Certbot
+ configuration directory at /etc/letsencrypt. You should make a
+ secure backup of this folder now. This configuration directory will
+ also contain certificates and private keys obtained by Certbot so
+ making regular backups of this folder is ideal.
+ ```
+
+1. Create certificate and private key files. Using the contents of the files
+ returned by Certbot, we'll create two files in order to create the
+ Kubernetes secret:
+
+ Run the following command to see the contents of `fullchain.pem`:
+
+ ```sh
+ sudo cat /etc/letsencrypt/live/node-function-11909507.knative.info/fullchain.pem
+ ```
+
+ Output should look like this:
+
+ ```sh
+ -----BEGIN CERTIFICATE-----
+ 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
+ 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
+ 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
+ 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
+ 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
+ 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
+ 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
+ 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
+ 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
+ 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
+ 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
+ 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
+ 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
+ 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
+ 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
+ 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
+ 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
+ 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
+ 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
+ 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
+ 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
+ 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
+ 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
+ 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
+ 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
+ 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
+ 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
+ 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
+ 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
+ 04f294d1eaca42b8692017b4ag==
+ -----END CERTIFICATE-----
+ -----BEGIN CERTIFICATE-----
+ 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
+ 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
+ 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
+ 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
+ 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
+ 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
+ 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
+ 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
+ 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
+ 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
+ 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
+ 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
+ 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
+ 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
+ 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
+ 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
+ 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
+ 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
+ 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
+ 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
+ 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
+ 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
+ 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
+ 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
+ K2fcb195768c39e9a94cec2c2e30Qg==
+ -----END CERTIFICATE-----
+ ```
+
+ Create a file with the name `cert.pem` with the contents of the entire output.
+
+ Once `cert.pem` is created, run the following command to see the contents of `privkey.pem`:
+
+ ```sh
+ sudo cat /etc/letsencrypt/live/namespace.example/privkey.pem
+ ```
+
+ Output should look like this:
+
+ ```sh
+ -----BEGIN PRIVATE KEY-----
+ 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
+ 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
+ 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
+ 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
+ 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
+ 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
+ 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
+ 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
+ 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
+ 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
+ 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
+ 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
+ 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
+ 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
+ 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
+ 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
+ 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
+ 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
+ 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
+ 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
+ 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
+ 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
+ 2fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
+ 04f294d1eaca42b8692017b426d53bbc8fe75f827734f0260710b83a556082df
+ -----BEGIN CERTIFICATE-----
+ fcb195768c39e9a94cec2c2e32c59c0aad7a3365c10892e8116b5d83d4096b6
+ 4f294d1eaca42b8692017b4262==
+ -----END PRIVATE KEY-----
+ ```
+
+ Create a new file with the name `cert.pk` with the contents of the entire output.
+
+1. Create a Kubernetes secret to hold your TLS certificate, `cert.pem`, and
+ the private key `cert.pk`:
+
+ NOTE: **Note:**
+ Running `kubectl` commands on your cluster requires setting up access to the cluster first.
+ For clusters created on GKE, see
+ [GKE Cluster Access](https://cloud.google.com/kubernetes-engine/docs/how-to/cluster-access-for-kubectl).
+ For other platforms, [install `kubectl`](https://kubernetes.io/docs/tasks/tools/install-kubectl/).
+
+ ```sh
+ kubectl create --namespace istio-system secret tls istio-ingressgateway-certs \
+ --key cert.pk \
+ --cert cert.pem
+ ```
+
+ Where `cert.pem` and `cert.pk` are your certificate and private key files. Note that the `istio-ingressgateway-certs` secret name is required.
+
+1. Configure Knative to use the new secret that you created for HTTPS
+ connections. Run the
+ following command to open the Knative shared `gateway` in edit mode:
+
+ ```sh
+ kubectl edit gateway knative-ingress-gateway --namespace knative-serving
+ ```
+
+ Update the gateway to include the following tls: section and configuration:
+
+ ```sh
+ tls:
+ mode: SIMPLE
+ privateKey: /etc/istio/ingressgateway-certs/tls.key
+ serverCertificate: /etc/istio/ingressgateway-certs/tls.crt
+ ```
+
+ Example:
+
+ ```sh
+ apiVersion: networking.istio.io/v1alpha3
+ kind: Gateway
+ metadata:
+ # ... skipped ...
+ spec:
+ selector:
+ istio: ingressgateway
+ servers:
+ - hosts:
+ - "*"
+ port:
+ name: http
+ number: 80
+ protocol: HTTP
+ - hosts:
+ - "*"
+ port:
+ name: https
+ number: 443
+ protocol: HTTPS
+ tls:
+ mode: SIMPLE
+ privateKey: /etc/istio/ingressgateway-certs/tls.key
+ serverCertificate: /etc/istio/ingressgateway-certs/tls.crt
+ ```
+
+ After your changes are running on your Knative cluster, you can begin using the HTTPS protocol for secure access your deployed Knative services.
+ In the event a mistake is made during this process and you need to update the cert, you will need to edit the gateway `knative-ingress-gateway`
+ to switch back to `PASSTHROUGH` mode. Once corrections are made, edit the file again so the gateway will use the new certificates. \ No newline at end of file
diff --git a/doc/user/project/container_registry.md b/doc/user/project/container_registry.md
index 58b7fe33906..7d567da1c9a 100644
--- a/doc/user/project/container_registry.md
+++ b/doc/user/project/container_registry.md
@@ -113,6 +113,7 @@ This feature requires GitLab 8.8 and GitLab Runner 1.2.
Make sure that your GitLab Runner is configured to allow building Docker images by
following the [Using Docker Build](../../ci/docker/using_docker_build.md)
and [Using the GitLab Container Registry documentation](../../ci/docker/using_docker_build.md#using-the-gitlab-container-registry).
+Alternatively, you can [build images with Kaniko](../../ci/docker/using_kaniko.md) if the Docker builds are not an option for you.
## Using with private projects
@@ -167,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/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..5e11e7c0203 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 ca59fe3cc7d..7520237251a 100644
--- a/doc/user/project/description_templates.md
+++ b/doc/user/project/description_templates.md
@@ -25,14 +25,14 @@ templates of the default branch will be taken into account.
## Use-cases
- Add a template to be used in every issue for a specific project,
-giving instructions and guidelines, requiring for information specific to that subject.
-For example, if you have a project for tracking new blog posts, you can require the
-title, outlines, author name, author social media information, etc.
+ giving instructions and guidelines, requiring for information specific to that subject.
+ For example, if you have a project for tracking new blog posts, you can require the
+ title, outlines, author name, author social media information, etc.
- Following the previous example, you can make a template for every MR submitted
-with a new blog post, requiring information about the post date, frontmatter data,
-images guidelines, link to the related issue, reviewer name, etc.
+ with a new blog post, requiring information about the post date, frontmatter data,
+ images guidelines, link to the related issue, reviewer name, etc.
- You can also create issues and merge request templates for different
-stages of your workflow, e.g., feature proposal, feature improvement, bug report, etc.
+ stages of your workflow, e.g., feature proposal, feature improvement, bug report, etc.
## Creating issue templates
diff --git a/doc/user/project/import/gemnasium.md b/doc/user/project/import/gemnasium.md
index 7f79ebf6353..3b071ff590f 100644
--- a/doc/user/project/import/gemnasium.md
+++ b/doc/user/project/import/gemnasium.md
@@ -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/index.md b/doc/user/project/index.md
index 587b4121e4e..06286951e20 100644
--- a/doc/user/project/index.md
+++ b/doc/user/project/index.md
@@ -193,6 +193,28 @@ 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]**
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/3264) in [GitLab Premium](https://about.gitlab.com/pricing/) 12.1.
+
+When migrating repositories to GitLab and they are being accessed by other systems,
+it's very useful to be able to access them using the same name especially when
+they are a lot. It reduces the risk of changing significant number of Git URLs in
+a large number of systems.
+
+GitLab provides a functionality to help with this. In GitLab, repositories are
+usually accessed with a namespace and project name. It is also possible to access
+them via a project alias. This feature is only available on Git over SSH.
+
+A project alias can be only created via API and only by GitLab administrators.
+Follow the [Project Aliases API documentation](../../api/project_aliases.md) for
+more details.
+
+Once an alias has been created for a project (e.g., an alias `gitlab-ce` for the
+project `https://gitlab.com/gitlab-org/gitlab-ce`), the repository can be cloned
+using the alias (e.g `git clone git@gitlab.com:gitlab-ce.git` instead of
+`git clone git@gitlab.com:gitlab-org/gitlab-ce.git`).
+
## Project APIs
There are numerous [APIs](../../api/README.md) to use with your projects:
@@ -212,3 +234,4 @@ There are numerous [APIs](../../api/README.md) to use with your projects:
- [Templates](../../api/project_templates.md)
- [Traffic](../../api/project_statistics.md)
- [Variables](../../api/project_level_variables.md)
+- [Aliases](../../api/project_aliases.md)
diff --git a/doc/user/project/insights/index.md b/doc/user/project/insights/index.md
index 2e2a27f112e..1c6ad0b8b2b 100644
--- a/doc/user/project/insights/index.md
+++ b/doc/user/project/insights/index.md
@@ -1,7 +1,6 @@
# Insights **[ULTIMATE]**
-> Introduced in [GitLab Ultimate](https://about.gitlab.com/pricing/) 11.9 behind the `insights` feature flag.
-> **Generally Available** (GA) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 12.0.
+> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/725) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 12.0.
Configure the Insights that matter for your projects to explore data such as
triage hygiene, issues created/closed per a given period, average time for merge
diff --git a/doc/user/project/integrations/github.md b/doc/user/project/integrations/github.md
index cdb0e34fdf6..680fcdb78bb 100644
--- a/doc/user/project/integrations/github.md
+++ b/doc/user/project/integrations/github.md
@@ -17,7 +17,7 @@ and is automatically configured on [GitHub import](../../../integration/github.m
This integration requires a [GitHub API token](https://help.github.com/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/hipchat.md b/doc/user/project/integrations/hipchat.md
index 0fd847d415f..7a0540aa9e3 100644
--- a/doc/user/project/integrations/hipchat.md
+++ b/doc/user/project/integrations/hipchat.md
@@ -23,7 +23,7 @@ allow GitLab to send messages only to *one* room.
1. Find "Build Your Own!" and click "Create".
1. Select the desired room, name the integration "GitLab", and click "Create".
1. In the "Send messages to this room by posting this URL" column, you should
-see a URL in the format:
+ see a URL in the format:
```
https://api.hipchat.com/v2/room/<room>/notification?auth_token=<token>
diff --git a/doc/user/project/integrations/jira.md b/doc/user/project/integrations/jira.md
index 234e3ad31cc..8f2e5a55b5f 100644
--- a/doc/user/project/integrations/jira.md
+++ b/doc/user/project/integrations/jira.md
@@ -39,7 +39,7 @@ 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
+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
@@ -47,13 +47,13 @@ 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:
+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:
-- [Setting up a user in JIRA server](jira_server_configuration.md)
+- [Setting up a user in Jira Server](jira_server_configuration.md)
-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:
+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:
-- [Setting up a user in JIRA cloud](jira_cloud_configuration.md)
+- [Setting up a user in Jira Cloud](jira_cloud_configuration.md)
### Configuring GitLab
@@ -77,8 +77,8 @@ in the table below.
| ----- | ----------- |
| `Web URL` | The base URL to the Jira instance web interface which is being linked to this GitLab project. E.g., `https://Jira.example.com`. |
| `Jira API URL` | The base URL to the Jira instance API. Web URL value will be used if not set. E.g., `https://jira-api.example.com`. |
-| `Username/Email` | Created when [configuring Jira step](#configuring-jira). Use `username` for **JIRA server** or `email` for **JIRA cloud**. |
-| `Password/API token` |Created in [configuring Jira step](#configuring-jira). Use `password` for **JIRA server** or `API token` for **JIRA cloud**. |
+| `Username/Email` | Created when [configuring Jira step](#configuring-jira). Use `username` for **Jira Server** or `email` for **Jira Cloud**. |
+| `Password/API token` |Created in [configuring Jira step](#configuring-jira). Use `password` for **Jira Server** or `API token` for **Jira Cloud**. |
| `Transition ID` | This is the ID of a transition that moves issues to the desired state. It is possible to insert transition ids separated by `,` or `;` which means the issue will be moved to each state after another using the given order. **Closing Jira issues via commits or Merge Requests won't work if you don't set the ID correctly.** |
### Obtaining a transition ID
diff --git a/doc/user/project/integrations/jira_cloud_configuration.md b/doc/user/project/integrations/jira_cloud_configuration.md
index 849df707521..614f05d5b7e 100644
--- a/doc/user/project/integrations/jira_cloud_configuration.md
+++ b/doc/user/project/integrations/jira_cloud_configuration.md
@@ -1,18 +1,18 @@
-# Creating an API token in JIRA cloud
+# Creating an API token in Jira Cloud
-An API token is needed when integrating with JIRA Cloud, follow the steps
+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**.
-![JIRA API token](img/jira_api_token_menu.png)
+![Jira API token](img/jira_api_token_menu.png)
-![JIRA API token](img/jira_api_token.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.
+It is important that the user associated with this email has 'write' access to projects in Jira.
-The JIRA configuration is complete. You are going to need this new 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 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).
diff --git a/doc/user/project/integrations/jira_server_configuration.md b/doc/user/project/integrations/jira_server_configuration.md
index 13d65c4d8e4..32991714973 100644
--- a/doc/user/project/integrations/jira_server_configuration.md
+++ b/doc/user/project/integrations/jira_server_configuration.md
@@ -1,4 +1,4 @@
-# Creating a username and password for JIRA server
+# Creating a username and password for Jira Server
We need to create a user in Jira which will have access to all projects that
need to integrate with GitLab.
diff --git a/doc/user/project/integrations/project_services.md b/doc/user/project/integrations/project_services.md
index 0bfee3bac99..0e4c71a9d3e 100644
--- a/doc/user/project/integrations/project_services.md
+++ b/doc/user/project/integrations/project_services.md
@@ -38,7 +38,7 @@ Click on the service links to see further configuration instructions and details
| [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 |
+| [Jira](jira.md) | Jira issue tracker |
| [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 |
diff --git a/doc/user/project/integrations/prometheus.md b/doc/user/project/integrations/prometheus.md
index 751e8e44e60..aab7131e353 100644
--- a/doc/user/project/integrations/prometheus.md
+++ b/doc/user/project/integrations/prometheus.md
@@ -160,7 +160,7 @@ receivers:
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/4925) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 11.11.
-Alerts can be used to trigger actions, like open an issue automatically. To configure the actions:
+Alerts can be used to trigger actions, like open an issue automatically (enabled by default since `12.1`). To configure the actions:
1. Navigate to your project's **Settings > Operations > Incidents**.
1. Enable the option to create issues.
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/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/issues/index.md b/doc/user/project/issues/index.md
index 76dc6e49bce..4acbb4cc3f6 100644
--- a/doc/user/project/issues/index.md
+++ b/doc/user/project/issues/index.md
@@ -134,4 +134,4 @@ For more information, see [Crosslinking issues](crosslinking_issues.md).
- [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.
+ or Bugzilla.
diff --git a/doc/user/project/merge_requests/merge_request_approvals.md b/doc/user/project/merge_requests/merge_request_approvals.md
index fd151a6df45..8e8ec26daf2 100644
--- a/doc/user/project/merge_requests/merge_request_approvals.md
+++ b/doc/user/project/merge_requests/merge_request_approvals.md
@@ -12,9 +12,9 @@ to approve a merge request before it can be unblocked for merging.
## Use cases
1. Enforcing review of all code that gets merged into a repository.
-2. Specifying code maintainers for an entire repository.
-3. Specifying reviewers for a given proposed code change.
-4. Specifying categories of reviewers, such as BE, FE, QA, DB, etc., for all proposed code changes.
+1. Specifying code maintainers for an entire repository.
+1. Specifying reviewers for a given proposed code change.
+1. Specifying categories of reviewers, such as BE, FE, QA, DB, etc., for all proposed code changes.
## Enabling the new approvals interface
@@ -246,7 +246,7 @@ restrictions (compared to [GitLab Starter](#overriding-the-merge-request-approva
- Approval rules can be added to an MR with no restriction.
- For project sourced approval rules, editing and removing approvers is not allowed.
- The approvals required of all approval rules is configurable, but if a rule is backed by a project rule, then it is restricted
-to the minimum approvals required set in the project's corresponding rule.
+ to the minimum approvals required set in the project's corresponding rule.
## Resetting approvals on push
diff --git a/doc/user/project/merge_requests/merge_when_pipeline_succeeds.md b/doc/user/project/merge_requests/merge_when_pipeline_succeeds.md
index c93c7a5fe08..0dd60d84c42 100644
--- a/doc/user/project/merge_requests/merge_when_pipeline_succeeds.md
+++ b/doc/user/project/merge_requests/merge_when_pipeline_succeeds.md
@@ -42,6 +42,8 @@ Navigate to your project's settings page and expand the **Merge requests** secti
In the **Merge checks** subsection, select the **Pipelines must succeed** check
box and hit **Save** for the changes to take effect.
+NOTE: **Note:** This setting also prevents merge requests from being merged if there is no pipeline.
+
![Pipelines must succeed settings](img/merge_when_pipeline_succeeds_only_if_succeeds_settings.png)
From now on, every time the pipeline fails you will not be able to merge the
@@ -49,6 +51,21 @@ merge request from the UI, until you make all relevant jobs pass.
![Only allow merge if pipeline succeeds message](img/merge_when_pipeline_succeeds_only_if_succeeds_msg.png)
+### Limitations
+
+When this setting is enabled, a merge request is prevented from being merged if there is no pipeline. This may conflict with some use cases where [`only/except`](../../../ci/yaml/README.md#onlyexcept-advanced) rules are used and they don't generate any pipelines.
+
+Users that expect to be able to merge a merge request in this scenario should ensure that [there is always a pipeline](https://gitlab.com/gitlab-org/gitlab-ce/issues/54226) and that it's succesful.
+
+For example, to that on merge requests there is always a passing job even though `only/except` rules may not generate any other jobs:
+
+```yaml
+enable_merge:
+ only: merge_requests
+ script:
+ - echo true
+```
+
<!-- ## Troubleshooting
Include any troubleshooting steps that you can foresee. If you know beforehand what issues
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/pages/getting_started_part_three.md b/doc/user/project/pages/getting_started_part_three.md
index d585c19fc5c..bc9a11504cd 100644
--- a/doc/user/project/pages/getting_started_part_three.md
+++ b/doc/user/project/pages/getting_started_part_three.md
@@ -1,5 +1,5 @@
---
-last_updated: 2019-06-04
+last_updated: 2019-06-25
type: concepts, reference, howto
---
@@ -138,9 +138,9 @@ verify your domain's ownership with a TXT record:
> - **Do not** add any special chars after the default Pages
domain. E.g., **do not** point your `subdomain.domain.com` to
`namespace.gitlab.io.` or `namespace.gitlab.io/`.
-> - GitLab Pages IP on GitLab.com [was changed](https://about.gitlab.com/2017/03/06/we-are-changing-the-ip-of-gitlab-pages-on-gitlab-com/) in 2017
+> - GitLab Pages IP on GitLab.com [was changed](https://about.gitlab.com/2017/03/06/we-are-changing-the-ip-of-gitlab-pages-on-gitlab-com/) in 2017.
> - GitLab Pages IP on GitLab.com [has been changed](https://about.gitlab.com/2018/07/19/gcp-move-update/#gitlab-pages-and-custom-domains)
- from `52.167.214.135` to `35.185.44.232` in 2018
+ from `52.167.214.135` to `35.185.44.232` in 2018.
### Add your custom domain to GitLab Pages settings
@@ -199,7 +199,7 @@ Certificates are NOT required to add to your custom
highly recommendable.
Let's start with an introduction to the importance of HTTPS.
-Alternatively, jump ahead to [adding certificates to your project](#adding-certificates-to-your-project).
+Alternatively, jump ahead to [adding certificates to your project](#adding-certificates-to-pages).
### Why should I care about HTTPS?
@@ -255,12 +255,12 @@ which also offers a [free CDN service](https://blog.cloudflare.com/cloudflares-f
Their certs are valid up to 15 years. See the tutorial on
[how to add a CloudFlare Certificate to your GitLab Pages website](https://about.gitlab.com/2017/02/07/setting-up-gitlab-pages-with-cloudflare-certificates/).
-### Adding certificates to your project
+### Adding certificates to Pages
Regardless the CA you choose, the steps to add your certificate to
your Pages project are the same.
-### What do you need
+#### Requirements
1. A PEM certificate
1. An intermediate certificate
@@ -270,7 +270,7 @@ your Pages project are the same.
These fields are found under your **Project**'s **Settings** > **Pages** > **New Domain**.
-### What's what?
+#### Certificate types
- A PEM certificate is the certificate generated by the CA,
which needs to be added to the field **Certificate (PEM)**.
@@ -283,21 +283,32 @@ These fields are found under your **Project**'s **Settings** > **Pages** > **New
- A private key is an encrypted key which validates
your PEM against your domain.
-### Now what?
+#### Add the certificate to your project
-Now that you hopefully understand why you need all
-of this, it's simple:
+Once you've met the requirements:
-- Your PEM certificate needs to be added to the first field
+- Your PEM certificate needs to be added to the first field.
- If your certificate is missing its intermediate, copy
and paste the root certificate (usually available from your CA website)
and paste it in the [same field as your PEM certificate](https://about.gitlab.com/2017/02/07/setting-up-gitlab-pages-with-cloudflare-certificates/),
just jumping a line between them.
-- Copy your private key and paste it in the last field
+- Copy your private key and paste it in the last field.
->**Note:**
+NOTE: **Note:**
**Do not** open certificates or encryption keys in
regular text editors. Always use code editors (such as
Sublime Text, Atom, Dreamweaver, Brackets, etc).
-_Read on about [Creating and Tweaking GitLab CI/CD for GitLab Pages](getting_started_part_four.md)_
+## Force HTTPS for GitLab Pages websites
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/28857) in GitLab 10.7.
+
+To make your website's visitors even more secure, you can choose to
+force HTTPS for GitLab Pages. By doing so, all attempts to visit your
+website via HTTP will be automatically redirected to HTTPS via 301.
+
+It works with both GitLab's default domain and with your custom
+domain (as long as you've set a valid certificate for it).
+
+To enable this setting, navigate to your project's **Settings > Pages**
+and tick the checkbox **Force HTTPS (requires valid certificates)**.
diff --git a/doc/user/project/pages/getting_started_part_two.md b/doc/user/project/pages/getting_started_part_two.md
index 3e50cd4887c..fe92d19567d 100644
--- a/doc/user/project/pages/getting_started_part_two.md
+++ b/doc/user/project/pages/getting_started_part_two.md
@@ -77,10 +77,10 @@ containing the most popular SSGs templates to get you started.
1. [Fork](../../../gitlab-basics/fork-project.md) a sample project from the [GitLab Pages examples](https://gitlab.com/pages) group.
1. From the left sidebar, navigate to your project's **CI/CD > Pipelines**
-and click **Run pipeline** to trigger GitLab CI/CD to build and deploy your
-site to the server.
+ and click **Run pipeline** to trigger GitLab CI/CD to build and deploy your
+ site to the server.
1. Once the pipeline has finished successfully, find the link to visit your
-website from your project's **Settings > Pages**.
+ website from your project's **Settings > Pages**.
You can also take some **optional** further steps:
@@ -89,14 +89,14 @@ You can also take some **optional** further steps:
![remove fork relationship](img/remove_fork_relationship.png)
- _Make it a user or group website._ To turn a **project website** forked
-from the Pages group into a **user/group** website, you'll need to:
+ from the Pages group into a **user/group** website, you'll need to:
- Rename it to `namespace.gitlab.io`: go to your project's
- **Settings > General** and expand **Advanced**. Scroll down to
- **Rename repository** and change the path to `namespace.gitlab.io`.
+ **Settings > General** and expand **Advanced**. Scroll down to
+ **Rename repository** and change the path to `namespace.gitlab.io`.
- Adjust your SSG's [base URL](#urls-and-baseurls) from `"project-name"` to
- `""`. This setting will be at a different place for each SSG, as each of them
- have their own structure and file tree. Most likely, it will be in the SSG's
- config file.
+ `""`. This setting will be at a different place for each SSG, as each of them
+ have their own structure and file tree. Most likely, it will be in the SSG's
+ config file.
### Create a project from scratch
diff --git a/doc/user/project/pages/index.md b/doc/user/project/pages/index.md
index 04bda212128..fa79c393b72 100644
--- a/doc/user/project/pages/index.md
+++ b/doc/user/project/pages/index.md
@@ -12,7 +12,6 @@ type: index, reference
> - Support for subgroup project's websites was [introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/30548) in GitLab 11.8.
> - Bundled project templates were [introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/47857) in GitLab 11.8.
-
**GitLab Pages is a feature that allows you to publish static websites
directly from a repository in GitLab.**
@@ -105,10 +104,10 @@ To get started with GitLab Pages, you can either:
![Project templates for Pages](img/pages_project_templates_11-8.png)
1. From the left sidebar, navigate to your project's **CI/CD > Pipelines**
-and click **Run pipeline** to trigger GitLab CI/CD to build and deploy your
-site to the server.
+ and click **Run pipeline** to trigger GitLab CI/CD to build and deploy your
+ site to the server.
1. Once the pipeline has finished successfully, find the link to visit your
-website from your project's **Settings > Pages**.
+ website from your project's **Settings > Pages**.
Your website is then visible on your domain, and you can modify yourfiles
as you wish. For every modification pushed to your repository, GitLab CI/CD
diff --git a/doc/user/project/pages/introduction.md b/doc/user/project/pages/introduction.md
index 4fab7f79e0c..4ea3bd9be9b 100644
--- a/doc/user/project/pages/introduction.md
+++ b/doc/user/project/pages/introduction.md
@@ -13,17 +13,17 @@ To familiarize yourself with GitLab Pages first:
- Read an [introduction to GitLab Pages](index.md#overview).
- Learn [how to get started with Pages](index.md#getting-started).
- Learn how to enable GitLab Pages
-across your GitLab instance on the [administrator documentation](../../../administration/pages/index.md).
+ across your GitLab instance on the [administrator documentation](../../../administration/pages/index.md).
## GitLab Pages requirements
In brief, this is what you need to upload your website in GitLab Pages:
1. Domain of the instance: domain name that is used for GitLab Pages
-(ask your administrator).
+ (ask your administrator).
1. GitLab CI/CD: a `.gitlab-ci.yml` file with a specific job named [`pages`][pages] in the root directory of your repository.
1. A directory called `public` in your site's repo containing the content
-to be published.
+ to be published.
1. GitLab Runner enabled for the project.
## GitLab Pages on GitLab.com
diff --git a/doc/user/project/pipelines/job_artifacts.md b/doc/user/project/pipelines/job_artifacts.md
index 002addfc043..f9feae36dbc 100644
--- a/doc/user/project/pipelines/job_artifacts.md
+++ b/doc/user/project/pipelines/job_artifacts.md
@@ -187,7 +187,8 @@ 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)
+If you are either the owner of a given job or have Master
+[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.
diff --git a/doc/user/project/quick_actions.md b/doc/user/project/quick_actions.md
index 7215b86ddeb..aa15fe987db 100644
--- a/doc/user/project/quick_actions.md
+++ b/doc/user/project/quick_actions.md
@@ -57,6 +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]** | ✓ | |
## Quick actions for commit messages
diff --git a/doc/user/project/settings/index.md b/doc/user/project/settings/index.md
index ba890c5ac01..2bf8d4dfe7b 100644
--- a/doc/user/project/settings/index.md
+++ b/doc/user/project/settings/index.md
@@ -18,7 +18,7 @@ Adjust your project's name, description, avatar, [default branch](../repository/
![general project settings](img/general_settings.png)
-The project description also partially supports [standard markdown](../../markdown.md#standard-markdown). You can use [emphasis](../../markdown.md#emphasis), [links](../../markdown.md#links), and [line-breaks](../../markdown.md#line-breaks) to add more context to the project description.
+The project description also partially supports [standard markdown](../../markdown.md#standard-markdown-and-extensions-in-gitlab). You can use [emphasis](../../markdown.md#emphasis), [links](../../markdown.md#links), and [line-breaks](../../markdown.md#line-breaks) to add more context to the project description.
### Sharing and permissions
@@ -26,10 +26,10 @@ 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 Lables 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
+You can still access them with direct links if you can access Merge Requests. This is deliberate, if you can see
Issues or Merge Requests, both of which use Labels and Milestones, then you shouldn't be denied access to Labels and Milestones pages.
### Issue settings
@@ -109,8 +109,8 @@ You can transfer an existing project into a [group](../../group/index.md) if:
1. You have at least **Maintainer** [permissions] to that group.
1. The project is in a subgroup you own.
1. You are at least a **Maintainer** of the project under your personal namespace.
-Similarly, if you are an owner of a group, you can transfer any of its projects
-under your own user.
+ Similarly, if you are an owner of a group, you can transfer any of its projects
+ under your own user.
To transfer a project:
diff --git a/doc/user/project/web_ide/index.md b/doc/user/project/web_ide/index.md
index b2bf85335c5..7d85f4adfed 100644
--- a/doc/user/project/web_ide/index.md
+++ b/doc/user/project/web_ide/index.md
@@ -171,13 +171,13 @@ syntax but with some restrictions:
- No global blocks can be defined (ie: `before_script` or `after_script`)
- Only one job named `terminal` can be added to this file.
- Only the keywords `image`, `services`, `tags`, `before_script`, `script`, and
-`variables` are allowed to be used to configure the job.
+ `variables` are allowed to be used to configure the job.
- To connect to the interactive terminal, the `terminal` job must be still alive
-and running, otherwise the terminal won't be able to connect to the job's session.
-By default the `script` keyword has the value `sleep 60` to prevent
-the job from ending and giving the Web IDE enough time to connect. This means
-that, if you override the default `script` value, you'll have to add a command
-which would keep the job running, like `sleep`.
+ and running, otherwise the terminal won't be able to connect to the job's session.
+ By default the `script` keyword has the value `sleep 60` to prevent
+ the job from ending and giving the Web IDE enough time to connect. This means
+ that, if you override the default `script` value, you'll have to add a command
+ which would keep the job running, like `sleep`.
In the code below there is an example of this configuration file:
diff --git a/doc/workflow/gitlab_flow.md b/doc/workflow/gitlab_flow.md
index 3e24557591c..0cb390e1242 100644
--- a/doc/workflow/gitlab_flow.md
+++ b/doc/workflow/gitlab_flow.md
@@ -175,7 +175,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.
diff --git a/doc/workflow/notifications.md b/doc/workflow/notifications.md
index 5d560f2e000..d49d29c805a 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
diff --git a/doc/workflow/time_tracking.md b/doc/workflow/time_tracking.md
index c03dffa967d..4286a3625a2 100644
--- a/doc/workflow/time_tracking.md
+++ b/doc/workflow/time_tracking.md
@@ -73,7 +73,15 @@ The following time units are available:
Default conversion rates are 1mo = 4w, 1w = 5d and 1d = 8h.
-Other interesting links:
+### Limit displayed units to hours
+
+> Introduced in GitLab 12.0.
+
+The display of time units can be limited to hours through the option in **Admin Area > Settings > Preferences** under 'Localization'.
+
+With this option enabled, `75h` is displayed instead of `1w 4d 3h`.
+
+## Other interesting links
- [Time Tracking landing page on about.gitlab.com](https://about.gitlab.com/solutions/time-tracking/)
diff --git a/lib/after_commit_queue.rb b/lib/after_commit_queue.rb
index 6fb7985f955..6a180fdf338 100644
--- a/lib/after_commit_queue.rb
+++ b/lib/after_commit_queue.rb
@@ -15,7 +15,7 @@ module AfterCommitQueue
end
def run_after_commit_or_now(&block)
- if AfterCommitQueue.inside_transaction?
+ if Gitlab::Database.inside_transaction?
if ActiveRecord::Base.connection.current_transaction.records.include?(self)
run_after_commit(&block)
else
@@ -32,18 +32,6 @@ module AfterCommitQueue
true
end
- def self.open_transactions_baseline
- if ::Rails.env.test?
- return DatabaseCleaner.connections.count { |conn| conn.strategy.is_a?(DatabaseCleaner::ActiveRecord::Transaction) }
- end
-
- 0
- end
-
- def self.inside_transaction?
- ActiveRecord::Base.connection.open_transactions > open_transactions_baseline
- end
-
protected
def _run_after_commit_queue
diff --git a/lib/api/boards.rb b/lib/api/boards.rb
index b7c77730afb..4e31f74f18a 100644
--- a/lib/api/boards.rb
+++ b/lib/api/boards.rb
@@ -27,7 +27,7 @@ module API
end
get '/' do
authorize!(:read_board, user_project)
- present paginate(board_parent.boards), with: Entities::Board
+ present paginate(board_parent.boards.with_associations), with: Entities::Board
end
desc 'Find a project board' do
diff --git a/lib/api/boards_responses.rb b/lib/api/boards_responses.rb
index 86d9b24802f..68497a08fb8 100644
--- a/lib/api/boards_responses.rb
+++ b/lib/api/boards_responses.rb
@@ -11,7 +11,7 @@ module API
end
def board_lists
- board.lists.destroyable
+ board.destroyable_lists
end
def create_list
diff --git a/lib/api/branches.rb b/lib/api/branches.rb
index 65d7f68bbf9..c3821630b6b 100644
--- a/lib/api/branches.rb
+++ b/lib/api/branches.rb
@@ -8,7 +8,10 @@ module API
BRANCH_ENDPOINT_REQUIREMENTS = API::NAMESPACE_OR_PROJECT_REQUIREMENTS.merge(branch: API::NO_SLASH_URL_PART_REGEX)
- before { authorize! :download_code, user_project }
+ before do
+ require_repository_enabled!
+ authorize! :download_code, user_project
+ end
helpers do
params :filter_params do
diff --git a/lib/api/commits.rb b/lib/api/commits.rb
index 80913f4ca07..eebded87ebc 100644
--- a/lib/api/commits.rb
+++ b/lib/api/commits.rb
@@ -6,7 +6,10 @@ module API
class Commits < Grape::API
include PaginationParams
- before { authorize! :download_code, user_project }
+ before do
+ require_repository_enabled!
+ authorize! :download_code, user_project
+ end
helpers do
def user_access
diff --git a/lib/api/entities.rb b/lib/api/entities.rb
index ead01dc53f7..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
@@ -1101,7 +1103,7 @@ module API
expose :project, using: Entities::BasicProjectDetails
expose :lists, using: Entities::List do |board|
- board.lists.destroyable
+ board.destroyable_lists
end
end
@@ -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/group_boards.rb b/lib/api/group_boards.rb
index 9a20ee8c8b9..feb2254963e 100644
--- a/lib/api/group_boards.rb
+++ b/lib/api/group_boards.rb
@@ -37,7 +37,7 @@ module API
use :pagination
end
get '/' do
- present paginate(board_parent.boards), with: Entities::Board
+ present paginate(board_parent.boards.with_associations), with: Entities::Board
end
end
diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb
index 6382d295f79..8ae42c6dadd 100644
--- a/lib/api/helpers.rb
+++ b/lib/api/helpers.rb
@@ -250,6 +250,10 @@ module API
authorize! :update_build, user_project
end
+ def require_repository_enabled!(subject = :global)
+ not_found!("Repository") unless user_project.feature_available?(:repository, current_user)
+ end
+
def require_gitlab_workhorse!
unless env['HTTP_GITLAB_WORKHORSE'].present?
forbidden!('Request should be executed via GitLab Workhorse')
diff --git a/lib/api/helpers/services_helpers.rb b/lib/api/helpers/services_helpers.rb
index cf2e9d01356..c4ecf55969c 100644
--- a/lib/api/helpers/services_helpers.rb
+++ b/lib/api/helpers/services_helpers.rb
@@ -462,31 +462,31 @@ module API
required: true,
name: :url,
type: String,
- desc: 'The base URL to the JIRA instance web interface which is being linked to this GitLab project. E.g., https://jira.example.com'
+ desc: 'The base URL to the Jira instance web interface which is being linked to this GitLab project. E.g., https://jira.example.com'
},
{
required: false,
name: :api_url,
type: String,
- desc: 'The base URL to the JIRA instance API. Web URL value will be used if not set. E.g., https://jira-api.example.com'
+ desc: 'The base URL to the Jira instance API. Web URL value will be used if not set. E.g., https://jira-api.example.com'
},
{
required: true,
name: :username,
type: String,
- desc: 'The username of the user created to be used with GitLab/JIRA'
+ desc: 'The username of the user created to be used with GitLab/Jira'
},
{
required: true,
name: :password,
type: String,
- desc: 'The password of the user created to be used with GitLab/JIRA'
+ desc: 'The password of the user created to be used with GitLab/Jira'
},
{
required: false,
name: :jira_issue_transition_id,
type: String,
- desc: '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`'
+ desc: '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`'
}
],
'kubernetes' => [
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..6b8c1a2c0e8 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
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/settings.rb b/lib/api/settings.rb
index 6767ef882cb..4275d911708 100644
--- a/lib/api/settings.rb
+++ b/lib/api/settings.rb
@@ -36,10 +36,6 @@ module API
given akismet_enabled: ->(val) { val } do
requires :akismet_api_key, type: String, desc: 'Generate API key at http://www.akismet.com'
end
- optional :clientside_sentry_enabled, type: Boolean, desc: 'Sentry can also be used for reporting and logging clientside exceptions. https://sentry.io/for/javascript/'
- given clientside_sentry_enabled: ->(val) { val } do
- requires :clientside_sentry_dsn, type: String, desc: 'Clientside Sentry Data Source Name'
- end
optional :container_registry_token_expire_delay, type: Integer, desc: 'Authorization token duration (minutes)'
optional :default_artifacts_expire_in, type: String, desc: "Set the default expiration time for each job's artifacts"
optional :default_project_creation, type: Integer, values: ::Gitlab::Access.project_creation_values, desc: 'Determine if developers can create projects in the group'
@@ -59,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'
@@ -114,10 +112,6 @@ module API
end
optional :restricted_visibility_levels, type: Array[String], desc: 'Selected levels cannot be used by non-admin users for groups, projects or snippets. If the public level is restricted, user profiles are only visible to logged in users.'
optional :send_user_confirmation_email, type: Boolean, desc: 'Send confirmation email on sign-up'
- optional :sentry_enabled, type: Boolean, desc: 'Sentry is an error reporting and logging tool which is currently not shipped with GitLab, get it here: https://getsentry.com'
- given sentry_enabled: ->(val) { val } do
- requires :sentry_dsn, type: String, desc: 'Sentry Data Source Name'
- end
optional :session_expire_delay, type: Integer, desc: 'Session duration in minutes. GitLab restart is required to apply changes.'
optional :shared_runners_enabled, type: Boolean, desc: 'Enable shared runners for new projects'
given shared_runners_enabled: ->(val) { val } do
diff --git a/lib/api/todos.rb b/lib/api/todos.rb
index d2196f05173..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
@@ -77,7 +77,7 @@ module API
use :pagination
end
get do
- todos = paginate(find_todos.with_api_entity_associations)
+ todos = paginate(find_todos.with_entity_associations)
options = { with: Entities::Todo, current_user: current_user }
batch_load_issuable_metadata(todos, options)
diff --git a/lib/api/users.rb b/lib/api/users.rb
index 9ab5fa8d0bd..41418aa216c 100644
--- a/lib/api/users.rb
+++ b/lib/api/users.rb
@@ -158,6 +158,7 @@ module API
at_least_one_of :password, :reset_password
requires :name, type: String, desc: 'The name of the user'
requires :username, type: String, desc: 'The username of the user'
+ optional :force_random_password, type: Boolean, desc: 'Flag indicating a random password will be set'
use :optional_attributes
end
post do
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..22420e95ea2 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
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.rb b/lib/gitlab.rb
index fd4bbd69468..c62d1071dba 100644
--- a/lib/gitlab.rb
+++ b/lib/gitlab.rb
@@ -71,6 +71,10 @@ module Gitlab
end
end
+ def self.ee
+ yield if ee?
+ end
+
def self.http_proxy_env?
HTTP_PROXY_ENV_VARS.any? { |name| ENV[name] }
end
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/auth/ip_rate_limiter.rb b/lib/gitlab/auth/ip_rate_limiter.rb
index 81e616fa20a..0b7055b3256 100644
--- a/lib/gitlab/auth/ip_rate_limiter.rb
+++ b/lib/gitlab/auth/ip_rate_limiter.rb
@@ -3,6 +3,8 @@
module Gitlab
module Auth
class IpRateLimiter
+ include ::Gitlab::Utils::StrongMemoize
+
attr_reader :ip
def initialize(ip)
@@ -37,7 +39,20 @@ module Gitlab
end
def ip_can_be_banned?
- config.ip_whitelist.exclude?(ip)
+ !trusted_ip?
+ end
+
+ def trusted_ip?
+ trusted_ips.any? { |netmask| netmask.include?(ip) }
+ end
+
+ def trusted_ips
+ strong_memoize(:trusted_ips) do
+ config.ip_whitelist.map do |proxy|
+ IPAddr.new(proxy)
+ rescue IPAddr::InvalidAddressError
+ end.compact
+ 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/ansi2html.rb b/lib/gitlab/ci/ansi2html.rb
index 55411b5a8c4..fc3223e7442 100644
--- a/lib/gitlab/ci/ansi2html.rb
+++ b/lib/gitlab/ci/ansi2html.rb
@@ -200,9 +200,7 @@ module Gitlab
css_classes = %w[section line] + sections.map { |section| "s_#{section}" }
end
- ensure_open_new_tag
- write_raw %{<br/>}
- close_open_tags
+ write_in_tag %{<br/>}
write_raw %{<span class="#{css_classes.join(' ')}"></span>} if css_classes.any?
@lineno_in_section += 1
open_new_tag
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/Code-Quality.gitlab-ci.yml b/lib/gitlab/ci/templates/Jobs/Code-Quality.gitlab-ci.yml
index 46c4c755729..8a84744aa2d 100644
--- a/lib/gitlab/ci/templates/Jobs/Code-Quality.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Jobs/Code-Quality.gitlab-ci.yml
@@ -17,7 +17,7 @@ code_quality:
--env SOURCE_CODE="$PWD"
--volume "$PWD":/code
--volume /var/run/docker.sock:/var/run/docker.sock
- "registry.gitlab.com/gitlab-org/security-products/codequality:11-8-stable" /code
+ "registry.gitlab.com/gitlab-org/security-products/codequality:12-0-stable" /code
artifacts:
reports:
codequality: gl-code-quality-report.json
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/trace.rb b/lib/gitlab/ci/trace.rb
index dfae260239e..ce5857965bf 100644
--- a/lib/gitlab/ci/trace.rb
+++ b/lib/gitlab/ci/trace.rb
@@ -5,7 +5,7 @@ module Gitlab
class Trace
include ::Gitlab::ExclusiveLeaseHelpers
- LOCK_TTL = 1.minute
+ LOCK_TTL = 10.minutes
LOCK_RETRIES = 2
LOCK_SLEEP = 0.001.seconds
diff --git a/lib/gitlab/cleanup/orphan_job_artifact_files.rb b/lib/gitlab/cleanup/orphan_job_artifact_files.rb
new file mode 100644
index 00000000000..ee7164b3e55
--- /dev/null
+++ b/lib/gitlab/cleanup/orphan_job_artifact_files.rb
@@ -0,0 +1,132 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Cleanup
+ class OrphanJobArtifactFiles
+ include Gitlab::Utils::StrongMemoize
+
+ ABSOLUTE_ARTIFACT_DIR = ::JobArtifactUploader.root.freeze
+ LOST_AND_FOUND = File.join(ABSOLUTE_ARTIFACT_DIR, '-', 'lost+found').freeze
+ BATCH_SIZE = 500
+ DEFAULT_NICENESS = 'Best-effort'
+
+ attr_accessor :batch, :total_found, :total_cleaned
+ attr_reader :limit, :dry_run, :niceness, :logger
+
+ def initialize(limit: nil, dry_run: true, niceness: nil, logger: nil)
+ @limit = limit
+ @dry_run = dry_run
+ @niceness = niceness || DEFAULT_NICENESS
+ @logger = logger || Rails.logger
+ @total_found = @total_cleaned = 0
+
+ new_batch!
+ end
+
+ def run!
+ log_info('Looking for orphan job artifacts to clean up')
+
+ find_artifacts do |artifact_file|
+ batch << artifact_file
+
+ clean_batch! if batch.full?
+ break if limit_reached?
+ end
+
+ clean_batch!
+
+ log_info("Processed #{total_found} job artifacts to find and clean #{total_cleaned} orphans.")
+ end
+
+ private
+
+ def new_batch!
+ self.batch = ::Gitlab::Cleanup::OrphanJobArtifactFilesBatch
+ .new(batch_size: batch_size, logger: logger, dry_run: dry_run)
+ end
+
+ def clean_batch!
+ batch.clean!
+
+ update_stats!(batch)
+
+ new_batch!
+ end
+
+ def update_stats!(batch)
+ self.total_found += batch.artifact_files.count
+ self.total_cleaned += batch.lost_and_found.count
+ end
+
+ def limit_reached?
+ return false unless limit
+
+ total_cleaned >= limit
+ end
+
+ def batch_size
+ return BATCH_SIZE unless limit
+ return if limit_reached?
+
+ todo = limit - total_cleaned
+ [BATCH_SIZE, todo].min
+ end
+
+ def find_artifacts
+ Open3.popen3(*find_command) do |stdin, stdout, stderr, status_thread|
+ stdout.each_line do |line|
+ yield line
+ end
+
+ log_error(stderr.read.color(:red)) unless status_thread.value.success?
+ end
+ end
+
+ def find_command
+ strong_memoize(:find_command) do
+ cmd = %W[find -L #{absolute_artifact_dir}]
+
+ # Search for Job Artifact IDs, they are found 6 directory
+ # levels deep. For example:
+ # shared/artifacts/2c/62/2c...a3/2019_02_27/836/628/job.log
+ # 1 2 3 4 5 6
+ # | | | ^- date | ^- Job Artifact ID
+ # | | | ^- Job ID
+ # ^--+--+- components of hashed storage project path
+ cmd += %w[-mindepth 6 -maxdepth 6]
+
+ # Artifact directories are named on their ID
+ cmd += %w[-type d]
+
+ if ionice
+ raise ArgumentError, 'Invalid niceness' unless niceness.match?(/^\w[\w\-]*$/)
+
+ cmd.unshift(*%W[#{ionice} --class #{niceness}])
+ end
+
+ log_info("find command: '#{cmd.join(' ')}'")
+
+ cmd
+ end
+ end
+
+ def absolute_artifact_dir
+ File.absolute_path(ABSOLUTE_ARTIFACT_DIR)
+ end
+
+ def ionice
+ strong_memoize(:ionice) do
+ Gitlab::Utils.which('ionice')
+ end
+ end
+
+ def log_info(msg, params = {})
+ logger.info("#{'[DRY RUN]' if dry_run} #{msg}")
+ end
+
+ def log_error(msg, params = {})
+ logger.error(msg)
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/cleanup/orphan_job_artifact_files_batch.rb b/lib/gitlab/cleanup/orphan_job_artifact_files_batch.rb
new file mode 100644
index 00000000000..5c30258c0fc
--- /dev/null
+++ b/lib/gitlab/cleanup/orphan_job_artifact_files_batch.rb
@@ -0,0 +1,80 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Cleanup
+ class OrphanJobArtifactFilesBatch
+ BatchFull = Class.new(StandardError)
+
+ class ArtifactFile
+ attr_accessor :path
+
+ def initialize(path)
+ @path = path
+ end
+
+ def artifact_id
+ path.split('/').last.to_i
+ end
+ end
+
+ include Gitlab::Utils::StrongMemoize
+
+ attr_reader :batch_size, :dry_run
+ attr_accessor :artifact_files
+
+ def initialize(batch_size:, dry_run: true, logger: Rails.logger)
+ @batch_size = batch_size
+ @dry_run = dry_run
+ @logger = logger
+ @artifact_files = []
+ end
+
+ def clean!
+ return if artifact_files.empty?
+
+ lost_and_found.each do |artifact|
+ clean_one!(artifact)
+ end
+ end
+
+ def full?
+ artifact_files.count >= batch_size
+ end
+
+ def <<(artifact_path)
+ raise BatchFull, "Batch full! Already contains #{artifact_files.count} artifacts" if full?
+
+ artifact_files << ArtifactFile.new(artifact_path)
+ end
+
+ def lost_and_found
+ strong_memoize(:lost_and_found) do
+ artifact_file_ids = artifact_files.map(&:artifact_id)
+ existing_artifact_ids = ::Ci::JobArtifact.id_in(artifact_file_ids).pluck_primary_key
+
+ artifact_files.reject { |artifact| existing_artifact_ids.include?(artifact.artifact_id) }
+ end
+ end
+
+ private
+
+ def clean_one!(artifact_file)
+ log_debug("Found orphan job artifact file @ #{artifact_file.path}")
+
+ remove_file!(artifact_file) unless dry_run
+ end
+
+ def remove_file!(artifact_file)
+ FileUtils.rm_rf(artifact_file.path)
+ end
+
+ def log_info(msg, params = {})
+ @logger.info("#{'[DRY RUN]' if dry_run} #{msg}")
+ end
+
+ def log_debug(msg, params = {})
+ @logger.debug(msg)
+ end
+ end
+ end
+end
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/database.rb b/lib/gitlab/database.rb
index 8da98cc3909..34c1e6ad8ca 100644
--- a/lib/gitlab/database.rb
+++ b/lib/gitlab/database.rb
@@ -2,6 +2,8 @@
module Gitlab
module Database
+ include Gitlab::Metrics::Methods
+
# The max value of INTEGER type is the same between MySQL and PostgreSQL:
# https://www.postgresql.org/docs/9.2/static/datatype-numeric.html
# http://dev.mysql.com/doc/refman/5.7/en/integer-types.html
@@ -11,6 +13,15 @@ module Gitlab
# https://dev.mysql.com/doc/refman/5.7/en/datetime.html
MAX_TIMESTAMP_VALUE = Time.at((1 << 31) - 1).freeze
+ # Minimum schema version from which migrations are supported
+ # Migrations before this version may have been removed
+ MIN_SCHEMA_VERSION = 20190506135400
+ MIN_SCHEMA_GITLAB_VERSION = '11.11.0'
+
+ define_histogram :gitlab_database_transaction_seconds do
+ docstring "Time spent in database transactions, in seconds"
+ end
+
def self.config
ActiveRecord::Base.configurations[Rails.env]
end
@@ -234,6 +245,7 @@ module Gitlab
def self.connection
ActiveRecord::Base.connection
end
+ private_class_method :connection
def self.cached_column_exists?(table_name, column_name)
connection.schema_cache.columns_hash(table_name).has_key?(column_name.to_s)
@@ -243,8 +255,6 @@ module Gitlab
connection.schema_cache.data_source_exists?(table_name)
end
- private_class_method :connection
-
def self.database_version
row = connection.execute("SELECT VERSION()").first
@@ -272,5 +282,47 @@ module Gitlab
end
end
end
+
+ # inside_transaction? will return true if the caller is running within a transaction. Handles special cases
+ # when running inside a test environment, in which the entire test is running with a DatabaseCleaner transaction
+ def self.inside_transaction?
+ ActiveRecord::Base.connection.open_transactions > open_transactions_baseline
+ end
+
+ def self.open_transactions_baseline
+ if ::Rails.env.test?
+ return DatabaseCleaner.connections.count { |conn| conn.strategy.is_a?(DatabaseCleaner::ActiveRecord::Transaction) }
+ end
+
+ 0
+ end
+ private_class_method :open_transactions_baseline
+
+ # Monkeypatch rails with upgraded database observability
+ def self.install_monkey_patches
+ ActiveRecord::Base.prepend(ActiveRecordBaseTransactionMetrics)
+ end
+
+ # observe_transaction_duration is called from ActiveRecordBaseTransactionMetrics.transaction and used to
+ # record transaction durations.
+ def self.observe_transaction_duration(duration_seconds)
+ labels = Gitlab::Metrics::Transaction.current&.labels || {}
+ gitlab_database_transaction_seconds.observe(labels, duration_seconds)
+ rescue Prometheus::Client::LabelSetValidator::LabelSetError => err
+ # Ensure that errors in recording these metrics don't affect the operation of the application
+ Rails.logger.error("Unable to observe database transaction duration: #{err}")
+ end
+
+ # MonkeyPatch for ActiveRecord::Base for adding observability
+ module ActiveRecordBaseTransactionMetrics
+ # A monkeypatch over ActiveRecord::Base.transaction.
+ # It provides observability into transactional methods.
+ def transaction(options = {}, &block)
+ start_time = Gitlab::Metrics::System.monotonic_time
+ super(options, &block)
+ ensure
+ Gitlab::Database.observe_transaction_duration(Gitlab::Metrics::System.monotonic_time - start_time)
+ end
+ end
end
end
diff --git a/lib/gitlab/database/migration_helpers.rb b/lib/gitlab/database/migration_helpers.rb
index 0b12e862ded..e2cbf91f281 100644
--- a/lib/gitlab/database/migration_helpers.rb
+++ b/lib/gitlab/database/migration_helpers.rb
@@ -434,7 +434,8 @@ module Gitlab
end
begin
- update_column_in_batches(table, column, default, &block)
+ default_after_type_cast = connection.type_cast(default, column_for(table, column))
+ update_column_in_batches(table, column, default_after_type_cast, &block)
change_column_null(table, column, false) unless allow_null
# We want to rescue _all_ exceptions here, even those that don't inherit
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/git/raw_diff_change.rb b/lib/gitlab/git/raw_diff_change.rb
index e1002af40f6..9a41f04a4db 100644
--- a/lib/gitlab/git/raw_diff_change.rb
+++ b/lib/gitlab/git/raw_diff_change.rb
@@ -11,8 +11,8 @@ module Gitlab
if raw_change.is_a?(Gitaly::GetRawChangesResponse::RawChange)
@blob_id = raw_change.blob_id
@blob_size = raw_change.size
- @old_path = raw_change.old_path.presence
- @new_path = raw_change.new_path.presence
+ @old_path = raw_change.old_path_bytes.presence
+ @new_path = raw_change.new_path_bytes.presence
@operation = raw_change.operation&.downcase || :unknown
else
parse(raw_change)
diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb
index a6739f12280..19b6aab1c4f 100644
--- a/lib/gitlab/git/repository.rb
+++ b/lib/gitlab/git/repository.rb
@@ -15,11 +15,6 @@ module Gitlab
SEARCH_CONTEXT_LINES = 3
REV_LIST_COMMIT_LIMIT = 2_000
- # In https://gitlab.com/gitlab-org/gitaly/merge_requests/698
- # We copied these two prefixes into gitaly-go, so don't change these
- # or things will break! (REBASE_WORKTREE_PREFIX and SQUASH_WORKTREE_PREFIX)
- REBASE_WORKTREE_PREFIX = 'rebase'.freeze
- SQUASH_WORKTREE_PREFIX = 'squash'.freeze
GITALY_INTERNAL_URL = 'ssh://gitaly/internal.git'.freeze
GITLAB_PROJECTS_TIMEOUT = Gitlab.config.gitlab_shell.git_timeout
EMPTY_REPOSITORY_CHECKSUM = '0000000000000000000000000000000000000000'.freeze
diff --git a/lib/gitlab/gitaly_client/commit_service.rb b/lib/gitlab/gitaly_client/commit_service.rb
index d21b98d36ea..a80ce462ab0 100644
--- a/lib/gitlab/gitaly_client/commit_service.rb
+++ b/lib/gitlab/gitaly_client/commit_service.rb
@@ -271,26 +271,30 @@ module Gitlab
end
def find_commit(revision)
- if Gitlab::SafeRequestStore.active?
- # We don't use Gitlab::SafeRequestStore.fetch(key) { ... } directly
- # because `revision` can be a branch name, so we can't use it as a key
- # as it could point to another commit later on (happens a lot in
- # tests).
- key = {
- storage: @gitaly_repo.storage_name,
- relative_path: @gitaly_repo.relative_path,
- commit_id: revision
- }
- return Gitlab::SafeRequestStore[key] if Gitlab::SafeRequestStore.exist?(key)
-
- commit = call_find_commit(revision)
- return unless commit
-
- key[:commit_id] = commit.id unless GitalyClient.ref_name_caching_allowed?
+ return call_find_commit(revision) unless Gitlab::SafeRequestStore.active?
+
+ # We don't use Gitlab::SafeRequestStore.fetch(key) { ... } directly
+ # because `revision` can be a branch name, so we can't use it as a key
+ # as it could point to another commit later on (happens a lot in
+ # tests).
+ key = {
+ storage: @gitaly_repo.storage_name,
+ relative_path: @gitaly_repo.relative_path,
+ commit_id: revision
+ }
+ return Gitlab::SafeRequestStore[key] if Gitlab::SafeRequestStore.exist?(key)
+
+ commit = call_find_commit(revision)
+
+ if GitalyClient.ref_name_caching_allowed?
Gitlab::SafeRequestStore[key] = commit
- else
- call_find_commit(revision)
+ return commit
end
+
+ return unless commit
+
+ key[:commit_id] = commit.id
+ Gitlab::SafeRequestStore[key] = commit
end
# rubocop: disable CodeReuse/ActiveRecord
diff --git a/lib/gitlab/gon_helper.rb b/lib/gitlab/gon_helper.rb
index 582c3065189..92917028851 100644
--- a/lib/gitlab/gon_helper.rb
+++ b/lib/gitlab/gon_helper.rb
@@ -16,8 +16,8 @@ module Gitlab
gon.shortcuts_path = Gitlab::Routing.url_helpers.help_page_path('shortcuts')
gon.user_color_scheme = Gitlab::ColorSchemes.for_user(current_user).css_class
- if Gitlab::CurrentSettings.clientside_sentry_enabled
- gon.sentry_dsn = Gitlab::CurrentSettings.clientside_sentry_dsn
+ if Gitlab.config.sentry.enabled
+ gon.sentry_dsn = Gitlab.config.sentry.clientside_dsn
gon.sentry_environment = Gitlab.config.sentry.environment
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/authorize/authorize_resource.rb b/lib/gitlab/graphql/authorize/authorize_resource.rb
index b367a97105c..ef5caaf5b0e 100644
--- a/lib/gitlab/graphql/authorize/authorize_resource.rb
+++ b/lib/gitlab/graphql/authorize/authorize_resource.rb
@@ -27,12 +27,6 @@ module Gitlab
raise NotImplementedError, "Implement #find_object in #{self.class.name}"
end
- def authorized_find(*args)
- object = find_object(*args)
-
- object if authorized?(object)
- end
-
def authorized_find!(*args)
object = find_object(*args)
authorize!(object)
@@ -48,6 +42,12 @@ module Gitlab
end
def authorized?(object)
+ # Sanity check. We don't want to accidentally allow a developer to authorize
+ # without first adding permissions to authorize against
+ if self.class.required_permissions.empty?
+ raise Gitlab::Graphql::Errors::ArgumentError, "#{self.class.name} has no authorizations"
+ end
+
self.class.required_permissions.all? do |ability|
# The actions could be performed across multiple objects. In which
# case the current user is common, and we could benefit from the
diff --git a/lib/gitlab/graphql/copy_field_description.rb b/lib/gitlab/graphql/copy_field_description.rb
new file mode 100644
index 00000000000..edd73083ff2
--- /dev/null
+++ b/lib/gitlab/graphql/copy_field_description.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Graphql
+ module CopyFieldDescription
+ extend ActiveSupport::Concern
+
+ class_methods do
+ # Returns the `description` for property of field `field_name` on type.
+ # This can be used to ensure, for example, that mutation argument descriptions
+ # are always identical to the corresponding query field descriptions.
+ #
+ # E.g.:
+ # argument :name, GraphQL::STRING_TYPE, description: copy_field_description(Types::UserType, :name)
+ def copy_field_description(type, field_name)
+ type.fields[field_name.to_s.camelize(:lower)].description
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/graphql/errors.rb b/lib/gitlab/graphql/errors.rb
index fe74549e322..40b90310e8b 100644
--- a/lib/gitlab/graphql/errors.rb
+++ b/lib/gitlab/graphql/errors.rb
@@ -6,6 +6,7 @@ module Gitlab
BaseError = Class.new(GraphQL::ExecutionError)
ArgumentError = Class.new(BaseError)
ResourceNotAvailable = Class.new(BaseError)
+ MutationError = Class.new(BaseError)
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/loaders/pipeline_for_sha_loader.rb b/lib/gitlab/graphql/loaders/pipeline_for_sha_loader.rb
new file mode 100644
index 00000000000..81c5cabf451
--- /dev/null
+++ b/lib/gitlab/graphql/loaders/pipeline_for_sha_loader.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Graphql
+ module Loaders
+ class PipelineForShaLoader
+ attr_accessor :project, :sha
+
+ def initialize(project, sha)
+ @project, @sha = project, sha
+ end
+
+ def find_last
+ BatchLoader.for(sha).batch(key: project) do |shas, loader, args|
+ pipelines = args[:key].ci_pipelines.latest_for_shas(shas)
+
+ pipelines.each do |pipeline|
+ loader.call(pipeline.sha, pipeline)
+ end
+ end
+ end
+ end
+ end
+ end
+end
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/json_cache.rb b/lib/gitlab/json_cache.rb
index d01183d7845..84c6817f3c7 100644
--- a/lib/gitlab/json_cache.rb
+++ b/lib/gitlab/json_cache.rb
@@ -34,7 +34,7 @@ module Gitlab
def read(key, klass = nil)
value = backend.read(cache_key(key))
- value = parse_value(value, klass) if value
+ value = parse_value(value, klass) unless value.nil?
value
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/lets_encrypt.rb b/lib/gitlab/lets_encrypt.rb
new file mode 100644
index 00000000000..cdf24f24647
--- /dev/null
+++ b/lib/gitlab/lets_encrypt.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module LetsEncrypt
+ def self.enabled?(pages_domain = nil)
+ return false unless Gitlab::CurrentSettings.lets_encrypt_terms_of_service_accepted
+
+ return false unless Feature.enabled?(:pages_auto_ssl)
+
+ # If no domain is passed, just check whether we're enabled globally
+ return true unless pages_domain
+
+ !!pages_domain.project && Feature.enabled?(:pages_auto_ssl_for_project, pages_domain.project)
+ end
+ end
+end
diff --git a/lib/gitlab/lets_encrypt/client.rb b/lib/gitlab/lets_encrypt/client.rb
index 66aea137012..ad2921ed555 100644
--- a/lib/gitlab/lets_encrypt/client.rb
+++ b/lib/gitlab/lets_encrypt/client.rb
@@ -34,14 +34,6 @@ module Gitlab
acme_client.terms_of_service
end
- def enabled?
- return false unless Feature.enabled?(:pages_auto_ssl)
-
- return false unless private_key
-
- Gitlab::CurrentSettings.lets_encrypt_terms_of_service_accepted
- end
-
private
def acme_client
@@ -65,7 +57,7 @@ module Gitlab
end
def ensure_account
- raise 'Acme integration is disabled' unless enabled?
+ raise 'Acme integration is disabled' unless ::Gitlab::LetsEncrypt.enabled?
@acme_account ||= acme_client.new_account(contact: contact, terms_of_service_agreed: true)
end
diff --git a/lib/gitlab/metrics/dashboard/base_service.rb b/lib/gitlab/metrics/dashboard/base_service.rb
index 90895eb237a..0628e82e592 100644
--- a/lib/gitlab/metrics/dashboard/base_service.rb
+++ b/lib/gitlab/metrics/dashboard/base_service.rb
@@ -10,6 +10,8 @@ module Gitlab
NOT_FOUND_ERROR = Gitlab::Template::Finders::RepoTemplateFinder::FileNotFoundError
def get_dashboard
+ return error('Insufficient permissions.', :unauthorized) unless allowed?
+
success(dashboard: process_dashboard)
rescue NOT_FOUND_ERROR
error("#{dashboard_path} could not be found.", :not_found)
@@ -30,6 +32,12 @@ module Gitlab
private
+ # Determines whether users should be able to view
+ # dashboards at all.
+ def allowed?
+ Ability.allowed?(current_user, :read_environment, project)
+ end
+
# Returns a new dashboard Hash, supplemented with DB info
def process_dashboard
Gitlab::Metrics::Dashboard::Processor
diff --git a/lib/gitlab/metrics/system.rb b/lib/gitlab/metrics/system.rb
index 33c0de91c11..34de40ca72f 100644
--- a/lib/gitlab/metrics/system.rb
+++ b/lib/gitlab/metrics/system.rb
@@ -57,17 +57,9 @@ module Gitlab
end
end
- # THREAD_CPUTIME is not supported on OS X
- if Process.const_defined?(:CLOCK_THREAD_CPUTIME_ID)
- def self.cpu_time
- Process
- .clock_gettime(Process::CLOCK_THREAD_CPUTIME_ID, :float_second)
- end
- else
- def self.cpu_time
- Process
- .clock_gettime(Process::CLOCK_PROCESS_CPUTIME_ID, :float_second)
- end
+ def self.cpu_time
+ Process
+ .clock_gettime(Process::CLOCK_PROCESS_CPUTIME_ID, :float_second)
end
# Returns the current real time in a given precision.
diff --git a/lib/gitlab/optimistic_locking.rb b/lib/gitlab/optimistic_locking.rb
index 868b2ae641a..0c0f46d3b77 100644
--- a/lib/gitlab/optimistic_locking.rb
+++ b/lib/gitlab/optimistic_locking.rb
@@ -5,6 +5,7 @@ module Gitlab
module_function
def retry_lock(subject, retries = 100, &block)
+ # TODO(Observability): We should be recording details of the number of retries and the duration of the total execution here
ActiveRecord::Base.transaction do
yield(subject)
end
diff --git a/lib/gitlab/path_regex.rb b/lib/gitlab/path_regex.rb
index a07b1246bee..a13b3f9e069 100644
--- a/lib/gitlab/path_regex.rb
+++ b/lib/gitlab/path_regex.rb
@@ -53,7 +53,6 @@ module Gitlab
sent_notifications
slash-command-logo.png
snippets
- u
unsubscribes
uploads
users
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/search/found_blob.rb b/lib/gitlab/search/found_blob.rb
index 01ce90c85f7..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 does not have project object (e.g. elastic search),
+ # 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/sentry.rb b/lib/gitlab/sentry.rb
index 72c44114001..764db14d720 100644
--- a/lib/gitlab/sentry.rb
+++ b/lib/gitlab/sentry.rb
@@ -4,7 +4,7 @@ module Gitlab
module Sentry
def self.enabled?
(Rails.env.production? || Rails.env.development?) &&
- Gitlab::CurrentSettings.sentry_enabled?
+ Gitlab.config.sentry.enabled
end
def self.context(current_user = nil)
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/time_tracking_formatter.rb b/lib/gitlab/time_tracking_formatter.rb
index cc206010e74..302da91328a 100644
--- a/lib/gitlab/time_tracking_formatter.rb
+++ b/lib/gitlab/time_tracking_formatter.rb
@@ -6,7 +6,7 @@ module Gitlab
def parse(string)
with_custom_config do
- string.sub!(/\A-/, '')
+ string = string.sub(/\A-/, '')
seconds = ChronicDuration.parse(string, default_unit: 'hours') rescue nil
seconds *= -1 if seconds && Regexp.last_match
@@ -16,10 +16,12 @@ module Gitlab
def output(seconds)
with_custom_config do
- ChronicDuration.output(seconds, format: :short, limit_to_hours: false, weeks: true) rescue nil
+ ChronicDuration.output(seconds, format: :short, limit_to_hours: limit_to_hours_setting, weeks: true) rescue nil
end
end
+ private
+
def with_custom_config
# We may want to configure it through project settings in a future version.
ChronicDuration.hours_per_day = 8
@@ -32,5 +34,9 @@ module Gitlab
result
end
+
+ def limit_to_hours_setting
+ Gitlab::CurrentSettings.time_tracking_limit_to_hours
+ 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..ad3c3c9fe01
--- /dev/null
+++ b/lib/peek/views/redis.rb
@@ -0,0 +1,82 @@
+# 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
+ 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)
+ # Scrub out the value of the SET calls to avoid binary
+ # data or large data from spilling into the view
+ if cmd.length >= 2 && cmd.first =~ /set/i
+ cmd[-1] = "<redacted>"
+ 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/gitlab/backup.rake b/lib/tasks/gitlab/backup.rake
index c531eb1d216..2bf71701b57 100644
--- a/lib/tasks/gitlab/backup.rake
+++ b/lib/tasks/gitlab/backup.rake
@@ -21,10 +21,10 @@ namespace :gitlab do
backup.cleanup
backup.remove_old
- puts "Warning: Your gitlab.rb and gitlab-secrets.json files contain sensitive data \n" \
+ progress.puts "Warning: Your gitlab.rb and gitlab-secrets.json files contain sensitive data \n" \
"and are not included in this backup. You will need these files to restore a backup.\n" \
"Please back them up manually.".color(:red)
- puts "Backup task is done."
+ progress.puts "Backup task is done."
end
# Restore backup of GitLab system
diff --git a/lib/tasks/gitlab/cleanup.rake b/lib/tasks/gitlab/cleanup.rake
index 760331620ef..105ef417df3 100644
--- a/lib/tasks/gitlab/cleanup.rake
+++ b/lib/tasks/gitlab/cleanup.rake
@@ -115,6 +115,18 @@ namespace :gitlab do
end
end
+ desc 'GitLab | Cleanup | Clean orphan job artifact files'
+ task orphan_job_artifact_files: :gitlab_environment do
+ warn_user_is_not_gitlab
+
+ cleaner = Gitlab::Cleanup::OrphanJobArtifactFiles.new(limit: limit, dry_run: dry_run?, niceness: niceness, logger: logger)
+ cleaner.run!
+
+ if dry_run?
+ logger.info "To clean up these files run this command with DRY_RUN=false".color(:yellow)
+ end
+ end
+
def remove?
ENV['REMOVE'] == 'true'
end
@@ -123,12 +135,25 @@ namespace :gitlab do
ENV['DRY_RUN'] != 'false'
end
+ def debug?
+ ENV['DEBUG'].present?
+ end
+
+ def limit
+ ENV['LIMIT']&.to_i
+ end
+
+ def niceness
+ ENV['NICENESS'].presence
+ end
+
def logger
return @logger if defined?(@logger)
@logger = if Rails.env.development? || Rails.env.production?
Logger.new(STDOUT).tap do |stdout_logger|
stdout_logger.extend(ActiveSupport::Logger.broadcast(Rails.logger))
+ stdout_logger.level = debug? ? Logger::DEBUG : Logger::INFO
end
else
Rails.logger
diff --git a/lib/tasks/migrate/schema_check.rake b/lib/tasks/migrate/schema_check.rake
new file mode 100644
index 00000000000..76f1f23c7bd
--- /dev/null
+++ b/lib/tasks/migrate/schema_check.rake
@@ -0,0 +1,20 @@
+# frozen_string_literal: true
+
+# Configures the database by running migrate, or by loading the schema and seeding if needed
+task schema_version_check: :environment do
+ next if ENV['SKIP_SCHEMA_VERSION_CHECK']
+
+ schema_version = ActiveRecord::Migrator.current_version
+
+ # Ensure migrations are being run from a supported schema version
+ # A schema verison of 0 is a fresh db, and should be safe to run migrations
+ # But a database with existing migrations less than our min version is not
+ if schema_version > 0 && schema_version < Gitlab::Database::MIN_SCHEMA_VERSION
+ raise "Your current database version is too old to be migrated. " \
+ "You should upgrade to GitLab #{Gitlab::Database::MIN_SCHEMA_GITLAB_VERSION} before moving to this version. " \
+ "Please see https://docs.gitlab.com/ee/policy/maintenance.html#upgrade-recommendations"
+ end
+end
+
+# Ensure the check is a pre-requisite when running db:migrate
+Rake::Task["db:migrate"].enhance [:schema_version_check]
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/ar_SA/gitlab.po b/locale/ar_SA/gitlab.po
index 1b561621f6f..7ccdfa282e8 100644
--- a/locale/ar_SA/gitlab.po
+++ b/locale/ar_SA/gitlab.po
@@ -7581,13 +7581,13 @@ msgstr ""
msgid "JiraService|If different from Web URL"
msgstr ""
-msgid "JiraService|JIRA API URL"
+msgid "JiraService|Jira API URL"
msgstr ""
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a commit."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a commit."
msgstr ""
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a merge request."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a merge request."
msgstr ""
msgid "JiraService|Jira issue tracker"
diff --git a/locale/bg/gitlab.po b/locale/bg/gitlab.po
index 4d72599f5a3..9e24b950cdd 100644
--- a/locale/bg/gitlab.po
+++ b/locale/bg/gitlab.po
@@ -7373,13 +7373,13 @@ msgstr ""
msgid "JiraService|If different from Web URL"
msgstr ""
-msgid "JiraService|JIRA API URL"
+msgid "JiraService|Jira API URL"
msgstr ""
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a commit."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a commit."
msgstr ""
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a merge request."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a merge request."
msgstr ""
msgid "JiraService|Jira issue tracker"
diff --git a/locale/bn_BD/gitlab.po b/locale/bn_BD/gitlab.po
index c1b139055cc..c7c0695b580 100644
--- a/locale/bn_BD/gitlab.po
+++ b/locale/bn_BD/gitlab.po
@@ -7373,13 +7373,13 @@ msgstr ""
msgid "JiraService|If different from Web URL"
msgstr ""
-msgid "JiraService|JIRA API URL"
+msgid "JiraService|Jira API URL"
msgstr ""
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a commit."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a commit."
msgstr ""
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a merge request."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a merge request."
msgstr ""
msgid "JiraService|Jira issue tracker"
diff --git a/locale/bn_IN/gitlab.po b/locale/bn_IN/gitlab.po
index 8c3512497e7..56c5a3b3704 100644
--- a/locale/bn_IN/gitlab.po
+++ b/locale/bn_IN/gitlab.po
@@ -7373,13 +7373,13 @@ msgstr ""
msgid "JiraService|If different from Web URL"
msgstr ""
-msgid "JiraService|JIRA API URL"
+msgid "JiraService|Jira API URL"
msgstr ""
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a commit."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a commit."
msgstr ""
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a merge request."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a merge request."
msgstr ""
msgid "JiraService|Jira issue tracker"
diff --git a/locale/ca_ES/gitlab.po b/locale/ca_ES/gitlab.po
index 69c1971701f..c0b4aea4a99 100644
--- a/locale/ca_ES/gitlab.po
+++ b/locale/ca_ES/gitlab.po
@@ -7373,13 +7373,13 @@ msgstr ""
msgid "JiraService|If different from Web URL"
msgstr ""
-msgid "JiraService|JIRA API URL"
+msgid "JiraService|Jira API URL"
msgstr ""
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a commit."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a commit."
msgstr ""
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a merge request."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a merge request."
msgstr ""
msgid "JiraService|Jira issue tracker"
diff --git a/locale/cs_CZ/gitlab.po b/locale/cs_CZ/gitlab.po
index 2e072b2a16e..1184a326ede 100644
--- a/locale/cs_CZ/gitlab.po
+++ b/locale/cs_CZ/gitlab.po
@@ -7477,13 +7477,13 @@ msgstr ""
msgid "JiraService|If different from Web URL"
msgstr ""
-msgid "JiraService|JIRA API URL"
+msgid "JiraService|Jira API URL"
msgstr ""
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a commit."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a commit."
msgstr ""
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a merge request."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a merge request."
msgstr ""
msgid "JiraService|Jira issue tracker"
diff --git a/locale/cy_GB/gitlab.po b/locale/cy_GB/gitlab.po
index 24ab2e96c78..019dcd25e72 100644
--- a/locale/cy_GB/gitlab.po
+++ b/locale/cy_GB/gitlab.po
@@ -7581,13 +7581,13 @@ msgstr ""
msgid "JiraService|If different from Web URL"
msgstr ""
-msgid "JiraService|JIRA API URL"
+msgid "JiraService|Jira API URL"
msgstr ""
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a commit."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a commit."
msgstr ""
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a merge request."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a merge request."
msgstr ""
msgid "JiraService|Jira issue tracker"
diff --git a/locale/da_DK/gitlab.po b/locale/da_DK/gitlab.po
index bada56b442a..f30fbc0806c 100644
--- a/locale/da_DK/gitlab.po
+++ b/locale/da_DK/gitlab.po
@@ -7373,13 +7373,13 @@ msgstr ""
msgid "JiraService|If different from Web URL"
msgstr ""
-msgid "JiraService|JIRA API URL"
+msgid "JiraService|Jira API URL"
msgstr ""
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a commit."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a commit."
msgstr ""
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a merge request."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a merge request."
msgstr ""
msgid "JiraService|Jira issue tracker"
diff --git a/locale/de/gitlab.po b/locale/de/gitlab.po
index daf877d3cff..7faeed34e59 100644
--- a/locale/de/gitlab.po
+++ b/locale/de/gitlab.po
@@ -7373,13 +7373,13 @@ msgstr ""
msgid "JiraService|If different from Web URL"
msgstr ""
-msgid "JiraService|JIRA API URL"
+msgid "JiraService|Jira API URL"
msgstr ""
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a commit."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a commit."
msgstr ""
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a merge request."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a merge request."
msgstr ""
msgid "JiraService|Jira issue tracker"
diff --git a/locale/el_GR/gitlab.po b/locale/el_GR/gitlab.po
index f2d8321020c..2ac09933c10 100644
--- a/locale/el_GR/gitlab.po
+++ b/locale/el_GR/gitlab.po
@@ -7373,13 +7373,13 @@ msgstr ""
msgid "JiraService|If different from Web URL"
msgstr ""
-msgid "JiraService|JIRA API URL"
+msgid "JiraService|Jira API URL"
msgstr ""
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a commit."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a commit."
msgstr ""
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a merge request."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a merge request."
msgstr ""
msgid "JiraService|Jira issue tracker"
diff --git a/locale/eo/gitlab.po b/locale/eo/gitlab.po
index 7960be28abd..df88e81f3d3 100644
--- a/locale/eo/gitlab.po
+++ b/locale/eo/gitlab.po
@@ -7373,13 +7373,13 @@ msgstr ""
msgid "JiraService|If different from Web URL"
msgstr ""
-msgid "JiraService|JIRA API URL"
+msgid "JiraService|Jira API URL"
msgstr ""
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a commit."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a commit."
msgstr ""
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a merge request."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a merge request."
msgstr ""
msgid "JiraService|Jira issue tracker"
diff --git a/locale/es/gitlab.po b/locale/es/gitlab.po
index ca2c3450b4d..616ef854a7d 100644
--- a/locale/es/gitlab.po
+++ b/locale/es/gitlab.po
@@ -7373,13 +7373,13 @@ msgstr "Los eventos para %{noteable_model_name} están deshabilitados."
msgid "JiraService|If different from Web URL"
msgstr "Si es diferente de la URL Web"
-msgid "JiraService|JIRA API URL"
+msgid "JiraService|Jira API URL"
msgstr "URL del API de JIRA"
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a commit."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a commit."
msgstr "Los comentarios de JIRA se crearán cuando se haga referencia a una incidencia en un commit."
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a merge request."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a merge request."
msgstr "Los comentarios de JIRA se crearán cuando se haga referencia a una incidencia en un commit."
msgid "JiraService|Jira issue tracker"
diff --git a/locale/et_EE/gitlab.po b/locale/et_EE/gitlab.po
index f1ed6ff3630..c7473191a42 100644
--- a/locale/et_EE/gitlab.po
+++ b/locale/et_EE/gitlab.po
@@ -7373,13 +7373,13 @@ msgstr ""
msgid "JiraService|If different from Web URL"
msgstr ""
-msgid "JiraService|JIRA API URL"
+msgid "JiraService|Jira API URL"
msgstr ""
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a commit."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a commit."
msgstr ""
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a merge request."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a merge request."
msgstr ""
msgid "JiraService|Jira issue tracker"
diff --git a/locale/fil_PH/gitlab.po b/locale/fil_PH/gitlab.po
index 30b0e53ea19..be757241241 100644
--- a/locale/fil_PH/gitlab.po
+++ b/locale/fil_PH/gitlab.po
@@ -7373,13 +7373,13 @@ msgstr ""
msgid "JiraService|If different from Web URL"
msgstr ""
-msgid "JiraService|JIRA API URL"
+msgid "JiraService|Jira API URL"
msgstr ""
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a commit."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a commit."
msgstr ""
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a merge request."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a merge request."
msgstr ""
msgid "JiraService|Jira issue tracker"
diff --git a/locale/fr/gitlab.po b/locale/fr/gitlab.po
index 12edcf96cff..9b938ee38e6 100644
--- a/locale/fr/gitlab.po
+++ b/locale/fr/gitlab.po
@@ -7373,13 +7373,13 @@ msgstr ""
msgid "JiraService|If different from Web URL"
msgstr ""
-msgid "JiraService|JIRA API URL"
+msgid "JiraService|Jira API URL"
msgstr ""
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a commit."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a commit."
msgstr ""
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a merge request."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a merge request."
msgstr ""
msgid "JiraService|Jira issue tracker"
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index aa6f5dd8bc7..63923eb39dd 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -16,6 +16,9 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
+msgid " (from %{timeoutSource})"
+msgstr ""
+
msgid " Please sign in."
msgstr ""
@@ -38,6 +41,11 @@ msgid_plural "%d commits behind"
msgstr[0] ""
msgstr[1] ""
+msgid "%d commit,"
+msgid_plural "%d commits,"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d commits"
msgstr ""
@@ -223,6 +231,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] ""
@@ -243,6 +254,9 @@ msgstr ""
msgid "%{user_name} profile page"
msgstr ""
+msgid "%{username}'s avatar"
+msgstr ""
+
msgid "%{verb} %{time_spent_value} spent time."
msgstr ""
@@ -337,9 +351,6 @@ msgstr ""
msgid "2FA"
msgstr ""
-msgid "2FA enabled"
-msgstr ""
-
msgid "2FADevice|Registered On"
msgstr ""
@@ -388,6 +399,9 @@ msgstr ""
msgid "<no name set>"
msgstr ""
+msgid "<no scopes selected>"
+msgstr ""
+
msgid "<strong>%{changedFilesLength} unstaged</strong> and <strong>%{stagedFilesLength} staged</strong> changes"
msgstr ""
@@ -499,6 +513,54 @@ msgstr ""
msgid "Access to '%{classification_label}' not allowed"
msgstr ""
+msgid "AccessTokens|Access Tokens"
+msgstr ""
+
+msgid "AccessTokens|Are you sure? Any RSS or calendar URLs currently in use will stop working."
+msgstr ""
+
+msgid "AccessTokens|Are you sure? Any issue email addresses currently in use will stop working."
+msgstr ""
+
+msgid "AccessTokens|Created"
+msgstr ""
+
+msgid "AccessTokens|Feed token"
+msgstr ""
+
+msgid "AccessTokens|Incoming email token"
+msgstr ""
+
+msgid "AccessTokens|It cannot be used to access any other data."
+msgstr ""
+
+msgid "AccessTokens|Keep this token secret. Anyone who gets ahold of it can create issues as if they were you. You should %{link_reset_it} if that ever happens."
+msgstr ""
+
+msgid "AccessTokens|Keep this token secret. Anyone who gets ahold of it can read activity and issue RSS feeds or your calendar feed as if they were you. You should %{link_reset_it} if that ever happens."
+msgstr ""
+
+msgid "AccessTokens|Personal Access Tokens"
+msgstr ""
+
+msgid "AccessTokens|They are the only accepted password when you have Two-Factor Authentication (2FA) enabled."
+msgstr ""
+
+msgid "AccessTokens|You can also use personal access tokens to authenticate against Git over HTTP."
+msgstr ""
+
+msgid "AccessTokens|You can generate a personal access token for each application you use that needs access to the GitLab API."
+msgstr ""
+
+msgid "AccessTokens|Your feed token is used to authenticate you when your RSS reader loads a personalized RSS feed or when your calendar application loads a personalized calendar, and is included in those feed URLs."
+msgstr ""
+
+msgid "AccessTokens|Your incoming email token is used to authenticate you when you create a new issue by email, and is included in your personal project-specific email addresses."
+msgstr ""
+
+msgid "AccessTokens|reset it"
+msgstr ""
+
msgid "Account"
msgstr ""
@@ -511,12 +573,20 @@ msgstr ""
msgid "Active"
msgstr ""
+msgid "Active %{type} Tokens (%{token_length})"
+msgstr ""
+
msgid "Active Sessions"
msgstr ""
msgid "Activity"
msgstr ""
+msgid "Add %d issue"
+msgid_plural "Add %d issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "Add CHANGELOG"
msgstr ""
@@ -529,9 +599,15 @@ msgstr ""
msgid "Add README"
msgstr ""
+msgid "Add a %{type} token"
+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 ""
@@ -577,6 +653,9 @@ msgstr ""
msgid "Add image comment"
msgstr ""
+msgid "Add issues"
+msgstr ""
+
msgid "Add italic text"
msgstr ""
@@ -1003,6 +1082,9 @@ msgstr ""
msgid "An error occurred. Please try again."
msgstr ""
+msgid "An issue can be a bug, a todo or a feature request that needs to be discussed in a project. Besides, issues are searchable and filterable."
+msgstr ""
+
msgid "Anonymous"
msgstr ""
@@ -1153,6 +1235,9 @@ msgstr ""
msgid "Are you sure you want to reset the health check token?"
msgstr ""
+msgid "Are you sure you want to revoke this %{type} Token? This action cannot be undone."
+msgstr ""
+
msgid "Are you sure you want to revoke this nickname?"
msgstr ""
@@ -1509,9 +1594,27 @@ msgstr ""
msgid "Blog"
msgstr ""
+msgid "BoardBlankState|Add default lists"
+msgstr ""
+
+msgid "BoardBlankState|Add the following default lists to your Issue Board with one click:"
+msgstr ""
+
+msgid "BoardBlankState|Nevermind, I'll use my own"
+msgstr ""
+
+msgid "BoardBlankState|Starting out with the default set of lists will get you right on the way to making the most of your board."
+msgstr ""
+
msgid "Boards"
msgstr ""
+msgid "Boards|Collapse"
+msgstr ""
+
+msgid "Boards|Expand"
+msgstr ""
+
msgid "Branch %{branchName} was not found in this project's repository."
msgstr ""
@@ -1770,6 +1873,9 @@ msgstr ""
msgid "Cancel"
msgstr ""
+msgid "Cancel running"
+msgstr ""
+
msgid "Cancel this job"
msgstr ""
@@ -1920,9 +2026,6 @@ msgstr ""
msgid "Choose visibility level, enable/disable project features (issues, repository, wiki, snippets) and set permissions."
msgstr ""
-msgid "Choose your merge method, options, checks, and set up a default merge request description template."
-msgstr ""
-
msgid "CiStatusLabel|canceled"
msgstr ""
@@ -2052,12 +2155,18 @@ msgstr ""
msgid "Clear"
msgstr ""
+msgid "Clear recent searches"
+msgstr ""
+
msgid "Clear search"
msgstr ""
msgid "Clear search input"
msgstr ""
+msgid "Clear templates search input"
+msgstr ""
+
msgid "Click any <strong>project name</strong> in the project list below to navigate to the project milestone."
msgstr ""
@@ -2106,6 +2215,9 @@ msgstr ""
msgid "Close"
msgstr ""
+msgid "Close %{tabname}"
+msgstr ""
+
msgid "Close milestone"
msgstr ""
@@ -2163,6 +2275,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 ""
@@ -2655,10 +2770,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"
@@ -2783,9 +2898,15 @@ msgstr ""
msgid "Configure Let's Encrypt"
msgstr ""
+msgid "Configure Prometheus"
+msgstr ""
+
msgid "Configure automatic git checks and housekeeping on repositories."
msgstr ""
+msgid "Configure existing installation"
+msgstr ""
+
msgid "Configure limits for web and API requests."
msgstr ""
@@ -2825,25 +2946,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}:"
+msgid "ContainerRegistry|Container Registry"
msgstr ""
-msgid "ContainerRegistry|GitLab supports up to 3 levels of image names. The following examples of images are valid for your project:"
-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"
@@ -2864,10 +2979,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."
@@ -2876,7 +2997,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"
@@ -2972,6 +3093,9 @@ msgstr ""
msgid "Copy link"
msgstr ""
+msgid "Copy personal access token to clipboard"
+msgstr ""
+
msgid "Copy reference to clipboard"
msgstr ""
@@ -3020,6 +3144,9 @@ msgstr ""
msgid "Create"
msgstr ""
+msgid "Create %{type} token"
+msgstr ""
+
msgid "Create New Directory"
msgstr ""
@@ -3140,6 +3267,9 @@ msgstr ""
msgid "Creates branch '%{branch_name}' and a merge request to resolve this issue"
msgstr ""
+msgid "Creating graphs uses the data from the Prometheus server. If this takes a long time, ensure that data is available."
+msgstr ""
+
msgid "Cron Timezone"
msgstr ""
@@ -3358,6 +3488,9 @@ msgstr ""
msgid "Deploy key was successfully updated."
msgstr ""
+msgid "Deploy to..."
+msgstr ""
+
msgid "DeployKeys|+%{count} others"
msgstr ""
@@ -3430,6 +3563,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 ""
@@ -3496,6 +3632,9 @@ msgstr ""
msgid "Description:"
msgstr ""
+msgid "Deselect all"
+msgstr ""
+
msgid "Destroy"
msgstr ""
@@ -3511,6 +3650,9 @@ msgstr ""
msgid "Diff limits"
msgstr ""
+msgid "DiffsCompareBaseBranch|(base)"
+msgstr ""
+
msgid "Diffs|No file name available"
msgstr ""
@@ -3595,6 +3737,9 @@ msgstr ""
msgid "Dockerfile"
msgstr ""
+msgid "Doing"
+msgstr ""
+
msgid "Domain"
msgstr ""
@@ -3778,12 +3923,15 @@ msgstr ""
msgid "Enable HTML emails"
msgstr ""
-msgid "Enable Sentry for error reporting and logging."
+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 ""
@@ -3796,6 +3944,9 @@ msgstr ""
msgid "Enable error tracking"
msgstr ""
+msgid "Enable feature to choose access level"
+msgstr ""
+
msgid "Enable for this project"
msgstr ""
@@ -4000,9 +4151,6 @@ msgstr ""
msgid "Error"
msgstr ""
-msgid "Error Reporting and Logging"
-msgstr ""
-
msgid "Error Tracking"
msgstr ""
@@ -4015,6 +4163,9 @@ msgstr ""
msgid "Error fetching contributors data."
msgstr ""
+msgid "Error fetching diverging counts for branches. Please try again."
+msgstr ""
+
msgid "Error fetching labels."
msgstr ""
@@ -4087,6 +4238,9 @@ msgstr ""
msgid "Error saving label update."
msgstr ""
+msgid "Error setting up editor. Please try again."
+msgstr ""
+
msgid "Error updating %{issuableType}"
msgstr ""
@@ -4186,6 +4340,9 @@ msgstr ""
msgid "Everyone"
msgstr ""
+msgid "Everyone With Access"
+msgstr ""
+
msgid "Everyone can contribute"
msgstr ""
@@ -4228,6 +4385,12 @@ msgstr ""
msgid "Expired %{expiredOn}"
msgstr ""
+msgid "Expires"
+msgstr ""
+
+msgid "Expires at"
+msgstr ""
+
msgid "Expires in %{expires_at}"
msgstr ""
@@ -4653,6 +4816,9 @@ msgstr ""
msgid "Get started with error tracking"
msgstr ""
+msgid "Get started with performance monitoring"
+msgstr ""
+
msgid "Getting started with releases"
msgstr ""
@@ -4740,6 +4906,9 @@ msgstr ""
msgid "Go back"
msgstr ""
+msgid "Go back to %{startTag}Open issues%{endTag} and select some issues to add to your board."
+msgstr ""
+
msgid "Go full screen"
msgstr ""
@@ -4773,6 +4942,9 @@ msgstr ""
msgid "Got it!"
msgstr ""
+msgid "Grafana URL"
+msgstr ""
+
msgid "Grant access"
msgstr ""
@@ -4998,6 +5170,9 @@ msgstr ""
msgid "Help page text and support page url."
msgstr ""
+msgid "Helps prevent bots from creating accounts. We currently only support %{recaptcha_v2_link_start}reCAPTCHA v2%{recaptcha_v2_link_end}"
+msgstr ""
+
msgid "Hide archived projects"
msgstr ""
@@ -5330,6 +5505,9 @@ msgstr ""
msgid "Install a soft token authenticator like %{free_otp_link} or Google Authenticator from your application repository and scan this QR code. More information is available in the %{help_link_start}documentation%{help_link_end}."
msgstr ""
+msgid "Install on clusters"
+msgstr ""
+
msgid "Installed"
msgstr ""
@@ -5420,6 +5598,9 @@ msgstr ""
msgid "Invite member"
msgstr ""
+msgid "Invocations"
+msgstr ""
+
msgid "Invoke Count"
msgstr ""
@@ -5447,6 +5628,24 @@ msgstr ""
msgid "IssueBoards|Board"
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 ""
@@ -5477,13 +5676,13 @@ msgstr ""
msgid "JiraService|If different from Web URL"
msgstr ""
-msgid "JiraService|JIRA API URL"
+msgid "JiraService|Jira API URL"
msgstr ""
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a commit."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a commit."
msgstr ""
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a merge request."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a merge request."
msgstr ""
msgid "JiraService|Jira issue tracker"
@@ -5836,6 +6035,9 @@ msgstr ""
msgid "Let's Encrypt is a free, automated, and open certificate authority (CA) that gives digital certificates in order to enable HTTPS (SSL/TLS) for websites. Learn more about Let's Encrypt configuration by following the %{docs_link_start}documentation on GitLab Pages%{docs_link_end}."
msgstr ""
+msgid "Limit display of time tracking units to hours."
+msgstr ""
+
msgid "Limited to showing %d event at most"
msgid_plural "Limited to showing %d events at most"
msgstr[0] ""
@@ -5871,6 +6073,9 @@ msgstr ""
msgid "Loading functions timed out. Please reload the page to try again."
msgstr ""
+msgid "Loading issues"
+msgstr ""
+
msgid "Loading the GitLab IDE..."
msgstr ""
@@ -5904,6 +6109,9 @@ msgstr ""
msgid "Locked"
msgstr ""
+msgid "Locked by %{fileLockUserName}"
+msgstr ""
+
msgid "Locked to current projects"
msgstr ""
@@ -5928,6 +6136,9 @@ msgstr ""
msgid "Make issue confidential."
msgstr ""
+msgid "Make sure you save it - you won't be able to access it again."
+msgstr ""
+
msgid "Make sure you're logged into the account that owns the projects you'd like to import."
msgstr ""
@@ -5976,6 +6187,9 @@ msgstr ""
msgid "Manual job"
msgstr ""
+msgid "ManualOrdering|Couldn't save the order of the issues"
+msgstr ""
+
msgid "Map a FogBugz account ID to a GitLab user"
msgstr ""
@@ -6129,7 +6343,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"
@@ -6150,19 +6364,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}"
@@ -6192,12 +6406,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 ""
@@ -6545,6 +6765,9 @@ msgstr ""
msgid "No"
msgstr ""
+msgid "No %{header} for this request."
+msgstr ""
+
msgid "No %{providerTitle} repositories available to import"
msgstr ""
@@ -6575,15 +6798,15 @@ 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 ""
msgid "No contributions were found"
msgstr ""
+msgid "No data found"
+msgstr ""
+
msgid "No details available"
msgstr ""
@@ -6647,6 +6870,9 @@ msgstr ""
msgid "No schedules"
msgstr ""
+msgid "No template"
+msgstr ""
+
msgid "No, directly import the existing email addresses and usernames."
msgstr ""
@@ -6823,6 +7049,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 ""
@@ -6856,6 +7085,12 @@ msgstr ""
msgid "Open in Xcode"
msgstr ""
+msgid "Open in file view"
+msgstr ""
+
+msgid "Open issues"
+msgstr ""
+
msgid "Open raw"
msgstr ""
@@ -7024,6 +7259,18 @@ msgstr ""
msgid "Performance optimization"
msgstr ""
+msgid "PerformanceBar|Gitaly calls"
+msgstr ""
+
+msgid "PerformanceBar|SQL queries"
+msgstr ""
+
+msgid "PerformanceBar|profile"
+msgstr ""
+
+msgid "PerformanceBar|trace"
+msgstr ""
+
msgid "Permissions"
msgstr ""
@@ -7051,6 +7298,9 @@ msgstr ""
msgid "Pick a name"
msgstr ""
+msgid "Pick a name for the application, and we'll give you a unique %{type} token."
+msgstr ""
+
msgid "Pin code"
msgstr ""
@@ -7345,9 +7595,6 @@ msgstr ""
msgid "Please wait while we import the repository for you. Refresh at will."
msgstr ""
-msgid "Pre-release"
-msgstr ""
-
msgid "Preferences"
msgstr ""
@@ -7576,6 +7823,9 @@ msgstr ""
msgid "Profiles|Full name"
msgstr ""
+msgid "Profiles|Impersonation"
+msgstr ""
+
msgid "Profiles|Include private contributions on my profile"
msgstr ""
@@ -7618,6 +7868,9 @@ msgstr ""
msgid "Profiles|Path"
msgstr ""
+msgid "Profiles|Personal Access"
+msgstr ""
+
msgid "Profiles|Position and size your new avatar"
msgstr ""
@@ -7753,6 +8006,12 @@ msgstr ""
msgid "Profiles|e.g. My MacBook key"
msgstr ""
+msgid "Profiles|impersonation"
+msgstr ""
+
+msgid "Profiles|personal access"
+msgstr ""
+
msgid "Profiles|username"
msgstr ""
@@ -7930,6 +8189,9 @@ msgstr ""
msgid "ProjectSettings|Badges"
msgstr ""
+msgid "ProjectSettings|Choose your merge method, merge options, and merge checks."
+msgstr ""
+
msgid "ProjectSettings|Customize your project badges."
msgstr ""
@@ -8071,6 +8333,9 @@ msgstr ""
msgid "ProjectsDropdown|This feature requires browser localStorage support"
msgstr ""
+msgid "Prometheus server"
+msgstr ""
+
msgid "PrometheusService|%{exporters} with %{metrics} were found"
msgstr ""
@@ -8379,6 +8644,9 @@ msgstr ""
msgid "Remove fork relationship"
msgstr ""
+msgid "Remove from board"
+msgstr ""
+
msgid "Remove group"
msgstr ""
@@ -8541,7 +8809,10 @@ msgstr ""
msgid "Reset runners registration token"
msgstr ""
-msgid "Resolve all discussions in new issue"
+msgid "Reset template"
+msgstr ""
+
+msgid "Resolve all threads in new issue"
msgstr ""
msgid "Resolve conflicts on source branch"
@@ -8550,6 +8821,9 @@ msgstr ""
msgid "Resolve discussion"
msgstr ""
+msgid "Resolve thread"
+msgstr ""
+
msgid "Resolved"
msgstr ""
@@ -8753,6 +9027,9 @@ msgstr ""
msgid "Save variables"
msgstr ""
+msgid "Saving"
+msgstr ""
+
msgid "Saving project."
msgstr ""
@@ -8780,6 +9057,9 @@ msgstr ""
msgid "Scoped label"
msgstr ""
+msgid "Scopes"
+msgstr ""
+
msgid "Scroll down to <strong>Google Code Project Hosting</strong> and enable the switch on the right."
msgstr ""
@@ -8897,9 +9177,15 @@ msgstr ""
msgid "Select a new namespace"
msgstr ""
+msgid "Select a project"
+msgstr ""
+
msgid "Select a timezone"
msgstr ""
+msgid "Select all"
+msgstr ""
+
msgid "Select an existing Kubernetes cluster or create a new one"
msgstr ""
@@ -8987,6 +9273,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 ""
@@ -9017,9 +9306,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 ""
@@ -9155,6 +9456,9 @@ msgstr ""
msgid "Show command"
msgstr ""
+msgid "Show comments"
+msgstr ""
+
msgid "Show comments only"
msgstr ""
@@ -9184,6 +9488,12 @@ msgid_plural "Showing %d events"
msgstr[0] ""
msgstr[1] ""
+msgid "Showing all issues"
+msgstr ""
+
+msgid "Showing last %{size} of log -"
+msgstr ""
+
msgid "Side-by-side"
msgstr ""
@@ -9538,6 +9848,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 ""
@@ -9553,16 +9866,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"
@@ -9589,6 +9902,9 @@ msgstr ""
msgid "Status:"
msgstr ""
+msgid "Stay updated about the performance and health of your environment by configuring Prometheus to monitor your deployments."
+msgstr ""
+
msgid "Stop environment"
msgstr ""
@@ -9628,6 +9944,9 @@ msgstr ""
msgid "Submit feedback"
msgstr ""
+msgid "Submit issue"
+msgstr ""
+
msgid "Submit search"
msgstr ""
@@ -9901,6 +10220,9 @@ msgstr ""
msgid "Templates"
msgstr ""
+msgid "Terminal"
+msgstr ""
+
msgid "Terminal for environment"
msgstr ""
@@ -10200,6 +10522,9 @@ msgstr ""
msgid "There are no issues to show"
msgstr ""
+msgid "There are no issues to show."
+msgstr ""
+
msgid "There are no labels yet"
msgstr ""
@@ -10332,6 +10657,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 ""
@@ -10488,6 +10816,9 @@ msgstr ""
msgid "This user cannot be unlocked manually from GitLab"
msgstr ""
+msgid "This user has no active %{type} Tokens."
+msgstr ""
+
msgid "This user has no identities"
msgstr ""
@@ -10500,6 +10831,9 @@ msgstr ""
msgid "Thursday"
msgstr ""
+msgid "Time"
+msgstr ""
+
msgid "Time based: Yes"
msgstr ""
@@ -10753,6 +11087,9 @@ msgstr ""
msgid "To preserve performance only <strong>%{display_size} of %{real_size}</strong> files are displayed."
msgstr ""
+msgid "To see all the user's personal access tokens you must impersonate them first."
+msgstr ""
+
msgid "To specify the notification level per project of a group you belong to, you need to visit project page and change notification level there."
msgstr ""
@@ -10795,15 +11132,15 @@ msgstr ""
msgid "Toggle commit list"
msgstr ""
-msgid "Toggle discussion"
-msgstr ""
-
msgid "Toggle emoji award"
msgstr ""
msgid "Toggle navigation"
msgstr ""
+msgid "Toggle thread"
+msgstr ""
+
msgid "ToggleButton|Toggle Status: OFF"
msgstr ""
@@ -10945,6 +11282,9 @@ msgstr ""
msgid "U2F only works with HTTPS-enabled websites. Contact your administrator for more details."
msgstr ""
+msgid "Unable to connect to Prometheus server"
+msgstr ""
+
msgid "Unable to connect to server: %{error}"
msgstr ""
@@ -10978,6 +11318,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 ""
@@ -11005,6 +11351,9 @@ msgstr ""
msgid "Unresolve discussion"
msgstr ""
+msgid "Unresolve thread"
+msgstr ""
+
msgid "Unschedule job"
msgstr ""
@@ -11050,6 +11399,9 @@ msgstr ""
msgid "Upcoming"
msgstr ""
+msgid "Upcoming Release"
+msgstr ""
+
msgid "Update"
msgstr ""
@@ -11083,6 +11435,9 @@ msgstr ""
msgid "Updated"
msgstr ""
+msgid "Updated to"
+msgstr ""
+
msgid "Updating"
msgstr ""
@@ -11350,6 +11705,9 @@ msgstr ""
msgid "View details: %{details_url}"
msgstr ""
+msgid "View documentation"
+msgstr ""
+
msgid "View file @ "
msgstr ""
@@ -11425,6 +11783,9 @@ msgstr ""
msgid "Wait for the source to load to copy it to the clipboard"
msgstr ""
+msgid "Waiting for performance data"
+msgstr ""
+
msgid "Want to see the data? Please ask an administrator for access."
msgstr ""
@@ -11682,6 +12043,9 @@ msgstr ""
msgid "You are attempting to update a file that has changed since you started editing it."
msgstr ""
+msgid "You are connected to the Prometheus server, but there is currently no data to display."
+msgstr ""
+
msgid "You are going to remove %{group_name}, this will also remove all of its subgroups and projects. Removed groups CANNOT be restored! Are you ABSOLUTELY sure?"
msgstr ""
@@ -11823,6 +12187,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 ""
@@ -11844,6 +12211,12 @@ msgstr ""
msgid "You have reached your project limit"
msgstr ""
+msgid "You haven't added any issues to your project yet"
+msgstr ""
+
+msgid "You haven't selected any issues yet"
+msgstr ""
+
msgid "You left the \"%{membershipable_human_name}\" %{source_type}."
msgstr ""
@@ -11961,6 +12334,9 @@ msgstr ""
msgid "Your Groups"
msgstr ""
+msgid "Your New Personal Access Token"
+msgstr ""
+
msgid "Your Primary Email will be used for avatar detection."
msgstr ""
@@ -12128,20 +12504,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 ""
@@ -12444,7 +12812,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."
@@ -12498,6 +12866,9 @@ msgstr ""
msgid "none"
msgstr ""
+msgid "not found"
+msgstr ""
+
msgid "notification emails"
msgstr ""
@@ -12526,9 +12897,6 @@ msgstr[1] ""
msgid "password"
msgstr ""
-msgid "personal access token"
-msgstr ""
-
msgid "private"
msgstr ""
@@ -12547,6 +12915,9 @@ msgstr ""
msgid "register"
msgstr ""
+msgid "released %{time}"
+msgstr ""
+
msgid "remaining"
msgstr ""
@@ -12612,6 +12983,14 @@ msgstr ""
msgid "this document"
msgstr ""
+msgid "thread resolved"
+msgid_plural "threads resolved"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "to list"
+msgstr ""
+
msgid "triggered"
msgstr ""
@@ -12627,6 +13006,9 @@ msgstr ""
msgid "verify ownership"
msgstr ""
+msgid "version %{versionIndex}"
+msgstr ""
+
msgid "via %{closed_via}"
msgstr ""
diff --git a/locale/gl_ES/gitlab.po b/locale/gl_ES/gitlab.po
index 880d0f2e9a9..50d4d42f36a 100644
--- a/locale/gl_ES/gitlab.po
+++ b/locale/gl_ES/gitlab.po
@@ -7373,13 +7373,13 @@ msgstr ""
msgid "JiraService|If different from Web URL"
msgstr ""
-msgid "JiraService|JIRA API URL"
+msgid "JiraService|Jira API URL"
msgstr ""
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a commit."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a commit."
msgstr ""
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a merge request."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a merge request."
msgstr ""
msgid "JiraService|Jira issue tracker"
diff --git a/locale/he_IL/gitlab.po b/locale/he_IL/gitlab.po
index dcfe3ceb8a3..dc6ff543726 100644
--- a/locale/he_IL/gitlab.po
+++ b/locale/he_IL/gitlab.po
@@ -7477,13 +7477,13 @@ msgstr ""
msgid "JiraService|If different from Web URL"
msgstr ""
-msgid "JiraService|JIRA API URL"
+msgid "JiraService|Jira API URL"
msgstr ""
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a commit."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a commit."
msgstr ""
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a merge request."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a merge request."
msgstr ""
msgid "JiraService|Jira issue tracker"
diff --git a/locale/hi_IN/gitlab.po b/locale/hi_IN/gitlab.po
index 76b060f25c3..126759c5828 100644
--- a/locale/hi_IN/gitlab.po
+++ b/locale/hi_IN/gitlab.po
@@ -7373,13 +7373,13 @@ msgstr ""
msgid "JiraService|If different from Web URL"
msgstr ""
-msgid "JiraService|JIRA API URL"
+msgid "JiraService|Jira API URL"
msgstr ""
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a commit."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a commit."
msgstr ""
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a merge request."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a merge request."
msgstr ""
msgid "JiraService|Jira issue tracker"
diff --git a/locale/hr_HR/gitlab.po b/locale/hr_HR/gitlab.po
index ae4a40dd8f7..1f3242a6731 100644
--- a/locale/hr_HR/gitlab.po
+++ b/locale/hr_HR/gitlab.po
@@ -7425,13 +7425,13 @@ msgstr ""
msgid "JiraService|If different from Web URL"
msgstr ""
-msgid "JiraService|JIRA API URL"
+msgid "JiraService|Jira API URL"
msgstr ""
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a commit."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a commit."
msgstr ""
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a merge request."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a merge request."
msgstr ""
msgid "JiraService|Jira issue tracker"
diff --git a/locale/hu_HU/gitlab.po b/locale/hu_HU/gitlab.po
index 131782290b2..142845c24a7 100644
--- a/locale/hu_HU/gitlab.po
+++ b/locale/hu_HU/gitlab.po
@@ -7373,13 +7373,13 @@ msgstr ""
msgid "JiraService|If different from Web URL"
msgstr ""
-msgid "JiraService|JIRA API URL"
+msgid "JiraService|Jira API URL"
msgstr ""
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a commit."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a commit."
msgstr ""
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a merge request."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a merge request."
msgstr ""
msgid "JiraService|Jira issue tracker"
diff --git a/locale/id_ID/gitlab.po b/locale/id_ID/gitlab.po
index f1680909623..be6c29d933c 100644
--- a/locale/id_ID/gitlab.po
+++ b/locale/id_ID/gitlab.po
@@ -7321,13 +7321,13 @@ msgstr ""
msgid "JiraService|If different from Web URL"
msgstr ""
-msgid "JiraService|JIRA API URL"
+msgid "JiraService|Jira API URL"
msgstr ""
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a commit."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a commit."
msgstr ""
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a merge request."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a merge request."
msgstr ""
msgid "JiraService|Jira issue tracker"
diff --git a/locale/it/gitlab.po b/locale/it/gitlab.po
index 02fa65dfa10..9b3ec180972 100644
--- a/locale/it/gitlab.po
+++ b/locale/it/gitlab.po
@@ -7373,13 +7373,13 @@ msgstr ""
msgid "JiraService|If different from Web URL"
msgstr ""
-msgid "JiraService|JIRA API URL"
+msgid "JiraService|Jira API URL"
msgstr ""
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a commit."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a commit."
msgstr ""
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a merge request."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a merge request."
msgstr ""
msgid "JiraService|Jira issue tracker"
diff --git a/locale/ja/gitlab.po b/locale/ja/gitlab.po
index 8964d2081bf..cc27cb06364 100644
--- a/locale/ja/gitlab.po
+++ b/locale/ja/gitlab.po
@@ -7321,13 +7321,13 @@ msgstr ""
msgid "JiraService|If different from Web URL"
msgstr ""
-msgid "JiraService|JIRA API URL"
+msgid "JiraService|Jira API URL"
msgstr "JIRA APIのURL"
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a commit."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a commit."
msgstr "課題がコミットで参照されると Jiraコメントが作成されます。"
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a merge request."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a merge request."
msgstr ""
msgid "JiraService|Jira issue tracker"
diff --git a/locale/ka_GE/gitlab.po b/locale/ka_GE/gitlab.po
index 5510c93d891..f6d768828ca 100644
--- a/locale/ka_GE/gitlab.po
+++ b/locale/ka_GE/gitlab.po
@@ -7373,13 +7373,13 @@ msgstr ""
msgid "JiraService|If different from Web URL"
msgstr ""
-msgid "JiraService|JIRA API URL"
+msgid "JiraService|Jira API URL"
msgstr ""
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a commit."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a commit."
msgstr ""
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a merge request."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a merge request."
msgstr ""
msgid "JiraService|Jira issue tracker"
diff --git a/locale/ko/gitlab.po b/locale/ko/gitlab.po
index e9ae48c0a96..6138874ac7d 100644
--- a/locale/ko/gitlab.po
+++ b/locale/ko/gitlab.po
@@ -7321,13 +7321,13 @@ msgstr ""
msgid "JiraService|If different from Web URL"
msgstr ""
-msgid "JiraService|JIRA API URL"
+msgid "JiraService|Jira API URL"
msgstr ""
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a commit."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a commit."
msgstr ""
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a merge request."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a merge request."
msgstr ""
msgid "JiraService|Jira issue tracker"
diff --git a/locale/mn_MN/gitlab.po b/locale/mn_MN/gitlab.po
index 3e127d662ab..11bb2a40d14 100644
--- a/locale/mn_MN/gitlab.po
+++ b/locale/mn_MN/gitlab.po
@@ -7373,13 +7373,13 @@ msgstr ""
msgid "JiraService|If different from Web URL"
msgstr ""
-msgid "JiraService|JIRA API URL"
+msgid "JiraService|Jira API URL"
msgstr ""
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a commit."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a commit."
msgstr ""
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a merge request."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a merge request."
msgstr ""
msgid "JiraService|Jira issue tracker"
diff --git a/locale/nb_NO/gitlab.po b/locale/nb_NO/gitlab.po
index 1a65c08fd32..7f150c167ee 100644
--- a/locale/nb_NO/gitlab.po
+++ b/locale/nb_NO/gitlab.po
@@ -7373,13 +7373,13 @@ msgstr ""
msgid "JiraService|If different from Web URL"
msgstr ""
-msgid "JiraService|JIRA API URL"
+msgid "JiraService|Jira API URL"
msgstr ""
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a commit."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a commit."
msgstr ""
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a merge request."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a merge request."
msgstr ""
msgid "JiraService|Jira issue tracker"
diff --git a/locale/nl_NL/gitlab.po b/locale/nl_NL/gitlab.po
index a21a659f33d..faa40d15de9 100644
--- a/locale/nl_NL/gitlab.po
+++ b/locale/nl_NL/gitlab.po
@@ -7373,13 +7373,13 @@ msgstr ""
msgid "JiraService|If different from Web URL"
msgstr ""
-msgid "JiraService|JIRA API URL"
+msgid "JiraService|Jira API URL"
msgstr ""
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a commit."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a commit."
msgstr ""
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a merge request."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a merge request."
msgstr ""
msgid "JiraService|Jira issue tracker"
diff --git a/locale/pa_IN/gitlab.po b/locale/pa_IN/gitlab.po
index f24100b1dc5..723f2d4cb22 100644
--- a/locale/pa_IN/gitlab.po
+++ b/locale/pa_IN/gitlab.po
@@ -7373,13 +7373,13 @@ msgstr ""
msgid "JiraService|If different from Web URL"
msgstr ""
-msgid "JiraService|JIRA API URL"
+msgid "JiraService|Jira API URL"
msgstr ""
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a commit."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a commit."
msgstr ""
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a merge request."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a merge request."
msgstr ""
msgid "JiraService|Jira issue tracker"
diff --git a/locale/pl_PL/gitlab.po b/locale/pl_PL/gitlab.po
index 00fa4c3f03c..e3b257d8c16 100644
--- a/locale/pl_PL/gitlab.po
+++ b/locale/pl_PL/gitlab.po
@@ -7477,13 +7477,13 @@ msgstr ""
msgid "JiraService|If different from Web URL"
msgstr ""
-msgid "JiraService|JIRA API URL"
+msgid "JiraService|Jira API URL"
msgstr ""
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a commit."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a commit."
msgstr ""
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a merge request."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a merge request."
msgstr ""
msgid "JiraService|Jira issue tracker"
diff --git a/locale/pt_BR/gitlab.po b/locale/pt_BR/gitlab.po
index b5dab7c6379..0a1e2508d66 100644
--- a/locale/pt_BR/gitlab.po
+++ b/locale/pt_BR/gitlab.po
@@ -7373,13 +7373,13 @@ msgstr "Eventos para %{noteable_model_name} estão desabilitados."
msgid "JiraService|If different from Web URL"
msgstr "Se diferente do URL da Web"
-msgid "JiraService|JIRA API URL"
+msgid "JiraService|Jira API URL"
msgstr "URL da API do JIRA"
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a commit."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a commit."
msgstr ""
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a merge request."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a merge request."
msgstr ""
msgid "JiraService|Jira issue tracker"
diff --git a/locale/pt_PT/gitlab.po b/locale/pt_PT/gitlab.po
index c9921faf129..f9174152adf 100644
--- a/locale/pt_PT/gitlab.po
+++ b/locale/pt_PT/gitlab.po
@@ -7373,13 +7373,13 @@ msgstr ""
msgid "JiraService|If different from Web URL"
msgstr ""
-msgid "JiraService|JIRA API URL"
+msgid "JiraService|Jira API URL"
msgstr ""
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a commit."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a commit."
msgstr ""
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a merge request."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a merge request."
msgstr ""
msgid "JiraService|Jira issue tracker"
diff --git a/locale/ro_RO/gitlab.po b/locale/ro_RO/gitlab.po
index 3d77b1552b4..71e8f9b199d 100644
--- a/locale/ro_RO/gitlab.po
+++ b/locale/ro_RO/gitlab.po
@@ -7425,13 +7425,13 @@ msgstr ""
msgid "JiraService|If different from Web URL"
msgstr ""
-msgid "JiraService|JIRA API URL"
+msgid "JiraService|Jira API URL"
msgstr ""
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a commit."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a commit."
msgstr ""
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a merge request."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a merge request."
msgstr ""
msgid "JiraService|Jira issue tracker"
diff --git a/locale/ru/gitlab.po b/locale/ru/gitlab.po
index 521c7ea6203..bb9e59a36a4 100644
--- a/locale/ru/gitlab.po
+++ b/locale/ru/gitlab.po
@@ -7477,13 +7477,13 @@ msgstr ""
msgid "JiraService|If different from Web URL"
msgstr ""
-msgid "JiraService|JIRA API URL"
+msgid "JiraService|Jira API URL"
msgstr ""
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a commit."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a commit."
msgstr ""
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a merge request."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a merge request."
msgstr ""
msgid "JiraService|Jira issue tracker"
diff --git a/locale/sk_SK/gitlab.po b/locale/sk_SK/gitlab.po
index 763bb4a46f8..0b014f91082 100644
--- a/locale/sk_SK/gitlab.po
+++ b/locale/sk_SK/gitlab.po
@@ -7477,13 +7477,13 @@ msgstr ""
msgid "JiraService|If different from Web URL"
msgstr ""
-msgid "JiraService|JIRA API URL"
+msgid "JiraService|Jira API URL"
msgstr ""
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a commit."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a commit."
msgstr ""
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a merge request."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a merge request."
msgstr ""
msgid "JiraService|Jira issue tracker"
diff --git a/locale/sq_AL/gitlab.po b/locale/sq_AL/gitlab.po
index d136efa8675..2e43589b1fc 100644
--- a/locale/sq_AL/gitlab.po
+++ b/locale/sq_AL/gitlab.po
@@ -7373,13 +7373,13 @@ msgstr ""
msgid "JiraService|If different from Web URL"
msgstr ""
-msgid "JiraService|JIRA API URL"
+msgid "JiraService|Jira API URL"
msgstr ""
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a commit."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a commit."
msgstr ""
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a merge request."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a merge request."
msgstr ""
msgid "JiraService|Jira issue tracker"
diff --git a/locale/sr_CS/gitlab.po b/locale/sr_CS/gitlab.po
index 4b89734ad03..34ba686fc45 100644
--- a/locale/sr_CS/gitlab.po
+++ b/locale/sr_CS/gitlab.po
@@ -7425,13 +7425,13 @@ msgstr ""
msgid "JiraService|If different from Web URL"
msgstr ""
-msgid "JiraService|JIRA API URL"
+msgid "JiraService|Jira API URL"
msgstr ""
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a commit."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a commit."
msgstr ""
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a merge request."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a merge request."
msgstr ""
msgid "JiraService|Jira issue tracker"
diff --git a/locale/sr_SP/gitlab.po b/locale/sr_SP/gitlab.po
index 8a796c7d2c4..cefbe0910c4 100644
--- a/locale/sr_SP/gitlab.po
+++ b/locale/sr_SP/gitlab.po
@@ -7425,13 +7425,13 @@ msgstr ""
msgid "JiraService|If different from Web URL"
msgstr ""
-msgid "JiraService|JIRA API URL"
+msgid "JiraService|Jira API URL"
msgstr ""
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a commit."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a commit."
msgstr ""
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a merge request."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a merge request."
msgstr ""
msgid "JiraService|Jira issue tracker"
diff --git a/locale/sv_SE/gitlab.po b/locale/sv_SE/gitlab.po
index 5fc6478d022..33c75c49a0f 100644
--- a/locale/sv_SE/gitlab.po
+++ b/locale/sv_SE/gitlab.po
@@ -7373,13 +7373,13 @@ msgstr ""
msgid "JiraService|If different from Web URL"
msgstr ""
-msgid "JiraService|JIRA API URL"
+msgid "JiraService|Jira API URL"
msgstr ""
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a commit."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a commit."
msgstr ""
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a merge request."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a merge request."
msgstr ""
msgid "JiraService|Jira issue tracker"
diff --git a/locale/sw_KE/gitlab.po b/locale/sw_KE/gitlab.po
index 3b0ac677db7..63860064d3c 100644
--- a/locale/sw_KE/gitlab.po
+++ b/locale/sw_KE/gitlab.po
@@ -7373,13 +7373,13 @@ msgstr ""
msgid "JiraService|If different from Web URL"
msgstr ""
-msgid "JiraService|JIRA API URL"
+msgid "JiraService|Jira API URL"
msgstr ""
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a commit."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a commit."
msgstr ""
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a merge request."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a merge request."
msgstr ""
msgid "JiraService|Jira issue tracker"
diff --git a/locale/tr_TR/gitlab.po b/locale/tr_TR/gitlab.po
index a35ff0ce09f..3b552a3cbda 100644
--- a/locale/tr_TR/gitlab.po
+++ b/locale/tr_TR/gitlab.po
@@ -7373,13 +7373,13 @@ msgstr ""
msgid "JiraService|If different from Web URL"
msgstr ""
-msgid "JiraService|JIRA API URL"
+msgid "JiraService|Jira API URL"
msgstr ""
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a commit."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a commit."
msgstr ""
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a merge request."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a merge request."
msgstr ""
msgid "JiraService|Jira issue tracker"
diff --git a/locale/uk/gitlab.po b/locale/uk/gitlab.po
index b802c6fa323..ee9d9bc0fee 100644
--- a/locale/uk/gitlab.po
+++ b/locale/uk/gitlab.po
@@ -7477,13 +7477,13 @@ msgstr ""
msgid "JiraService|If different from Web URL"
msgstr ""
-msgid "JiraService|JIRA API URL"
+msgid "JiraService|Jira API URL"
msgstr ""
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a commit."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a commit."
msgstr ""
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a merge request."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a merge request."
msgstr ""
msgid "JiraService|Jira issue tracker"
diff --git a/locale/zh_CN/gitlab.po b/locale/zh_CN/gitlab.po
index 77064035305..bfa6064303c 100644
--- a/locale/zh_CN/gitlab.po
+++ b/locale/zh_CN/gitlab.po
@@ -7321,13 +7321,13 @@ msgstr "%{noteable_model_name} 事件已禁用。"
msgid "JiraService|If different from Web URL"
msgstr "如果与 Web URL 不同"
-msgid "JiraService|JIRA API URL"
+msgid "JiraService|Jira API URL"
msgstr "JIRA API URL"
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a commit."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a commit."
msgstr "在提交中引用议题时将创建 JIRA 评论。"
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a merge request."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a merge request."
msgstr "在合并请求中引用议题时将创建 JIRA 评论。"
msgid "JiraService|Jira issue tracker"
diff --git a/locale/zh_HK/gitlab.po b/locale/zh_HK/gitlab.po
index 8485e17cd0d..541978fd726 100644
--- a/locale/zh_HK/gitlab.po
+++ b/locale/zh_HK/gitlab.po
@@ -7321,13 +7321,13 @@ msgstr ""
msgid "JiraService|If different from Web URL"
msgstr ""
-msgid "JiraService|JIRA API URL"
+msgid "JiraService|Jira API URL"
msgstr ""
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a commit."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a commit."
msgstr ""
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a merge request."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a merge request."
msgstr ""
msgid "JiraService|Jira issue tracker"
diff --git a/locale/zh_TW/gitlab.po b/locale/zh_TW/gitlab.po
index e7be5df3c80..22de348bdaa 100644
--- a/locale/zh_TW/gitlab.po
+++ b/locale/zh_TW/gitlab.po
@@ -7321,13 +7321,13 @@ msgstr ""
msgid "JiraService|If different from Web URL"
msgstr ""
-msgid "JiraService|JIRA API URL"
+msgid "JiraService|Jira API URL"
msgstr ""
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a commit."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a commit."
msgstr ""
-msgid "JiraService|JIRA comments will be created when an issue gets referenced in a merge request."
+msgid "JiraService|Jira comments will be created when an issue gets referenced in a merge request."
msgstr ""
msgid "JiraService|Jira issue tracker"
diff --git a/package.json b/package.json
index 54998cc81dd..e645eb8ed1c 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": "^4.3.0",
+ "@gitlab/svgs": "^1.66.0",
+ "@gitlab/ui": "^5.1.0",
"apollo-cache-inmemory": "^1.5.1",
"apollo-client": "^2.5.1",
"apollo-link": "^1.2.11",
@@ -46,7 +46,7 @@
"apollo-upload-client": "^10.0.0",
"at.js": "^1.5.4",
"autosize": "^4.0.0",
- "axios": "^0.17.1",
+ "axios": "^0.19.0",
"babel-loader": "^8.0.5",
"bootstrap": "4.3.1",
"brace-expansion": "^1.1.8",
@@ -87,7 +87,7 @@
"imports-loader": "^0.8.0",
"jed": "^1.1.1",
"jest-transform-graphql": "^2.1.0",
- "jquery": "^3.2.1",
+ "jquery": "^3.4.1",
"jquery-ujs": "1.2.2",
"jquery.caret": "^0.3.1",
"jquery.waitforimages": "^2.2.0",
@@ -96,7 +96,7 @@
"jszip-utils": "^0.0.2",
"katex": "^0.10.0",
"marked": "^0.3.12",
- "mermaid": "^8.0.0",
+ "mermaid": "^8.1.0",
"monaco-editor": "^0.15.6",
"monaco-editor-webpack-plugin": "^1.7.0",
"mousetrap": "^1.4.6",
@@ -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/qa.rb b/qa/qa.rb
index 944dcc31917..10d44b6f6d9 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'
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/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/settings.rb b/qa/qa/page/project/sub_menus/settings.rb
index 22743ebd0a1..88b45ec55ae 100644
--- a/qa/qa/page/project/sub_menus/settings.rb
+++ b/qa/qa/page/project/sub_menus/settings.rb
@@ -10,6 +10,7 @@ module QA
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 +39,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/page/settings/common.rb b/qa/qa/page/settings/common.rb
index 8cd0b6bb49c..bede3fde105 100644
--- a/qa/qa/page/settings/common.rb
+++ b/qa/qa/page/settings/common.rb
@@ -11,7 +11,7 @@ module QA
within_element(element_name) do
# Because it is possible to click the button before the JS toggle code is bound
wait(reload: false) do
- click_button 'Expand' unless first('button', text: 'Collapse')
+ click_button 'Expand' unless has_css?('button', text: 'Collapse')
has_content?('Collapse')
end
diff --git a/qa/qa/resource/api_fabricator.rb b/qa/qa/resource/api_fabricator.rb
index de04467ff5b..d1d75b6179e 100644
--- a/qa/qa/resource/api_fabricator.rb
+++ b/qa/qa/resource/api_fabricator.rb
@@ -13,6 +13,8 @@ module QA
ResourceURLMissingError = Class.new(RuntimeError)
attr_reader :api_resource, :api_response
+ attr_writer :api_client
+ attr_accessor :user
def api_support?
respond_to?(:api_get_path) &&
@@ -29,9 +31,12 @@ module QA
end
def eager_load_api_client!
+ return unless api_client.nil?
+
api_client.tap do |client|
# Eager-load the API client so that the personal token creation isn't
# taken in account in the actual resource creation timing.
+ client.user = user
client.personal_access_token
end
end
@@ -76,7 +81,7 @@ module QA
def api_client
@api_client ||= begin
- Runtime::API::Client.new(:gitlab, is_new_session: !current_url.start_with?('http'))
+ Runtime::API::Client.new(:gitlab, is_new_session: !current_url.start_with?('http'), user: user)
end
end
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/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/resource/merge_request_from_fork.rb b/qa/qa/resource/merge_request_from_fork.rb
index 5d20a6e9c75..6c9a096289b 100644
--- a/qa/qa/resource/merge_request_from_fork.rb
+++ b/qa/qa/resource/merge_request_from_fork.rb
@@ -21,7 +21,7 @@ module QA
def fabricate!
populate(:push)
- fork.visit!
+ fork.project.visit!
Page::Project::Show.perform(&:new_merge_request)
Page::MergeRequest::New.perform(&:create_merge_request)
diff --git a/qa/qa/resource/project.rb b/qa/qa/resource/project.rb
index e8ea947581a..c0a6004fe27 100644
--- a/qa/qa/resource/project.rb
+++ b/qa/qa/resource/project.rb
@@ -11,7 +11,9 @@ module QA
attribute :id
attribute :name
+ attribute :add_name_uuid
attribute :description
+ attribute :standalone
attribute :group do
Group.fabricate!
@@ -38,18 +40,21 @@ module QA
end
def initialize
+ @add_name_uuid = true
+ @standalone = false
@description = 'My awesome project'
@initialize_with_readme = false
end
def name=(raw_name)
- @name = "#{raw_name}-#{SecureRandom.hex(8)}"
+ @name = @add_name_uuid ? "#{raw_name}-#{SecureRandom.hex(8)}" : raw_name
end
def fabricate!
- group.visit!
-
- Page::Group::Show.perform(&:go_to_new_project)
+ unless @standalone
+ group.visit!
+ Page::Group::Show.perform(&:go_to_new_project)
+ end
Page::Project::New.perform do |page|
page.choose_test_namespace
@@ -71,19 +76,28 @@ module QA
"/projects/#{CGI.escape(path_with_namespace)}"
end
+ def api_get_archive_path(type = 'tar.gz')
+ "#{api_get_path}/repository/archive.#{type}"
+ end
+
def api_post_path
'/projects'
end
def api_post_body
- {
- namespace_id: group.id,
- path: name,
+ post_body = {
name: name,
description: description,
visibility: 'public',
initialize_with_readme: @initialize_with_readme
}
+
+ unless @standalone
+ post_body[:namespace_id] = group.id
+ post_body[:path] = name
+ end
+
+ post_body
end
private
diff --git a/qa/qa/resource/user.rb b/qa/qa/resource/user.rb
index 6c5e91b6488..eec46f46d99 100644
--- a/qa/qa/resource/user.rb
+++ b/qa/qa/resource/user.rb
@@ -88,7 +88,7 @@ module QA
}.merge(ldap_post_body)
end
- def self.fabricate_or_use(username, password)
+ def self.fabricate_or_use(username = nil, password = nil)
if Runtime::Env.signup_disabled?
self.new.tap do |user|
user.username = username
diff --git a/qa/qa/runtime/api/client.rb b/qa/qa/runtime/api/client.rb
index 40a3bc85195..663be27a849 100644
--- a/qa/qa/runtime/api/client.rb
+++ b/qa/qa/runtime/api/client.rb
@@ -6,31 +6,34 @@ module QA
module Runtime
module API
class Client
- attr_reader :address
+ attr_reader :address, :user
- def initialize(address = :gitlab, personal_access_token: nil, is_new_session: true)
+ def initialize(address = :gitlab, personal_access_token: nil, is_new_session: true, user: nil)
@address = address
@personal_access_token = personal_access_token
@is_new_session = is_new_session
+ @user = user
end
def personal_access_token
@personal_access_token ||= begin
# you can set the environment variable GITLAB_QA_ACCESS_TOKEN
# to use a specific access token rather than create one from the UI
- Runtime::Env.personal_access_token ||= create_personal_access_token
+ # unless a specific user has been passed
+ @user.nil? ? Runtime::Env.personal_access_token ||= create_personal_access_token : create_personal_access_token
end
end
private
def create_personal_access_token
- Runtime::Browser.visit(@address, Page::Main::Login) if @is_new_session
- do_create_personal_access_token
- end
+ Page::Main::Menu.perform(&:sign_out) if @is_new_session && Page::Main::Menu.perform { |p| p.has_personal_area?(wait: 0) }
+
+ unless Page::Main::Menu.perform { |p| p.has_personal_area?(wait: 0) }
+ Runtime::Browser.visit(@address, Page::Main::Login)
+ Page::Main::Login.perform { |login| login.sign_in_using_credentials(@user) }
+ end
- def do_create_personal_access_token
- Page::Main::Login.perform(&:sign_in_using_credentials)
Resource::PersonalAccessToken.fabricate!.access_token
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/api/3_create/repository/project_archive_compare_spec.rb b/qa/qa/specs/features/api/3_create/repository/project_archive_compare_spec.rb
new file mode 100644
index 00000000000..3fe04e8b835
--- /dev/null
+++ b/qa/qa/specs/features/api/3_create/repository/project_archive_compare_spec.rb
@@ -0,0 +1,75 @@
+# frozen_string_literal: true
+
+require 'securerandom'
+require 'digest'
+
+module QA
+ context 'Create' do
+ describe 'Compare archives of different user projects with the same name and check they\'re different' do
+ include Support::Api
+
+ before(:all) do
+ @project_name = "project-archive-download-#{SecureRandom.hex(8)}"
+ @archive_types = %w(tar.gz tar.bz2 tar zip)
+ @users = {
+ user1: { username: Runtime::Env.gitlab_qa_username_1, password: Runtime::Env.gitlab_qa_password_1 },
+ user2: { username: Runtime::Env.gitlab_qa_username_2, password: Runtime::Env.gitlab_qa_password_2 }
+ }
+
+ @users.each do |_, user_info|
+ user_info[:user] = Resource::User.fabricate_or_use(user_info[:username], user_info[:password])
+ user_info[:api_client] = Runtime::API::Client.new(:gitlab, user: user_info[:user])
+ user_info[:api_client].personal_access_token
+ user_info[:project] = create_project(user_info[:user], user_info[:api_client], @project_name)
+ Page::Main::Menu.perform(&:sign_out)
+ end
+ end
+
+ it 'download archives of each user project then check they are different' do
+ archive_checksums = {}
+
+ @users.each do |user_key, user_info|
+ archive_checksums[user_key] = {}
+
+ @archive_types.each do |type|
+ archive_path = download_project_archive_via_api(user_info[:api_client], user_info[:project], type).path
+ archive_checksums[user_key][type] = Digest::MD5.hexdigest(File.read(archive_path))
+ end
+ end
+
+ QA::Runtime::Logger.debug("Archive checksums are #{archive_checksums}")
+
+ expect(archive_checksums[:user1]).not_to include(archive_checksums[:user2])
+ end
+
+ def create_project(user, api_client, project_name)
+ project = Resource::Project.fabricate! do |project|
+ project.standalone = true
+ project.add_name_uuid = false
+ project.name = project_name
+ project.path_with_namespace = "#{user.name}/#{project_name}"
+ project.user = user
+ project.api_client = api_client
+ end
+
+ Resource::Repository::ProjectPush.fabricate! do |push|
+ push.project = project
+ push.file_name = 'README.md'
+ push.file_content = '# This is a test project'
+ push.commit_message = 'Add README.md'
+ push.user = user
+ end
+
+ project
+ end
+
+ def download_project_archive_via_api(api_client, project, type = 'tar.gz')
+ get_project_archive_zip = Runtime::API::Request.new(api_client, project.api_get_archive_path(type))
+ project_archive_download = get(get_project_archive_zip.url, raw_response: true)
+ expect(project_archive_download.code).to eq(200)
+
+ project_archive_download.file
+ end
+ end
+ end
+end
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/3_create/repository/add_file_template_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/add_file_template_spec.rb
index 2750b171a85..567c6a83ddf 100644
--- a/qa/qa/specs/features/browser_ui/3_create/repository/add_file_template_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/repository/add_file_template_spec.rb
@@ -2,8 +2,7 @@
module QA
context 'Create' do
- # Issue: https://gitlab.com/gitlab-org/quality/nightly/issues/97
- describe 'File templates', :quarantine do
+ describe 'File templates' do
include Runtime::Fixtures
def login
diff --git a/qa/qa/specs/features/browser_ui/3_create/snippet/create_snippet_spec.rb b/qa/qa/specs/features/browser_ui/3_create/snippet/create_snippet_spec.rb
index f6f0468e76e..796de44a012 100644
--- a/qa/qa/specs/features/browser_ui/3_create/snippet/create_snippet_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/snippet/create_snippet_spec.rb
@@ -1,8 +1,7 @@
# frozen_string_literal: true
module QA
- # Failure issue: https://gitlab.com/gitlab-org/quality/staging/issues/49
- context 'Create', :smoke, :quarantine do
+ context 'Create', :smoke do
describe 'Snippet creation' do
it 'User creates a snippet' do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
@@ -13,7 +12,7 @@ module QA
Resource::Snippet.fabricate_via_browser_ui! do |snippet|
snippet.title = 'Snippet title'
snippet.description = 'Snippet description'
- snippet.visibility = 'Public'
+ snippet.visibility = 'Private'
snippet.file_name = 'New snippet file name'
snippet.file_content = 'Snippet file text'
end
@@ -21,8 +20,7 @@ module QA
Page::Dashboard::Snippet::Show.perform do |snippet|
expect(snippet).to have_snippet_title('Snippet title')
expect(snippet).to have_snippet_description('Snippet description')
- expect(snippet).to have_embed_type('Embed')
- expect(snippet).to have_visibility_type('Public')
+ expect(snippet).to have_visibility_type('Private')
expect(snippet).to have_file_name('New snippet file name')
expect(snippet).to have_file_content('Snippet file text')
end
diff --git a/qa/qa/specs/features/browser_ui/3_create/web_ide/add_file_template_spec.rb b/qa/qa/specs/features/browser_ui/3_create/web_ide/add_file_template_spec.rb
index 078d3b2b5b1..c09c65a57a5 100644
--- a/qa/qa/specs/features/browser_ui/3_create/web_ide/add_file_template_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/web_ide/add_file_template_spec.rb
@@ -1,8 +1,7 @@
# frozen_string_literal: true
module QA
- # Failure issue: https://gitlab.com/gitlab-org/quality/staging/issues/46
- context 'Create', :quarantine do
+ context 'Create' do
describe 'Web IDE file templates' do
include Runtime::Fixtures
diff --git a/qa/qa/support/api.rb b/qa/qa/support/api.rb
index a5c86425465..203064b2665 100644
--- a/qa/qa/support/api.rb
+++ b/qa/qa/support/api.rb
@@ -16,11 +16,12 @@ module QA
e.response
end
- def get(url)
+ def get(url, raw_response: false)
RestClient::Request.execute(
method: :get,
url: url,
- verify_ssl: false)
+ verify_ssl: false,
+ raw_response: raw_response)
rescue RestClient::ExceptionWithResponse => e
e.response
end
diff --git a/qa/spec/runtime/api/client_spec.rb b/qa/spec/runtime/api/client_spec.rb
index cf19b52700b..6f7020d6595 100644
--- a/qa/spec/runtime/api/client_spec.rb
+++ b/qa/spec/runtime/api/client_spec.rb
@@ -16,26 +16,56 @@ describe QA::Runtime::API::Client do
end
describe '#personal_access_token' do
- context 'when QA::Runtime::Env.personal_access_token is present' do
+ context 'when user is nil and QA::Runtime::Env.personal_access_token is present' do
before do
allow(QA::Runtime::Env).to receive(:personal_access_token).and_return('a_token')
end
it 'returns specified token from env' do
- expect(described_class.new.personal_access_token).to eq 'a_token'
+ expect(subject.personal_access_token).to eq 'a_token'
end
end
- context 'when QA::Runtime::Env.personal_access_token is nil' do
+ context 'when user is present and QA::Runtime::Env.personal_access_token is nil' do
before do
allow(QA::Runtime::Env).to receive(:personal_access_token).and_return(nil)
end
it 'returns a created token' do
+ subject { described_class.new(user: { username: 'foo' }) }
+
expect(subject).to receive(:create_personal_access_token).and_return('created_token')
expect(subject.personal_access_token).to eq 'created_token'
end
end
+
+ context 'when user is nil and QA::Runtime::Env.personal_access_token is nil' do
+ before do
+ allow(QA::Runtime::Env).to receive(:personal_access_token).and_return(nil)
+ end
+
+ it 'returns a created token' do
+ client = described_class.new
+
+ expect(client).to receive(:create_personal_access_token).and_return('created_token')
+
+ expect(client.personal_access_token).to eq 'created_token'
+ end
+ end
+
+ context 'when user is present and QA::Runtime::Env.personal_access_token is present' do
+ before do
+ allow(QA::Runtime::Env).to receive(:personal_access_token).and_return('a_token')
+ end
+
+ it 'returns a created token' do
+ client = described_class.new(user: { username: 'foo' })
+
+ expect(client).to receive(:create_personal_access_token).and_return('created_token')
+
+ expect(client.personal_access_token).to eq 'created_token'
+ end
+ end
end
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-gems-memory-metrics-static b/scripts/generate-gems-memory-metrics-static
new file mode 100755
index 00000000000..aa7ce3615bf
--- /dev/null
+++ b/scripts/generate-gems-memory-metrics-static
@@ -0,0 +1,18 @@
+#!/usr/bin/env ruby
+
+abort "usage: #{__FILE__} <memory_bundle_objects_file_name>" unless ARGV.length == 1
+memory_bundle_objects_file_name = ARGV.first
+
+full_report = File.readlines(memory_bundle_objects_file_name)
+
+allocated_str = full_report[1]
+retained_str = full_report[2]
+allocated_stats = /Total allocated: (?<bytes>.*) bytes \((?<objects>.*) objects\)/.match(allocated_str)
+retained_stats = /Total retained: (?<bytes>.*) bytes \((?<objects>.*) objects\)/.match(retained_str)
+
+abort 'failed to process the benchmark output' unless allocated_stats && retained_stats
+
+puts "memory_static_objects_allocated_mb #{(allocated_stats[:bytes].to_f / (1024 * 1024)).round(1)}"
+puts "memory_static_objects_retained_mb #{(retained_stats[:bytes].to_f / (1024 * 1024)).round(1)}"
+puts "memory_static_objects_allocated_items #{allocated_stats[:objects]}"
+puts "memory_static_objects_retained_items #{retained_stats[:objects]}"
diff --git a/scripts/generate-gems-size-metrics-static b/scripts/generate-gems-size-metrics-static
new file mode 100755
index 00000000000..ceec8aaccf1
--- /dev/null
+++ b/scripts/generate-gems-size-metrics-static
@@ -0,0 +1,30 @@
+#!/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.readlines(memory_bundle_mem_file_name)
+
+def total_size(memory_bundle_mem_report)
+ stats = /TOP: (?<total_mibs_str>.*) MiB/.match(memory_bundle_mem_report.first)
+ abort 'failed to process the benchmark output' unless stats
+ "gem_total_size_mb #{stats[:total_mibs_str].to_f.round(1)}"
+end
+
+TOP_LEVEL_GEM_LOG_FORMAT = /^ (?<gem_name>\S.*):\s*(?<gem_size>\d[.\d]*)\s*MiB/.freeze
+def all_gems(memory_bundle_mem_report)
+ memory_bundle_mem_report.map do |line|
+ TOP_LEVEL_GEM_LOG_FORMAT.match(line)
+ end.compact
+end
+
+def gems_as_metrics(gems_match_data)
+ gems_match_data.map do |gem|
+ gem_name = gem[:gem_name]
+ gem_size_mb = gem[:gem_size].to_f.round(1)
+ "gem_size_mb{name=\"#{gem_name}\"} #{gem_size_mb}"
+ end
+end
+
+puts total_size(full_report)
+puts gems_as_metrics(all_gems(full_report)).sort(&:casecmp)
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/memory-static b/scripts/memory-static
deleted file mode 100755
index 54f147a7a91..00000000000
--- a/scripts/memory-static
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/usr/bin/env ruby
-
-require_relative '../lib/gitlab/popen'
-
-full_report_filename, metrics_filename = ARGV
-abort 'usage: memory-static <full_report_filename> <metrics_filename>' unless full_report_filename && metrics_filename
-
-full_report, status = Gitlab::Popen.popen(%w(bundle exec derailed bundle:mem))
-abort 'failed to execute the benchmark' unless status.zero?
-
-File.open(full_report_filename, 'w') do |f|
- f.write(full_report)
-end
-
-stats = /TOP: (?<total_mibs_str>.*) MiB/.match(full_report.lines.first)
-abort 'failed to process the benchmark output' unless stats
-
-File.open(metrics_filename, 'a') do |f|
- f.puts "memory_static_total_mb #{stats[:total_mibs_str].to_f.round(1)}"
-end
diff --git a/scripts/memory-static-objects b/scripts/memory-static-objects
deleted file mode 100755
index 2ad38d9717c..00000000000
--- a/scripts/memory-static-objects
+++ /dev/null
@@ -1,27 +0,0 @@
-#!/usr/bin/env ruby
-
-require_relative '../lib/gitlab/popen'
-
-full_report_filename, metrics_filename = ARGV
-abort 'usage: memory-static-objects <full_report_filename> <metrics_filename>' unless full_report_filename && metrics_filename
-
-full_report, status = Gitlab::Popen.popen(%w(bundle exec derailed bundle:objects))
-abort 'failed to execute the benchmark' unless status.zero?
-
-File.open(full_report_filename, 'w') do |f|
- f.write(full_report)
-end
-
-allocated_str = full_report.lines[1]
-retained_str = full_report.lines[2]
-allocated_stats = /Total allocated: (?<bytes>.*) bytes \((?<objects>.*) objects\)/.match(allocated_str)
-retained_stats = /Total retained: (?<bytes>.*) bytes \((?<objects>.*) objects\)/.match(retained_str)
-
-abort 'failed to process the benchmark output' unless allocated_stats && retained_stats
-
-File.open(metrics_filename, 'a') do |f|
- f.puts "memory_static_objects_allocated_mb #{(allocated_stats[:bytes].to_f / (1024 * 1024)).round(1)}"
- f.puts "memory_static_objects_retained_mb #{(retained_stats[:bytes].to_f / (104 * 1024)).round(1)}"
- f.puts "memory_static_objects_allocated_items #{allocated_stats[:objects]}"
- f.puts "memory_static_objects_retained_items #{retained_stats[:objects]}"
-end
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 3bae2e08a6f..633ea28e96c 100755
--- a/scripts/review_apps/review-apps.sh
+++ b/scripts/review_apps/review-apps.sh
@@ -1,7 +1,7 @@
[[ "$TRACE" ]] && set -x
export TILLER_NAMESPACE="$KUBE_NAMESPACE"
-function deployExists() {
+function deploy_exists() {
local namespace="${1}"
local deploy="${2}"
echoinfo "Checking if ${deploy} exists in the ${namespace} namespace..." true
@@ -13,8 +13,7 @@ function deployExists() {
return $deploy_exists
}
-function previousDeployFailed() {
- set +e
+function previous_deploy_failed() {
local deploy="${1}"
echoinfo "Checking for previous deployment of ${deploy}" true
@@ -34,7 +33,6 @@ function previousDeployFailed() {
else
echoerr "Previous deployment NOT found."
fi
- set -e
return $status
}
@@ -51,49 +49,35 @@ function delete() {
helm delete --purge "$name"
}
-function cleanup() {
- if [ -z "$CI_ENVIRONMENT_SLUG" ]; then
- echoerr "No release given, aborting the delete!"
- return
- fi
-
- echoinfo "Cleaning up '$CI_ENVIRONMENT_SLUG'..." true
-
- kubectl -n "$KUBE_NAMESPACE" delete \
- ingress,svc,pdb,hpa,deploy,statefulset,job,pod,secret,configmap,pvc,secret,clusterrole,clusterrolebinding,role,rolebinding,sa \
- --now --ignore-not-found --include-uninitialized \
- -l release="$CI_ENVIRONMENT_SLUG"
-}
-
function get_pod() {
local app_name="${1}"
local status="${2-Running}"
get_pod_cmd="kubectl get pods -n ${KUBE_NAMESPACE} --field-selector=status.phase=${status} -lapp=${app_name},release=${CI_ENVIRONMENT_SLUG} --no-headers -o=custom-columns=NAME:.metadata.name"
- echoinfo "Running '${get_pod_cmd}'" true
+ echoinfo "Waiting till '${app_name}' pod is ready" true
+ echoinfo "Running '${get_pod_cmd}'"
+ local interval=5
+ local elapsed_seconds=0
+ local max_seconds=$((2 * 60))
while true; do
local pod_name
pod_name="$(eval "${get_pod_cmd}")"
[[ "${pod_name}" == "" ]] || break
- echoinfo "Waiting till '${app_name}' pod is ready";
- sleep 5;
+ if [[ "${elapsed_seconds}" -gt "${max_seconds}" ]]; then
+ echoerr "The pod name couldn't be found after ${elapsed_seconds} seconds, aborting."
+ break
+ fi
+
+ printf "."
+ let "elapsed_seconds+=interval"
+ sleep ${interval}
done
echoinfo "The pod name is '${pod_name}'."
echo "${pod_name}"
}
-function perform_review_app_deployment() {
- check_kube_domain
- ensure_namespace
- install_tiller
- install_external_dns
- time deploy
- wait_for_review_app_to_be_accessible
- add_license
-}
-
function check_kube_domain() {
echoinfo "Checking that Kube domain exists..." true
@@ -119,9 +103,16 @@ function install_tiller() {
echoinfo "Initiating the Helm client..."
helm init --client-only
+ # Set toleration for Tiller to be installed on a specific node pool
helm init \
+ --wait \
--upgrade \
- --replicas 2
+ --node-selectors "app=helm" \
+ --replicas 3 \
+ --override "spec.template.spec.tolerations[0].key"="dedicated" \
+ --override "spec.template.spec.tolerations[0].operator"="Equal" \
+ --override "spec.template.spec.tolerations[0].value"="helm" \
+ --override "spec.template.spec.tolerations[0].effect"="NoSchedule"
kubectl rollout status -n "$TILLER_NAMESPACE" -w "deployment/tiller-deploy"
@@ -137,7 +128,7 @@ function install_external_dns() {
domain=$(echo "${REVIEW_APPS_DOMAIN}" | awk -F. '{printf "%s.%s", $(NF-1), $NF}')
echoinfo "Installing external DNS for domain ${domain}..." true
- if ! deployExists "${KUBE_NAMESPACE}" "${release_name}" || previousDeployFailed "${release_name}" ; then
+ if ! deploy_exists "${KUBE_NAMESPACE}" "${release_name}" || previous_deploy_failed "${release_name}" ; then
echoinfo "Installing external-dns Helm chart"
helm repo update
helm install stable/external-dns \
@@ -156,7 +147,7 @@ function install_external_dns() {
fi
}
-function create_secret() {
+function create_application_secret() {
echoinfo "Creating the ${CI_ENVIRONMENT_SLUG}-gitlab-initial-root-password secret in the ${KUBE_NAMESPACE} namespace..." true
kubectl create secret generic -n "$KUBE_NAMESPACE" \
@@ -165,7 +156,7 @@ function create_secret() {
--dry-run -o json | kubectl apply -f -
}
-function download_gitlab_chart() {
+function download_chart() {
echoinfo "Downloading the GitLab chart..." true
curl -o gitlab.tar.bz2 "https://gitlab.com/charts/gitlab/-/archive/${GITLAB_HELM_CHART_REF}/gitlab-${GITLAB_HELM_CHART_REF}.tar.bz2"
@@ -194,14 +185,12 @@ function deploy() {
gitlab_workhorse_image_repository="${IMAGE_REPOSITORY}/gitlab-workhorse-${IMAGE_VERSION}"
# Cleanup and previous installs, as FAILED and PENDING_UPGRADE will cause errors with `upgrade`
- if [ "$CI_ENVIRONMENT_SLUG" != "production" ] && previousDeployFailed "$CI_ENVIRONMENT_SLUG" ; then
+ if [ "$CI_ENVIRONMENT_SLUG" != "production" ] && previous_deploy_failed "$CI_ENVIRONMENT_SLUG" ; then
echo "Deployment in bad state, cleaning up $CI_ENVIRONMENT_SLUG"
delete
- cleanup
fi
- create_secret
- download_gitlab_chart
+ create_application_secret
HELM_CMD=$(cat << EOF
helm upgrade --install \
@@ -216,7 +205,7 @@ HELM_CMD=$(cat << EOF
--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 global.ingress.annotations."external-dns\.alpha\.kubernetes\.io/ttl"="10" \
--set nginx-ingress.controller.service.enableHttp=false \
--set nginx-ingress.defaultBackend.resources.requests.memory=7Mi \
--set nginx-ingress.controller.resources.requests.memory=440M \
@@ -252,14 +241,35 @@ EOF
echoinfo "Deploying with:"
echoinfo "${HELM_CMD}"
- eval $HELM_CMD || true
+ eval "${HELM_CMD}"
+}
+
+function display_deployment_debug() {
+ migrations_pod=$(get_pod "migrations");
+ if [ -z "${migrations_pod}" ]; then
+ echoerr "Migrations pod not found."
+ else
+ echoinfo "Logs tail of the ${migrations_pod} pod..."
+
+ kubectl logs -n "$KUBE_NAMESPACE" "${migrations_pod}" | sed "s/${REVIEW_APPS_ROOT_PASSWORD}/[REDACTED]/g"
+ fi
+
+ unicorn_pod=$(get_pod "unicorn");
+ if [ -z "${unicorn_pod}" ]; then
+ echoerr "Unicorn pod not found."
+ else
+ echoinfo "Logs tail of the ${unicorn_pod} pod..."
+
+ kubectl logs -n "$KUBE_NAMESPACE" -c unicorn "${unicorn_pod}" | sed "s/${REVIEW_APPS_ROOT_PASSWORD}/[REDACTED]/g"
+ fi
}
function wait_for_review_app_to_be_accessible() {
- # In case the Review App isn't completely available yet. Keep trying for 5 minutes.
+ echoinfo "Waiting for the Review App at ${CI_ENVIRONMENT_URL} to be accessible..." true
+
local interval=5
local elapsed_seconds=0
- local max_seconds=$((5 * 60))
+ local max_seconds=$((2 * 60))
while true; do
local review_app_http_code
review_app_http_code=$(curl --silent --output /dev/null --max-time 5 --write-out "%{http_code}" "${CI_ENVIRONMENT_URL}/users/sign_in")
@@ -272,10 +282,10 @@ function wait_for_review_app_to_be_accessible() {
sleep ${interval}
done
- if [[ "${review_app_http_code}" == "200" ]]; then
- echoinfo "The Review App at ${CI_ENVIRONMENT_URL} is ready!"
+ if [[ "${review_app_http_code}" -eq "200" ]]; then
+ echoinfo "The Review App at ${CI_ENVIRONMENT_URL} is ready after ${elapsed_seconds} seconds!"
else
- echoerr "The Review App at ${CI_ENVIRONMENT_URL} isn't ready after 5 minutes of polling..."
+ echoerr "The Review App at ${CI_ENVIRONMENT_URL} isn't ready after ${max_seconds} seconds of polling..."
exit 1
fi
}
diff --git a/scripts/trigger-build b/scripts/trigger-build
index 52bc61cac56..4d8110fce10 100755
--- a/scripts/trigger-build
+++ b/scripts/trigger-build
@@ -122,7 +122,14 @@ module Trigger
end
def ref
- ENV['CNG_BRANCH'] || 'master'
+ default_ref =
+ if ENV['CI_COMMIT_REF_NAME'] =~ /^[\d-]+-stable(-ee)?$/
+ ENV['CI_COMMIT_REF_NAME']
+ else
+ 'master'
+ end
+
+ ENV['CNG_BRANCH'] || default_ref
end
def trigger_token
diff --git a/spec/controllers/admin/clusters/applications_controller_spec.rb b/spec/controllers/admin/clusters/applications_controller_spec.rb
index 76f261e7d3f..cf202d88acc 100644
--- a/spec/controllers/admin/clusters/applications_controller_spec.rb
+++ b/spec/controllers/admin/clusters/applications_controller_spec.rb
@@ -13,16 +13,6 @@ describe Admin::Clusters::ApplicationsController do
it { expect { subject }.to be_allowed_for(:admin) }
it { expect { subject }.to be_denied_for(:user) }
it { expect { subject }.to be_denied_for(:external) }
-
- context 'when instance clusters are disabled' do
- before do
- stub_feature_flags(instance_clusters: false)
- end
-
- it 'returns 404' do
- is_expected.to have_http_status(:not_found)
- end
- end
end
let(:cluster) { create(:cluster, :instance, :provided_by_gcp) }
diff --git a/spec/controllers/admin/clusters_controller_spec.rb b/spec/controllers/admin/clusters_controller_spec.rb
index 7709f525119..e5501535875 100644
--- a/spec/controllers/admin/clusters_controller_spec.rb
+++ b/spec/controllers/admin/clusters_controller_spec.rb
@@ -17,66 +17,48 @@ describe Admin::ClustersController do
get :index, params: params
end
- context 'when feature flag is not enabled' do
- before do
- stub_feature_flags(instance_clusters: false)
- end
+ describe 'functionality' do
+ context 'when instance has one or more clusters' do
+ let!(:enabled_cluster) do
+ create(:cluster, :provided_by_gcp, :instance)
+ end
- it 'responds with not found' do
- get_index
+ let!(:disabled_cluster) do
+ create(:cluster, :disabled, :provided_by_gcp, :production_environment, :instance)
+ end
- expect(response).to have_gitlab_http_status(404)
- end
- end
+ it 'lists available clusters' do
+ get_index
- context 'when feature flag is enabled' do
- before do
- stub_feature_flags(instance_clusters: true)
- end
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to render_template(:index)
+ expect(assigns(:clusters)).to match_array([enabled_cluster, disabled_cluster])
+ end
- describe 'functionality' do
- context 'when instance has one or more clusters' do
- let!(:enabled_cluster) do
- create(:cluster, :provided_by_gcp, :instance)
- end
+ context 'when page is specified' do
+ let(:last_page) { Clusters::Cluster.instance_type.page.total_pages }
- let!(:disabled_cluster) do
- create(:cluster, :disabled, :provided_by_gcp, :production_environment, :instance)
+ before do
+ allow(Clusters::Cluster).to receive(:paginates_per).and_return(1)
+ create_list(:cluster, 2, :provided_by_gcp, :production_environment, :instance)
end
- it 'lists available clusters' do
- get_index
+ it 'redirects to the page' do
+ get_index(page: last_page)
expect(response).to have_gitlab_http_status(:ok)
- expect(response).to render_template(:index)
- expect(assigns(:clusters)).to match_array([enabled_cluster, disabled_cluster])
- end
-
- context 'when page is specified' do
- let(:last_page) { Clusters::Cluster.instance_type.page.total_pages }
-
- before do
- allow(Clusters::Cluster).to receive(:paginates_per).and_return(1)
- create_list(:cluster, 2, :provided_by_gcp, :production_environment, :instance)
- end
-
- it 'redirects to the page' do
- get_index(page: last_page)
-
- expect(response).to have_gitlab_http_status(:ok)
- expect(assigns(:clusters).current_page).to eq(last_page)
- end
+ expect(assigns(:clusters).current_page).to eq(last_page)
end
end
+ end
- context 'when instance does not have a cluster' do
- it 'returns an empty state page' do
- get_index
+ context 'when instance does not have a cluster' do
+ it 'returns an empty state page' do
+ get_index
- expect(response).to have_gitlab_http_status(:ok)
- expect(response).to render_template(:index, partial: :empty_state)
- expect(assigns(:clusters)).to eq([])
- end
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to render_template(:index, partial: :empty_state)
+ expect(assigns(:clusters)).to eq([])
end
end
end
diff --git a/spec/controllers/concerns/continue_params_spec.rb b/spec/controllers/concerns/continue_params_spec.rb
index 5e47f5e9f28..b4b62cbe1e3 100644
--- a/spec/controllers/concerns/continue_params_spec.rb
+++ b/spec/controllers/concerns/continue_params_spec.rb
@@ -18,6 +18,14 @@ describe ContinueParams do
ActionController::Parameters.new(continue: params)
end
+ it 'returns an empty hash if params are not present' do
+ allow(controller).to receive(:params) do
+ ActionController::Parameters.new
+ end
+
+ expect(controller.continue_params).to eq({})
+ end
+
it 'cleans up any params that are not allowed' do
allow(controller).to receive(:params) do
strong_continue_params(to: '/hello',
diff --git a/spec/controllers/concerns/internal_redirect_spec.rb b/spec/controllers/concerns/internal_redirect_spec.rb
index 97119438ca1..da68c8c8697 100644
--- a/spec/controllers/concerns/internal_redirect_spec.rb
+++ b/spec/controllers/concerns/internal_redirect_spec.rb
@@ -15,44 +15,71 @@ describe InternalRedirect do
subject(:controller) { controller_class.new }
describe '#safe_redirect_path' do
- it 'is `nil` for invalid uris' do
- expect(controller.safe_redirect_path('Hello world')).to be_nil
+ where(:input) do
+ [
+ 'Hello world',
+ '//example.com/hello/world',
+ 'https://example.com/hello/world'
+ ]
end
- it 'is `nil` for paths trying to include a host' do
- expect(controller.safe_redirect_path('//example.com/hello/world')).to be_nil
+ with_them 'being invalid' do
+ it 'returns nil' do
+ expect(controller.safe_redirect_path(input)).to be_nil
+ end
end
- it 'returns the path if it is valid' do
- expect(controller.safe_redirect_path('/hello/world')).to eq('/hello/world')
+ where(:input) do
+ [
+ '/hello/world',
+ '/-/ide/project/path'
+ ]
end
- it 'returns the path with querystring if it is valid' do
- expect(controller.safe_redirect_path('/hello/world?hello=world#L123'))
- .to eq('/hello/world?hello=world#L123')
+ with_them 'being valid' do
+ it 'returns the path' do
+ expect(controller.safe_redirect_path(input)).to eq(input)
+ end
+
+ it 'returns the path with querystring and fragment' do
+ expect(controller.safe_redirect_path("#{input}?hello=world#L123"))
+ .to eq("#{input}?hello=world#L123")
+ end
end
end
describe '#safe_redirect_path_for_url' do
- it 'is `nil` for invalid urls' do
- expect(controller.safe_redirect_path_for_url('Hello world')).to be_nil
+ where(:input) do
+ [
+ 'Hello world',
+ 'http://example.com/hello/world',
+ 'http://test.host:3000/hello/world'
+ ]
end
- it 'is `nil` for urls from a with a different host' do
- expect(controller.safe_redirect_path_for_url('http://example.com/hello/world')).to be_nil
+ with_them 'being invalid' do
+ it 'returns nil' do
+ expect(controller.safe_redirect_path_for_url(input)).to be_nil
+ end
end
- it 'is `nil` for urls from a with a different port' do
- expect(controller.safe_redirect_path_for_url('http://test.host:3000/hello/world')).to be_nil
+ where(:input) do
+ [
+ 'http://test.host/hello/world'
+ ]
end
- it 'returns the path if the url is on the same host' do
- expect(controller.safe_redirect_path_for_url('http://test.host/hello/world')).to eq('/hello/world')
- end
+ with_them 'being on the same host' do
+ let(:path) { URI(input).path }
- it 'returns the path including querystring if the url is on the same host' do
- expect(controller.safe_redirect_path_for_url('http://test.host/hello/world?hello=world#L123'))
- .to eq('/hello/world?hello=world#L123')
+ it 'returns the path' do
+ expect(controller.safe_redirect_path_for_url(input)).to eq(path)
+ end
+
+ it 'returns the path with querystring and fragment' do
+ expect(controller.safe_redirect_path_for_url("#{input}?hello=world#L123"))
+ .to eq("#{path}?hello=world#L123")
+ end
end
end
@@ -82,12 +109,16 @@ describe InternalRedirect do
end
describe '#host_allowed?' do
- it 'allows uris with the same host and port' do
+ it 'allows URI with the same host and port' do
expect(controller.host_allowed?(URI('http://test.host/test'))).to be(true)
end
- it 'rejects uris with other host and port' do
+ it 'rejects URI with other host' do
expect(controller.host_allowed?(URI('http://example.com/test'))).to be(false)
end
+
+ it 'rejects URI with other port' do
+ expect(controller.host_allowed?(URI('http://test.host:3000/test'))).to be(false)
+ end
end
end
diff --git a/spec/controllers/dashboard/todos_controller_spec.rb b/spec/controllers/dashboard/todos_controller_spec.rb
index 6243ddc03c0..9a3fbfaac51 100644
--- a/spec/controllers/dashboard/todos_controller_spec.rb
+++ b/spec/controllers/dashboard/todos_controller_spec.rb
@@ -44,6 +44,34 @@ describe Dashboard::TodosController do
end
end
+ context "with render_views" do
+ render_views
+
+ it 'avoids N+1 queries', :request_store do
+ merge_request = create(:merge_request, source_project: project)
+ create(:todo, project: project, author: author, user: user, target: merge_request)
+ create(:issue, project: project, assignees: [user])
+
+ group = create(:group)
+ group.add_owner(user)
+
+ get :index
+
+ control = ActiveRecord::QueryRecorder.new { get :index }
+
+ create(:issue, project: project, assignees: [user])
+ group_2 = create(:group)
+ group_2.add_owner(user)
+ project_2 = create(:project)
+ project_2.add_developer(user)
+ merge_request_2 = create(:merge_request, source_project: project_2)
+ create(:todo, project: project, author: author, user: user, target: merge_request_2)
+
+ expect { get :index }.not_to exceed_query_limit(control)
+ expect(response.status).to eq(200)
+ end
+ end
+
context 'group authorization' do
it 'renders 404 when user does not have read access on given group' do
unauthorized_group = create(:group, :private)
diff --git a/spec/controllers/groups/boards_controller_spec.rb b/spec/controllers/groups/boards_controller_spec.rb
index 881d0018b79..5e0f64ccca4 100644
--- a/spec/controllers/groups/boards_controller_spec.rb
+++ b/spec/controllers/groups/boards_controller_spec.rb
@@ -59,7 +59,7 @@ describe Groups::BoardsController do
it 'return an array with one group board' do
create(:board, group: group)
- expect(Boards::Visits::LatestService).not_to receive(:new)
+ expect(Boards::VisitsFinder).not_to receive(:new)
list_boards format: :json
diff --git a/spec/controllers/groups/clusters_controller_spec.rb b/spec/controllers/groups/clusters_controller_spec.rb
index 2f64c7f3460..09677b42887 100644
--- a/spec/controllers/groups/clusters_controller_spec.rb
+++ b/spec/controllers/groups/clusters_controller_spec.rb
@@ -20,70 +20,52 @@ describe Groups::ClustersController do
get :index, params: params.reverse_merge(group_id: group)
end
- context 'when feature flag is not enabled' do
- before do
- stub_feature_flags(group_clusters: false)
- end
+ describe 'functionality' do
+ context 'when group has one or more clusters' do
+ let(:group) { create(:group) }
- it 'renders 404' do
- go
+ let!(:enabled_cluster) do
+ create(:cluster, :provided_by_gcp, cluster_type: :group_type, groups: [group])
+ end
- expect(response).to have_gitlab_http_status(404)
- end
- end
+ let!(:disabled_cluster) do
+ create(:cluster, :disabled, :provided_by_gcp, :production_environment, cluster_type: :group_type, groups: [group])
+ end
- context 'when feature flag is enabled' do
- before do
- stub_feature_flags(group_clusters: true)
- end
+ it 'lists available clusters' do
+ go
- describe 'functionality' do
- context 'when group has one or more clusters' do
- let(:group) { create(:group) }
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to render_template(:index)
+ expect(assigns(:clusters)).to match_array([enabled_cluster, disabled_cluster])
+ end
- let!(:enabled_cluster) do
- create(:cluster, :provided_by_gcp, cluster_type: :group_type, groups: [group])
- end
+ context 'when page is specified' do
+ let(:last_page) { group.clusters.page.total_pages }
- let!(:disabled_cluster) do
- create(:cluster, :disabled, :provided_by_gcp, :production_environment, cluster_type: :group_type, groups: [group])
+ before do
+ allow(Clusters::Cluster).to receive(:paginates_per).and_return(1)
+ create_list(:cluster, 2, :provided_by_gcp, :production_environment, cluster_type: :group_type, groups: [group])
end
- it 'lists available clusters' do
- go
+ it 'redirects to the page' do
+ go(page: last_page)
expect(response).to have_gitlab_http_status(:ok)
- expect(response).to render_template(:index)
- expect(assigns(:clusters)).to match_array([enabled_cluster, disabled_cluster])
- end
-
- context 'when page is specified' do
- let(:last_page) { group.clusters.page.total_pages }
-
- before do
- allow(Clusters::Cluster).to receive(:paginates_per).and_return(1)
- create_list(:cluster, 2, :provided_by_gcp, :production_environment, cluster_type: :group_type, groups: [group])
- end
-
- it 'redirects to the page' do
- go(page: last_page)
-
- expect(response).to have_gitlab_http_status(:ok)
- expect(assigns(:clusters).current_page).to eq(last_page)
- end
+ expect(assigns(:clusters).current_page).to eq(last_page)
end
end
+ end
- context 'when group does not have a cluster' do
- let(:group) { create(:group) }
+ context 'when group does not have a cluster' do
+ let(:group) { create(:group) }
- it 'returns an empty state page' do
- go
+ it 'returns an empty state page' do
+ go
- expect(response).to have_gitlab_http_status(:ok)
- expect(response).to render_template(:index, partial: :empty_state)
- expect(assigns(:clusters)).to eq([])
- end
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to render_template(:index, partial: :empty_state)
+ expect(assigns(:clusters)).to eq([])
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/boards_controller_spec.rb b/spec/controllers/projects/boards_controller_spec.rb
index ae85000b4e0..c07afc57aea 100644
--- a/spec/controllers/projects/boards_controller_spec.rb
+++ b/spec/controllers/projects/boards_controller_spec.rb
@@ -65,7 +65,7 @@ describe Projects::BoardsController do
it 'returns a list of project boards' do
create_list(:board, 2, project: project)
- expect(Boards::Visits::LatestService).not_to receive(:new)
+ expect(Boards::VisitsFinder).not_to receive(:new)
list_boards format: :json
diff --git a/spec/controllers/projects/branches_controller_spec.rb b/spec/controllers/projects/branches_controller_spec.rb
index cf201c9f735..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 }
@@ -507,4 +576,27 @@ describe Projects::BranchesController do
end
end
end
+
+ describe 'GET diverging_commit_counts' do
+ before do
+ sign_in(user)
+
+ get :diverging_commit_counts,
+ format: :json,
+ params: {
+ namespace_id: project.namespace,
+ project_id: project,
+ names: ['fix', 'add-pdf-file', 'branch-merged']
+ }
+ end
+
+ it 'returns the commit counts behind and ahead of default branch' do
+ parsed_response = JSON.parse(response.body)
+ expect(parsed_response).to eq(
+ "fix" => { "behind" => 29, "ahead" => 2 },
+ "branch-merged" => { "behind" => 1, "ahead" => 0 },
+ "add-pdf-file" => { "behind" => 0, "ahead" => 3 }
+ )
+ end
+ end
end
diff --git a/spec/controllers/projects/forks_controller_spec.rb b/spec/controllers/projects/forks_controller_spec.rb
index 3423fdf4c41..5ac5279e997 100644
--- a/spec/controllers/projects/forks_controller_spec.rb
+++ b/spec/controllers/projects/forks_controller_spec.rb
@@ -115,24 +115,34 @@ describe Projects::ForksController do
end
describe 'POST create' do
- def post_create
+ def post_create(params = {})
post :create,
params: {
namespace_id: project.namespace,
project_id: project,
namespace_key: user.namespace.id
- }
+ }.merge(params)
end
context 'when user is signed in' do
- it 'responds with status 302' do
+ before do
sign_in(user)
+ end
+ it 'responds with status 302' do
post_create
expect(response).to have_gitlab_http_status(302)
expect(response).to redirect_to(namespace_project_import_path(user.namespace, project))
end
+
+ it 'passes continue params to the redirect' do
+ continue_params = { to: '/-/ide/project/path', notice: 'message' }
+ post_create continue: continue_params
+
+ expect(response).to have_gitlab_http_status(302)
+ expect(response).to redirect_to(namespace_project_import_path(user.namespace, project, continue: continue_params))
+ end
end
context 'when user is not signed in' do
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/content_controller_spec.rb b/spec/controllers/projects/merge_requests/content_controller_spec.rb
new file mode 100644
index 00000000000..2879e06aee4
--- /dev/null
+++ b/spec/controllers/projects/merge_requests/content_controller_spec.rb
@@ -0,0 +1,60 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Projects::MergeRequests::ContentController do
+ let(:project) { create(:project, :repository) }
+ let(:user) { create(:user) }
+ let(:merge_request) { create(:merge_request, target_project: project, source_project: project) }
+
+ before do
+ sign_in(user)
+ end
+
+ def do_request
+ get :widget, params: {
+ namespace_id: project.namespace.to_param,
+ project_id: project,
+ id: merge_request.iid,
+ format: :json
+ }
+ end
+
+ describe 'GET widget' do
+ context 'user has access to the project' do
+ before do
+ expect(::Gitlab::GitalyClient).to receive(:allow_ref_name_caching).and_call_original
+
+ project.add_maintainer(user)
+ end
+
+ it 'renders widget MR entity as json' do
+ do_request
+
+ expect(response).to match_response_schema('entities/merge_request_widget')
+ end
+
+ it 'checks whether the MR can be merged' do
+ controller.instance_variable_set(:@merge_request, merge_request)
+
+ expect(merge_request).to receive(:check_mergeability)
+
+ do_request
+ end
+
+ it 'closes an MR with moved source project' do
+ merge_request.update_column(:source_project_id, nil)
+
+ expect { do_request }.to change { merge_request.reload.open? }.from(true).to(false)
+ end
+ end
+
+ context 'user does not have access to the project' do
+ it 'renders widget MR entity as json' do
+ do_request
+
+ expect(response).to have_http_status(:not_found)
+ end
+ end
+ end
+end
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/services_controller_spec.rb b/spec/controllers/projects/services_controller_spec.rb
index 5c7f8d95f82..68eabce8513 100644
--- a/spec/controllers/projects/services_controller_spec.rb
+++ b/spec/controllers/projects/services_controller_spec.rb
@@ -128,7 +128,7 @@ describe Projects::ServicesController do
params: { namespace_id: project.namespace, project_id: project, id: service.to_param, service: { active: true } }
expect(response).to redirect_to(project_settings_integrations_path(project))
- expect(flash[:notice]).to eq 'JIRA activated.'
+ expect(flash[:notice]).to eq 'Jira activated.'
end
end
@@ -137,17 +137,17 @@ describe Projects::ServicesController do
put :update,
params: { namespace_id: project.namespace, project_id: project, id: service.to_param, service: { active: false } }
- expect(flash[:notice]).to eq 'JIRA settings saved, but not activated.'
+ expect(flash[:notice]).to eq 'Jira settings saved, but not activated.'
end
end
- context 'when activating JIRA service from a template' do
+ context 'when activating Jira service from a template' do
let(:template_service) { create(:jira_service, project: project, template: true) }
- it 'activate JIRA service from template' do
+ it 'activate Jira service from template' do
put :update, params: { namespace_id: project.namespace, project_id: project, id: service.to_param, service: { active: true } }
- expect(flash[:notice]).to eq 'JIRA activated.'
+ expect(flash[:notice]).to eq 'Jira activated.'
end
end
end
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/registrations_controller_spec.rb b/spec/controllers/registrations_controller_spec.rb
index 9a598790ff2..faf3c990cb2 100644
--- a/spec/controllers/registrations_controller_spec.rb
+++ b/spec/controllers/registrations_controller_spec.rb
@@ -6,7 +6,8 @@ describe RegistrationsController do
include TermsHelper
describe '#create' do
- let(:user_params) { { user: { name: 'new_user', username: 'new_username', email: 'new@user.com', password: 'Any_password' } } }
+ let(:base_user_params) { { name: 'new_user', username: 'new_username', email: 'new@user.com', password: 'Any_password' } }
+ let(:user_params) { { user: base_user_params } }
context 'email confirmation' do
around do |example|
@@ -105,6 +106,20 @@ describe RegistrationsController do
expect(subject.current_user.terms_accepted?).to be(true)
end
end
+
+ it "logs a 'User Created' message" do
+ stub_feature_flags(registrations_recaptcha: false)
+
+ expect(Gitlab::AppLogger).to receive(:info).with(/\AUser Created: username=new_username email=new@user.com.+\z/).and_call_original
+
+ post(:create, params: user_params)
+ end
+
+ it 'handles when params are new_user' do
+ post(:create, params: { new_user: base_user_params })
+
+ expect(subject.current_user).not_to be_nil
+ end
end
describe '#destroy' do
diff --git a/spec/controllers/search_controller_spec.rb b/spec/controllers/search_controller_spec.rb
index 4634d1d4bb3..5a5c0a1f6ac 100644
--- a/spec/controllers/search_controller_spec.rb
+++ b/spec/controllers/search_controller_spec.rb
@@ -17,6 +17,10 @@ describe SearchController do
set(:project) { create(:project, :public, :repository, :wiki_repo) }
+ before do
+ expect(::Gitlab::GitalyClient).to receive(:allow_ref_name_caching).and_call_original
+ end
+
subject { get(:show, params: { project_id: project.id, scope: scope, search: 'merge' }) }
where(:partial, :scope) do
@@ -35,6 +39,19 @@ describe SearchController do
end
end
+ context 'global search' do
+ render_views
+
+ it 'omits pipeline status from load' do
+ project = create(:project, :public)
+ expect(Gitlab::Cache::Ci::ProjectPipelineStatus).not_to receive(:load_in_batch_for_projects)
+
+ get :show, params: { scope: 'projects', search: project.name }
+
+ expect(assigns[:search_objects].first).to eq project
+ end
+ end
+
it 'finds issue comments' do
project = create(:project, :public)
note = create(:note_on_issue, project: project)
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/award_emoji.rb b/spec/factories/award_emoji.rb
index d37e2bf511e..43753fa650c 100644
--- a/spec/factories/award_emoji.rb
+++ b/spec/factories/award_emoji.rb
@@ -5,7 +5,7 @@ FactoryBot.define do
awardable factory: :issue
after(:create) do |award, evaluator|
- award.awardable.project.add_guest(evaluator.user)
+ award.awardable.project&.add_guest(evaluator.user)
end
trait :upvote
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/deployments.rb b/spec/factories/deployments.rb
index db438ad32d3..1c7787bc1a6 100644
--- a/spec/factories/deployments.rb
+++ b/spec/factories/deployments.rb
@@ -22,6 +22,10 @@ FactoryBot.define do
ref 'pages-deploy'
end
+ trait :on_cluster do
+ cluster factory: %i(cluster provided_by_gcp)
+ end
+
trait :running do
status :running
end
diff --git a/spec/factories/namespace/aggregation_schedules.rb b/spec/factories/namespace/aggregation_schedules.rb
new file mode 100644
index 00000000000..c172c3360e2
--- /dev/null
+++ b/spec/factories/namespace/aggregation_schedules.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+FactoryBot.define do
+ factory :namespace_aggregation_schedules, class: Namespace::AggregationSchedule do
+ namespace
+ end
+end
diff --git a/spec/factories/namespace/root_storage_statistics.rb b/spec/factories/namespace/root_storage_statistics.rb
new file mode 100644
index 00000000000..54c5921eb44
--- /dev/null
+++ b/spec/factories/namespace/root_storage_statistics.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+FactoryBot.define do
+ factory :namespace_root_storage_statistics, class: Namespace::RootStorageStatistics do
+ namespace
+ end
+end
diff --git a/spec/factories/namespaces.rb b/spec/factories/namespaces.rb
index 6feafa5ece9..0cfc6e3aa46 100644
--- a/spec/factories/namespaces.rb
+++ b/spec/factories/namespaces.rb
@@ -19,5 +19,13 @@ FactoryBot.define do
owner.namespace = namespace
end
end
+
+ trait :with_aggregation_schedule do
+ association :aggregation_schedule, factory: :namespace_aggregation_schedules
+ end
+
+ trait :with_root_storage_statistics do
+ association :root_storage_statistics, factory: :namespace_root_storage_statistics
+ end
end
end
diff --git a/spec/factories/pages_domains.rb b/spec/factories/pages_domains.rb
index 8da19a37a6a..3e0baab04ce 100644
--- a/spec/factories/pages_domains.rb
+++ b/spec/factories/pages_domains.rb
@@ -182,6 +182,7 @@ ZDXgrA==
end
trait :letsencrypt do
+ auto_ssl_enabled { true }
certificate_source { :gitlab_provided }
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_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/boards/sidebar_spec.rb b/spec/features/boards/sidebar_spec.rb
index b1798c11361..6c9ae343e01 100644
--- a/spec/features/boards/sidebar_spec.rb
+++ b/spec/features/boards/sidebar_spec.rb
@@ -16,7 +16,9 @@ describe 'Issue Boards', :js do
let!(:issue2) { create(:labeled_issue, project: project, labels: [development, stretch], relative_position: 1) }
let(:board) { create(:board, project: project) }
let!(:list) { create(:list, board: board, label: development, position: 0) }
- let(:card) { find('.board:nth-child(2)').first('.board-card') }
+ let(:card) { find('.board:nth-child(2)').first('.board-card') }
+
+ let(:application_settings) { {} }
around do |example|
Timecop.freeze { example.run }
@@ -27,6 +29,8 @@ describe 'Issue Boards', :js do
sign_in(user)
+ stub_application_setting(application_settings)
+
visit project_board_path(project, board)
wait_for_requests
end
@@ -223,16 +227,24 @@ describe 'Issue Boards', :js do
end
context 'time tracking' do
+ let(:compare_meter_tooltip) { find('.time-tracking .time-tracking-content .compare-meter')['data-original-title'] }
+
before do
issue2.timelogs.create(time_spent: 14400, user: user)
- issue2.update!(time_estimate: 28800)
+ issue2.update!(time_estimate: 128800)
+
+ click_card(card)
end
it 'shows time tracking progress bar' do
- click_card(card)
+ expect(compare_meter_tooltip).to eq('Time remaining: 3d 7h 46m')
+ end
+
+ context 'when time_tracking_limit_to_hours is true' do
+ let(:application_settings) { { time_tracking_limit_to_hours: true } }
- page.within('.time-tracking') do
- expect(find('.time-tracking-content .compare-meter')['data-original-title']).to eq('Time remaining: 4h')
+ it 'shows time tracking progress bar' do
+ expect(compare_meter_tooltip).to eq('Time remaining: 31h 46m')
end
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/discussion_comments/commit_spec.rb b/spec/features/discussion_comments/commit_spec.rb
index 7a3b1d7ed47..b3f1731ec95 100644
--- a/spec/features/discussion_comments/commit_spec.rb
+++ b/spec/features/discussion_comments/commit_spec.rb
@@ -1,11 +1,13 @@
require 'spec_helper'
-describe 'Discussion Comments Commit', :js do
+describe 'Thread Comments Commit', :js do
include RepoHelpers
let(:user) { create(:user) }
let(:project) { create(:project, :repository) }
let(:merge_request) { create(:merge_request, source_project: project) }
+ let!(:commit_discussion_note1) { create(:discussion_note_on_commit, project: project) }
+ let!(:commit_discussion_note2) { create(:discussion_note_on_commit, in_reply_to: commit_discussion_note1) }
before do
project.add_maintainer(user)
@@ -14,5 +16,19 @@ 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')
+ end
+
+ it 'adds award to the correct note' do
+ find("#note_#{commit_discussion_note2.id} .js-note-emoji").click
+ first('.emoji-menu .js-emoji-btn').click
+
+ wait_for_requests
+
+ expect(find("#note_#{commit_discussion_note1.id}")).not_to have_css('.js-awards-block')
+ expect(find("#note_#{commit_discussion_note2.id}")).to have_css('.js-awards-block')
+ end
end
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 176f4a668ff..0ada530781c 100644
--- a/spec/features/groups/issues_spec.rb
+++ b/spec/features/groups/issues_spec.rb
@@ -2,6 +2,7 @@ require 'spec_helper'
describe 'Group issues page' do
include FilteredSearchHelpers
+ include DragTo
let(:group) { create(:group) }
let(:project) { create(:project, :public, group: group)}
@@ -99,4 +100,81 @@ describe 'Group issues page' do
end
end
end
+
+ context 'manual ordering' do
+ let(:user_in_group) { create(:group_member, :maintainer, user: create(:user), group: group ).user }
+
+ let!(:issue1) { create(:issue, project: project, title: 'Issue #1', relative_position: 1) }
+ let!(:issue2) { create(:issue, project: project, title: 'Issue #2', relative_position: 2) }
+ let!(:issue3) { create(:issue, project: project, title: 'Issue #3', relative_position: 3) }
+
+ before do
+ sign_in(user_in_group)
+ end
+
+ it 'displays all issues' do
+ visit issues_group_path(group, sort: 'relative_position')
+
+ page.within('.issues-list') do
+ expect(page).to have_selector('li.issue', count: 3)
+ end
+ end
+
+ it 'has manual-ordering css applied' do
+ visit issues_group_path(group, sort: 'relative_position')
+
+ expect(page).to have_selector('.manual-ordering')
+ end
+
+ it 'each issue item has a user-can-drag css applied' do
+ visit issues_group_path(group, sort: 'relative_position')
+
+ page.within('.manual-ordering') do
+ expect(page).to have_selector('.issue.user-can-drag', count: 3)
+ end
+ end
+
+ it 'issues should be draggable and persist order', :js do
+ visit issues_group_path(group, sort: 'relative_position')
+
+ drag_to(selector: '.manual-ordering',
+ from_index: 0,
+ to_index: 2)
+
+ wait_for_requests
+
+ check_issue_order
+
+ visit issues_group_path(group, sort: 'relative_position')
+
+ 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')
+ expect(find('.issue:nth-child(2) .title')).to have_content('Issue #3')
+ expect(find('.issue:nth-child(3) .title')).to have_content('Issue #1')
+ end
+ end
+ end
end
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/gfm_autocomplete_spec.rb b/spec/features/issues/gfm_autocomplete_spec.rb
index 8eb413bdd8d..40845ec48f9 100644
--- a/spec/features/issues/gfm_autocomplete_spec.rb
+++ b/spec/features/issues/gfm_autocomplete_spec.rb
@@ -3,14 +3,14 @@ require 'rails_helper'
describe 'GFM autocomplete', :js do
let(:issue_xss_title) { 'This will execute alert<img src=x onerror=alert(2)&lt;img src=x onerror=alert(1)&gt;' }
let(:user_xss_title) { 'eve <img src=x onerror=alert(2)&lt;img src=x onerror=alert(1)&gt;' }
- let(:label_xss_title) { 'alert label &lt;img src=x onerror="alert(\'Hello xss\');" a'}
+ let(:label_xss_title) { 'alert label &lt;img src=x onerror="alert(\'Hello xss\');" a' }
let(:milestone_xss_title) { 'alert milestone &lt;img src=x onerror="alert(\'Hello xss\');" a' }
let(:user_xss) { create(:user, name: user_xss_title, username: 'xss.user') }
- let(:user) { create(:user, name: '💃speciąl someone💃', username: 'someone.special') }
+ let(:user) { create(:user, name: '💃speciąl someone💃', username: 'someone.special') }
let(:project) { create(:project) }
let(:label) { create(:label, project: project, title: 'special+') }
- let(:issue) { create(:issue, project: project) }
+ let(:issue) { create(:issue, project: project) }
before do
project.add_maintainer(user)
@@ -293,6 +293,70 @@ describe 'GFM autocomplete', :js do
expect(find('.atwho-view-ul').text).to have_content('alert label')
end
end
+
+ it 'allows colons when autocompleting scoped labels' do
+ create(:label, project: project, title: 'scoped:label')
+
+ note = find('#note-body')
+ type(note, '~scoped:')
+
+ wait_for_requests
+
+ page.within '.atwho-container #at-view-labels' do
+ expect(find('.atwho-view-ul').text).to have_content('scoped:label')
+ end
+ end
+
+ it 'allows colons when autocompleting scoped labels with double colons' do
+ create(:label, project: project, title: 'scoped::label')
+
+ note = find('#note-body')
+ type(note, '~scoped::')
+
+ wait_for_requests
+
+ page.within '.atwho-container #at-view-labels' do
+ expect(find('.atwho-view-ul').text).to have_content('scoped::label')
+ end
+ end
+
+ it 'allows spaces when autocompleting multi-word labels' do
+ create(:label, project: project, title: 'Accepting merge requests')
+
+ note = find('#note-body')
+ type(note, '~Accepting merge')
+
+ wait_for_requests
+
+ page.within '.atwho-container #at-view-labels' do
+ expect(find('.atwho-view-ul').text).to have_content('Accepting merge requests')
+ end
+ end
+
+ it 'only autocompletes the latest label' do
+ create(:label, project: project, title: 'Accepting merge requests')
+ create(:label, project: project, title: 'Accepting job applicants')
+
+ note = find('#note-body')
+ type(note, '~Accepting merge requests foo bar ~Accepting job')
+
+ wait_for_requests
+
+ page.within '.atwho-container #at-view-labels' do
+ expect(find('.atwho-view-ul').text).to have_content('Accepting job applicants')
+ end
+ end
+
+ it 'does not autocomplete labels if no tilde is typed' do
+ create(:label, project: project, title: 'Accepting merge requests')
+
+ note = find('#note-body')
+ type(note, 'Accepting merge')
+
+ wait_for_requests
+
+ expect(page).not_to have_css('.atwho-container #at-view-labels')
+ end
end
shared_examples 'autocomplete suggestions' do
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 08fa4a98feb..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 except on last discussion' 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(0)
+ 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_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/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/environments/environment_metrics_spec.rb b/spec/features/projects/environments/environment_metrics_spec.rb
index edbab14f7c1..b08ccdc2a7c 100644
--- a/spec/features/projects/environments/environment_metrics_spec.rb
+++ b/spec/features/projects/environments/environment_metrics_spec.rb
@@ -9,11 +9,11 @@ describe 'Environment > Metrics' do
let(:build) { create(:ci_build, pipeline: pipeline) }
let(:environment) { create(:environment, project: project) }
let(:current_time) { Time.now.utc }
+ let!(:staging) { create(:environment, name: 'staging', project: project) }
before do
project.add_developer(user)
- create(:deployment, environment: environment, deployable: build)
- stub_all_prometheus_requests(environment.slug)
+ stub_any_prometheus_request
sign_in(user)
visit_environment(environment)
@@ -23,15 +23,50 @@ describe 'Environment > Metrics' do
Timecop.freeze(current_time) { example.run }
end
+ shared_examples 'has environment selector' do
+ it 'has a working environment selector', :js do
+ click_link('See metrics')
+
+ expect(page).to have_metrics_path(environment)
+ expect(page).to have_css('div.js-environments-dropdown')
+
+ within('div.js-environments-dropdown') do
+ # Click on the dropdown
+ click_on(environment.name)
+
+ # Select the staging environment
+ click_on(staging.name)
+ end
+
+ expect(page).to have_metrics_path(staging)
+
+ wait_for_requests
+ end
+ end
+
+ context 'without deployments' do
+ it_behaves_like 'has environment selector'
+ end
+
context 'with deployments and related deployable present' do
+ before do
+ create(:deployment, environment: environment, deployable: build)
+ end
+
it 'shows metrics' do
click_link('See metrics')
expect(page).to have_css('div#prometheus-graphs')
end
+
+ it_behaves_like 'has environment selector'
end
def visit_environment(environment)
visit project_environment_path(environment.project, environment)
end
+
+ def have_metrics_path(environment)
+ have_current_path(metrics_project_environment_path(project, id: environment.id))
+ end
end
diff --git a/spec/features/projects/files/user_edits_files_spec.rb b/spec/features/projects/files/user_edits_files_spec.rb
index 683268d064a..e0fa9dbb5fa 100644
--- a/spec/features/projects/files/user_edits_files_spec.rb
+++ b/spec/features/projects/files/user_edits_files_spec.rb
@@ -118,19 +118,31 @@ describe 'Projects > Files > User edits files', :js do
wait_for_requests
end
- it 'inserts a content of a file in a forked project' do
- click_link('.gitignore')
- find('.js-edit-blob').click
-
+ def expect_fork_prompt
expect(page).to have_link('Fork')
expect(page).to have_button('Cancel')
+ expect(page).to have_content(
+ "You're not allowed to edit files in this project directly. "\
+ "Please fork this project, make your changes there, and submit a merge request."
+ )
+ end
- click_link('Fork')
-
+ def expect_fork_status
expect(page).to have_content(
"You're not allowed to make changes to this project directly. "\
"A fork of this project has been created that you can make changes in, so you can submit a merge request."
)
+ end
+
+ it 'inserts a content of a file in a forked project' do
+ click_link('.gitignore')
+ click_button('Edit')
+
+ expect_fork_prompt
+
+ click_link('Fork')
+
+ expect_fork_status
find('.file-editor', match: :first)
@@ -140,12 +152,24 @@ describe 'Projects > Files > User edits files', :js do
expect(evaluate_script('ace.edit("editor").getValue()')).to eq('*.rbca')
end
+ it 'opens the Web IDE in a forked project' do
+ click_link('.gitignore')
+ click_button('Web IDE')
+
+ expect_fork_prompt
+
+ click_link('Fork')
+
+ expect_fork_status
+
+ expect(page).to have_css('.ide .multi-file-tab', text: '.gitignore')
+ end
+
it 'commits an edited file in a forked project' do
click_link('.gitignore')
find('.js-edit-blob').click
- expect(page).to have_link('Fork')
- expect(page).to have_button('Cancel')
+ expect_fork_prompt
click_link('Fork')
diff --git a/spec/features/projects/files/user_reads_pipeline_status_spec.rb b/spec/features/projects/files/user_reads_pipeline_status_spec.rb
index ff0aa933a3e..5bce96d9b80 100644
--- a/spec/features/projects/files/user_reads_pipeline_status_spec.rb
+++ b/spec/features/projects/files/user_reads_pipeline_status_spec.rb
@@ -7,6 +7,8 @@ describe 'user reads pipeline status', :js do
let(:x110_pipeline) { create_pipeline('x1.1.0', 'failed') }
before do
+ stub_feature_flags(vue_file_list: false)
+
project.add_maintainer(user)
project.repository.add_tag(user, 'x1.1.0', 'v1.1.0')
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/services/user_activates_jira_spec.rb b/spec/features/projects/services/user_activates_jira_spec.rb
index 08e1855d034..c52f38e2806 100644
--- a/spec/features/projects/services/user_activates_jira_spec.rb
+++ b/spec/features/projects/services/user_activates_jira_spec.rb
@@ -29,27 +29,27 @@ describe 'User activates Jira', :js do
server_info = { key: 'value' }.to_json
WebMock.stub_request(:get, test_url).with(basic_auth: %w(username password)).to_return(body: server_info)
- click_link('JIRA')
+ click_link('Jira')
fill_form
click_button('Test settings and save changes')
wait_for_requests
end
- it 'activates the JIRA service' do
- expect(page).to have_content('JIRA activated.')
+ it 'activates the Jira service' do
+ expect(page).to have_content('Jira activated.')
expect(current_path).to eq(project_settings_integrations_path(project))
end
- it 'shows the JIRA link in the menu' do
+ it 'shows the Jira link in the menu' do
page.within('.nav-sidebar') do
- expect(page).to have_link('JIRA', href: url)
+ expect(page).to have_link('Jira', href: url)
end
end
end
context 'when Jira connection test fails' do
it 'shows errors when some required fields are not filled in' do
- click_link('JIRA')
+ click_link('Jira')
check 'Active'
fill_in 'service_password', with: 'password'
@@ -60,11 +60,11 @@ describe 'User activates Jira', :js do
end
end
- it 'activates the JIRA service' do
+ it 'activates the Jira service' do
WebMock.stub_request(:get, test_url).with(basic_auth: %w(username password))
.to_raise(JIRA::HTTPError.new(double(message: 'message')))
- click_link('JIRA')
+ click_link('Jira')
fill_form
click_button('Test settings and save changes')
wait_for_requests
@@ -75,7 +75,7 @@ describe 'User activates Jira', :js do
find('.flash-alert .flash-action').click
wait_for_requests
- expect(page).to have_content('JIRA activated.')
+ expect(page).to have_content('Jira activated.')
expect(current_path).to eq(project_settings_integrations_path(project))
end
end
@@ -83,19 +83,19 @@ describe 'User activates Jira', :js do
describe 'user sets Jira Service but keeps it disabled' do
before do
- click_link('JIRA')
+ click_link('Jira')
fill_form(false)
click_button('Save changes')
end
- it 'saves but does not activate the JIRA service' do
- expect(page).to have_content('JIRA settings saved, but not activated.')
+ it 'saves but does not activate the Jira service' do
+ expect(page).to have_content('Jira settings saved, but not activated.')
expect(current_path).to eq(project_settings_integrations_path(project))
end
- it 'does not show the JIRA link in the menu' do
+ it 'does not show the Jira link in the menu' do
page.within('.nav-sidebar') do
- expect(page).not_to have_link('JIRA', href: url)
+ expect(page).not_to have_link('Jira', href: url)
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/projects/show/user_sees_last_commit_ci_status_spec.rb b/spec/features/projects/show/user_sees_last_commit_ci_status_spec.rb
index e277bfb8011..89ce4b50781 100644
--- a/spec/features/projects/show/user_sees_last_commit_ci_status_spec.rb
+++ b/spec/features/projects/show/user_sees_last_commit_ci_status_spec.rb
@@ -3,6 +3,10 @@ require 'spec_helper'
describe 'Projects > Show > User sees last commit CI status' do
set(:project) { create(:project, :repository, :public) }
+ before do
+ stub_feature_flags(vue_file_list: false)
+ end
+
it 'shows the project README', :js do
project.enable_ci
pipeline = create(:ci_pipeline, project: project, sha: project.commit.sha, ref: 'master')
diff --git a/spec/features/raven_js_spec.rb b/spec/features/raven_js_spec.rb
index 9a049764dec..a4dd79b3179 100644
--- a/spec/features/raven_js_spec.rb
+++ b/spec/features/raven_js_spec.rb
@@ -10,7 +10,7 @@ describe 'RavenJS' do
end
it 'loads raven if sentry is enabled' do
- stub_application_setting(clientside_sentry_dsn: 'https://key@domain.com/id', clientside_sentry_enabled: true)
+ stub_sentry_settings
visit new_user_session_path
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/signup_spec.rb b/spec/features/users/signup_spec.rb
index 8a6901ea4e9..50befa7028d 100644
--- a/spec/features/users/signup_spec.rb
+++ b/spec/features/users/signup_spec.rb
@@ -90,7 +90,7 @@ describe 'Signup' do
expect(page).to have_content("Invalid input, please avoid emojis")
end
- it 'shows a pending message if the username availability is being fetched' do
+ it 'shows a pending message if the username availability is being fetched', :quarantine do
fill_in 'new_user_username', with: 'new-user'
expect(find('.username > .validation-pending')).not_to have_css '.hide'
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/autocomplete/acts_as_taggable_on/tags_finder_spec.rb b/spec/finders/autocomplete/acts_as_taggable_on/tags_finder_spec.rb
index 79d2f9cdb45..c4e6c9cc9f5 100644
--- a/spec/finders/autocomplete/acts_as_taggable_on/tags_finder_spec.rb
+++ b/spec/finders/autocomplete/acts_as_taggable_on/tags_finder_spec.rb
@@ -17,13 +17,13 @@ describe Autocomplete::ActsAsTaggableOn::TagsFinder do
context 'filter by search' do
context 'with an empty search term' do
- it 'returns an empty collection' do
- ActsAsTaggableOn::Tag.create!(name: 'tag1')
- ActsAsTaggableOn::Tag.create!(name: 'tag2')
+ it 'returns all tags' do
+ tag1 = ActsAsTaggableOn::Tag.create!(name: 'tag1')
+ tag2 = ActsAsTaggableOn::Tag.create!(name: 'tag2')
tags = described_class.new(params: { search: '' }).execute
- expect(tags).to be_empty
+ expect(tags).to match_array [tag1, tag2]
end
end
diff --git a/spec/finders/boards/visits_finder_spec.rb b/spec/finders/boards/visits_finder_spec.rb
new file mode 100644
index 00000000000..4d40f4826f8
--- /dev/null
+++ b/spec/finders/boards/visits_finder_spec.rb
@@ -0,0 +1,59 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Boards::VisitsFinder do
+ describe '#latest' do
+ let(:user) { create(:user) }
+
+ context 'when a project board' do
+ let(:project) { create(:project) }
+ let(:project_board) { create(:board, project: project) }
+
+ subject(:finder) { described_class.new(project_board.parent, user) }
+
+ it 'returns nil when there is no user' do
+ finder.current_user = nil
+
+ expect(finder.execute).to eq nil
+ end
+
+ it 'queries for most recent visit' do
+ expect(BoardProjectRecentVisit).to receive(:latest).once
+
+ finder.execute
+ end
+
+ it 'queries for last N visits' do
+ expect(BoardProjectRecentVisit).to receive(:latest).with(user, project, count: 5).once
+
+ described_class.new(project_board.parent, user).latest(5)
+ end
+ end
+
+ context 'when a group board' do
+ let(:group) { create(:group) }
+ let(:group_board) { create(:board, group: group) }
+
+ subject(:finder) { described_class.new(group_board.parent, user) }
+
+ it 'returns nil when there is no user' do
+ finder.current_user = nil
+
+ expect(finder.execute).to eq nil
+ end
+
+ it 'queries for most recent visit' do
+ expect(BoardGroupRecentVisit).to receive(:latest).once
+
+ finder.latest
+ end
+
+ it 'queries for last N visits' do
+ expect(BoardGroupRecentVisit).to receive(:latest).with(user, group, count: 5).once
+
+ described_class.new(group_board.parent, user).latest(5)
+ end
+ end
+ end
+end
diff --git a/spec/finders/branches_finder_spec.rb b/spec/finders/branches_finder_spec.rb
index 7d164539d9a..3fc86f3e408 100644
--- a/spec/finders/branches_finder_spec.rb
+++ b/spec/finders/branches_finder_spec.rb
@@ -62,6 +62,15 @@ describe BranchesFinder do
expect(result.count).to eq(0)
end
+
+ it 'filters branches by provided names' do
+ branches_finder = described_class.new(repository, { names: ['fix', 'csv', 'lfs', 'does-not-exist'] })
+
+ result = branches_finder.execute
+
+ expect(result.count).to eq(3)
+ expect(result.map(&:name)).to eq(%w{csv fix lfs})
+ end
end
context 'filter and sort' do
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/fixtures/api/schemas/entities/merge_request_widget.json b/spec/fixtures/api/schemas/entities/merge_request_widget.json
index 7018cb9a305..eac1dbc6474 100644
--- a/spec/fixtures/api/schemas/entities/merge_request_widget.json
+++ b/spec/fixtures/api/schemas/entities/merge_request_widget.json
@@ -99,7 +99,8 @@
"revert_in_fork_path": { "type": ["string", "null"] },
"email_patches_path": { "type": "string" },
"plain_diff_path": { "type": "string" },
- "status_path": { "type": "string" },
+ "merge_request_basic_path": { "type": "string" },
+ "merge_request_widget_path": { "type": "string" },
"new_blob_path": { "type": ["string", "null"] },
"merge_check_path": { "type": "string" },
"ci_environments_status_path": { "type": "string" },
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/boards/modal_store_spec.js b/spec/frontend/boards/modal_store_spec.js
index 4dd27e94d97..5b5ae4b6556 100644
--- a/spec/frontend/boards/modal_store_spec.js
+++ b/spec/frontend/boards/modal_store_spec.js
@@ -25,7 +25,7 @@ describe('Modal store', () => {
});
issue2 = new ListIssue({
title: 'Testing',
- id: 1,
+ id: 2,
iid: 2,
confidential: false,
labels: [],
diff --git a/spec/frontend/boards/services/board_service_spec.js b/spec/frontend/boards/services/board_service_spec.js
new file mode 100644
index 00000000000..de9fc998360
--- /dev/null
+++ b/spec/frontend/boards/services/board_service_spec.js
@@ -0,0 +1,390 @@
+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';
+
+describe('BoardService', () => {
+ const dummyResponse = "without type checking this doesn't matter";
+ const boardId = 'dummy-board-id';
+ const endpoints = {
+ boardsEndpoint: `${TEST_HOST}/boards`,
+ listsEndpoint: `${TEST_HOST}/lists`,
+ bulkUpdatePath: `${TEST_HOST}/bulk/update`,
+ recentBoardsEndpoint: `${TEST_HOST}/recent/boards`,
+ };
+
+ let service;
+ let axiosMock;
+
+ beforeEach(() => {
+ axiosMock = new AxiosMockAdapter(axios);
+ service = new BoardService({
+ ...endpoints,
+ boardId,
+ });
+ });
+
+ describe('all', () => {
+ it('makes a request to fetch lists', () => {
+ axiosMock.onGet(endpoints.listsEndpoint).replyOnce(200, dummyResponse);
+ const expectedResponse = expect.objectContaining({ data: dummyResponse });
+
+ return expect(service.all()).resolves.toEqual(expectedResponse);
+ });
+
+ it('fails for error response', () => {
+ axiosMock.onGet(endpoints.listsEndpoint).replyOnce(500);
+
+ return expect(service.all()).rejects.toThrow();
+ });
+ });
+
+ describe('generateDefaultLists', () => {
+ const listsEndpointGenerate = `${endpoints.listsEndpoint}/generate.json`;
+
+ it('makes a request to generate default lists', () => {
+ axiosMock.onPost(listsEndpointGenerate).replyOnce(200, dummyResponse);
+ const expectedResponse = expect.objectContaining({ data: dummyResponse });
+
+ return expect(service.generateDefaultLists()).resolves.toEqual(expectedResponse);
+ });
+
+ it('fails for error response', () => {
+ axiosMock.onPost(listsEndpointGenerate).replyOnce(500);
+
+ return expect(service.generateDefaultLists()).rejects.toThrow();
+ });
+ });
+
+ describe('createList', () => {
+ const entityType = 'moorhen';
+ const entityId = 'quack';
+ const expectedRequest = expect.objectContaining({
+ data: JSON.stringify({ list: { [entityType]: entityId } }),
+ });
+
+ let requestSpy;
+
+ beforeEach(() => {
+ requestSpy = jest.fn();
+ axiosMock.onPost(endpoints.listsEndpoint).replyOnce(config => requestSpy(config));
+ });
+
+ it('makes a request to create a list', () => {
+ requestSpy.mockReturnValue([200, dummyResponse]);
+ const expectedResponse = expect.objectContaining({ data: dummyResponse });
+
+ return expect(service.createList(entityId, entityType))
+ .resolves.toEqual(expectedResponse)
+ .then(() => {
+ expect(requestSpy).toHaveBeenCalledWith(expectedRequest);
+ });
+ });
+
+ it('fails for error response', () => {
+ requestSpy.mockReturnValue([500]);
+
+ return expect(service.createList(entityId, entityType))
+ .rejects.toThrow()
+ .then(() => {
+ expect(requestSpy).toHaveBeenCalledWith(expectedRequest);
+ });
+ });
+ });
+
+ describe('updateList', () => {
+ const id = 'David Webb';
+ const position = 'unknown';
+ const expectedRequest = expect.objectContaining({
+ data: JSON.stringify({ list: { position } }),
+ });
+
+ let requestSpy;
+
+ beforeEach(() => {
+ requestSpy = jest.fn();
+ axiosMock.onPut(`${endpoints.listsEndpoint}/${id}`).replyOnce(config => requestSpy(config));
+ });
+
+ it('makes a request to update a list position', () => {
+ requestSpy.mockReturnValue([200, dummyResponse]);
+ const expectedResponse = expect.objectContaining({ data: dummyResponse });
+
+ return expect(service.updateList(id, position))
+ .resolves.toEqual(expectedResponse)
+ .then(() => {
+ expect(requestSpy).toHaveBeenCalledWith(expectedRequest);
+ });
+ });
+
+ it('fails for error response', () => {
+ requestSpy.mockReturnValue([500]);
+
+ return expect(service.updateList(id, position))
+ .rejects.toThrow()
+ .then(() => {
+ expect(requestSpy).toHaveBeenCalledWith(expectedRequest);
+ });
+ });
+ });
+
+ describe('destroyList', () => {
+ const id = '-42';
+
+ let requestSpy;
+
+ beforeEach(() => {
+ requestSpy = jest.fn();
+ axiosMock
+ .onDelete(`${endpoints.listsEndpoint}/${id}`)
+ .replyOnce(config => requestSpy(config));
+ });
+
+ it('makes a request to delete a list', () => {
+ requestSpy.mockReturnValue([200, dummyResponse]);
+ const expectedResponse = expect.objectContaining({ data: dummyResponse });
+
+ return expect(service.destroyList(id))
+ .resolves.toEqual(expectedResponse)
+ .then(() => {
+ expect(requestSpy).toHaveBeenCalled();
+ });
+ });
+
+ it('fails for error response', () => {
+ requestSpy.mockReturnValue([500]);
+
+ return expect(service.destroyList(id))
+ .rejects.toThrow()
+ .then(() => {
+ expect(requestSpy).toHaveBeenCalled();
+ });
+ });
+ });
+
+ describe('getIssuesForList', () => {
+ const id = 'TOO-MUCH';
+ const url = `${endpoints.listsEndpoint}/${id}/issues?id=${id}`;
+
+ it('makes a request to fetch list issues', () => {
+ axiosMock.onGet(url).replyOnce(200, dummyResponse);
+ const expectedResponse = expect.objectContaining({ data: dummyResponse });
+
+ return expect(service.getIssuesForList(id)).resolves.toEqual(expectedResponse);
+ });
+
+ it('makes a request to fetch list issues with filter', () => {
+ const filter = { algal: 'scrubber' };
+ axiosMock.onGet(`${url}&algal=scrubber`).replyOnce(200, dummyResponse);
+ const expectedResponse = expect.objectContaining({ data: dummyResponse });
+
+ return expect(service.getIssuesForList(id, filter)).resolves.toEqual(expectedResponse);
+ });
+
+ it('fails for error response', () => {
+ axiosMock.onGet(url).replyOnce(500);
+
+ return expect(service.getIssuesForList(id)).rejects.toThrow();
+ });
+ });
+
+ describe('moveIssue', () => {
+ const urlRoot = 'potato';
+ const id = 'over 9000';
+ const fromListId = 'left';
+ const toListId = 'right';
+ const moveBeforeId = 'up';
+ const moveAfterId = 'down';
+ const expectedRequest = expect.objectContaining({
+ data: JSON.stringify({
+ from_list_id: fromListId,
+ to_list_id: toListId,
+ move_before_id: moveBeforeId,
+ move_after_id: moveAfterId,
+ }),
+ });
+
+ let requestSpy;
+
+ beforeAll(() => {
+ global.gon.relative_url_root = urlRoot;
+ });
+
+ afterAll(() => {
+ delete global.gon.relative_url_root;
+ });
+
+ beforeEach(() => {
+ requestSpy = jest.fn();
+ axiosMock
+ .onPut(`${urlRoot}/-/boards/${boardId}/issues/${id}`)
+ .replyOnce(config => requestSpy(config));
+ });
+
+ it('makes a request to move an issue between lists', () => {
+ requestSpy.mockReturnValue([200, dummyResponse]);
+ const expectedResponse = expect.objectContaining({ data: dummyResponse });
+
+ return expect(service.moveIssue(id, fromListId, toListId, moveBeforeId, moveAfterId))
+ .resolves.toEqual(expectedResponse)
+ .then(() => {
+ expect(requestSpy).toHaveBeenCalledWith(expectedRequest);
+ });
+ });
+
+ it('fails for error response', () => {
+ requestSpy.mockReturnValue([500]);
+
+ return expect(service.moveIssue(id, fromListId, toListId, moveBeforeId, moveAfterId))
+ .rejects.toThrow()
+ .then(() => {
+ expect(requestSpy).toHaveBeenCalledWith(expectedRequest);
+ });
+ });
+ });
+
+ describe('newIssue', () => {
+ const id = 'not-creative';
+ const issue = { some: 'issue data' };
+ const url = `${endpoints.listsEndpoint}/${id}/issues`;
+ const expectedRequest = expect.objectContaining({
+ data: JSON.stringify({
+ issue,
+ }),
+ });
+
+ let requestSpy;
+
+ beforeEach(() => {
+ requestSpy = jest.fn();
+ axiosMock.onPost(url).replyOnce(config => requestSpy(config));
+ });
+
+ it('makes a request to create a new issue', () => {
+ requestSpy.mockReturnValue([200, dummyResponse]);
+ const expectedResponse = expect.objectContaining({ data: dummyResponse });
+
+ return expect(service.newIssue(id, issue))
+ .resolves.toEqual(expectedResponse)
+ .then(() => {
+ expect(requestSpy).toHaveBeenCalledWith(expectedRequest);
+ });
+ });
+
+ it('fails for error response', () => {
+ requestSpy.mockReturnValue([500]);
+
+ return expect(service.newIssue(id, issue))
+ .rejects.toThrow()
+ .then(() => {
+ expect(requestSpy).toHaveBeenCalledWith(expectedRequest);
+ });
+ });
+ });
+
+ describe('getBacklog', () => {
+ const urlRoot = 'deep';
+ const url = `${urlRoot}/-/boards/${boardId}/issues.json?not=relevant`;
+ const requestParams = {
+ not: 'relevant',
+ };
+
+ beforeAll(() => {
+ global.gon.relative_url_root = urlRoot;
+ });
+
+ afterAll(() => {
+ delete global.gon.relative_url_root;
+ });
+
+ it('makes a request to fetch backlog', () => {
+ axiosMock.onGet(url).replyOnce(200, dummyResponse);
+ const expectedResponse = expect.objectContaining({ data: dummyResponse });
+
+ return expect(service.getBacklog(requestParams)).resolves.toEqual(expectedResponse);
+ });
+
+ it('fails for error response', () => {
+ axiosMock.onGet(url).replyOnce(500);
+
+ return expect(service.getBacklog(requestParams)).rejects.toThrow();
+ });
+ });
+
+ describe('bulkUpdate', () => {
+ const issueIds = [1, 2, 3];
+ const extraData = { moar: 'data' };
+ const expectedRequest = expect.objectContaining({
+ data: JSON.stringify({
+ update: {
+ ...extraData,
+ issuable_ids: '1,2,3',
+ },
+ }),
+ });
+
+ let requestSpy;
+
+ beforeEach(() => {
+ requestSpy = jest.fn();
+ axiosMock.onPost(endpoints.bulkUpdatePath).replyOnce(config => requestSpy(config));
+ });
+
+ it('makes a request to create a list', () => {
+ requestSpy.mockReturnValue([200, dummyResponse]);
+ const expectedResponse = expect.objectContaining({ data: dummyResponse });
+
+ return expect(service.bulkUpdate(issueIds, extraData))
+ .resolves.toEqual(expectedResponse)
+ .then(() => {
+ expect(requestSpy).toHaveBeenCalledWith(expectedRequest);
+ });
+ });
+
+ it('fails for error response', () => {
+ requestSpy.mockReturnValue([500]);
+
+ return expect(service.bulkUpdate(issueIds, extraData))
+ .rejects.toThrow()
+ .then(() => {
+ expect(requestSpy).toHaveBeenCalledWith(expectedRequest);
+ });
+ });
+ });
+
+ describe('getIssueInfo', () => {
+ const dummyEndpoint = `${TEST_HOST}/some/where`;
+
+ it('makes a request to the given endpoint', () => {
+ axiosMock.onGet(dummyEndpoint).replyOnce(200, dummyResponse);
+ const expectedResponse = expect.objectContaining({ data: dummyResponse });
+
+ return expect(BoardService.getIssueInfo(dummyEndpoint)).resolves.toEqual(expectedResponse);
+ });
+
+ it('fails for error response', () => {
+ axiosMock.onGet(dummyEndpoint).replyOnce(500);
+
+ return expect(BoardService.getIssueInfo(dummyEndpoint)).rejects.toThrow();
+ });
+ });
+
+ describe('toggleIssueSubscription', () => {
+ const dummyEndpoint = `${TEST_HOST}/some/where`;
+
+ it('makes a request to the given endpoint', () => {
+ axiosMock.onPost(dummyEndpoint).replyOnce(200, dummyResponse);
+ const expectedResponse = expect.objectContaining({ data: dummyResponse });
+
+ return expect(BoardService.toggleIssueSubscription(dummyEndpoint)).resolves.toEqual(
+ expectedResponse,
+ );
+ });
+
+ it('fails for error response', () => {
+ axiosMock.onPost(dummyEndpoint).replyOnce(500);
+
+ return expect(BoardService.toggleIssueSubscription(dummyEndpoint)).rejects.toThrow();
+ });
+ });
+});
diff --git a/spec/frontend/branches/divergence_graph_spec.js b/spec/frontend/branches/divergence_graph_spec.js
new file mode 100644
index 00000000000..4ed77c3a036
--- /dev/null
+++ b/spec/frontend/branches/divergence_graph_spec.js
@@ -0,0 +1,32 @@
+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 },
+ });
+
+ jest.spyOn(axios, 'get');
+
+ document.body.innerHTML = `
+ <div class="js-branch-item" data-name="master"></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'] },
+ });
+ }));
+});
diff --git a/spec/frontend/clusters/services/application_state_machine_spec.js b/spec/frontend/clusters/services/application_state_machine_spec.js
index c146ef79be7..8632c5c4e26 100644
--- a/spec/frontend/clusters/services/application_state_machine_spec.js
+++ b/spec/frontend/clusters/services/application_state_machine_spec.js
@@ -72,9 +72,10 @@ describe('applicationStateMachine', () => {
describe(`current state is ${INSTALLABLE}`, () => {
it.each`
- expectedState | event | effects
- ${INSTALLING} | ${INSTALL_EVENT} | ${{ installFailed: false }}
- ${INSTALLED} | ${INSTALLED} | ${NO_EFFECTS}
+ expectedState | event | effects
+ ${INSTALLING} | ${INSTALL_EVENT} | ${{ installFailed: false }}
+ ${INSTALLED} | ${INSTALLED} | ${NO_EFFECTS}
+ ${NOT_INSTALLABLE} | ${NOT_INSTALLABLE} | ${NO_EFFECTS}
`(`transitions to $expectedState on $event event and applies $effects`, data => {
const { expectedState, event, effects } = data;
const currentAppState = {
@@ -108,9 +109,10 @@ describe('applicationStateMachine', () => {
describe(`current state is ${INSTALLED}`, () => {
it.each`
- expectedState | event | effects
- ${UPDATING} | ${UPDATE_EVENT} | ${{ updateFailed: false, updateSuccessful: false }}
- ${UNINSTALLING} | ${UNINSTALL_EVENT} | ${{ uninstallFailed: false, uninstallSuccessful: false }}
+ expectedState | event | effects
+ ${UPDATING} | ${UPDATE_EVENT} | ${{ updateFailed: false, updateSuccessful: false }}
+ ${UNINSTALLING} | ${UNINSTALL_EVENT} | ${{ uninstallFailed: false, uninstallSuccessful: false }}
+ ${NOT_INSTALLABLE} | ${NOT_INSTALLABLE} | ${NO_EFFECTS}
`(`transitions to $expectedState on $event event and applies $effects`, data => {
const { expectedState, event, effects } = data;
const currentAppState = {
@@ -119,7 +121,7 @@ describe('applicationStateMachine', () => {
expect(transitionApplicationState(currentAppState, event)).toEqual({
status: expectedState,
- ...effects,
+ ...noEffectsToEmptyObject(effects),
});
});
});
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/helpers/vuex_action_helper.js b/spec/frontend/helpers/vuex_action_helper.js
index 88652202a8e..6c3569a2247 100644
--- a/spec/frontend/helpers/vuex_action_helper.js
+++ b/spec/frontend/helpers/vuex_action_helper.js
@@ -20,7 +20,7 @@ const noop = () => {};
* // expected mutations
* [
* { type: types.MUTATION}
- * { type: types.MUTATION_1, payload: jasmine.any(Number)}
+ * { type: types.MUTATION_1, payload: expect.any(Number)}
* ],
* // expected actions
* [
@@ -89,10 +89,7 @@ export default (
payload,
);
- return new Promise(resolve => {
- setImmediate(resolve);
- })
- .then(() => result)
+ return (result || new Promise(resolve => setImmediate(resolve)))
.catch(error => {
validateResults();
throw error;
diff --git a/spec/frontend/helpers/vuex_action_helper_spec.js b/spec/frontend/helpers/vuex_action_helper_spec.js
new file mode 100644
index 00000000000..61d05762a04
--- /dev/null
+++ b/spec/frontend/helpers/vuex_action_helper_spec.js
@@ -0,0 +1,166 @@
+import MockAdapter from 'axios-mock-adapter';
+import { TEST_HOST } from 'helpers/test_constants';
+import axios from '~/lib/utils/axios_utils';
+import testAction from './vuex_action_helper';
+
+describe('VueX test helper (testAction)', () => {
+ let originalExpect;
+ let assertion;
+ let mock;
+ const noop = () => {};
+
+ beforeEach(() => {
+ mock = new MockAdapter(axios);
+ /**
+ * In order to test the helper properly, we need to overwrite the Jest
+ * `expect` helper. We test that the testAction helper properly passes the
+ * dispatched actions/committed mutations to the Jest helper.
+ */
+ originalExpect = expect;
+ assertion = null;
+ global.expect = actual => ({
+ toEqual: () => {
+ originalExpect(actual).toEqual(assertion);
+ },
+ });
+ });
+
+ afterEach(() => {
+ mock.restore();
+ global.expect = originalExpect;
+ });
+
+ it('properly passes state and payload to action', () => {
+ const exampleState = { FOO: 12, BAR: 3 };
+ const examplePayload = { BAZ: 73, BIZ: 55 };
+
+ const action = ({ state }, payload) => {
+ originalExpect(state).toEqual(exampleState);
+ originalExpect(payload).toEqual(examplePayload);
+ };
+
+ assertion = { mutations: [], actions: [] };
+
+ testAction(action, examplePayload, exampleState);
+ });
+
+ describe('given a sync action', () => {
+ it('mocks committing mutations', () => {
+ const action = ({ commit }) => {
+ commit('MUTATION');
+ };
+
+ assertion = { mutations: [{ type: 'MUTATION' }], actions: [] };
+
+ testAction(action, null, {}, assertion.mutations, assertion.actions, noop);
+ });
+
+ it('mocks dispatching actions', () => {
+ const action = ({ dispatch }) => {
+ dispatch('ACTION');
+ };
+
+ assertion = { actions: [{ type: 'ACTION' }], mutations: [] };
+
+ testAction(action, null, {}, assertion.mutations, assertion.actions, noop);
+ });
+
+ it('works with done callback once finished', done => {
+ assertion = { mutations: [], actions: [] };
+
+ testAction(noop, null, {}, assertion.mutations, assertion.actions, done);
+ });
+
+ it('returns a promise', done => {
+ assertion = { mutations: [], actions: [] };
+
+ testAction(noop, null, {}, assertion.mutations, assertion.actions)
+ .then(done)
+ .catch(done.fail);
+ });
+ });
+
+ describe('given an async action (returning a promise)', () => {
+ let lastError;
+ const data = { FOO: 'BAR' };
+
+ const asyncAction = ({ commit, dispatch }) => {
+ dispatch('ACTION');
+
+ return axios
+ .get(TEST_HOST)
+ .catch(error => {
+ commit('ERROR');
+ lastError = error;
+ throw error;
+ })
+ .then(() => {
+ commit('SUCCESS');
+ return data;
+ });
+ };
+
+ beforeEach(() => {
+ lastError = null;
+ });
+
+ it('works with done callback once finished', done => {
+ mock.onGet(TEST_HOST).replyOnce(200, 42);
+
+ assertion = { mutations: [{ type: 'SUCCESS' }], actions: [{ type: 'ACTION' }] };
+
+ testAction(asyncAction, null, {}, assertion.mutations, assertion.actions, done);
+ });
+
+ it('returns original data of successful promise while checking actions/mutations', done => {
+ mock.onGet(TEST_HOST).replyOnce(200, 42);
+
+ assertion = { mutations: [{ type: 'SUCCESS' }], actions: [{ type: 'ACTION' }] };
+
+ testAction(asyncAction, null, {}, assertion.mutations, assertion.actions)
+ .then(res => {
+ originalExpect(res).toEqual(data);
+ done();
+ })
+ .catch(done.fail);
+ });
+
+ it('returns original error of rejected promise while checking actions/mutations', done => {
+ mock.onGet(TEST_HOST).replyOnce(500, '');
+
+ assertion = { mutations: [{ type: 'ERROR' }], actions: [{ type: 'ACTION' }] };
+
+ testAction(asyncAction, null, {}, assertion.mutations, assertion.actions)
+ .then(done.fail)
+ .catch(error => {
+ originalExpect(error).toBe(lastError);
+ done();
+ });
+ });
+ });
+
+ it('works with async actions not returning promises', done => {
+ const data = { FOO: 'BAR' };
+
+ const asyncAction = ({ commit, dispatch }) => {
+ dispatch('ACTION');
+
+ axios
+ .get(TEST_HOST)
+ .then(() => {
+ commit('SUCCESS');
+ return data;
+ })
+ .catch(error => {
+ commit('ERROR');
+ throw error;
+ });
+ };
+
+ mock.onGet(TEST_HOST).replyOnce(200, 42);
+
+ assertion = { mutations: [{ type: 'SUCCESS' }], actions: [{ type: 'ACTION' }] };
+
+ testAction(asyncAction, null, {}, assertion.mutations, assertion.actions, done);
+ });
+});
diff --git a/spec/frontend/ide/utils_spec.js b/spec/frontend/ide/utils_spec.js
new file mode 100644
index 00000000000..2b7dffdcd88
--- /dev/null
+++ b/spec/frontend/ide/utils_spec.js
@@ -0,0 +1,44 @@
+import { commitItemIconMap } from '~/ide/constants';
+import { getCommitIconMap } from '~/ide/utils';
+import { decorateData } from '~/ide/stores/utils';
+
+describe('WebIDE utils', () => {
+ const createFile = (name = 'name', id = name, type = '', parent = null) =>
+ decorateData({
+ id,
+ type,
+ icon: 'icon',
+ url: 'url',
+ name,
+ path: parent ? `${parent.path}/${name}` : name,
+ parentPath: parent ? parent.path : '',
+ lastCommit: {},
+ });
+
+ describe('getCommitIconMap', () => {
+ let entry;
+
+ beforeEach(() => {
+ entry = createFile('Entry item');
+ });
+
+ it('renders "deleted" icon for deleted entries', () => {
+ entry.deleted = true;
+ expect(getCommitIconMap(entry)).toEqual(commitItemIconMap.deleted);
+ });
+ it('renders "addition" icon for temp entries', () => {
+ entry.tempFile = true;
+ expect(getCommitIconMap(entry)).toEqual(commitItemIconMap.addition);
+ });
+ it('renders "modified" icon for newly-renamed entries', () => {
+ entry.prevPath = 'foo/bar';
+ entry.tempFile = false;
+ expect(getCommitIconMap(entry)).toEqual(commitItemIconMap.modified);
+ });
+ it('renders "modified" icon even for temp entries if they are newly-renamed', () => {
+ entry.prevPath = 'foo/bar';
+ entry.tempFile = true;
+ expect(getCommitIconMap(entry)).toEqual(commitItemIconMap.modified);
+ });
+ });
+});
diff --git a/spec/frontend/lib/utils/datetime_utility_spec.js b/spec/frontend/lib/utils/datetime_utility_spec.js
index 9f49e68cfe8..751fb5e1b94 100644
--- a/spec/frontend/lib/utils/datetime_utility_spec.js
+++ b/spec/frontend/lib/utils/datetime_utility_spec.js
@@ -334,6 +334,12 @@ describe('prettyTime methods', () => {
assertTimeUnits(aboveOneDay, 33, 2, 2, 0);
assertTimeUnits(aboveOneWeek, 26, 0, 1, 9);
});
+
+ it('should correctly parse values when limitedToHours is true', () => {
+ const twoDays = datetimeUtility.parseSeconds(173000, { limitToHours: true });
+
+ assertTimeUnits(twoDays, 3, 48, 0, 0);
+ });
});
describe('stringifyTime', () => {
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/notes/components/discussion_notes_spec.js b/spec/frontend/notes/components/discussion_notes_spec.js
index c3204b3aaa0..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);
@@ -112,6 +112,44 @@ describe('DiscussionNotes', () => {
});
});
+ describe('events', () => {
+ describe('with groupped notes and replies expanded', () => {
+ const findNoteAtIndex = index => wrapper.find(`.note:nth-of-type(${index + 1}`);
+
+ beforeEach(() => {
+ createComponent({ shouldGroupReplies: true, isExpanded: true });
+ });
+
+ it('emits deleteNote when first note emits handleDeleteNote', () => {
+ findNoteAtIndex(0).vm.$emit('handleDeleteNote');
+ expect(wrapper.emitted().deleteNote).toBeTruthy();
+ });
+
+ it('emits startReplying when first note emits startReplying', () => {
+ findNoteAtIndex(0).vm.$emit('startReplying');
+ expect(wrapper.emitted().startReplying).toBeTruthy();
+ });
+
+ it('emits deleteNote when second note emits handleDeleteNote', () => {
+ findNoteAtIndex(1).vm.$emit('handleDeleteNote');
+ expect(wrapper.emitted().deleteNote).toBeTruthy();
+ });
+ });
+
+ describe('with ungroupped notes', () => {
+ let note;
+ beforeEach(() => {
+ createComponent();
+ note = wrapper.find('.note');
+ });
+
+ it('emits deleteNote when first note emits handleDeleteNote', () => {
+ note.vm.$emit('handleDeleteNote');
+ expect(wrapper.emitted().deleteNote).toBeTruthy();
+ });
+ });
+ });
+
describe('componentData', () => {
beforeEach(() => {
createComponent();
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/repository/components/__snapshots__/last_commit_spec.js.snap b/spec/frontend/repository/components/__snapshots__/last_commit_spec.js.snap
index 3ad6bfa9e5f..cd8372a8800 100644
--- a/spec/frontend/repository/components/__snapshots__/last_commit_spec.js.snap
+++ b/spec/frontend/repository/components/__snapshots__/last_commit_spec.js.snap
@@ -27,8 +27,8 @@ exports[`Repository last commit component renders commit widget 1`] = `
href="https://test.com/commit/123"
>
- Commit title
-
+ Commit title
+
</gllink-stub>
<!---->
@@ -41,12 +41,12 @@ exports[`Repository last commit component renders commit widget 1`] = `
href="https://test.com/test"
>
- Test
-
+ Test
+
</gllink-stub>
- authored
-
+ authored
+
<timeagotooltip-stub
cssclass=""
time="2019-01-01"
@@ -81,8 +81,8 @@ exports[`Repository last commit component renders commit widget 1`] = `
class="label label-monospace monospace"
>
- 12345678
-
+ 12345678
+
</div>
<clipboardbutton-stub
diff --git a/spec/frontend/repository/components/last_commit_spec.js b/spec/frontend/repository/components/last_commit_spec.js
index 972690a60f6..14479f3c3a4 100644
--- a/spec/frontend/repository/components/last_commit_spec.js
+++ b/spec/frontend/repository/components/last_commit_spec.js
@@ -1,4 +1,5 @@
import { shallowMount } from '@vue/test-utils';
+import { GlLoadingIcon } from '@gitlab/ui';
import LastCommit from '~/repository/components/last_commit.vue';
import UserAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link.vue';
@@ -6,7 +7,7 @@ let vm;
function createCommitData(data = {}) {
return {
- id: '123456789',
+ sha: '123456789',
title: 'Commit title',
message: 'Commit message',
webUrl: 'https://test.com/commit/123',
@@ -16,7 +17,7 @@ function createCommitData(data = {}) {
avatarUrl: 'https://test.com',
webUrl: 'https://test.com/test',
},
- pipeline: {
+ latestPipeline: {
detailedStatus: {
detailsPath: 'https://test.com/pipeline',
icon: 'failed',
@@ -52,12 +53,12 @@ describe('Repository last commit component', () => {
it.each`
loading | label
- ${true} | ${'hides'}
- ${false} | ${'shows'}
- `('$label when $loading is true', ({ loading }) => {
+ ${true} | ${'shows'}
+ ${false} | ${'hides'}
+ `('$label when loading icon $loading is true', ({ loading }) => {
factory(createCommitData(), loading);
- expect(vm.isEmpty()).toBe(loading);
+ expect(vm.find(GlLoadingIcon).exists()).toBe(loading);
});
it('renders commit widget', () => {
@@ -73,11 +74,17 @@ describe('Repository last commit component', () => {
});
it('hides pipeline components when pipeline does not exist', () => {
- factory(createCommitData({ pipeline: null }));
+ factory(createCommitData({ latestPipeline: null }));
expect(vm.find('.js-commit-pipeline').exists()).toBe(false);
});
+ it('renders pipeline components', () => {
+ factory();
+
+ expect(vm.find('.js-commit-pipeline').exists()).toBe(true);
+ });
+
it('hides author component when author does not exist', () => {
factory(createCommitData({ author: null }));
diff --git a/spec/frontend/repository/components/table/__snapshots__/row_spec.js.snap b/spec/frontend/repository/components/table/__snapshots__/row_spec.js.snap
index 1f06d693411..d55dc553031 100644
--- a/spec/frontend/repository/components/table/__snapshots__/row_spec.js.snap
+++ b/spec/frontend/repository/components/table/__snapshots__/row_spec.js.snap
@@ -29,10 +29,20 @@ exports[`Repository table row component renders table row 1`] = `
<td
class="d-none d-sm-table-cell tree-commit"
- />
+ >
+ <glskeletonloading-stub
+ class="h-auto"
+ lines="1"
+ />
+ </td>
<td
class="tree-time-ago text-right"
- />
+ >
+ <glskeletonloading-stub
+ class="ml-auto h-auto w-50"
+ lines="1"
+ />
+ </td>
</tr>
`;
diff --git a/spec/frontend/repository/components/table/row_spec.js b/spec/frontend/repository/components/table/row_spec.js
index 5a345ddeacd..c566057ad3f 100644
--- a/spec/frontend/repository/components/table/row_spec.js
+++ b/spec/frontend/repository/components/table/row_spec.js
@@ -16,6 +16,8 @@ function factory(propsData = {}) {
vm = shallowMount(TableRow, {
propsData: {
...propsData,
+ name: propsData.path,
+ projectPath: 'gitlab-org/gitlab-ce',
url: `https://test.com`,
},
mocks: {
diff --git a/spec/frontend/repository/log_tree_spec.js b/spec/frontend/repository/log_tree_spec.js
new file mode 100644
index 00000000000..a9499f7c61b
--- /dev/null
+++ b/spec/frontend/repository/log_tree_spec.js
@@ -0,0 +1,129 @@
+import MockAdapter from 'axios-mock-adapter';
+import axios from '~/lib/utils/axios_utils';
+import { normalizeData, resolveCommit, fetchLogsTree } from '~/repository/log_tree';
+
+const mockData = [
+ {
+ commit: {
+ id: '123',
+ message: 'testing message',
+ committed_date: '2019-01-01',
+ },
+ commit_path: `https://test.com`,
+ file_name: 'index.js',
+ type: 'blob',
+ },
+];
+
+describe('normalizeData', () => {
+ it('normalizes data into LogTreeCommit object', () => {
+ expect(normalizeData(mockData)).toEqual([
+ {
+ sha: '123',
+ message: 'testing message',
+ committedDate: '2019-01-01',
+ commitPath: 'https://test.com',
+ fileName: 'index.js',
+ type: 'blob',
+ __typename: 'LogTreeCommit',
+ },
+ ]);
+ });
+});
+
+describe('resolveCommit', () => {
+ it('calls resolve when commit found', () => {
+ const resolver = {
+ entry: { name: 'index.js', type: 'blob' },
+ resolve: jest.fn(),
+ };
+ const commits = [{ fileName: 'index.js', type: 'blob' }];
+
+ resolveCommit(commits, resolver);
+
+ expect(resolver.resolve).toHaveBeenCalledWith({ fileName: 'index.js', type: 'blob' });
+ });
+});
+
+describe('fetchLogsTree', () => {
+ let mock;
+ let client;
+ let resolver;
+
+ beforeEach(() => {
+ mock = new MockAdapter(axios);
+
+ mock.onGet(/(.*)/).reply(200, mockData, {});
+
+ jest.spyOn(axios, 'get');
+
+ global.gon = { gitlab_url: 'https://test.com' };
+
+ client = {
+ readQuery: () => ({
+ projectPath: 'gitlab-org/gitlab-ce',
+ ref: 'master',
+ commits: [],
+ }),
+ writeQuery: jest.fn(),
+ };
+
+ resolver = {
+ entry: { name: 'index.js', type: 'blob' },
+ resolve: jest.fn(),
+ };
+ });
+
+ afterEach(() => {
+ mock.restore();
+ });
+
+ it('calls axios get', () =>
+ fetchLogsTree(client, '', '0', resolver).then(() => {
+ expect(axios.get).toHaveBeenCalledWith(
+ 'https://test.com/gitlab-org/gitlab-ce/refs/master/logs_tree',
+ { params: { format: 'json', offset: '0' } },
+ );
+ }));
+
+ it('calls axios get once', () =>
+ Promise.all([
+ fetchLogsTree(client, '', '0', resolver),
+ fetchLogsTree(client, '', '0', resolver),
+ ]).then(() => {
+ expect(axios.get.mock.calls.length).toEqual(1);
+ }));
+
+ it('calls entry resolver', () =>
+ fetchLogsTree(client, '', '0', resolver).then(() => {
+ expect(resolver.resolve).toHaveBeenCalledWith({
+ __typename: 'LogTreeCommit',
+ commitPath: 'https://test.com',
+ committedDate: '2019-01-01',
+ fileName: 'index.js',
+ message: 'testing message',
+ sha: '123',
+ type: 'blob',
+ });
+ }));
+
+ it('writes query to client', () =>
+ fetchLogsTree(client, '', '0', resolver).then(() => {
+ expect(client.writeQuery).toHaveBeenCalledWith({
+ query: expect.anything(),
+ data: {
+ commits: [
+ {
+ __typename: 'LogTreeCommit',
+ commitPath: 'https://test.com',
+ committedDate: '2019-01-01',
+ fileName: 'index.js',
+ message: 'testing message',
+ sha: '123',
+ type: 'blob',
+ },
+ ],
+ },
+ });
+ }));
+});
diff --git a/spec/frontend/test_setup.js b/spec/frontend/test_setup.js
index 7e7cc1488b8..15cf18700ed 100644
--- a/spec/frontend/test_setup.js
+++ b/spec/frontend/test_setup.js
@@ -1,10 +1,17 @@
import Vue from 'vue';
import * as jqueryMatchers from 'custom-jquery-matchers';
+import $ from 'jquery';
import Translate from '~/vue_shared/translate';
import axios from '~/lib/utils/axios_utils';
+import { config as testUtilsConfig } from '@vue/test-utils';
import { initializeTestTimeout } from './helpers/timeout';
import { loadHTMLFixture, setHTMLFixture } from './helpers/fixtures';
+// Expose jQuery so specs using jQuery plugins can be imported nicely.
+// Here is an issue to explore better alternatives:
+// https://gitlab.com/gitlab-org/gitlab-ee/issues/12448
+window.jQuery = $;
+
process.on('unhandledRejection', global.promiseRejectionHandler);
afterEach(() =>
@@ -54,9 +61,21 @@ Object.assign(global, {
preloadFixtures() {},
});
+Object.assign(global, {
+ MutationObserver() {
+ return {
+ disconnect() {},
+ observe() {},
+ };
+ },
+});
+
// custom-jquery-matchers was written for an old Jest version, we need to make it compatible
Object.entries(jqueryMatchers).forEach(([matcherName, matcherFactory]) => {
expect.extend({
[matcherName]: matcherFactory().compare,
});
});
+
+// Tech debt issue TBD
+testUtilsConfig.logModifiedComponents = false;
diff --git a/spec/frontend/vue_shared/components/issue/related_issuable_item_spec.js b/spec/frontend/vue_shared/components/issue/related_issuable_item_spec.js
index e43d5301a50..b85e2673624 100644
--- a/spec/frontend/vue_shared/components/issue/related_issuable_item_spec.js
+++ b/spec/frontend/vue_shared/components/issue/related_issuable_item_spec.js
@@ -88,7 +88,7 @@ describe('RelatedIssuableItem', () => {
});
it('renders state title', () => {
- const stateTitle = tokenState.attributes('data-original-title');
+ const stateTitle = tokenState.attributes('title');
const formatedCreateDate = formatDate(props.createdAt);
expect(stateTitle).toContain('<span class="bold">Opened</span>');
@@ -155,7 +155,9 @@ describe('RelatedIssuableItem', () => {
describe('token assignees', () => {
it('renders assignees avatars', () => {
- expect(wrapper.findAll('.item-assignees .user-avatar-link').length).toBe(2);
+ // Expect 2 times 2 because assignees are rendered twice, due to layout issues
+ expect(wrapper.findAll('.item-assignees .user-avatar-link').length).toBeDefined();
+
expect(wrapper.find('.item-assignees .avatar-counter').text()).toContain('+2');
});
});
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 4076c1f824b..d36e428a8ee 100644
--- a/spec/graphql/gitlab_schema_spec.rb
+++ b/spec/graphql/gitlab_schema_spec.rb
@@ -113,7 +113,7 @@ describe GitlabSchema do
end
it "raises a meaningful error if a global id couldn't be generated" do
- expect { described_class.id_from_object(build(:commit)) }
+ expect { described_class.id_from_object(build(:wiki_directory)) }
.to raise_error(RuntimeError, /include `GlobalID::Identification` into/i)
end
end
diff --git a/spec/graphql/types/award_emojis/award_emoji_type_spec.rb b/spec/graphql/types/award_emojis/award_emoji_type_spec.rb
new file mode 100644
index 00000000000..5663a3d7195
--- /dev/null
+++ b/spec/graphql/types/award_emojis/award_emoji_type_spec.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe GitlabSchema.types['AwardEmoji'] do
+ it { expect(described_class.graphql_name).to eq('AwardEmoji') }
+
+ it { is_expected.to require_graphql_authorizations(:read_emoji) }
+
+ it { expect(described_class).to have_graphql_fields(:description, :unicode_version, :emoji, :name, :unicode, :user) }
+end
diff --git a/spec/graphql/types/commit_type_spec.rb b/spec/graphql/types/commit_type_spec.rb
new file mode 100644
index 00000000000..5d8edcf254c
--- /dev/null
+++ b/spec/graphql/types/commit_type_spec.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe GitlabSchema.types['Commit'] do
+ it { expect(described_class.graphql_name).to eq('Commit') }
+
+ it { expect(described_class).to require_graphql_authorizations(:download_code) }
+
+ it { expect(described_class).to have_graphql_fields(:id, :sha, :title, :description, :message, :authored_date, :author, :web_url, :latest_pipeline) }
+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/graphql/types/tree/tree_type_spec.rb b/spec/graphql/types/tree/tree_type_spec.rb
index b9c5570115e..23779d75600 100644
--- a/spec/graphql/types/tree/tree_type_spec.rb
+++ b/spec/graphql/types/tree/tree_type_spec.rb
@@ -5,5 +5,5 @@ require 'spec_helper'
describe Types::Tree::TreeType do
it { expect(described_class.graphql_name).to eq('Tree') }
- it { expect(described_class).to have_graphql_fields(:trees, :submodules, :blobs) }
+ it { expect(described_class).to have_graphql_fields(:trees, :submodules, :blobs, :last_commit) }
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/recaptcha_experiment_helper_spec.rb b/spec/helpers/recaptcha_experiment_helper_spec.rb
new file mode 100644
index 00000000000..775c2caa082
--- /dev/null
+++ b/spec/helpers/recaptcha_experiment_helper_spec.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe RecaptchaExperimentHelper, type: :helper do
+ describe '.show_recaptcha_sign_up?' do
+ context 'when reCAPTCHA is disabled' do
+ it 'returns false' do
+ stub_application_setting(recaptcha_enabled: false)
+
+ expect(helper.show_recaptcha_sign_up?).to be(false)
+ end
+ end
+
+ context 'when reCAPTCHA is enabled' do
+ it 'returns true' do
+ stub_application_setting(recaptcha_enabled: true)
+
+ expect(helper.show_recaptcha_sign_up?).to be(true)
+ end
+ end
+ end
+end
diff --git a/spec/helpers/search_helper_spec.rb b/spec/helpers/search_helper_spec.rb
index da14f7f16fb..c69493b579f 100644
--- a/spec/helpers/search_helper_spec.rb
+++ b/spec/helpers/search_helper_spec.rb
@@ -114,7 +114,7 @@ describe SearchHelper do
end
it 'includes project endpoints' do
- expect(search_filter_input_options('')[:data]['base-endpoint']).to eq(project_path(@project))
+ expect(search_filter_input_options('')[:data]['runner-tags-endpoint']).to eq(tag_list_admin_runners_path)
expect(search_filter_input_options('')[:data]['labels-endpoint']).to eq(project_labels_path(@project))
expect(search_filter_input_options('')[:data]['milestones-endpoint']).to eq(project_milestones_path(@project))
end
@@ -134,7 +134,7 @@ describe SearchHelper do
end
it 'includes group endpoints' do
- expect(search_filter_input_options('')[:data]['base-endpoint']).to eq("/groups#{group_path(@group)}")
+ expect(search_filter_input_options('')[:data]['runner-tags-endpoint']).to eq(tag_list_admin_runners_path)
expect(search_filter_input_options('')[:data]['labels-endpoint']).to eq(group_labels_path(@group))
expect(search_filter_input_options('')[:data]['milestones-endpoint']).to eq(group_milestones_path(@group))
end
@@ -147,7 +147,7 @@ describe SearchHelper do
end
it 'includes dashboard endpoints' do
- expect(search_filter_input_options('')[:data]['base-endpoint']).to eq("/dashboard")
+ expect(search_filter_input_options('')[:data]['runner-tags-endpoint']).to eq(tag_list_admin_runners_path)
expect(search_filter_input_options('')[:data]['labels-endpoint']).to eq(dashboard_labels_path)
expect(search_filter_input_options('')[:data]['milestones-endpoint']).to eq(dashboard_milestones_path)
end
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/boards_store_spec.js b/spec/javascripts/boards/boards_store_spec.js
index e81115e10c9..5266b1bdbfc 100644
--- a/spec/javascripts/boards/boards_store_spec.js
+++ b/spec/javascripts/boards/boards_store_spec.js
@@ -355,4 +355,14 @@ describe('Store', () => {
expect(boardsStore.moving.list).toEqual(dummyList);
});
});
+
+ describe('setTimeTrackingLimitToHours', () => {
+ it('sets the timeTracking.LimitToHours option', () => {
+ boardsStore.timeTracking.limitToHours = false;
+
+ boardsStore.setTimeTrackingLimitToHours('true');
+
+ expect(boardsStore.timeTracking.limitToHours).toEqual(true);
+ });
+ });
});
diff --git a/spec/javascripts/boards/components/board_spec.js b/spec/javascripts/boards/components/board_spec.js
index d08ee41802b..683783334c6 100644
--- a/spec/javascripts/boards/components/board_spec.js
+++ b/spec/javascripts/boards/components/board_spec.js
@@ -1,7 +1,6 @@
import Vue from 'vue';
-import '~/boards/services/board_service';
import Board from '~/boards/components/board';
-import '~/boards/models/list';
+import List from '~/boards/models/list';
import { mockBoardService } from '../mock_data';
describe('Board component', () => {
@@ -27,7 +26,6 @@ describe('Board component', () => {
disabled: false,
issueLinkBase: '/',
rootPath: '/',
- // eslint-disable-next-line no-undef
list: new List({
id: 1,
position: 0,
@@ -53,57 +51,62 @@ describe('Board component', () => {
expect(vm.$el.classList.contains('is-expandable')).toBe(true);
});
- it('board is expandable when list type is closed', done => {
- vm.list.type = 'closed';
-
- Vue.nextTick(() => {
- expect(vm.$el.classList.contains('is-expandable')).toBe(true);
-
- done();
- });
+ it('board is expandable when list type is closed', () => {
+ expect(new List({ id: 1, list_type: 'closed' }).isExpandable).toBe(true);
});
- it('board is not expandable when list type is label', done => {
- vm.list.type = 'label';
- vm.list.isExpandable = false;
-
- Vue.nextTick(() => {
- expect(vm.$el.classList.contains('is-expandable')).toBe(false);
+ it('board is expandable when list type is label', () => {
+ expect(new List({ id: 1, list_type: 'closed' }).isExpandable).toBe(true);
+ });
- done();
- });
+ it('board is not expandable when list type is blank', () => {
+ expect(new List({ id: 1, list_type: 'blank' }).isExpandable).toBe(false);
});
- it('collapses when clicking header', done => {
+ it('does not collapse when clicking header', done => {
+ vm.list.isExpanded = true;
vm.$el.querySelector('.board-header').click();
Vue.nextTick(() => {
- expect(vm.$el.classList.contains('is-collapsed')).toBe(true);
+ expect(vm.$el.classList.contains('is-collapsed')).toBe(false);
done();
});
});
- it('created sets isExpanded to true from localStorage', done => {
- vm.$el.querySelector('.board-header').click();
+ it('collapses when clicking the collapse icon', done => {
+ vm.list.isExpanded = true;
- return Vue.nextTick()
+ Vue.nextTick()
+ .then(() => {
+ vm.$el.querySelector('.board-title-caret').click();
+ })
.then(() => {
expect(vm.$el.classList.contains('is-collapsed')).toBe(true);
+ done();
+ })
+ .catch(done.fail);
+ });
- // call created manually
- vm.$options.created[0].call(vm);
+ it('expands when clicking the expand icon', done => {
+ vm.list.isExpanded = false;
- return Vue.nextTick();
+ Vue.nextTick()
+ .then(() => {
+ vm.$el.querySelector('.board-title-caret').click();
})
.then(() => {
- expect(vm.$el.classList.contains('is-collapsed')).toBe(true);
-
+ expect(vm.$el.classList.contains('is-collapsed')).toBe(false);
done();
})
.catch(done.fail);
});
+ it('is expanded when created', () => {
+ expect(vm.list.isExpanded).toBe(true);
+ expect(vm.$el.classList.contains('is-collapsed')).toBe(false);
+ });
+
it('does render add issue button', () => {
expect(vm.$el.querySelector('.issue-count-badge-add-button')).not.toBeNull();
});
diff --git a/spec/javascripts/boards/components/issue_time_estimate_spec.js b/spec/javascripts/boards/components/issue_time_estimate_spec.js
index ba65d3287da..de48e3f6091 100644
--- a/spec/javascripts/boards/components/issue_time_estimate_spec.js
+++ b/spec/javascripts/boards/components/issue_time_estimate_spec.js
@@ -1,40 +1,70 @@
import Vue from 'vue';
import IssueTimeEstimate from '~/boards/components/issue_time_estimate.vue';
+import boardsStore from '~/boards/stores/boards_store';
import mountComponent from '../../helpers/vue_mount_component_helper';
-describe('Issue Tine Estimate component', () => {
+describe('Issue Time Estimate component', () => {
let vm;
beforeEach(() => {
- const Component = Vue.extend(IssueTimeEstimate);
- vm = mountComponent(Component, {
- estimate: 374460,
- });
+ boardsStore.create();
});
afterEach(() => {
vm.$destroy();
});
- it('renders the correct time estimate', () => {
- expect(vm.$el.querySelector('time').textContent.trim()).toEqual('2w 3d 1m');
- });
+ describe('when limitToHours is false', () => {
+ beforeEach(() => {
+ boardsStore.timeTracking.limitToHours = false;
+
+ const Component = Vue.extend(IssueTimeEstimate);
+ vm = mountComponent(Component, {
+ estimate: 374460,
+ });
+ });
+
+ it('renders the correct time estimate', () => {
+ expect(vm.$el.querySelector('time').textContent.trim()).toEqual('2w 3d 1m');
+ });
+
+ it('renders expanded time estimate in tooltip', () => {
+ expect(vm.$el.querySelector('.js-issue-time-estimate').textContent).toContain(
+ '2 weeks 3 days 1 minute',
+ );
+ });
+
+ it('prevents tooltip xss', done => {
+ const alertSpy = spyOn(window, 'alert');
+ vm.estimate = 'Foo <script>alert("XSS")</script>';
- it('renders expanded time estimate in tooltip', () => {
- expect(vm.$el.querySelector('.js-issue-time-estimate').textContent).toContain(
- '2 weeks 3 days 1 minute',
- );
+ vm.$nextTick(() => {
+ expect(alertSpy).not.toHaveBeenCalled();
+ expect(vm.$el.querySelector('time').textContent.trim()).toEqual('0m');
+ expect(vm.$el.querySelector('.js-issue-time-estimate').textContent).toContain('0m');
+ done();
+ });
+ });
});
- it('prevents tooltip xss', done => {
- const alertSpy = spyOn(window, 'alert');
- vm.estimate = 'Foo <script>alert("XSS")</script>';
+ describe('when limitToHours is true', () => {
+ beforeEach(() => {
+ boardsStore.timeTracking.limitToHours = true;
+
+ const Component = Vue.extend(IssueTimeEstimate);
+ vm = mountComponent(Component, {
+ estimate: 374460,
+ });
+ });
+
+ it('renders the correct time estimate', () => {
+ expect(vm.$el.querySelector('time').textContent.trim()).toEqual('104h 1m');
+ });
- vm.$nextTick(() => {
- expect(alertSpy).not.toHaveBeenCalled();
- expect(vm.$el.querySelector('time').textContent.trim()).toEqual('0m');
- expect(vm.$el.querySelector('.js-issue-time-estimate').textContent).toContain('0m');
- done();
+ it('renders expanded time estimate in tooltip', () => {
+ expect(vm.$el.querySelector('.js-issue-time-estimate').textContent).toContain(
+ '104 hours 1 minute',
+ );
});
});
});
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..0b3890b68d6 100644
--- a/spec/javascripts/diffs/components/inline_diff_view_spec.js
+++ b/spec/javascripts/diffs/components/inline_diff_view_spec.js
@@ -36,10 +36,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-discussion li').length).toEqual(6);
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/filtered_search/visual_token_value_spec.js b/spec/javascripts/filtered_search/visual_token_value_spec.js
index d1d16afc977..10d844fd94b 100644
--- a/spec/javascripts/filtered_search/visual_token_value_spec.js
+++ b/spec/javascripts/filtered_search/visual_token_value_spec.js
@@ -155,7 +155,7 @@ describe('Filtered Search Visual Tokens', () => {
`);
const filteredSearchInput = document.querySelector('.filtered-search');
- filteredSearchInput.dataset.baseEndpoint = dummyEndpoint;
+ filteredSearchInput.dataset.runnerTagsEndpoint = `${dummyEndpoint}/admin/runners/tag_list`;
filteredSearchInput.dataset.labelsEndpoint = `${dummyEndpoint}/-/labels`;
filteredSearchInput.dataset.milestonesEndpoint = `${dummyEndpoint}/-/milestones`;
diff --git a/spec/javascripts/ide/components/ide_tree_list_spec.js b/spec/javascripts/ide/components/ide_tree_list_spec.js
index f63007c7dd2..554bd1ae3b5 100644
--- a/spec/javascripts/ide/components/ide_tree_list_spec.js
+++ b/spec/javascripts/ide/components/ide_tree_list_spec.js
@@ -58,6 +58,20 @@ describe('IDE tree list', () => {
it('renders list of files', () => {
expect(vm.$el.textContent).toContain('fileName');
});
+
+ it('does not render moved entries', done => {
+ const tree = [file('moved entry'), file('normal entry')];
+ tree[0].moved = true;
+ store.state.trees['abcproject/master'].tree = tree;
+ const container = vm.$el.querySelector('.ide-tree-body');
+
+ vm.$nextTick(() => {
+ expect(container.children.length).toBe(1);
+ expect(vm.$el.textContent).not.toContain('moved entry');
+ expect(vm.$el.textContent).toContain('normal entry');
+ done();
+ });
+ });
});
describe('empty-branch state', () => {
diff --git a/spec/javascripts/ide/components/repo_editor_spec.js b/spec/javascripts/ide/components/repo_editor_spec.js
index 002b5a005b8..f832096701f 100644
--- a/spec/javascripts/ide/components/repo_editor_spec.js
+++ b/spec/javascripts/ide/components/repo_editor_spec.js
@@ -14,7 +14,10 @@ describe('RepoEditor', () => {
let vm;
beforeEach(done => {
- const f = file();
+ const f = {
+ ...file(),
+ viewMode: 'editor',
+ };
const RepoEditor = Vue.extend(repoEditor);
vm = createComponentWithStore(RepoEditor, store, {
@@ -41,12 +44,17 @@ describe('RepoEditor', () => {
Editor.editorInstance.dispose();
});
- it('renders an ide container', done => {
- Vue.nextTick(() => {
- expect(vm.shouldHideEditor).toBeFalsy();
+ const findEditor = () => vm.$el.querySelector('.multi-file-editor-holder');
+ const changeRightPanelCollapsed = () => {
+ const { state } = vm.$store;
- done();
- });
+ state.rightPanelCollapsed = !state.rightPanelCollapsed;
+ };
+
+ it('renders an ide container', () => {
+ expect(vm.shouldHideEditor).toBeFalsy();
+ expect(vm.showEditor).toBe(true);
+ expect(findEditor()).not.toHaveCss({ display: 'none' });
});
it('renders only an edit tab', done => {
@@ -283,7 +291,7 @@ describe('RepoEditor', () => {
});
it('calls updateDimensions when rightPanelCollapsed is changed', done => {
- vm.$store.state.rightPanelCollapsed = true;
+ changeRightPanelCollapsed();
vm.$nextTick(() => {
expect(vm.editor.updateDimensions).toHaveBeenCalled();
@@ -358,6 +366,47 @@ describe('RepoEditor', () => {
});
});
+ describe('when files view mode is preview', () => {
+ beforeEach(done => {
+ spyOn(vm.editor, 'updateDimensions');
+ vm.file.viewMode = 'preview';
+ vm.$nextTick(done);
+ });
+
+ it('should hide editor', () => {
+ expect(vm.showEditor).toBe(false);
+ expect(findEditor()).toHaveCss({ display: 'none' });
+ });
+
+ it('should not update dimensions', done => {
+ changeRightPanelCollapsed();
+
+ vm.$nextTick()
+ .then(() => {
+ expect(vm.editor.updateDimensions).not.toHaveBeenCalled();
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+
+ describe('when file view mode changes to editor', () => {
+ beforeEach(done => {
+ vm.file.viewMode = 'editor';
+
+ // one tick to trigger watch
+ vm.$nextTick()
+ // another tick needed until we can update dimensions
+ .then(() => vm.$nextTick())
+ .then(done)
+ .catch(done.fail);
+ });
+
+ it('should update dimensions', () => {
+ expect(vm.editor.updateDimensions).toHaveBeenCalled();
+ });
+ });
+ });
+
it('calls removePendingTab when old file is pending', done => {
spyOnProperty(vm, 'shouldHideEditor').and.returnValue(true);
spyOn(vm, 'removePendingTab');
diff --git a/spec/javascripts/ide/stores/actions/file_spec.js b/spec/javascripts/ide/stores/actions/file_spec.js
index dd2313dc800..021c3076094 100644
--- a/spec/javascripts/ide/stores/actions/file_spec.js
+++ b/spec/javascripts/ide/stores/actions/file_spec.js
@@ -275,6 +275,43 @@ describe('IDE store file actions', () => {
});
});
+ describe('Re-named success', () => {
+ beforeEach(() => {
+ localFile = file(`newCreate-${Math.random()}`);
+ localFile.url = `project/getFileDataURL`;
+ localFile.prevPath = 'old-dull-file';
+ localFile.path = 'new-shiny-file';
+ store.state.entries[localFile.path] = localFile;
+
+ mock.onGet(`${RELATIVE_URL_ROOT}/project/getFileDataURL`).replyOnce(
+ 200,
+ {
+ blame_path: 'blame_path',
+ commits_path: 'commits_path',
+ permalink: 'permalink',
+ raw_path: 'raw_path',
+ binary: false,
+ html: '123',
+ render_error: '',
+ },
+ {
+ 'page-title': 'testing old-dull-file',
+ },
+ );
+ });
+
+ it('sets document title considering `prevPath` on a file', done => {
+ store
+ .dispatch('getFileData', { path: localFile.path })
+ .then(() => {
+ expect(document.title).toBe('testing new-shiny-file');
+
+ done();
+ })
+ .catch(done.fail);
+ });
+ });
+
describe('error', () => {
beforeEach(() => {
mock.onGet(`project/getFileDataURL`).networkError();
diff --git a/spec/javascripts/ide/stores/actions_spec.js b/spec/javascripts/ide/stores/actions_spec.js
index 37354283cab..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,42 @@ 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,
+ );
+ });
+
+ it('does not delete a folder after it is emptied', done => {
+ const testFolder = {
+ type: 'tree',
+ tree: [],
+ };
+ const testEntry = {
+ path: 'testFolder/entry-to-delete',
+ parentPath: 'testFolder',
+ opened: false,
+ tree: [],
+ };
+ testFolder.tree.push(testEntry);
+ store.state.entries = {
+ testFolder,
+ 'testFolder/entry-to-delete': testEntry,
+ };
+
+ testAction(
+ deleteEntry,
+ 'testFolder/entry-to-delete',
+ store.state,
+ [{ type: types.DELETE_ENTRY, payload: 'testFolder/entry-to-delete' }],
+ [
+ { type: 'burstUnusedSeal' },
+ { type: 'stageChange', payload: 'testFolder/entry-to-delete' },
+ { type: 'triggerFilesChange' },
+ ],
done,
);
});
@@ -509,8 +557,15 @@ describe('Multi-file store actions', () => {
type: types.RENAME_ENTRY,
payload: { path: 'test', name: 'new-name', entryPath: null, parentPath: 'parent-path' },
},
+ {
+ type: types.TOGGLE_FILE_CHANGED,
+ payload: {
+ file: store.state.entries['parent-path/new-name'],
+ changed: true,
+ },
+ },
],
- [{ type: 'deleteEntry', payload: 'test' }, { type: 'triggerFilesChange' }],
+ [{ type: 'triggerFilesChange' }],
done,
);
});
@@ -557,7 +612,6 @@ describe('Multi-file store actions', () => {
parentPath: 'parent-path/new-name',
},
},
- { type: 'deleteEntry', payload: 'test' },
{ 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..18ee4330f69 100644
--- a/spec/javascripts/ide/stores/mutations/file_spec.js
+++ b/spec/javascripts/ide/stores/mutations/file_spec.js
@@ -315,6 +315,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 5ee098bf17f..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);
});
});
@@ -309,7 +377,7 @@ describe('Multi-file store mutations', () => {
...localState.entries.oldPath,
id: 'newPath',
name: 'newPath',
- key: 'newPath-blob-name',
+ key: 'newPath-blob-oldPath',
path: 'newPath',
tempFile: true,
prevPath: 'oldPath',
@@ -318,6 +386,7 @@ describe('Multi-file store mutations', () => {
url: `${gl.TEST_HOST}/newPath`,
moved: jasmine.anything(),
movedPath: jasmine.anything(),
+ opened: false,
});
});
@@ -349,13 +418,5 @@ describe('Multi-file store mutations', () => {
expect(localState.entries.parentPath.tree.length).toBe(1);
});
-
- it('adds to openFiles if previously opened', () => {
- localState.entries.oldPath.opened = true;
-
- mutations.RENAME_ENTRY(localState, { path: 'oldPath', name: 'newPath' });
-
- expect(localState.openFiles).toEqual([localState.entries.newPath]);
- });
});
});
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/monitoring/charts/area_spec.js b/spec/javascripts/monitoring/charts/area_spec.js
index ac7e0bb12a1..d3a76f33679 100644
--- a/spec/javascripts/monitoring/charts/area_spec.js
+++ b/spec/javascripts/monitoring/charts/area_spec.js
@@ -1,14 +1,19 @@
import { shallowMount } from '@vue/test-utils';
+import { GlLink } from '@gitlab/ui';
import { GlAreaChart, GlChartSeriesLabel } from '@gitlab/ui/dist/charts';
import { shallowWrapperContainsSlotText } from 'spec/helpers/vue_test_utils_helper';
import Area from '~/monitoring/components/charts/area.vue';
import { createStore } from '~/monitoring/stores';
import * as types from '~/monitoring/stores/mutation_types';
+import { TEST_HOST } from 'spec/test_constants';
import MonitoringMock, { deploymentData } from '../mock_data';
describe('Area component', () => {
+ const mockSha = 'mockSha';
const mockWidgets = 'mockWidgets';
const mockSvgPathContent = 'mockSvgPathContent';
+ const projectPath = `${TEST_HOST}/path/to/project`;
+ const commitUrl = `${projectPath}/commit/${mockSha}`;
let mockGraphData;
let areaChart;
let spriteSpy;
@@ -26,6 +31,7 @@ describe('Area component', () => {
graphData: mockGraphData,
containerWidth: 0,
deploymentData: store.state.monitoringDashboard.deploymentData,
+ projectPath,
},
slots: {
default: mockWidgets,
@@ -88,11 +94,14 @@ describe('Area component', () => {
);
});
- it('renders commit sha in tooltip content', () => {
- const mockSha = 'mockSha';
+ it('renders clickable commit sha in tooltip content', () => {
areaChart.vm.tooltip.sha = mockSha;
+ areaChart.vm.tooltip.commitUrl = commitUrl;
- expect(shallowWrapperContainsSlotText(glAreaChart, 'tooltipContent', mockSha)).toBe(true);
+ const commitLink = areaChart.find(GlLink);
+
+ expect(shallowWrapperContainsSlotText(commitLink, 'default', mockSha)).toBe(true);
+ expect(commitLink.attributes('href')).toEqual(commitUrl);
});
});
});
diff --git a/spec/javascripts/monitoring/charts/column_spec.js b/spec/javascripts/monitoring/charts/column_spec.js
new file mode 100644
index 00000000000..d8ac68b9484
--- /dev/null
+++ b/spec/javascripts/monitoring/charts/column_spec.js
@@ -0,0 +1,58 @@
+import { shallowMount } from '@vue/test-utils';
+import { GlColumnChart } from '@gitlab/ui/dist/charts';
+import ColumnChart from '~/monitoring/components/charts/column.vue';
+
+describe('Column component', () => {
+ let columnChart;
+
+ beforeEach(() => {
+ columnChart = shallowMount(ColumnChart, {
+ propsData: {
+ graphData: {
+ queries: [
+ {
+ x_label: 'Time',
+ y_label: 'Usage',
+ result: [
+ {
+ metric: {},
+ values: [
+ [1495700554.925, '8.0390625'],
+ [1495700614.925, '8.0390625'],
+ [1495700674.925, '8.0390625'],
+ ],
+ },
+ ],
+ },
+ ],
+ },
+ containerWidth: 100,
+ },
+ });
+ });
+
+ afterEach(() => {
+ columnChart.destroy();
+ });
+
+ describe('wrapped components', () => {
+ describe('GitLab UI column chart', () => {
+ let glColumnChart;
+
+ beforeEach(() => {
+ glColumnChart = columnChart.find(GlColumnChart);
+ });
+
+ it('is a Vue instance', () => {
+ expect(glColumnChart.isVueInstance()).toBe(true);
+ });
+
+ it('receives data properties needed for proper chart render', () => {
+ const props = glColumnChart.props();
+
+ expect(props.data).toBe(columnChart.vm.chartData);
+ expect(props.option).toBe(columnChart.vm.chartOptions);
+ });
+ });
+ });
+});
diff --git a/spec/javascripts/monitoring/dashboard_spec.js b/spec/javascripts/monitoring/dashboard_spec.js
index f4166987aed..d3e10194d92 100644
--- a/spec/javascripts/monitoring/dashboard_spec.js
+++ b/spec/javascripts/monitoring/dashboard_spec.js
@@ -10,6 +10,7 @@ import {
mockApiEndpoint,
environmentData,
singleGroupResponse,
+ dashboardGitResponse,
} from './mock_data';
const propsData = {
@@ -62,16 +63,34 @@ describe('Dashboard', () => {
});
describe('no metrics are available yet', () => {
- it('shows a getting started empty state when no metrics are present', () => {
+ beforeEach(() => {
component = new DashboardComponent({
el: document.querySelector('.prometheus-graphs'),
propsData: { ...propsData },
store,
});
+ });
+ it('shows a getting started empty state when no metrics are present', () => {
expect(component.$el.querySelector('.prometheus-graphs')).toBe(null);
expect(component.emptyState).toEqual('gettingStarted');
});
+
+ it('shows the environment selector', () => {
+ expect(component.$el.querySelector('.js-environments-dropdown')).toBeTruthy();
+ });
+ });
+
+ describe('no data found', () => {
+ it('shows the environment selector dropdown', () => {
+ component = new DashboardComponent({
+ el: document.querySelector('.prometheus-graphs'),
+ propsData: { ...propsData, showEmptyState: true },
+ store,
+ });
+
+ expect(component.$el.querySelector('.js-environments-dropdown')).toBeTruthy();
+ });
});
describe('requests information to the server', () => {
@@ -150,14 +169,24 @@ describe('Dashboard', () => {
singleGroupResponse,
);
- setTimeout(() => {
- const dropdownMenuEnvironments = component.$el.querySelectorAll(
- '.js-environments-dropdown .dropdown-item',
- );
+ Vue.nextTick()
+ .then(() => {
+ const dropdownMenuEnvironments = component.$el.querySelectorAll(
+ '.js-environments-dropdown .dropdown-item',
+ );
- expect(dropdownMenuEnvironments.length).toEqual(component.environments.length);
- done();
- });
+ expect(component.environments.length).toEqual(environmentData.length);
+ expect(dropdownMenuEnvironments.length).toEqual(component.environments.length);
+
+ Array.from(dropdownMenuEnvironments).forEach((value, index) => {
+ if (environmentData[index].metrics_path) {
+ expect(value).toHaveAttr('href', environmentData[index].metrics_path);
+ }
+ });
+
+ done();
+ })
+ .catch(done.fail);
});
it('hides the environments dropdown list when there is no environments', done => {
@@ -212,7 +241,7 @@ describe('Dashboard', () => {
Vue.nextTick()
.then(() => {
const dropdownItems = component.$el.querySelectorAll(
- '.js-environments-dropdown .dropdown-item[active="true"]',
+ '.js-environments-dropdown .dropdown-item.active',
);
expect(dropdownItems.length).toEqual(1);
@@ -281,10 +310,6 @@ describe('Dashboard', () => {
const getTimeDiffSpy = spyOnDependency(Dashboard, 'getTimeDiff');
component.$store.commit(
- `monitoringDashboard/${types.SET_ENVIRONMENTS_ENDPOINT}`,
- '/environments',
- );
- component.$store.commit(
`monitoringDashboard/${types.RECEIVE_ENVIRONMENTS_DATA_SUCCESS}`,
environmentData,
);
@@ -402,4 +427,49 @@ describe('Dashboard', () => {
});
});
});
+
+ describe('Dashboard dropdown', () => {
+ beforeEach(() => {
+ mock.onGet(mockApiEndpoint).reply(200, metricsGroupsAPIResponse);
+
+ component = new DashboardComponent({
+ el: document.querySelector('.prometheus-graphs'),
+ propsData: {
+ ...propsData,
+ hasMetrics: true,
+ showPanels: false,
+ },
+ store,
+ });
+
+ component.$store.dispatch('monitoringDashboard/setFeatureFlags', {
+ prometheusEndpoint: false,
+ multipleDashboardsEnabled: true,
+ });
+
+ component.$store.commit(
+ `monitoringDashboard/${types.RECEIVE_ENVIRONMENTS_DATA_SUCCESS}`,
+ environmentData,
+ );
+
+ component.$store.commit(
+ `monitoringDashboard/${types.RECEIVE_METRICS_DATA_SUCCESS}`,
+ singleGroupResponse,
+ );
+
+ component.$store.commit(
+ `monitoringDashboard/${types.SET_ALL_DASHBOARDS}`,
+ dashboardGitResponse,
+ );
+ });
+
+ it('shows the dashboard dropdown', done => {
+ setTimeout(() => {
+ const dashboardDropdown = component.$el.querySelector('.js-dashboards-dropdown');
+
+ expect(dashboardDropdown).not.toEqual(null);
+ done();
+ });
+ });
+ });
});
diff --git a/spec/javascripts/monitoring/mock_data.js b/spec/javascripts/monitoring/mock_data.js
index 82e42fe9ade..7bbb215475a 100644
--- a/spec/javascripts/monitoring/mock_data.js
+++ b/spec/javascripts/monitoring/mock_data.js
@@ -922,3 +922,16 @@ export const metricsDashboardResponse = {
},
status: 'success',
};
+
+export const dashboardGitResponse = [
+ {
+ path: 'config/prometheus/common_metrics.yml',
+ display_name: 'Common Metrics',
+ default: true,
+ },
+ {
+ path: '.gitlab/dashboards/super.yml',
+ display_name: 'Custom Dashboard 1',
+ default: false,
+ },
+];
diff --git a/spec/javascripts/monitoring/store/actions_spec.js b/spec/javascripts/monitoring/store/actions_spec.js
index 083a01c4d74..677455275de 100644
--- a/spec/javascripts/monitoring/store/actions_spec.js
+++ b/spec/javascripts/monitoring/store/actions_spec.js
@@ -22,6 +22,7 @@ import {
environmentData,
metricsDashboardResponse,
metricsGroupsAPIResponse,
+ dashboardGitResponse,
} from '../mock_data';
describe('Monitoring store actions', () => {
@@ -212,17 +213,19 @@ describe('Monitoring store actions', () => {
describe('receiveMetricsDashboardSuccess', () => {
let commit;
let dispatch;
+ let state;
beforeEach(() => {
commit = jasmine.createSpy();
dispatch = jasmine.createSpy();
+ state = storeState();
});
it('stores groups ', () => {
const params = {};
const response = metricsDashboardResponse;
- receiveMetricsDashboardSuccess({ commit, dispatch }, { response, params });
+ receiveMetricsDashboardSuccess({ state, commit, dispatch }, { response, params });
expect(commit).toHaveBeenCalledWith(
types.RECEIVE_METRICS_DATA_SUCCESS,
@@ -231,6 +234,18 @@ describe('Monitoring store actions', () => {
expect(dispatch).toHaveBeenCalledWith('fetchPrometheusMetrics', params);
});
+
+ it('sets the dashboards loaded from the repository', () => {
+ const params = {};
+ const response = metricsDashboardResponse;
+
+ response.all_dashboards = dashboardGitResponse;
+ state.multipleDashboardsEnabled = true;
+
+ receiveMetricsDashboardSuccess({ state, commit, dispatch }, { response, params });
+
+ expect(commit).toHaveBeenCalledWith(types.SET_ALL_DASHBOARDS, dashboardGitResponse);
+ });
});
describe('receiveMetricsDashboardFailure', () => {
diff --git a/spec/javascripts/monitoring/store/mutations_spec.js b/spec/javascripts/monitoring/store/mutations_spec.js
index 02ff5847b34..91580366531 100644
--- a/spec/javascripts/monitoring/store/mutations_spec.js
+++ b/spec/javascripts/monitoring/store/mutations_spec.js
@@ -1,7 +1,12 @@
import mutations from '~/monitoring/stores/mutations';
import * as types from '~/monitoring/stores/mutation_types';
import state from '~/monitoring/stores/state';
-import { metricsGroupsAPIResponse, deploymentData, metricsDashboardResponse } from '../mock_data';
+import {
+ metricsGroupsAPIResponse,
+ deploymentData,
+ metricsDashboardResponse,
+ dashboardGitResponse,
+} from '../mock_data';
describe('Monitoring mutations', () => {
let stateCopy;
@@ -156,4 +161,12 @@ describe('Monitoring mutations', () => {
expect(stateCopy.metricsWithData).toEqual([]);
});
});
+
+ describe('SET_ALL_DASHBOARDS', () => {
+ it('stores the dashboards loaded from the git repository', () => {
+ mutations[types.SET_ALL_DASHBOARDS](stateCopy, dashboardGitResponse);
+
+ expect(stateCopy.allDashboards).toEqual(dashboardGitResponse);
+ });
+ });
});
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..65f72a135aa 100644
--- a/spec/javascripts/notes/stores/actions_spec.js
+++ b/spec/javascripts/notes/stores/actions_spec.js
@@ -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,
);
diff --git a/spec/javascripts/notes/stores/getters_spec.js b/spec/javascripts/notes/stores/getters_spec.js
index 8f3c493dd4c..c3ed079e33b 100644
--- a/spec/javascripts/notes/stores/getters_spec.js
+++ b/spec/javascripts/notes/stores/getters_spec.js
@@ -32,6 +32,26 @@ describe('Getters Notes Store', () => {
};
});
+ describe('showJumpToNextDiscussion', () => {
+ it('should return true if there are 2 or more unresolved discussions', () => {
+ const localGetters = {
+ unresolvedDiscussionsIdsByDate: ['123', '456'],
+ allResolvableDiscussions: [],
+ };
+
+ expect(getters.showJumpToNextDiscussion(state, localGetters)()).toBe(true);
+ });
+
+ it('should return false if there are 1 or less unresolved discussions', () => {
+ const localGetters = {
+ unresolvedDiscussionsIdsByDate: ['123'],
+ allResolvableDiscussions: [],
+ };
+
+ expect(getters.showJumpToNextDiscussion(state, localGetters)()).toBe(false);
+ });
+ });
+
describe('discussions', () => {
it('should return all discussions in the store', () => {
expect(getters.discussions(state)).toEqual([individualNote]);
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/registry/components/collapsible_container_spec.js b/spec/javascripts/registry/components/collapsible_container_spec.js
index 9ed4b04324a..55017b3e26b 100644
--- a/spec/javascripts/registry/components/collapsible_container_spec.js
+++ b/spec/javascripts/registry/components/collapsible_container_spec.js
@@ -72,21 +72,15 @@ describe('collapsible registry container', () => {
expect(findDeleteBtn()).not.toBeNull();
});
- describe('clicked on delete', () => {
- beforeEach(done => {
- findDeleteBtn().click();
- Vue.nextTick(done);
- });
-
- it('should open confirmation modal', () => {
- expect(vm.$el.querySelector('#confirm-repo-deletion-modal')).not.toBeNull();
- });
+ it('should call deleteItem when confirming deletion', done => {
+ findDeleteBtn().click();
+ spyOn(vm, 'deleteItem').and.returnValue(Promise.resolve());
- it('should call deleteItem when confirming deletion', () => {
- spyOn(vm, 'deleteItem').and.returnValue(Promise.resolve());
- vm.$el.querySelector('#confirm-repo-deletion-modal .btn-danger').click();
+ Vue.nextTick(() => {
+ document.querySelector('#confirm-repo-deletion-modal .btn-danger').click();
expect(vm.deleteItem).toHaveBeenCalledWith(vm.repo);
+ done();
});
});
});
diff --git a/spec/javascripts/registry/components/table_registry_spec.js b/spec/javascripts/registry/components/table_registry_spec.js
index d366c67a1b9..6a0b16f592e 100644
--- a/spec/javascripts/registry/components/table_registry_spec.js
+++ b/spec/javascripts/registry/components/table_registry_spec.js
@@ -46,23 +46,16 @@ describe('table registry', () => {
expect(findDeleteBtn()).toBeDefined();
});
- describe('clicked on delete', () => {
- beforeEach(done => {
- findDeleteBtn().click();
- Vue.nextTick(done);
- });
-
- it('should open confirmation modal and set itemToBeDeleted properly', () => {
- expect(vm.itemToBeDeleted).toEqual(firstImage);
- expect(vm.$el.querySelector('#confirm-image-deletion-modal')).not.toBeNull();
- });
+ it('should call deleteItem and reset itemToBeDeleted when confirming deletion', done => {
+ findDeleteBtn().click();
+ spyOn(vm, 'deleteItem').and.returnValue(Promise.resolve());
- it('should call deleteItem and reset itemToBeDeleted when confirming deletion', () => {
- spyOn(vm, 'deleteItem').and.returnValue(Promise.resolve());
- vm.$el.querySelector('#confirm-image-deletion-modal .btn-danger').click();
+ Vue.nextTick(() => {
+ document.querySelector('#confirm-image-deletion-modal .btn-danger').click();
expect(vm.deleteItem).toHaveBeenCalledWith(firstImage);
expect(vm.itemToBeDeleted).toBeNull();
+ 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/components/time_tracking/time_tracker_spec.js b/spec/javascripts/sidebar/components/time_tracking/time_tracker_spec.js
index 4c3dd713589..2e1863cff86 100644
--- a/spec/javascripts/sidebar/components/time_tracking/time_tracker_spec.js
+++ b/spec/javascripts/sidebar/components/time_tracking/time_tracker_spec.js
@@ -13,6 +13,7 @@ describe('Issuable Time Tracker', () => {
timeSpent,
timeEstimateHumanReadable,
timeSpentHumanReadable,
+ limitToHours,
}) => {
setFixtures(`
<div>
@@ -25,6 +26,7 @@ describe('Issuable Time Tracker', () => {
timeSpent,
humanTimeEstimate: timeEstimateHumanReadable,
humanTimeSpent: timeSpentHumanReadable,
+ limitToHours: Boolean(limitToHours),
rootPath: '/',
};
@@ -128,6 +130,29 @@ describe('Issuable Time Tracker', () => {
});
});
+ describe('Comparison pane when limitToHours is true', () => {
+ beforeEach(() => {
+ initTimeTrackingComponent({
+ timeEstimate: 100000, // 1d 3h
+ timeSpent: 5000, // 1h 23m
+ timeEstimateHumanReadable: '',
+ timeSpentHumanReadable: '',
+ limitToHours: true,
+ });
+ });
+
+ it('should show the correct tooltip text', done => {
+ Vue.nextTick(() => {
+ expect(vm.showComparisonState).toBe(true);
+ const $title = vm.$el.querySelector('.time-tracking-content .compare-meter').dataset
+ .originalTitle;
+
+ expect($title).toBe('Time remaining: 26h 23m');
+ done();
+ });
+ });
+ });
+
describe('Estimate only pane', () => {
beforeEach(() => {
initTimeTrackingComponent({
diff --git a/spec/javascripts/test_bundle.js b/spec/javascripts/test_bundle.js
index 8c80a425581..2cc476ed52a 100644
--- a/spec/javascripts/test_bundle.js
+++ b/spec/javascripts/test_bundle.js
@@ -10,12 +10,16 @@ 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';
import { getDefaultAdapter } from '~/lib/utils/axios_utils';
import { FIXTURES_PATH, TEST_HOST } from './test_constants';
import customMatchers from './matchers';
+// Tech debt issue TBD
+testUtilsConfig.logModifiedComponents = false;
+
const isHeadlessChrome = /\bHeadlessChrome\//.test(navigator.userAgent);
Vue.config.devtools = !isHeadlessChrome;
Vue.config.productionTip = false;
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_mr_widget/mock_data.js b/spec/javascripts/vue_mr_widget/mock_data.js
index 48f812f0db4..253413ae43e 100644
--- a/spec/javascripts/vue_mr_widget/mock_data.js
+++ b/spec/javascripts/vue_mr_widget/mock_data.js
@@ -218,7 +218,8 @@ export default {
'/root/acets-app/forks?continue%5Bnotice%5D=You%27re+not+allowed+to+make+changes+to+this+project+directly.+A+fork+of+this+project+has+been+created+that+you+can+make+changes+in%2C+so+you+can+submit+a+merge+request.+Try+to+cherry-pick+this+commit+again.&continue%5Bnotice_now%5D=You%27re+not+allowed+to+make+changes+to+this+project+directly.+A+fork+of+this+project+is+being+created+that+you+can+make+changes+in%2C+so+you+can+submit+a+merge+request.&continue%5Bto%5D=%2Froot%2Facets-app%2Fmerge_requests%2F22&namespace_key=1',
email_patches_path: '/root/acets-app/merge_requests/22.patch',
plain_diff_path: '/root/acets-app/merge_requests/22.diff',
- status_path: '/root/acets-app/merge_requests/22.json',
+ merge_request_basic_path: '/root/acets-app/merge_requests/22.json?serializer=basic',
+ merge_request_widget_path: '/root/acets-app/merge_requests/22/widget.json',
merge_check_path: '/root/acets-app/merge_requests/22/merge_check',
ci_environments_status_url: '/root/acets-app/merge_requests/22/ci_environments_status',
project_archived: false,
diff --git a/spec/javascripts/vue_mr_widget/mr_widget_options_spec.js b/spec/javascripts/vue_mr_widget/mr_widget_options_spec.js
index ac2fb16bd10..30e0504e4e1 100644
--- a/spec/javascripts/vue_mr_widget/mr_widget_options_spec.js
+++ b/spec/javascripts/vue_mr_widget/mr_widget_options_spec.js
@@ -473,7 +473,7 @@ describe('mrWidgetOptions', () => {
vm.mr.relatedLinks = {
assignToMe: null,
closing: `
- <a class="close-related-link" href="#'>
+ <a class="close-related-link" href="#">
Close
</a>
`,
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..403e0785d1b 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)
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/ip_rate_limiter_spec.rb b/spec/lib/gitlab/auth/ip_rate_limiter_spec.rb
new file mode 100644
index 00000000000..8d6bf45ab30
--- /dev/null
+++ b/spec/lib/gitlab/auth/ip_rate_limiter_spec.rb
@@ -0,0 +1,65 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Gitlab::Auth::IpRateLimiter, :use_clean_rails_memory_store_caching do
+ let(:ip) { '10.2.2.3' }
+ let(:whitelist) { ['127.0.0.1'] }
+ let(:options) do
+ {
+ enabled: true,
+ ip_whitelist: whitelist,
+ bantime: 1.minute,
+ findtime: 1.minute,
+ maxretry: 2
+ }
+ end
+
+ subject { described_class.new(ip) }
+
+ before do
+ stub_rack_attack_setting(options)
+ end
+
+ after do
+ subject.reset!
+ end
+
+ describe '#register_fail!' do
+ it 'bans after 3 consecutive failures' do
+ expect(subject.banned?).to be_falsey
+
+ 3.times { subject.register_fail! }
+
+ expect(subject.banned?).to be_truthy
+ end
+
+ shared_examples 'whitelisted IPs' do
+ it 'does not ban after max retry limit' do
+ expect(subject.banned?).to be_falsey
+
+ 3.times { subject.register_fail! }
+
+ expect(subject.banned?).to be_falsey
+ end
+ end
+
+ context 'with a whitelisted netmask' do
+ before do
+ options[:ip_whitelist] = ['127.0.0.1', '10.2.2.0/24', 'bad']
+ stub_rack_attack_setting(options)
+ end
+
+ it_behaves_like 'whitelisted IPs'
+ end
+
+ context 'with a whitelisted IP' do
+ before do
+ options[:ip_whitelist] = ['10.2.2.3']
+ stub_rack_attack_setting(options)
+ end
+
+ it_behaves_like 'whitelisted IPs'
+ end
+ end
+end
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/ci/ansi2html_spec.rb b/spec/lib/gitlab/ci/ansi2html_spec.rb
index aa4e358b148..3d57ce431ab 100644
--- a/spec/lib/gitlab/ci/ansi2html_spec.rb
+++ b/spec/lib/gitlab/ci/ansi2html_spec.rb
@@ -141,11 +141,11 @@ describe Gitlab::Ci::Ansi2html do
end
it "replaces newlines with line break tags" do
- expect(convert_html("\n")).to eq('<span class=""></span><br/><span class=""></span>')
+ expect(convert_html("\n")).to eq('<span class=""><br/><span class=""></span></span>')
end
it "groups carriage returns with newlines" do
- expect(convert_html("\r\n")).to eq('<span class=""></span><br/><span class=""></span>')
+ expect(convert_html("\r\n")).to eq('<span class=""><br/><span class=""></span></span>')
end
describe "incremental update" do
@@ -193,7 +193,7 @@ describe Gitlab::Ci::Ansi2html do
let(:pre_text) { "Hello\r" }
let(:pre_html) { "<span class=\"\">Hello\r</span>" }
let(:text) { "\nWorld" }
- let(:html) { "<span class=\"\"></span><br/><span class=\"\">World</span>" }
+ let(:html) { "<span class=\"\"><br/><span class=\"\">World</span></span>" }
it_behaves_like 'stateable converter'
end
@@ -232,7 +232,7 @@ describe Gitlab::Ci::Ansi2html do
it 'prints light red' do
text = "#{section_start}\e[91mHello\e[0m\n#{section_end}"
header = %{<span class="term-fg-l-red section js-section-header section-header js-s-#{class_name(section_name)}">Hello</span>}
- line_break = %{<span class="section js-section-header section-header js-s-#{class_name(section_name)}"></span><br/>}
+ line_break = %{<span class="section js-section-header section-header js-s-#{class_name(section_name)}"><br/></span>}
line = %{<span class="section line s_#{class_name(section_name)}"></span>}
empty_line = %{<span class="section js-s-#{class_name(section_name)}"></span>}
html = "#{section_start_html}#{header}#{line_break}#{line}#{empty_line}#{section_end_html}"
diff --git a/spec/lib/gitlab/ci/build/prerequisite/kubernetes_namespace_spec.rb b/spec/lib/gitlab/ci/build/prerequisite/kubernetes_namespace_spec.rb
index c5bc81a2b9e..d88a2097ba2 100644
--- a/spec/lib/gitlab/ci/build/prerequisite/kubernetes_namespace_spec.rb
+++ b/spec/lib/gitlab/ci/build/prerequisite/kubernetes_namespace_spec.rb
@@ -17,15 +17,12 @@ describe Gitlab::Ci::Build::Prerequisite::KubernetesNamespace do
end
context 'build has a deployment' do
- let!(:deployment) { create(:deployment, deployable: build) }
+ let!(:deployment) { create(:deployment, deployable: build, cluster: cluster) }
+ let(:cluster) { nil }
context 'and a cluster to deploy to' do
let(:cluster) { create(:cluster, :group) }
- before do
- allow(build.deployment).to receive(:cluster).and_return(cluster)
- end
-
it { is_expected.to be_truthy }
context 'and the cluster is not managed' do
@@ -48,28 +45,21 @@ describe Gitlab::Ci::Build::Prerequisite::KubernetesNamespace do
end
context 'and no cluster to deploy to' do
- before do
- expect(deployment.cluster).to be_nil
- end
-
it { is_expected.to be_falsey }
end
end
end
describe '#complete!' do
- let!(:deployment) { create(:deployment, deployable: build) }
+ let!(:deployment) { create(:deployment, deployable: build, cluster: cluster) }
let(:service) { double(execute: true) }
+ let(:cluster) { nil }
subject { described_class.new(build).complete! }
context 'completion is required' do
let(:cluster) { create(:cluster, :group) }
- before do
- allow(build.deployment).to receive(:cluster).and_return(cluster)
- end
-
it 'creates a kubernetes namespace' do
expect(Clusters::Gcp::Kubernetes::CreateOrUpdateNamespaceService)
.to receive(:new)
@@ -83,10 +73,6 @@ describe Gitlab::Ci::Build::Prerequisite::KubernetesNamespace do
end
context 'completion is not required' do
- before do
- expect(deployment.cluster).to be_nil
- end
-
it 'does not create a namespace' do
expect(Clusters::Gcp::Kubernetes::CreateOrUpdateNamespaceService).not_to receive(:new)
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/trace/stream_spec.rb b/spec/lib/gitlab/ci/trace/stream_spec.rb
index 0d03eef99c8..35250632e86 100644
--- a/spec/lib/gitlab/ci/trace/stream_spec.rb
+++ b/spec/lib/gitlab/ci/trace/stream_spec.rb
@@ -65,9 +65,9 @@ describe Gitlab::Ci::Trace::Stream, :clean_gitlab_redis_cache do
result = stream.html
expect(result).to eq(
- "<span class=\"\">ヾ(´༎ຶД༎ຶ`)ノ</span><br/><span class=\"\"></span>"\
- "<span class=\"term-fg-green\">許功蓋</span><span class=\"\"></span><br/>"\
- "<span class=\"\"></span>")
+ "<span class=\"\">ヾ(´༎ຶД༎ຶ`)ノ<br/><span class=\"\"></span></span>"\
+ "<span class=\"term-fg-green\">許功蓋</span><span class=\"\"><br/>"\
+ "<span class=\"\"></span></span>")
expect(result.encoding).to eq(Encoding.default_external)
end
end
@@ -306,8 +306,8 @@ describe Gitlab::Ci::Trace::Stream, :clean_gitlab_redis_cache do
shared_examples_for 'htmls' do
it "returns html" do
expect(stream.html).to eq(
- "<span class=\"\">12</span><br/><span class=\"\">34</span><br/>"\
- "<span class=\"\">56</span>")
+ "<span class=\"\">12<br/><span class=\"\">34<br/>"\
+ "<span class=\"\">56</span></span></span>")
end
it "returns html for last line only" do
diff --git a/spec/lib/gitlab/cleanup/orphan_job_artifact_files_batch_spec.rb b/spec/lib/gitlab/cleanup/orphan_job_artifact_files_batch_spec.rb
new file mode 100644
index 00000000000..4d8edfeac80
--- /dev/null
+++ b/spec/lib/gitlab/cleanup/orphan_job_artifact_files_batch_spec.rb
@@ -0,0 +1,66 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Gitlab::Cleanup::OrphanJobArtifactFilesBatch do
+ let(:batch_size) { 10 }
+ let(:dry_run) { true }
+
+ subject(:batch) { described_class.new(batch_size: batch_size, dry_run: dry_run) }
+
+ context 'no dry run' do
+ let(:dry_run) { false }
+
+ it 'deletes only orphan job artifacts from disk' do
+ job_artifact = create(:ci_job_artifact, :archive)
+ orphan_artifact = create(:ci_job_artifact, :archive)
+ batch << artifact_path(job_artifact)
+ batch << artifact_path(orphan_artifact)
+ orphan_artifact.delete
+
+ batch.clean!
+
+ expect(batch.artifact_files.count).to eq(2)
+ expect(batch.lost_and_found.count).to eq(1)
+ expect(batch.lost_and_found.first.artifact_id).to eq(orphan_artifact.id)
+ end
+
+ it 'does not mix up job ID and artifact ID' do
+ # take maximum ID of both tables to avoid any collision
+ max_id = [Ci::Build.maximum(:id), Ci::JobArtifact.maximum(:id)].compact.max.to_i
+ job_a = create(:ci_build, id: max_id + 1)
+ job_b = create(:ci_build, id: max_id + 2)
+ # reuse the build IDs for the job artifact IDs, but swap them
+ job_artifact_b = create(:ci_job_artifact, :archive, job: job_b, id: max_id + 1)
+ job_artifact_a = create(:ci_job_artifact, :archive, job: job_a, id: max_id + 2)
+
+ batch << artifact_path(job_artifact_a)
+ batch << artifact_path(job_artifact_b)
+
+ job_artifact_b.delete
+
+ batch.clean!
+
+ expect(File.exist?(job_artifact_a.file.path)).to be_truthy
+ expect(File.exist?(job_artifact_b.file.path)).to be_falsey
+ end
+ end
+
+ context 'with dry run' do
+ it 'does not remove files' do
+ job_artifact = create(:ci_job_artifact, :archive)
+ batch << job_artifact.file.path
+ job_artifact.delete
+
+ expect(batch).not_to receive(:remove_file!)
+
+ batch.clean!
+
+ expect(File.exist?(job_artifact.file.path)).to be_truthy
+ end
+ end
+
+ def artifact_path(job_artifact)
+ Pathname.new(job_artifact.file.path).parent.to_s
+ end
+end
diff --git a/spec/lib/gitlab/cleanup/orphan_job_artifact_files_spec.rb b/spec/lib/gitlab/cleanup/orphan_job_artifact_files_spec.rb
new file mode 100644
index 00000000000..974cc2c4660
--- /dev/null
+++ b/spec/lib/gitlab/cleanup/orphan_job_artifact_files_spec.rb
@@ -0,0 +1,68 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Gitlab::Cleanup::OrphanJobArtifactFiles do
+ let(:null_logger) { Logger.new('/dev/null') }
+ subject(:cleanup) { described_class.new(logger: null_logger) }
+
+ before do
+ allow(null_logger).to receive(:info)
+ end
+
+ it 'passes on dry_run' do
+ expect(Gitlab::Cleanup::OrphanJobArtifactFilesBatch)
+ .to receive(:new)
+ .with(dry_run: false, batch_size: anything, logger: anything)
+ .at_least(:once)
+ .and_call_original
+
+ described_class.new(dry_run: false).run!
+ end
+
+ it 'errors when invalid niceness is given' do
+ cleanup = described_class.new(logger: null_logger, niceness: 'FooBar')
+
+ expect(null_logger).to receive(:error).with(/FooBar/)
+
+ cleanup.run!
+ end
+
+ it 'finds artifacts on disk' do
+ artifact = create(:ci_job_artifact, :archive)
+
+ expect(cleanup).to receive(:find_artifacts).and_yield(artifact.file.path)
+ cleanup.run!
+ end
+
+ it 'stops when limit is reached' do
+ cleanup = described_class.new(limit: 1)
+
+ mock_artifacts_found(cleanup, 'tmp/foo/bar/1', 'tmp/foo/bar/2')
+
+ cleanup.run!
+
+ expect(cleanup.total_found).to eq(1)
+ end
+
+ it 'cleans even if batch is not full' do
+ mock_artifacts_found(cleanup, 'tmp/foo/bar/1')
+
+ expect(cleanup).to receive(:clean_batch!).and_call_original
+ cleanup.run!
+ end
+
+ it 'cleans in batches' do
+ stub_const("#{described_class.name}::BATCH_SIZE", 2)
+ mock_artifacts_found(cleanup, 'tmp/foo/bar/1', 'tmp/foo/bar/2', 'tmp/foo/bar/3')
+
+ expect(cleanup).to receive(:clean_batch!).twice.and_call_original
+ cleanup.run!
+ end
+
+ def mock_artifacts_found(cleanup, *files)
+ mock = allow(cleanup).to receive(:find_artifacts)
+
+ files.each { |file| mock.and_yield(file) }
+ end
+end
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/database/migration_helpers_spec.rb b/spec/lib/gitlab/database/migration_helpers_spec.rb
index 3cf3d032bf4..7409572288c 100644
--- a/spec/lib/gitlab/database/migration_helpers_spec.rb
+++ b/spec/lib/gitlab/database/migration_helpers_spec.rb
@@ -583,6 +583,24 @@ describe Gitlab::Database::MigrationHelpers do
model.add_column_with_default(:projects, :foo, :integer, default: 10, limit: 8)
end
end
+
+ it 'adds a column with an array default value for a jsonb type' do
+ create(:project)
+ allow(model).to receive(:transaction_open?).and_return(false)
+ allow(model).to receive(:transaction).and_yield
+ expect(model).to receive(:update_column_in_batches).with(:projects, :foo, '[{"foo":"json"}]').and_call_original
+
+ model.add_column_with_default(:projects, :foo, :jsonb, default: [{ foo: "json" }])
+ end
+
+ it 'adds a column with an object default value for a jsonb type' do
+ create(:project)
+ allow(model).to receive(:transaction_open?).and_return(false)
+ allow(model).to receive(:transaction).and_yield
+ expect(model).to receive(:update_column_in_batches).with(:projects, :foo, '{"foo":"json"}').and_call_original
+
+ model.add_column_with_default(:projects, :foo, :jsonb, default: { foo: "json" })
+ end
end
context 'inside a transaction' do
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/git/repository_spec.rb b/spec/lib/gitlab/git/repository_spec.rb
index e72fb9c6fbc..cceeae8afe6 100644
--- a/spec/lib/gitlab/git/repository_spec.rb
+++ b/spec/lib/gitlab/git/repository_spec.rb
@@ -2038,24 +2038,24 @@ describe Gitlab::Git::Repository, :seed_helper do
end
describe '#clean_stale_repository_files' do
- let(:worktree_path) { File.join(repository_path, 'worktrees', 'delete-me') }
+ let(:worktree_id) { 'rebase-1' }
+ let(:gitlab_worktree_path) { File.join(repository_path, 'gitlab-worktree', worktree_id) }
+ let(:admin_dir) { File.join(repository_path, 'worktrees') }
it 'cleans up the files' do
- create_worktree = %W[git -C #{repository_path} worktree add --detach #{worktree_path} master]
+ create_worktree = %W[git -C #{repository_path} worktree add --detach #{gitlab_worktree_path} master]
raise 'preparation failed' unless system(*create_worktree, err: '/dev/null')
- FileUtils.touch(worktree_path, mtime: Time.now - 8.hours)
+ FileUtils.touch(gitlab_worktree_path, mtime: Time.now - 8.hours)
# git rev-list --all will fail in git 2.16 if HEAD is pointing to a non-existent object,
# but the HEAD must be 40 characters long or git will ignore it.
- File.write(File.join(worktree_path, 'HEAD'), Gitlab::Git::BLANK_SHA)
-
- # git 2.16 fails with "fatal: bad object HEAD"
- expect(rev_list_all).to be false
+ File.write(File.join(admin_dir, worktree_id, 'HEAD'), Gitlab::Git::BLANK_SHA)
+ expect(rev_list_all).to be(false)
repository.clean_stale_repository_files
- expect(rev_list_all).to be true
- expect(File.exist?(worktree_path)).to be_falsey
+ expect(rev_list_all).to be(true)
+ expect(File.exist?(gitlab_worktree_path)).to be_falsey
end
def rev_list_all
diff --git a/spec/lib/gitlab/gitaly_client/commit_service_spec.rb b/spec/lib/gitlab/gitaly_client/commit_service_spec.rb
index 6d6107ca3e7..ba6abba4e61 100644
--- a/spec/lib/gitlab/gitaly_client/commit_service_spec.rb
+++ b/spec/lib/gitlab/gitaly_client/commit_service_spec.rb
@@ -223,6 +223,19 @@ describe Gitlab::GitalyClient::CommitService do
end
context 'when caching of the ref name is enabled' do
+ it 'caches negative entries' do
+ expect_any_instance_of(Gitaly::CommitService::Stub).to receive(:find_commit).once.and_return(double(commit: nil))
+
+ commit = nil
+ 2.times do
+ ::Gitlab::GitalyClient.allow_ref_name_caching do
+ commit = described_class.new(repository).find_commit('master')
+ end
+ end
+
+ expect(commit).to eq(nil)
+ end
+
it 'returns a cached commit' do
expect_any_instance_of(Gitaly::CommitService::Stub).to receive(:find_commit).once.and_return(double(commit: commit_dbl))
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/authorize/authorize_resource_spec.rb b/spec/lib/gitlab/graphql/authorize/authorize_resource_spec.rb
index 13cf52fd795..50138d272c4 100644
--- a/spec/lib/gitlab/graphql/authorize/authorize_resource_spec.rb
+++ b/spec/lib/gitlab/graphql/authorize/authorize_resource_spec.rb
@@ -34,12 +34,6 @@ describe Gitlab::Graphql::Authorize::AuthorizeResource do
end
end
- describe '#authorized_find' do
- it 'returns the object' do
- expect(loading_resource.authorized_find).to eq(project)
- end
- end
-
describe '#authorized_find!' do
it 'returns the object' do
expect(loading_resource.authorized_find!).to eq(project)
@@ -66,12 +60,6 @@ describe Gitlab::Graphql::Authorize::AuthorizeResource do
end
end
- describe '#authorized_find' do
- it 'returns `nil`' do
- expect(loading_resource.authorized_find).to be_nil
- end
- end
-
describe '#authorized_find!' do
it 'raises an error' do
expect { loading_resource.authorize!(project) }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
@@ -79,7 +67,7 @@ describe Gitlab::Graphql::Authorize::AuthorizeResource do
end
describe '#authorize!' do
- it 'does not raise an error' do
+ it 'raises an error' do
expect { loading_resource.authorize!(project) }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
end
end
@@ -101,6 +89,45 @@ describe Gitlab::Graphql::Authorize::AuthorizeResource do
end
end
+ context 'when the class does not define authorize' do
+ let(:fake_class) do
+ Class.new do
+ include Gitlab::Graphql::Authorize::AuthorizeResource
+
+ attr_reader :user, :found_object
+
+ def initialize(user, found_object)
+ @user, @found_object = user, found_object
+ end
+
+ def find_object(*_args)
+ found_object
+ end
+
+ def current_user
+ user
+ end
+
+ def self.name
+ 'TestClass'
+ end
+ end
+ end
+ let(:error) { /#{fake_class.name} has no authorizations/ }
+
+ describe '#authorized_find!' do
+ it 'raises a comprehensive error message' do
+ expect { loading_resource.authorized_find! }.to raise_error(error)
+ end
+ end
+
+ describe '#authorized?' do
+ it 'raises a comprehensive error message' do
+ expect { loading_resource.authorized?(project) }.to raise_error(error)
+ end
+ end
+ end
+
describe '#authorize' do
it 'adds permissions from subclasses to those of superclasses when used on classes' do
base_class = Class.new do
diff --git a/spec/lib/gitlab/graphql/copy_field_description_spec.rb b/spec/lib/gitlab/graphql/copy_field_description_spec.rb
new file mode 100644
index 00000000000..e7462c5b954
--- /dev/null
+++ b/spec/lib/gitlab/graphql/copy_field_description_spec.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Gitlab::Graphql::CopyFieldDescription do
+ subject { Class.new.include(described_class) }
+
+ describe '.copy_field_description' do
+ let(:type) do
+ Class.new(Types::BaseObject) do
+ graphql_name "TestType"
+
+ field :field_name, GraphQL::STRING_TYPE, null: true, description: 'Foo'
+ end
+ end
+
+ it 'returns the correct description' do
+ expect(subject.copy_field_description(type, :field_name)).to eq('Foo')
+ 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/graphql/loaders/pipeline_for_sha_loader_spec.rb b/spec/lib/gitlab/graphql/loaders/pipeline_for_sha_loader_spec.rb
new file mode 100644
index 00000000000..927476cc655
--- /dev/null
+++ b/spec/lib/gitlab/graphql/loaders/pipeline_for_sha_loader_spec.rb
@@ -0,0 +1,20 @@
+require 'spec_helper'
+
+describe Gitlab::Graphql::Loaders::PipelineForShaLoader do
+ include GraphqlHelpers
+
+ describe '#find_last' do
+ it 'batch-resolves latest pipeline' do
+ project = create(:project, :repository)
+ pipeline1 = create(:ci_pipeline, project: project, ref: project.default_branch, sha: project.commit.sha)
+ pipeline2 = create(:ci_pipeline, project: project, ref: project.default_branch, sha: project.commit.sha)
+ pipeline3 = create(:ci_pipeline, project: project, ref: 'improve/awesome', sha: project.commit('improve/awesome').sha)
+
+ result = batch(max_queries: 1) do
+ [pipeline1.sha, pipeline3.sha].map { |sha| described_class.new(project, sha).find_last }
+ end
+
+ expect(result).to contain_exactly(pipeline2, pipeline3)
+ end
+ end
+end
diff --git a/spec/lib/gitlab/import_export/all_models.yml b/spec/lib/gitlab/import_export/all_models.yml
index 7a250603b6b..7baa52ffb4f 100644
--- a/spec/lib/gitlab/import_export/all_models.yml
+++ b/spec/lib/gitlab/import_export/all_models.yml
@@ -397,6 +397,7 @@ project:
- incident_management_setting
- merge_trains
- designs
+- project_aliases
award_emoji:
- awardable
- user
diff --git a/spec/lib/gitlab/import_export/project.json b/spec/lib/gitlab/import_export/project.json
index 6512fe80a3b..8be074f4b9b 100644
--- a/spec/lib/gitlab/import_export/project.json
+++ b/spec/lib/gitlab/import_export/project.json
@@ -6760,7 +6760,7 @@
},
{
"id": 95,
- "title": "JIRA",
+ "title": "Jira",
"project_id": 5,
"created_at": "2016-06-14T15:01:51.255Z",
"updated_at": "2016-06-14T15:01:51.255Z",
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/issuable_sorter_spec.rb b/spec/lib/gitlab/issuable_sorter_spec.rb
index 642a6cb6caa..5bd76bc6081 100644
--- a/spec/lib/gitlab/issuable_sorter_spec.rb
+++ b/spec/lib/gitlab/issuable_sorter_spec.rb
@@ -26,7 +26,7 @@ describe Gitlab::IssuableSorter do
expect(described_class.sort(project1, unsorted)).to eq(sorted)
end
- context 'for JIRA issues' do
+ context 'for Jira issues' do
let(:sorted) do
[ExternalIssue.new('JIRA-1', project1),
ExternalIssue.new('JIRA-2', project1),
diff --git a/spec/lib/gitlab/json_cache_spec.rb b/spec/lib/gitlab/json_cache_spec.rb
index 59160741c45..39cdd42088e 100644
--- a/spec/lib/gitlab/json_cache_spec.rb
+++ b/spec/lib/gitlab/json_cache_spec.rb
@@ -129,19 +129,52 @@ describe Gitlab::JsonCache do
.with(expanded_key)
.and_return(nil)
+ expect(ActiveSupport::JSON).not_to receive(:decode)
expect(cache.read(key)).to be_nil
end
- context 'when the cached value is a boolean' do
+ context 'when the cached value is true' do
it 'parses the cached value' do
allow(backend).to receive(:read)
.with(expanded_key)
.and_return(true)
+ expect(ActiveSupport::JSON).to receive(:decode).with("true").and_call_original
expect(cache.read(key, BroadcastMessage)).to eq(true)
end
end
+ context 'when the cached value is false' do
+ it 'parses the cached value' do
+ allow(backend).to receive(:read)
+ .with(expanded_key)
+ .and_return(false)
+
+ expect(ActiveSupport::JSON).to receive(:decode).with("false").and_call_original
+ expect(cache.read(key, BroadcastMessage)).to eq(false)
+ end
+ end
+
+ context 'when the cached value is a JSON true value' do
+ it 'parses the cached value' do
+ allow(backend).to receive(:read)
+ .with(expanded_key)
+ .and_return("true")
+
+ expect(cache.read(key, BroadcastMessage)).to eq(true)
+ end
+ end
+
+ context 'when the cached value is a JSON false value' do
+ it 'parses the cached value' do
+ allow(backend).to receive(:read)
+ .with(expanded_key)
+ .and_return("false")
+
+ expect(cache.read(key, BroadcastMessage)).to eq(false)
+ end
+ end
+
context 'when the cached value is a hash' do
it 'parses the cached value' do
allow(backend).to receive(:read)
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/lets_encrypt/client_spec.rb b/spec/lib/gitlab/lets_encrypt/client_spec.rb
index 5454d9c1af4..cbb862cb0c9 100644
--- a/spec/lib/gitlab/lets_encrypt/client_spec.rb
+++ b/spec/lib/gitlab/lets_encrypt/client_spec.rb
@@ -116,42 +116,6 @@ describe ::Gitlab::LetsEncrypt::Client do
end
end
- describe '#enabled?' do
- subject { client.enabled? }
-
- context 'when terms of service are accepted' do
- it { is_expected.to eq(true) }
-
- context "when private_key isn't present and database is read only" do
- before do
- allow(::Gitlab::Database).to receive(:read_only?).and_return(true)
- end
-
- it 'returns false' do
- expect(::Gitlab::CurrentSettings.lets_encrypt_private_key).to eq(nil)
-
- is_expected.to eq(false)
- end
- end
-
- context 'when feature flag is disabled' do
- before do
- stub_feature_flags(pages_auto_ssl: false)
- end
-
- it { is_expected.to eq(false) }
- end
- end
-
- context 'when terms of service are not accepted' do
- before do
- stub_application_setting(lets_encrypt_terms_of_service_accepted: false)
- end
-
- it { is_expected.to eq(false) }
- end
- end
-
describe '#terms_of_service_url' do
subject { client.terms_of_service_url }
diff --git a/spec/lib/gitlab/lets_encrypt_spec.rb b/spec/lib/gitlab/lets_encrypt_spec.rb
new file mode 100644
index 00000000000..674b114e9d3
--- /dev/null
+++ b/spec/lib/gitlab/lets_encrypt_spec.rb
@@ -0,0 +1,56 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe ::Gitlab::LetsEncrypt do
+ include LetsEncryptHelpers
+
+ before do
+ stub_lets_encrypt_settings
+ end
+
+ describe '.enabled?' do
+ let(:project) { create(:project) }
+ let(:pages_domain) { create(:pages_domain, project: project) }
+
+ subject { described_class.enabled?(pages_domain) }
+
+ context 'when terms of service are accepted' do
+ it { is_expected.to eq(true) }
+
+ context 'when feature flag is disabled' do
+ before do
+ stub_feature_flags(pages_auto_ssl: false)
+ end
+
+ it { is_expected.to eq(false) }
+ end
+ end
+
+ context 'when terms of service are not accepted' do
+ before do
+ stub_application_setting(lets_encrypt_terms_of_service_accepted: false)
+ end
+
+ it { is_expected.to eq(false) }
+ end
+
+ context 'when feature flag for project is disabled' do
+ before do
+ stub_feature_flags(pages_auto_ssl_for_project: false)
+ end
+
+ it 'returns false' do
+ is_expected.to eq(false)
+ end
+ end
+
+ context 'when domain has not project' do
+ let(:pages_domain) { create(:pages_domain) }
+
+ it 'returns false' do
+ is_expected.to eq(false)
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/metrics/dashboard/dynamic_dashboard_service_spec.rb b/spec/lib/gitlab/metrics/dashboard/dynamic_dashboard_service_spec.rb
index eecd257b38d..79a78df44ae 100644
--- a/spec/lib/gitlab/metrics/dashboard/dynamic_dashboard_service_spec.rb
+++ b/spec/lib/gitlab/metrics/dashboard/dynamic_dashboard_service_spec.rb
@@ -6,13 +6,19 @@ describe Gitlab::Metrics::Dashboard::DynamicDashboardService, :use_clean_rails_m
include MetricsDashboardHelpers
set(:project) { build(:project) }
+ set(:user) { create(:user) }
set(:environment) { create(:environment, project: project) }
+ before do
+ project.add_maintainer(user)
+ end
+
describe '#get_dashboard' do
- let(:service_params) { [project, nil, { environment: environment, dashboard_path: nil }] }
+ let(:service_params) { [project, user, { environment: environment, dashboard_path: nil }] }
let(:service_call) { described_class.new(*service_params).get_dashboard }
it_behaves_like 'valid embedded dashboard service response'
+ it_behaves_like 'raises error for users with insufficient permissions'
it 'caches the unprocessed dashboard for subsequent calls' do
expect(YAML).to receive(:safe_load).once.and_call_original
diff --git a/spec/lib/gitlab/metrics/dashboard/finder_spec.rb b/spec/lib/gitlab/metrics/dashboard/finder_spec.rb
index b9a5ee9c2b3..d8ed54c0248 100644
--- a/spec/lib/gitlab/metrics/dashboard/finder_spec.rb
+++ b/spec/lib/gitlab/metrics/dashboard/finder_spec.rb
@@ -6,12 +6,17 @@ describe Gitlab::Metrics::Dashboard::Finder, :use_clean_rails_memory_store_cachi
include MetricsDashboardHelpers
set(:project) { build(:project) }
+ set(:user) { create(:user) }
set(:environment) { create(:environment, project: project) }
let(:system_dashboard_path) { Gitlab::Metrics::Dashboard::SystemDashboardService::SYSTEM_DASHBOARD_PATH}
+ before do
+ project.add_maintainer(user)
+ end
+
describe '.find' do
let(:dashboard_path) { '.gitlab/dashboards/test.yml' }
- let(:service_call) { described_class.find(project, nil, environment, dashboard_path: dashboard_path) }
+ let(:service_call) { described_class.find(project, user, environment, dashboard_path: dashboard_path) }
it_behaves_like 'misconfigured dashboard service response', :not_found
@@ -41,13 +46,13 @@ describe Gitlab::Metrics::Dashboard::Finder, :use_clean_rails_memory_store_cachi
end
context 'when no dashboard is specified' do
- let(:service_call) { described_class.find(project, nil, environment) }
+ let(:service_call) { described_class.find(project, user, environment) }
it_behaves_like 'valid dashboard service response'
end
context 'when the dashboard is expected to be embedded' do
- let(:service_call) { described_class.find(project, nil, environment, dashboard_path: nil, embedded: true) }
+ let(:service_call) { described_class.find(project, user, environment, dashboard_path: nil, embedded: true) }
it_behaves_like 'valid embedded dashboard service response'
end
diff --git a/spec/lib/gitlab/metrics/dashboard/project_dashboard_service_spec.rb b/spec/lib/gitlab/metrics/dashboard/project_dashboard_service_spec.rb
index 57d82421b5d..468e8ec9ef2 100644
--- a/spec/lib/gitlab/metrics/dashboard/project_dashboard_service_spec.rb
+++ b/spec/lib/gitlab/metrics/dashboard/project_dashboard_service_spec.rb
@@ -5,8 +5,8 @@ require 'rails_helper'
describe Gitlab::Metrics::Dashboard::ProjectDashboardService, :use_clean_rails_memory_store_caching do
include MetricsDashboardHelpers
- set(:user) { build(:user) }
- set(:project) { build(:project) }
+ set(:user) { create(:user) }
+ set(:project) { create(:project) }
set(:environment) { create(:environment, project: project) }
before do
@@ -22,6 +22,8 @@ describe Gitlab::Metrics::Dashboard::ProjectDashboardService, :use_clean_rails_m
it_behaves_like 'misconfigured dashboard service response', :not_found
end
+ it_behaves_like 'raises error for users with insufficient permissions'
+
context 'when the dashboard exists' do
let(:project) { project_with_dashboard(dashboard_path) }
diff --git a/spec/lib/gitlab/metrics/dashboard/system_dashboard_service_spec.rb b/spec/lib/gitlab/metrics/dashboard/system_dashboard_service_spec.rb
index 2af745bd4d7..13f22dd01c5 100644
--- a/spec/lib/gitlab/metrics/dashboard/system_dashboard_service_spec.rb
+++ b/spec/lib/gitlab/metrics/dashboard/system_dashboard_service_spec.rb
@@ -5,15 +5,21 @@ require 'spec_helper'
describe Gitlab::Metrics::Dashboard::SystemDashboardService, :use_clean_rails_memory_store_caching do
include MetricsDashboardHelpers
- set(:project) { build(:project) }
+ set(:user) { create(:user) }
+ set(:project) { create(:project) }
set(:environment) { create(:environment, project: project) }
+ before do
+ project.add_maintainer(user)
+ end
+
describe 'get_dashboard' do
let(:dashboard_path) { described_class::SYSTEM_DASHBOARD_PATH }
- let(:service_params) { [project, nil, { environment: environment, dashboard_path: dashboard_path }] }
+ let(:service_params) { [project, user, { environment: environment, dashboard_path: dashboard_path }] }
let(:service_call) { described_class.new(*service_params).get_dashboard }
it_behaves_like 'valid dashboard service response'
+ it_behaves_like 'raises error for users with insufficient permissions'
it 'caches the unprocessed dashboard for subsequent calls' do
expect(YAML).to receive(:safe_load).once.and_call_original
diff --git a/spec/lib/gitlab/metrics/system_spec.rb b/spec/lib/gitlab/metrics/system_spec.rb
index b0603d96eb2..da87df15746 100644
--- a/spec/lib/gitlab/metrics/system_spec.rb
+++ b/spec/lib/gitlab/metrics/system_spec.rb
@@ -52,13 +52,13 @@ describe Gitlab::Metrics::System do
end
describe '.cpu_time' do
- it 'returns a Fixnum' do
+ it 'returns a Float' do
expect(described_class.cpu_time).to be_an(Float)
end
end
describe '.real_time' do
- it 'returns a Fixnum' do
+ it 'returns a Float' do
expect(described_class.real_time).to be_an(Float)
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/reference_extractor_spec.rb b/spec/lib/gitlab/reference_extractor_spec.rb
index d982053d92e..7513dbeeb6f 100644
--- a/spec/lib/gitlab/reference_extractor_spec.rb
+++ b/spec/lib/gitlab/reference_extractor_spec.rb
@@ -197,14 +197,14 @@ describe Gitlab::ReferenceExtractor do
let(:issue) { create(:issue, project: project) }
context 'when GitLab issues are enabled' do
- it 'returns both JIRA and internal issues' do
+ it 'returns both Jira and internal issues' do
subject.analyze("JIRA-123 and FOOBAR-4567 and #{issue.to_reference}")
expect(subject.issues).to eq [ExternalIssue.new('JIRA-123', project),
ExternalIssue.new('FOOBAR-4567', project),
issue]
end
- it 'returns only JIRA issues if the internal one does not exists' do
+ it 'returns only Jira issues if the internal one does not exists' do
subject.analyze("JIRA-123 and FOOBAR-4567 and #999")
expect(subject.issues).to eq [ExternalIssue.new('JIRA-123', project),
ExternalIssue.new('FOOBAR-4567', project)]
@@ -217,7 +217,7 @@ describe Gitlab::ReferenceExtractor do
project.save!
end
- it 'returns only JIRA issues' do
+ it 'returns only Jira issues' do
subject.analyze("JIRA-123 and FOOBAR-4567 and #{issue.to_reference}")
expect(subject.issues).to eq [ExternalIssue.new('JIRA-123', project),
ExternalIssue.new('FOOBAR-4567', project)]
diff --git a/spec/lib/gitlab/time_tracking_formatter_spec.rb b/spec/lib/gitlab/time_tracking_formatter_spec.rb
new file mode 100644
index 00000000000..a85d418777f
--- /dev/null
+++ b/spec/lib/gitlab/time_tracking_formatter_spec.rb
@@ -0,0 +1,43 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Gitlab::TimeTrackingFormatter do
+ describe '#parse' do
+ subject { described_class.parse(duration_string) }
+
+ context 'positive durations' do
+ let(:duration_string) { '3h 20m' }
+
+ it { expect(subject).to eq(12_000) }
+ end
+
+ context 'negative durations' do
+ let(:duration_string) { '-3h 20m' }
+
+ it { expect(subject).to eq(-12_000) }
+ end
+ end
+
+ describe '#output' do
+ let(:num_seconds) { 178_800 }
+
+ subject { described_class.output(num_seconds) }
+
+ context 'time_tracking_limit_to_hours setting is true' do
+ before do
+ stub_application_setting(time_tracking_limit_to_hours: true)
+ end
+
+ it { expect(subject).to eq('49h 40m') }
+ end
+
+ context 'time_tracking_limit_to_hours setting is false' do
+ before do
+ stub_application_setting(time_tracking_limit_to_hours: false)
+ end
+
+ it { expect(subject).to eq('1w 1d 1h 40m') }
+ 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/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/backport_enterprise_schema_spec.rb b/spec/migrations/backport_enterprise_schema_spec.rb
new file mode 100644
index 00000000000..8d2d9d4953a
--- /dev/null
+++ b/spec/migrations/backport_enterprise_schema_spec.rb
@@ -0,0 +1,41 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+require Rails.root.join('db', 'migrate', '20190402150158_backport_enterprise_schema.rb')
+
+describe BackportEnterpriseSchema, :migration, schema: 20190329085614 do
+ include MigrationsHelpers
+
+ def drop_if_exists(table)
+ active_record_base.connection.drop_table(table) if active_record_base.connection.table_exists?(table)
+ end
+
+ describe '#up' do
+ it 'creates new EE tables' do
+ migrate!
+
+ expect(active_record_base.connection.table_exists?(:epics)).to be true
+ expect(active_record_base.connection.table_exists?(:geo_nodes)).to be true
+ end
+
+ context 'missing EE columns' do
+ before do
+ drop_if_exists(:epics)
+
+ active_record_base.connection.create_table "epics" do |t|
+ t.integer :group_id, null: false, index: true
+ t.integer :author_id, null: false, index: true
+ end
+ end
+
+ after do
+ drop_if_exists(:epics)
+ end
+
+ it 'flags an error' do
+ expect { migrate! }.to raise_error(/Your database is missing.*that is present for GitLab EE/)
+ end
+ end
+ 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/application_setting_spec.rb b/spec/models/application_setting_spec.rb
index f8dc1541dd3..ab6f6dfe720 100644
--- a/spec/models/application_setting_spec.rb
+++ b/spec/models/application_setting_spec.rb
@@ -354,36 +354,6 @@ describe ApplicationSetting do
end
end
- describe 'setting Sentry DSNs' do
- context 'server DSN' do
- it 'strips leading and trailing whitespace' do
- subject.update(sentry_dsn: ' http://test ')
-
- expect(subject.sentry_dsn).to eq('http://test')
- end
-
- it 'handles nil values' do
- subject.update(sentry_dsn: nil)
-
- expect(subject.sentry_dsn).to be_nil
- end
- end
-
- context 'client-side DSN' do
- it 'strips leading and trailing whitespace' do
- subject.update(clientside_sentry_dsn: ' http://test ')
-
- expect(subject.clientside_sentry_dsn).to eq('http://test')
- end
-
- it 'handles nil values' do
- subject.update(clientside_sentry_dsn: nil)
-
- expect(subject.clientside_sentry_dsn).to be_nil
- end
- end
- end
-
describe '#disabled_oauth_sign_in_sources=' do
before do
allow(Devise).to receive(:omniauth_providers).and_return([:github])
diff --git a/spec/models/broadcast_message_spec.rb b/spec/models/broadcast_message_spec.rb
index 4d53e4aad8a..020ada3c47a 100644
--- a/spec/models/broadcast_message_spec.rb
+++ b/spec/models/broadcast_message_spec.rb
@@ -48,14 +48,14 @@ describe BroadcastMessage do
expect(described_class.current).to be_empty
end
- it 'caches the output of the query' do
+ it 'caches the output of the query for two weeks' do
create(:broadcast_message)
- expect(described_class).to receive(:current_and_future_messages).and_call_original.once
+ expect(described_class).to receive(:current_and_future_messages).and_call_original.twice
described_class.current
- Timecop.travel(1.year) do
+ Timecop.travel(3.weeks) do
described_class.current
end
end
diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb
index 6ebc6337d50..55cea48b641 100644
--- a/spec/models/ci/pipeline_spec.rb
+++ b/spec/models/ci/pipeline_spec.rb
@@ -1886,6 +1886,17 @@ describe Ci::Pipeline, :mailer do
end
end
+ describe '.latest_for_shas' do
+ let(:sha) { 'abc' }
+
+ it 'returns latest pipeline for sha' do
+ create(:ci_pipeline, sha: sha)
+ pipeline2 = create(:ci_pipeline, sha: sha)
+
+ expect(described_class.latest_for_shas(sha)).to contain_exactly(pipeline2)
+ end
+ end
+
describe '.latest_successful_ids_per_project' do
let(:projects) { create_list(:project, 2) }
let!(:pipeline1) { create(:ci_pipeline, :success, project: projects[0]) }
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/platforms/kubernetes_spec.rb b/spec/models/clusters/platforms/kubernetes_spec.rb
index 05b3035e591..471769e4aab 100644
--- a/spec/models/clusters/platforms/kubernetes_spec.rb
+++ b/spec/models/clusters/platforms/kubernetes_spec.rb
@@ -2,13 +2,11 @@
require 'spec_helper'
-describe Clusters::Platforms::Kubernetes, :use_clean_rails_memory_store_caching do
+describe Clusters::Platforms::Kubernetes do
include KubernetesHelpers
- include ReactiveCachingHelpers
it { is_expected.to belong_to(:cluster) }
it { is_expected.to be_kind_of(Gitlab::Kubernetes) }
- it { is_expected.to be_kind_of(ReactiveCaching) }
it { is_expected.to respond_to :ca_pem }
it { is_expected.to validate_exclusion_of(:namespace).in_array(%w(gitlab-managed-apps)) }
@@ -397,17 +395,16 @@ describe Clusters::Platforms::Kubernetes, :use_clean_rails_memory_store_caching
end
describe '#terminals' do
- subject { service.terminals(environment) }
+ subject { service.terminals(environment, pods: pods) }
let!(:cluster) { create(:cluster, :project, platform_kubernetes: service) }
let(:project) { cluster.project }
let(:service) { create(:cluster_platform_kubernetes, :configured) }
let(:environment) { build(:environment, project: project, name: "env", slug: "env-000000") }
+ let(:pods) { [{ "bad" => "pod" }] }
context 'with invalid pods' do
it 'returns no terminals' do
- stub_reactive_cache(service, pods: [{ "bad" => "pod" }])
-
is_expected.to be_empty
end
end
@@ -416,13 +413,7 @@ describe Clusters::Platforms::Kubernetes, :use_clean_rails_memory_store_caching
let(:pod) { kube_pod(environment_slug: environment.slug, namespace: cluster.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
+ let(:pods) { [pod, pod, pod_with_no_terminal, kube_pod(environment_slug: "should-be-filtered-out")] }
it 'returns terminals' do
is_expected.to eq(terminals + terminals)
@@ -437,16 +428,18 @@ describe Clusters::Platforms::Kubernetes, :use_clean_rails_memory_store_caching
end
end
- describe '#calculate_reactive_cache' do
- subject { service.calculate_reactive_cache }
-
- let!(:cluster) { create(:cluster, :project, enabled: enabled, platform_kubernetes: service) }
+ describe '#calculate_reactive_cache_for' do
let(:service) { create(:cluster_platform_kubernetes, :configured) }
- let(:enabled) { true }
- let(:namespace) { cluster.kubernetes_namespace_for(cluster.project) }
+ let(:pod) { kube_pod }
+ let(:namespace) { pod["metadata"]["namespace"] }
+ let(:environment) { instance_double(Environment, deployment_namespace: namespace) }
- context 'when cluster is disabled' do
- let(:enabled) { false }
+ subject { service.calculate_reactive_cache_for(environment) }
+
+ context 'when the kubernetes integration is disabled' do
+ before do
+ allow(service).to receive(:enabled?).and_return(false)
+ end
it { is_expected.to be_nil }
end
@@ -457,7 +450,7 @@ describe Clusters::Platforms::Kubernetes, :use_clean_rails_memory_store_caching
stub_kubeclient_deployments(namespace)
end
- it { is_expected.to include(pods: [kube_pod]) }
+ it { is_expected.to include(pods: [pod]) }
end
context 'when kubernetes responds with 500s' do
@@ -477,11 +470,5 @@ describe Clusters::Platforms::Kubernetes, :use_clean_rails_memory_store_caching
it { is_expected.to include(pods: []) }
end
-
- context 'when the cluster is not project level' do
- let(:cluster) { create(:cluster, :group, platform_kubernetes: service) }
-
- it { is_expected.to include(pods: []) }
- 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/deployable_spec.rb b/spec/models/concerns/deployable_spec.rb
index 42bed9434f5..bb73dd8ade0 100644
--- a/spec/models/concerns/deployable_spec.rb
+++ b/spec/models/concerns/deployable_spec.rb
@@ -7,10 +7,6 @@ describe Deployable do
let(:deployment) { job.deployment }
let(:environment) { deployment&.environment }
- before do
- job.reload
- end
-
context 'when the deployable object will deploy to production' do
let!(:job) { create(:ci_build, :start_review_app) }
@@ -26,6 +22,16 @@ describe Deployable do
end
end
+ context 'when the deployable object will deploy to a cluster' do
+ let(:project) { create(:project) }
+ let!(:cluster) { create(:cluster, :provided_by_user, projects: [project]) }
+ let!(:job) { create(:ci_build, :start_review_app, project: project) }
+
+ it 'creates a deployment with cluster association' do
+ expect(deployment.cluster).to eq(cluster)
+ end
+ end
+
context 'when the deployable object will stop an environment' do
let!(:job) { create(:ci_build, :stop_review_app) }
diff --git a/spec/models/concerns/deployment_platform_spec.rb b/spec/models/concerns/deployment_platform_spec.rb
index 96465a51db2..2378f400540 100644
--- a/spec/models/concerns/deployment_platform_spec.rb
+++ b/spec/models/concerns/deployment_platform_spec.rb
@@ -82,16 +82,6 @@ describe DeploymentPlatform do
end
end
end
-
- context 'feature flag disabled' do
- before do
- stub_feature_flags(group_clusters: false)
- end
-
- it 'returns nil' do
- is_expected.to be_nil
- end
- end
end
end
end
diff --git a/spec/models/concerns/mentionable_spec.rb b/spec/models/concerns/mentionable_spec.rb
index f31e3e8821d..6034344d034 100644
--- a/spec/models/concerns/mentionable_spec.rb
+++ b/spec/models/concerns/mentionable_spec.rb
@@ -18,7 +18,7 @@ describe Mentionable do
let(:project) { create(:project) }
let(:mentionable) { Example.new }
- it 'excludes JIRA references' do
+ it 'excludes Jira references' do
allow(project).to receive_messages(jira_tracker?: true)
mentionable.project = project
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_spec.rb b/spec/models/deployment_spec.rb
index 1dceef3fc00..8d0eb0f4a06 100644
--- a/spec/models/deployment_spec.rb
+++ b/spec/models/deployment_spec.rb
@@ -7,6 +7,7 @@ describe Deployment do
it { is_expected.to belong_to(:project).required }
it { is_expected.to belong_to(:environment).required }
+ it { is_expected.to belong_to(:cluster).class_name('Clusters::Cluster') }
it { is_expected.to belong_to(:user) }
it { is_expected.to belong_to(:deployable) }
@@ -294,6 +295,67 @@ 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) }
@@ -380,12 +442,12 @@ describe Deployment do
end
end
- describe '#cluster' do
+ describe '#deployment_platform_cluster' do
let(:deployment) { create(:deployment) }
let(:project) { deployment.project }
let(:environment) { deployment.environment }
- subject { deployment.cluster }
+ subject { deployment.deployment_platform_cluster }
before do
expect(project).to receive(:deployment_platform)
diff --git a/spec/models/environment_spec.rb b/spec/models/environment_spec.rb
index 379dda1f5c4..fe4d64818b4 100644
--- a/spec/models/environment_spec.rb
+++ b/spec/models/environment_spec.rb
@@ -2,10 +2,14 @@
require 'spec_helper'
-describe Environment do
+describe Environment, :use_clean_rails_memory_store_caching do
+ include ReactiveCachingHelpers
+
let(:project) { create(:project, :stubbed_repository) }
subject(:environment) { create(:environment, project: project) }
+ it { is_expected.to be_kind_of(ReactiveCaching) }
+
it { is_expected.to belong_to(:project).required }
it { is_expected.to have_many(:deployments) }
@@ -573,32 +577,65 @@ describe Environment do
describe '#terminals' do
subject { environment.terminals }
- context 'when the environment has terminals' do
+ before do
+ allow(environment).to receive(:deployment_platform).and_return(double)
+ end
+
+ context 'reactive cache is empty' do
before do
- allow(environment).to receive(:has_terminals?).and_return(true)
+ stub_reactive_cache(environment, nil)
end
- context 'when user configured kubernetes from CI/CD > Clusters' do
- let!(:cluster) { create(:cluster, :project, :provided_by_gcp) }
- let(:project) { cluster.project }
+ it { is_expected.to be_nil }
+ end
+
+ context 'reactive cache has pod data' do
+ let(:cache_data) { Hash(pods: %w(pod1 pod2)) }
+
+ before do
+ stub_reactive_cache(environment, cache_data)
+ end
- it 'returns the terminals from the deployment service' do
- expect(environment.deployment_platform)
- .to receive(:terminals).with(environment)
- .and_return(:fake_terminals)
+ it 'retrieves terminals from the deployment platform' do
+ expect(environment.deployment_platform)
+ .to receive(:terminals).with(environment, cache_data)
+ .and_return(:fake_terminals)
- is_expected.to eq(:fake_terminals)
- end
+ is_expected.to eq(:fake_terminals)
end
end
+ end
+
+ describe '#calculate_reactive_cache' do
+ let(:cluster) { create(:cluster, :project, :provided_by_user) }
+ let(:project) { cluster.project }
+ let(:environment) { create(:environment, project: project) }
+ let!(:deployment) { create(:deployment, :success, environment: environment) }
+
+ subject { environment.calculate_reactive_cache }
+
+ it 'returns cache data from the deployment platform' do
+ expect(environment.deployment_platform).to receive(:calculate_reactive_cache_for)
+ .with(environment).and_return(pods: %w(pod1 pod2))
+
+ is_expected.to eq(pods: %w(pod1 pod2))
+ end
- context 'when the environment does not have terminals' do
+ context 'environment does not have terminals available' do
before do
allow(environment).to receive(:has_terminals?).and_return(false)
end
it { is_expected.to be_nil }
end
+
+ context 'project is pending deletion' do
+ before do
+ allow(environment.project).to receive(:pending_delete?).and_return(true)
+ end
+
+ it { is_expected.to be_nil }
+ end
end
describe '#has_metrics?' do
diff --git a/spec/models/group_spec.rb b/spec/models/group_spec.rb
index d7accbef6bd..470ce65707d 100644
--- a/spec/models/group_spec.rb
+++ b/spec/models/group_spec.rb
@@ -866,35 +866,6 @@ describe Group do
end
end
- describe '#group_clusters_enabled?' do
- before do
- # Override global stub in spec/spec_helper.rb
- expect(Feature).to receive(:enabled?).and_call_original
- end
-
- subject { group.group_clusters_enabled? }
-
- it { is_expected.to be_truthy }
-
- context 'explicitly disabled for root ancestor' do
- before do
- feature = Feature.get(:group_clusters)
- feature.disable(group.root_ancestor)
- end
-
- it { is_expected.to be_falsey }
- end
-
- context 'explicitly disabled for root ancestor' do
- before do
- feature = Feature.get(:group_clusters)
- feature.enable(group.root_ancestor)
- end
-
- it { is_expected.to be_truthy }
- end
- end
-
describe '#first_auto_devops_config' do
using RSpec::Parameterized::TableSyntax
diff --git a/spec/models/internal_id_spec.rb b/spec/models/internal_id_spec.rb
index 806b4f61bd8..28630f7d3fe 100644
--- a/spec/models/internal_id_spec.rb
+++ b/spec/models/internal_id_spec.rb
@@ -158,7 +158,7 @@ describe InternalId do
before do
described_class.reset_column_information
# Project factory will also call the current_version
- expect(ActiveRecord::Migrator).to receive(:current_version).twice.and_return(InternalId::REQUIRED_SCHEMA_VERSION - 1)
+ expect(ActiveRecord::Migrator).to receive(:current_version).at_least(:once).and_return(InternalId::REQUIRED_SCHEMA_VERSION - 1)
end
it 'does not reset any of the iids' do
diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb
index fc28c216b21..a2547755510 100644
--- a/spec/models/merge_request_spec.rb
+++ b/spec/models/merge_request_spec.rb
@@ -2124,7 +2124,7 @@ describe MergeRequest do
allow(subject).to receive(:head_pipeline) { nil }
end
- it { expect(subject.mergeable_ci_state?).to be_truthy }
+ it { expect(subject.mergeable_ci_state?).to be_falsey }
end
end
diff --git a/spec/models/namespace/aggregation_schedule_spec.rb b/spec/models/namespace/aggregation_schedule_spec.rb
new file mode 100644
index 00000000000..8ed0248e1b2
--- /dev/null
+++ b/spec/models/namespace/aggregation_schedule_spec.rb
@@ -0,0 +1,78 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+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
+ 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
new file mode 100644
index 00000000000..3229a32234e
--- /dev/null
+++ b/spec/models/namespace/root_storage_statistics_spec.rb
@@ -0,0 +1,75 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Namespace::RootStorageStatistics, type: :model do
+ it { is_expected.to belong_to :namespace }
+ 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 d80183af33e..f908f3504e0 100644
--- a/spec/models/namespace_spec.rb
+++ b/spec/models/namespace_spec.rb
@@ -15,6 +15,8 @@ describe Namespace do
it { is_expected.to have_many :project_statistics }
it { is_expected.to belong_to :parent }
it { is_expected.to have_many :children }
+ it { is_expected.to have_one :root_storage_statistics }
+ it { is_expected.to have_one :aggregation_schedule }
end
describe 'validations' do
@@ -835,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/pages_domain_spec.rb b/spec/models/pages_domain_spec.rb
index 4fb7b71a3c7..661957cf08b 100644
--- a/spec/models/pages_domain_spec.rb
+++ b/spec/models/pages_domain_spec.rb
@@ -479,4 +479,30 @@ describe PagesDomain do
end
end
end
+
+ describe '.need_auto_ssl_renewal' do
+ subject { described_class.need_auto_ssl_renewal }
+
+ let!(:domain_with_user_provided_certificate) { create(:pages_domain) }
+ let!(:domain_with_expired_user_provided_certificate) do
+ create(:pages_domain, :with_expired_certificate)
+ end
+ let!(:domain_with_user_provided_certificate_and_auto_ssl) do
+ create(:pages_domain, auto_ssl_enabled: true)
+ end
+
+ let!(:domain_with_gitlab_provided_certificate) { create(:pages_domain, :letsencrypt) }
+ let!(:domain_with_expired_gitlab_provided_certificate) do
+ create(:pages_domain, :letsencrypt, :with_expired_certificate)
+ end
+
+ it 'contains only domains needing verification' do
+ is_expected.to(
+ contain_exactly(
+ domain_with_user_provided_certificate_and_auto_ssl,
+ domain_with_expired_gitlab_provided_certificate
+ )
+ )
+ end
+ end
end
diff --git a/spec/models/postgresql/replication_slot_spec.rb b/spec/models/postgresql/replication_slot_spec.rb
index e100af7ddc7..95ae204a8a8 100644
--- a/spec/models/postgresql/replication_slot_spec.rb
+++ b/spec/models/postgresql/replication_slot_spec.rb
@@ -47,5 +47,13 @@ describe Postgresql::ReplicationSlot, :postgresql do
expect(described_class.lag_too_great?).to eq(false)
end
+
+ it 'returns false when there is a nil replication lag' do
+ expect(described_class)
+ .to receive(:pluck)
+ .and_return([0.megabytes, nil])
+
+ expect(described_class.lag_too_great?).to eq(false)
+ 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/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 04ae9390436..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) }
@@ -158,7 +222,7 @@ describe JiraService do
WebMock.stub_request(:post, @remote_link_url).with(basic_auth: %w(gitlab_jira_username gitlab_jira_password))
end
- it 'calls JIRA API' do
+ it 'calls Jira API' do
@jira_service.close_issue(resource, ExternalIssue.new('JIRA-123', project))
expect(WebMock).to have_requested(:post, @comment_url).with(
@@ -175,14 +239,14 @@ describe JiraService do
# Check https://developer.atlassian.com/jiradev/jira-platform/guides/other/guide-jira-remote-issue-links/fields-in-remote-issue-links
# for more information
- it 'creates Remote Link reference in JIRA for comment' do
+ it 'creates Remote Link reference in Jira for comment' do
@jira_service.close_issue(resource, ExternalIssue.new('JIRA-123', project))
favicon_path = "http://localhost/assets/#{find_asset('favicon.png').digest_path}"
# Creates comment
expect(WebMock).to have_requested(:post, @comment_url)
- # Creates Remote Link in JIRA issue fields
+ # Creates Remote Link in Jira issue fields
expect(WebMock).to have_requested(:post, @remote_link_url).with(
body: hash_including(
GlobalID: 'GitLab',
@@ -319,7 +383,7 @@ describe JiraService do
end
context 'when the test succeeds' do
- it 'tries to get JIRA project with URL when API URL not set' do
+ it 'tries to get Jira project with URL when API URL not set' do
test_settings('jira.example.com')
end
@@ -327,7 +391,7 @@ describe JiraService do
expect(test_settings).to eq( { success: true, result: { 'url' => 'http://url' } })
end
- it 'tries to get JIRA project with API URL if set' do
+ it 'tries to get Jira project with API URL if set' do
jira_service.update(api_url: 'http://jira.api.com')
test_settings('jira.api.com')
end
@@ -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/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_spec.rb b/spec/models/project_spec.rb
index cc0f5002a1e..1bc092fa41a 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -497,7 +497,6 @@ describe Project do
it { is_expected.to delegate_method(:members).to(:team).with_prefix(true) }
it { is_expected.to delegate_method(:name).to(:owner).with_prefix(true).with_arguments(allow_nil: true) }
- it { is_expected.to delegate_method(:group_clusters_enabled?).to(:group).with_arguments(allow_nil: true) }
it { is_expected.to delegate_method(:root_ancestor).to(:namespace).with_arguments(allow_nil: true) }
it { is_expected.to delegate_method(:last_pipeline).to(:commit).with_arguments(allow_nil: true) }
end
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 c5ab7e57272..13da7bd7407 100644
--- a/spec/models/repository_spec.rb
+++ b/spec/models/repository_spec.rb
@@ -844,6 +844,19 @@ describe Repository do
end
end
+ describe '#get_raw_changes' do
+ context `with non-UTF8 bytes in paths` do
+ let(:old_rev) { 'd0888d297eadcd7a345427915c309413b1231e65' }
+ let(:new_rev) { '19950f03c765f7ac8723a73a0599764095f52fc0' }
+ let(:changes) { repository.raw_changes_between(old_rev, new_rev) }
+
+ it 'returns the changes' do
+ expect { changes }.not_to raise_error
+ expect(changes.first.new_path.bytes).to eq("hello\x80world".bytes)
+ end
+ end
+ end
+
describe '#create_ref' do
it 'redirects the call to write_ref' do
ref, ref_path = '1', '2'
@@ -2285,48 +2298,6 @@ describe Repository do
end
end
- describe '#diverging_commit_counts' do
- let(:diverged_branch) { repository.find_branch('fix') }
- let(:root_ref_sha) { repository.raw_repository.commit(repository.root_ref).id }
- let(:diverged_branch_sha) { diverged_branch.dereferenced_target.sha }
-
- it 'returns the commit counts behind and ahead of default branch' do
- result = repository.diverging_commit_counts(diverged_branch)
-
- 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])
-
- repository.diverging_commit_counts(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])
-
- repository.diverging_commit_counts(diverged_branch)
- end
- end
- end
-
describe '#refresh_method_caches' do
it 'refreshes the caches of the given types' do
expect(repository).to receive(:expire_method_caches)
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/policies/award_emoji_policy_spec.rb b/spec/policies/award_emoji_policy_spec.rb
new file mode 100644
index 00000000000..2e3693c58d7
--- /dev/null
+++ b/spec/policies/award_emoji_policy_spec.rb
@@ -0,0 +1,54 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe AwardEmojiPolicy do
+ let(:user) { create(:user) }
+ let(:award_emoji) { create(:award_emoji, awardable: awardable) }
+
+ subject { described_class.new(user, award_emoji) }
+
+ shared_examples 'when the user can read the awardable' do
+ context do
+ let(:project) { create(:project, :public) }
+
+ it { expect_allowed(:read_emoji) }
+ end
+ end
+
+ shared_examples 'when the user cannot read the awardable' do
+ context do
+ let(:project) { create(:project, :private) }
+
+ it { expect_disallowed(:read_emoji) }
+ end
+ end
+
+ context 'when the awardable is an issue' do
+ let(:awardable) { create(:issue, project: project) }
+
+ include_examples 'when the user can read the awardable'
+ include_examples 'when the user cannot read the awardable'
+ end
+
+ context 'when the awardable is a merge request' do
+ let(:awardable) { create(:merge_request, source_project: project) }
+
+ include_examples 'when the user can read the awardable'
+ include_examples 'when the user cannot read the awardable'
+ end
+
+ context 'when the awardable is a note' do
+ let(:awardable) { create(:note_on_merge_request, project: project) }
+
+ include_examples 'when the user can read the awardable'
+ include_examples 'when the user cannot read the awardable'
+ end
+
+ context 'when the awardable is a snippet' do
+ let(:awardable) { create(:project_snippet, :public, project: project) }
+
+ include_examples 'when the user can read the awardable'
+ include_examples 'when the user cannot read the awardable'
+ end
+end
diff --git a/spec/policies/clusters/instance_policy_spec.rb b/spec/policies/clusters/instance_policy_spec.rb
index 9d755c6d29d..7b61819e079 100644
--- a/spec/policies/clusters/instance_policy_spec.rb
+++ b/spec/policies/clusters/instance_policy_spec.rb
@@ -16,21 +16,9 @@ describe Clusters::InstancePolicy do
context 'when admin' do
let(:user) { create(:admin) }
- context 'with instance_level_clusters enabled' do
- it { expect(policy).to be_allowed :read_cluster }
- it { expect(policy).to be_allowed :update_cluster }
- it { expect(policy).to be_allowed :admin_cluster }
- end
-
- context 'with instance_level_clusters disabled' do
- before do
- stub_feature_flags(instance_clusters: false)
- end
-
- it { expect(policy).to be_disallowed :read_cluster }
- it { expect(policy).to be_disallowed :update_cluster }
- it { expect(policy).to be_disallowed :admin_cluster }
- end
+ it { expect(policy).to be_allowed :read_cluster }
+ it { expect(policy).to be_allowed :update_cluster }
+ it { expect(policy).to be_allowed :admin_cluster }
end
end
end
diff --git a/spec/presenters/award_emoji_presenter_spec.rb b/spec/presenters/award_emoji_presenter_spec.rb
new file mode 100644
index 00000000000..e2ada2a3c93
--- /dev/null
+++ b/spec/presenters/award_emoji_presenter_spec.rb
@@ -0,0 +1,36 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe AwardEmojiPresenter do
+ let(:emoji_name) { 'thumbsup' }
+ let(:award_emoji) { build(:award_emoji, name: emoji_name) }
+ let(:presenter) { described_class.new(award_emoji) }
+
+ describe '#description' do
+ it { expect(presenter.description).to eq Gitlab::Emoji.emojis[emoji_name]['description'] }
+ end
+
+ describe '#unicode' do
+ it { expect(presenter.unicode).to eq Gitlab::Emoji.emojis[emoji_name]['unicode'] }
+ end
+
+ describe '#unicode_version' do
+ it { expect(presenter.unicode_version).to eq Gitlab::Emoji.emoji_unicode_version(emoji_name) }
+ end
+
+ describe '#emoji' do
+ it { expect(presenter.emoji).to eq Gitlab::Emoji.emojis[emoji_name]['moji'] }
+ end
+
+ describe 'when presenting an award emoji with an invalid name' do
+ let(:emoji_name) { 'invalid-name' }
+
+ it 'returns nil for all properties' do
+ expect(presenter.description).to be_nil
+ expect(presenter.emoji).to be_nil
+ expect(presenter.unicode).to be_nil
+ expect(presenter.unicode_version).to be_nil
+ end
+ end
+end
diff --git a/spec/requests/api/branches_spec.rb b/spec/requests/api/branches_spec.rb
index 8b503777443..f9c8b42afa8 100644
--- a/spec/requests/api/branches_spec.rb
+++ b/spec/requests/api/branches_spec.rb
@@ -65,7 +65,7 @@ describe API::Branches do
context 'when repository is disabled' do
include_context 'disabled repository'
- it_behaves_like '403 response' do
+ it_behaves_like '404 response' do
let(:request) { get api(route, current_user) }
end
end
@@ -175,7 +175,7 @@ describe API::Branches do
context 'when repository is disabled' do
include_context 'disabled repository'
- it_behaves_like '403 response' do
+ it_behaves_like '404 response' do
let(:request) { get api(route, current_user) }
end
end
@@ -337,7 +337,7 @@ describe API::Branches do
context 'when repository is disabled' do
include_context 'disabled repository'
- it_behaves_like '403 response' do
+ it_behaves_like '404 response' do
let(:request) { put api(route, current_user) }
end
end
@@ -471,7 +471,7 @@ describe API::Branches do
context 'when repository is disabled' do
include_context 'disabled repository'
- it_behaves_like '403 response' do
+ it_behaves_like '404 response' do
let(:request) { put api(route, current_user) }
end
end
@@ -547,7 +547,7 @@ describe API::Branches do
context 'when repository is disabled' do
include_context 'disabled repository'
- it_behaves_like '403 response' do
+ it_behaves_like '404 response' do
let(:request) { post api(route, current_user) }
end
end
diff --git a/spec/requests/api/commits_spec.rb b/spec/requests/api/commits_spec.rb
index f104da6ebba..3df5d9412f8 100644
--- a/spec/requests/api/commits_spec.rb
+++ b/spec/requests/api/commits_spec.rb
@@ -736,7 +736,7 @@ describe API::Commits do
context 'when repository is disabled' do
include_context 'disabled repository'
- it_behaves_like '403 response' do
+ it_behaves_like '404 response' do
let(:request) { get api(route, current_user) }
end
end
@@ -825,7 +825,7 @@ describe API::Commits do
context 'when repository is disabled' do
include_context 'disabled repository'
- it_behaves_like '403 response' do
+ it_behaves_like '404 response' do
let(:request) { get api(route, current_user) }
end
end
@@ -968,7 +968,7 @@ describe API::Commits do
context 'when repository is disabled' do
include_context 'disabled repository'
- it_behaves_like '403 response' do
+ it_behaves_like '404 response' do
let(:request) { get api(route, current_user) }
end
end
@@ -1067,7 +1067,7 @@ describe API::Commits do
context 'when repository is disabled' do
include_context 'disabled repository'
- it_behaves_like '403 response' do
+ it_behaves_like '404 response' do
let(:request) { get api(route, current_user) }
end
end
@@ -1169,7 +1169,7 @@ describe API::Commits do
context 'when repository is disabled' do
include_context 'disabled repository'
- it_behaves_like '403 response' do
+ it_behaves_like '404 response' do
let(:request) { post api(route, current_user), params: { branch: 'master' } }
end
end
@@ -1324,7 +1324,7 @@ describe API::Commits do
context 'when repository is disabled' do
include_context 'disabled repository'
- it_behaves_like '403 response' do
+ it_behaves_like '404 response' do
let(:request) { post api(route, current_user), params: { branch: branch } }
end
end
@@ -1435,7 +1435,7 @@ describe API::Commits do
context 'when repository is disabled' do
include_context 'disabled repository'
- it_behaves_like '403 response' do
+ it_behaves_like '404 response' do
let(:request) { post api(route, current_user), params: { note: 'My comment' } }
end
end
diff --git a/spec/requests/api/graphql/mutations/award_emojis/add_spec.rb b/spec/requests/api/graphql/mutations/award_emojis/add_spec.rb
new file mode 100644
index 00000000000..3982125a38a
--- /dev/null
+++ b/spec/requests/api/graphql/mutations/award_emojis/add_spec.rb
@@ -0,0 +1,100 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe 'Adding an AwardEmoji' do
+ include GraphqlHelpers
+
+ let(:current_user) { create(:user) }
+ let(:awardable) { create(:note) }
+ let(:project) { awardable.project }
+ let(:emoji_name) { 'thumbsup' }
+ let(:mutation) do
+ variables = {
+ awardable_id: GitlabSchema.id_from_object(awardable).to_s,
+ name: emoji_name
+ }
+
+ graphql_mutation(:add_award_emoji, variables)
+ end
+
+ def mutation_response
+ graphql_mutation_response(:add_award_emoji)
+ end
+
+ shared_examples 'a mutation that does not create an AwardEmoji' do
+ it do
+ expect do
+ post_graphql_mutation(mutation, current_user: current_user)
+ end.not_to change { AwardEmoji.count }
+ end
+ end
+
+ context 'when the user does not have permission' do
+ it_behaves_like 'a mutation that does not create an AwardEmoji'
+
+ it_behaves_like 'a mutation that returns top-level errors',
+ errors: ['The resource that you are attempting to access does not exist or you don\'t have permission to perform this action']
+ end
+
+ context 'when the user has permission' do
+ before do
+ project.add_developer(current_user)
+ end
+
+ context 'when the given awardable is not an Awardable' do
+ let(:awardable) { create(:label) }
+
+ it_behaves_like 'a mutation that does not create an AwardEmoji'
+
+ it_behaves_like 'a mutation that returns top-level errors',
+ errors: ['Cannot award emoji to this resource']
+ end
+
+ context 'when the given awardable is an Awardable but still cannot be awarded an emoji' do
+ let(:awardable) { create(:system_note) }
+
+ it_behaves_like 'a mutation that does not create an AwardEmoji'
+
+ it_behaves_like 'a mutation that returns top-level errors',
+ errors: ['Cannot award emoji to this resource']
+ end
+
+ context 'when the given awardable an Awardable' do
+ it 'creates an emoji' do
+ expect do
+ post_graphql_mutation(mutation, current_user: current_user)
+ end.to change { AwardEmoji.count }.by(1)
+ end
+
+ it 'returns the emoji' do
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ expect(mutation_response['awardEmoji']['name']).to eq(emoji_name)
+ end
+
+ context 'when there were active record validation errors' do
+ before do
+ expect_next_instance_of(AwardEmoji) do |award|
+ expect(award).to receive(:valid?).at_least(:once).and_return(false)
+ expect(award).to receive_message_chain(
+ :errors,
+ :full_messages
+ ).and_return(['Error 1', 'Error 2'])
+ end
+ end
+
+ it_behaves_like 'a mutation that does not create an AwardEmoji'
+
+ it_behaves_like 'a mutation that returns errors in the response', errors: ['Error 1', 'Error 2']
+
+ it 'returns an empty awardEmoji' do
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ expect(mutation_response).to have_key('awardEmoji')
+ expect(mutation_response['awardEmoji']).to be_nil
+ end
+ end
+ end
+ end
+end
diff --git a/spec/requests/api/graphql/mutations/award_emojis/remove_spec.rb b/spec/requests/api/graphql/mutations/award_emojis/remove_spec.rb
new file mode 100644
index 00000000000..c78f0c7ca27
--- /dev/null
+++ b/spec/requests/api/graphql/mutations/award_emojis/remove_spec.rb
@@ -0,0 +1,80 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe 'Removing an AwardEmoji' do
+ include GraphqlHelpers
+
+ let(:current_user) { create(:user) }
+ let(:awardable) { create(:note) }
+ let(:project) { awardable.project }
+ let(:emoji_name) { 'thumbsup' }
+ let(:input) { { awardable_id: GitlabSchema.id_from_object(awardable).to_s, name: emoji_name } }
+
+ let(:mutation) do
+ graphql_mutation(:remove_award_emoji, input)
+ end
+
+ def mutation_response
+ graphql_mutation_response(:remove_award_emoji)
+ end
+
+ def create_award_emoji(user)
+ create(:award_emoji, name: emoji_name, awardable: awardable, user: user )
+ end
+
+ shared_examples 'a mutation that does not destroy an AwardEmoji' do
+ it do
+ expect do
+ post_graphql_mutation(mutation, current_user: current_user)
+ end.not_to change { AwardEmoji.count }
+ end
+ end
+
+ shared_examples 'a mutation that does not authorize the user' do
+ it_behaves_like 'a mutation that does not destroy an AwardEmoji'
+
+ it_behaves_like 'a mutation that returns top-level errors',
+ errors: ['The resource that you are attempting to access does not exist or you don\'t have permission to perform this action']
+ end
+
+ context 'when the current_user does not own the award emoji' do
+ let!(:award_emoji) { create_award_emoji(create(:user)) }
+
+ it_behaves_like 'a mutation that does not authorize the user'
+ end
+
+ context 'when the current_user owns the award emoji' do
+ let!(:award_emoji) { create_award_emoji(current_user) }
+
+ context 'when the given awardable is not an Awardable' do
+ let(:awardable) { create(:label) }
+
+ it_behaves_like 'a mutation that does not destroy an AwardEmoji'
+
+ it_behaves_like 'a mutation that returns top-level errors',
+ errors: ['Cannot award emoji to this resource']
+ end
+
+ context 'when the given awardable is an Awardable' do
+ it 'removes the emoji' do
+ expect do
+ post_graphql_mutation(mutation, current_user: current_user)
+ end.to change { AwardEmoji.count }.by(-1)
+ end
+
+ it 'returns no errors' do
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ expect(graphql_errors).to be_nil
+ end
+
+ it 'returns an empty awardEmoji' do
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ expect(mutation_response).to have_key('awardEmoji')
+ expect(mutation_response['awardEmoji']).to be_nil
+ end
+ end
+ end
+end
diff --git a/spec/requests/api/graphql/mutations/award_emojis/toggle_spec.rb b/spec/requests/api/graphql/mutations/award_emojis/toggle_spec.rb
new file mode 100644
index 00000000000..31145730f10
--- /dev/null
+++ b/spec/requests/api/graphql/mutations/award_emojis/toggle_spec.rb
@@ -0,0 +1,142 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe 'Toggling an AwardEmoji' do
+ include GraphqlHelpers
+
+ let(:current_user) { create(:user) }
+ let(:awardable) { create(:note) }
+ let(:project) { awardable.project }
+ let(:emoji_name) { 'thumbsup' }
+ let(:mutation) do
+ variables = {
+ awardable_id: GitlabSchema.id_from_object(awardable).to_s,
+ name: emoji_name
+ }
+
+ graphql_mutation(:toggle_award_emoji, variables)
+ end
+
+ def mutation_response
+ graphql_mutation_response(:toggle_award_emoji)
+ end
+
+ shared_examples 'a mutation that does not create or destroy an AwardEmoji' do
+ it do
+ expect do
+ post_graphql_mutation(mutation, current_user: current_user)
+ end.not_to change { AwardEmoji.count }
+ end
+ end
+
+ def create_award_emoji(user)
+ create(:award_emoji, name: emoji_name, awardable: awardable, user: user )
+ end
+
+ context 'when the user has permission' do
+ before do
+ project.add_developer(current_user)
+ end
+
+ context 'when the given awardable is not an Awardable' do
+ let(:awardable) { create(:label) }
+
+ it_behaves_like 'a mutation that does not create or destroy an AwardEmoji'
+
+ it_behaves_like 'a mutation that returns top-level errors',
+ errors: ['Cannot award emoji to this resource']
+ end
+
+ context 'when the given awardable is an Awardable but still cannot be awarded an emoji' do
+ let(:awardable) { create(:system_note) }
+
+ it_behaves_like 'a mutation that does not create or destroy an AwardEmoji'
+
+ it_behaves_like 'a mutation that returns top-level errors',
+ errors: ['Cannot award emoji to this resource']
+ end
+
+ context 'when the given awardable is an Awardable' do
+ context 'when no emoji has been awarded by the current_user yet' do
+ # Create an award emoji for another user. This therefore tests that
+ # toggling is correctly scoped to the user's emoji only.
+ let!(:award_emoji) { create_award_emoji(create(:user)) }
+
+ it 'creates an emoji' do
+ expect do
+ post_graphql_mutation(mutation, current_user: current_user)
+ end.to change { AwardEmoji.count }.by(1)
+ end
+
+ it 'returns the emoji' do
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ expect(mutation_response['awardEmoji']['name']).to eq(emoji_name)
+ end
+
+ it 'returns toggledOn as true' do
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ expect(mutation_response['toggledOn']).to eq(true)
+ end
+
+ context 'when there were active record validation errors' do
+ before do
+ expect_next_instance_of(AwardEmoji) do |award|
+ expect(award).to receive(:valid?).at_least(:once).and_return(false)
+ expect(award).to receive_message_chain(:errors, :full_messages).and_return(['Error 1', 'Error 2'])
+ end
+ end
+
+ it_behaves_like 'a mutation that does not create or destroy an AwardEmoji'
+
+ it_behaves_like 'a mutation that returns errors in the response', errors: ['Error 1', 'Error 2']
+
+ it 'returns an empty awardEmoji' do
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ expect(mutation_response).to have_key('awardEmoji')
+ expect(mutation_response['awardEmoji']).to be_nil
+ end
+ end
+ end
+
+ context 'when an emoji has been awarded by the current_user' do
+ let!(:award_emoji) { create_award_emoji(current_user) }
+
+ it 'removes the emoji' do
+ expect do
+ post_graphql_mutation(mutation, current_user: current_user)
+ end.to change { AwardEmoji.count }.by(-1)
+ end
+
+ it 'returns no errors' do
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ expect(graphql_errors).to be_nil
+ end
+
+ it 'returns an empty awardEmoji' do
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ expect(mutation_response).to have_key('awardEmoji')
+ expect(mutation_response['awardEmoji']).to be_nil
+ end
+
+ it 'returns toggledOn as false' do
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ expect(mutation_response['toggledOn']).to eq(false)
+ end
+ end
+ end
+ end
+
+ context 'when the user does not have permission' do
+ it_behaves_like 'a mutation that does not create or destroy an AwardEmoji'
+
+ it_behaves_like 'a mutation that returns top-level errors',
+ errors: ['The resource that you are attempting to access does not exist or you don\'t have permission to perform this action']
+ end
+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/project/tree/tree_spec.rb b/spec/requests/api/graphql/project/tree/tree_spec.rb
index b07aa1e12d3..94128cc21ee 100644
--- a/spec/requests/api/graphql/project/tree/tree_spec.rb
+++ b/spec/requests/api/graphql/project/tree/tree_spec.rb
@@ -33,6 +33,12 @@ describe 'getting a tree in a project' do
expect(graphql_data['project']['repository']['tree']['submodules']['edges']).to eq([])
expect(graphql_data['project']['repository']['tree']['blobs']['edges']).to eq([])
end
+
+ it 'returns null commit' do
+ post_graphql(query, current_user: current_user)
+
+ expect(graphql_data['project']['repository']['last_commit']).to be_nil
+ end
end
context 'when ref does not exist' do
@@ -45,6 +51,12 @@ describe 'getting a tree in a project' do
expect(graphql_data['project']['repository']['tree']['submodules']['edges']).to eq([])
expect(graphql_data['project']['repository']['tree']['blobs']['edges']).to eq([])
end
+
+ it 'returns null commit' do
+ post_graphql(query, current_user: current_user)
+
+ expect(graphql_data['project']['repository']['last_commit']).to be_nil
+ end
end
context 'when ref and path exist' do
@@ -61,6 +73,12 @@ describe 'getting a tree in a project' do
expect(graphql_data['project']['repository']['tree']['blobs']['edges'].size).to be > 0
expect(graphql_data['project']['repository']['tree']['submodules']['edges'].size).to be > 0
end
+
+ it 'returns tree latest commit' do
+ post_graphql(query, current_user: current_user)
+
+ expect(graphql_data['project']['repository']['tree']['lastCommit']).to be_present
+ end
end
context 'when current user is nil' do
diff --git a/spec/requests/api/helpers_spec.rb b/spec/requests/api/helpers_spec.rb
index ed907841bd8..1c69f5dbb67 100644
--- a/spec/requests/api/helpers_spec.rb
+++ b/spec/requests/api/helpers_spec.rb
@@ -226,10 +226,8 @@ describe API::Helpers do
allow_any_instance_of(self.class).to receive(:rack_response)
allow(Gitlab::Sentry).to receive(:enabled?).and_return(true)
- stub_application_setting(
- sentry_enabled: true,
- sentry_dsn: "dummy://12345:67890@sentry.localdomain/sentry/42"
- )
+ stub_sentry_settings
+
configure_sentry
Raven.client.configuration.encoding = 'json'
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..a82ecb4fd63 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)
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/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/users_spec.rb b/spec/requests/api/users_spec.rb
index bab1520b960..46925daf40a 100644
--- a/spec/requests/api/users_spec.rb
+++ b/spec/requests/api/users_spec.rb
@@ -416,7 +416,6 @@ describe API::Users do
expect(response).to have_gitlab_http_status(201)
user_id = json_response['id']
new_user = User.find(user_id)
- expect(new_user).not_to eq(nil)
expect(new_user.admin).to eq(true)
expect(new_user.can_create_group).to eq(true)
end
@@ -435,7 +434,6 @@ describe API::Users do
expect(response).to have_gitlab_http_status(201)
user_id = json_response['id']
new_user = User.find(user_id)
- expect(new_user).not_to eq(nil)
expect(new_user.admin).to eq(false)
expect(new_user.can_create_group).to eq(false)
end
@@ -445,7 +443,6 @@ describe API::Users do
expect(response).to have_gitlab_http_status(201)
user_id = json_response['id']
new_user = User.find(user_id)
- expect(new_user).not_to eq(nil)
expect(new_user.admin).to eq(false)
end
@@ -460,7 +457,6 @@ describe API::Users do
user_id = json_response['id']
new_user = User.find(user_id)
- expect(new_user).not_to eq nil
expect(new_user.external).to be_falsy
end
@@ -470,7 +466,6 @@ describe API::Users do
user_id = json_response['id']
new_user = User.find(user_id)
- expect(new_user).not_to eq nil
expect(new_user.external).to be_truthy
end
@@ -482,7 +477,19 @@ describe API::Users do
user_id = json_response['id']
new_user = User.find(user_id)
- expect(new_user).not_to eq(nil)
+ expect(new_user.recently_sent_password_reset?).to eq(true)
+ end
+
+ it "creates user with random password" do
+ params = attributes_for(:user, force_random_password: true, reset_password: true)
+ post api('/users', admin), params: params
+
+ expect(response).to have_gitlab_http_status(201)
+
+ user_id = json_response['id']
+ new_user = User.find(user_id)
+
+ expect(new_user.valid_password?(params[:password])).to eq(false)
expect(new_user.recently_sent_password_reset?).to eq(true)
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/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/routing_spec.rb b/spec/routing/routing_spec.rb
index a170bb14144..ff4228c9b99 100644
--- a/spec/routing/routing_spec.rb
+++ b/spec/routing/routing_spec.rb
@@ -1,12 +1,12 @@
require 'spec_helper'
-# user GET /u/:username/
-# user_groups GET /u/:username/groups(.:format)
-# user_projects GET /u/:username/projects(.:format)
-# user_contributed_projects GET /u/:username/contributed(.:format)
-# user_snippets GET /u/:username/snippets(.:format)
-# user_calendar GET /u/:username/calendar(.:format)
-# user_calendar_activities GET /u/:username/calendar_activities(.:format)
+# user GET /users/:username/
+# user_groups GET /users/:username/groups(.:format)
+# user_projects GET /users/:username/projects(.:format)
+# user_contributed_projects GET /users/:username/contributed(.:format)
+# user_snippets GET /users/:username/snippets(.:format)
+# user_calendar GET /users/:username/calendar(.:format)
+# user_calendar_activities GET /users/:username/calendar_activities(.:format)
describe UsersController, "routing" do
it "to #show" do
allow_any_instance_of(::Constraints::UserUrlConstrainer).to receive(:matches?).and_return(true)
@@ -37,22 +37,6 @@ describe UsersController, "routing" do
it "to #calendar_activities" do
expect(get("/users/User/calendar_activities")).to route_to('users#calendar_activities', username: 'User')
end
-
- describe 'redirect alias routes' do
- include RSpec::Rails::RequestExampleGroup
-
- it '/u/user1 redirects to /user1' do
- expect(get("/u/user1")).to redirect_to('/user1')
- end
-
- it '/u/user1/groups redirects to /user1/groups' do
- expect(get("/u/user1/groups")).to redirect_to('/users/user1/groups')
- end
-
- it '/u/user1/projects redirects to /user1/projects' do
- expect(get("/u/user1/projects")).to redirect_to('/users/user1/projects')
- end
- end
end
# search GET /search(.:format) search#show
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/services/boards/visits/latest_service_spec.rb b/spec/services/boards/visits/latest_service_spec.rb
deleted file mode 100644
index c8a0a5e4243..00000000000
--- a/spec/services/boards/visits/latest_service_spec.rb
+++ /dev/null
@@ -1,59 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-describe Boards::Visits::LatestService do
- describe '#execute' do
- let(:user) { create(:user) }
-
- context 'when a project board' do
- let(:project) { create(:project) }
- let(:project_board) { create(:board, project: project) }
-
- subject(:service) { described_class.new(project_board.parent, user) }
-
- it 'returns nil when there is no user' do
- service.current_user = nil
-
- expect(service.execute).to eq nil
- end
-
- it 'queries for most recent visit' do
- expect(BoardProjectRecentVisit).to receive(:latest).once
-
- service.execute
- end
-
- it 'queries for last N visits' do
- expect(BoardProjectRecentVisit).to receive(:latest).with(user, project, count: 5).once
-
- described_class.new(project_board.parent, user, count: 5).execute
- end
- end
-
- context 'when a group board' do
- let(:group) { create(:group) }
- let(:group_board) { create(:board, group: group) }
-
- subject(:service) { described_class.new(group_board.parent, user) }
-
- it 'returns nil when there is no user' do
- service.current_user = nil
-
- expect(service.execute).to eq nil
- end
-
- it 'queries for most recent visit' do
- expect(BoardGroupRecentVisit).to receive(:latest).once
-
- service.execute
- end
-
- it 'queries for last N visits' do
- expect(BoardGroupRecentVisit).to receive(:latest).with(user, group, count: 5).once
-
- described_class.new(group_board.parent, user, count: 5).execute
- 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
new file mode 100644
index 00000000000..370da773ab2
--- /dev/null
+++ b/spec/services/branches/diverging_commit_counts_service_spec.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Branches::DivergingCommitCountsService do
+ let(:project) { create(:project, :repository) }
+ let(:repository) { project.repository }
+
+ describe '#call' do
+ let(:diverged_branch) { repository.find_branch('fix') }
+ let(:root_ref_sha) { repository.raw_repository.commit(repository.root_ref).id }
+ let(:diverged_branch_sha) { diverged_branch.dereferenced_target.sha }
+
+ let(:service) { described_class.new(repository) }
+
+ it 'returns the commit counts behind and ahead of default branch' do
+ result = service.call(diverged_branch)
+
+ expect(result).to eq(behind: 29, ahead: 2)
+ 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
+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/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_service_spec.rb b/spec/services/merge_requests/merge_service_spec.rb
index 2fbe5468b21..aa759ac9edc 100644
--- a/spec/services/merge_requests/merge_service_spec.rb
+++ b/spec/services/merge_requests/merge_service_spec.rb
@@ -58,7 +58,7 @@ describe MergeRequests::MergeService do
expect(issue.reload.closed?).to be_truthy
end
- context 'with JIRA integration' do
+ context 'with Jira integration' do
include JiraServiceHelper
let(:jira_tracker) { project.create_jira_service }
@@ -72,7 +72,7 @@ describe MergeRequests::MergeService do
allow(merge_request).to receive(:commits).and_return([commit])
end
- it 'closes issues on JIRA issue tracker' do
+ it 'closes issues on Jira issue tracker' do
jira_issue = ExternalIssue.new('JIRA-123', project)
stub_jira_urls(jira_issue)
commit = double('commit', safe_message: "Fixes #{jira_issue.to_reference}")
@@ -98,7 +98,7 @@ describe MergeRequests::MergeService do
end
context "wrong issue markdown" do
- it 'does not close issues on JIRA issue tracker' do
+ it 'does not close issues on Jira issue tracker' do
jira_issue = ExternalIssue.new('#JIRA-123', project)
stub_jira_urls(jira_issue)
commit = double('commit', safe_message: "Fixes #{jira_issue.to_reference}")
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/pages_domains/obtain_lets_encrypt_certificate_service_spec.rb b/spec/services/pages_domains/obtain_lets_encrypt_certificate_service_spec.rb
index d5f77f3354b..8d43ce4f662 100644
--- a/spec/services/pages_domains/obtain_lets_encrypt_certificate_service_spec.rb
+++ b/spec/services/pages_domains/obtain_lets_encrypt_certificate_service_spec.rb
@@ -34,8 +34,12 @@ describe PagesDomains::ObtainLetsEncryptCertificateService do
end
context 'when there is no acme order' do
- it 'creates acme order' do
+ it 'creates acme order and schedules next step' do
expect_to_create_acme_challenge
+ expect(PagesDomainSslRenewalWorker).to(
+ receive(:perform_in).with(described_class::CHALLENGE_PROCESSING_DELAY, pages_domain.id)
+ .and_return(nil).once
+ )
service.execute
end
@@ -82,8 +86,12 @@ describe PagesDomains::ObtainLetsEncryptCertificateService do
stub_lets_encrypt_order(existing_order.url, 'ready')
end
- it 'request certificate' do
+ it 'request certificate and schedules next step' do
expect(api_order).to receive(:request_certificate).and_call_original
+ expect(PagesDomainSslRenewalWorker).to(
+ receive(:perform_in).with(described_class::CERTIFICATE_PROCESSING_DELAY, pages_domain.id)
+ .and_return(nil).once
+ )
service.execute
end
diff --git a/spec/services/projects/propagate_service_template_spec.rb b/spec/services/projects/propagate_service_template_spec.rb
index f93e5aae82a..2c3effec617 100644
--- a/spec/services/projects/propagate_service_template_spec.rb
+++ b/spec/services/projects/propagate_service_template_spec.rb
@@ -72,7 +72,7 @@ describe Projects::PropagateServiceTemplate do
expect(project.pushover_service.properties).to eq(service_template.properties)
end
- describe 'bulk update' do
+ describe 'bulk update', :use_sql_query_cache do
let(:project_total) { 5 }
before do
diff --git a/spec/services/system_note_service_spec.rb b/spec/services/system_note_service_spec.rb
index 2420817e1f7..2a2547f9400 100644
--- a/spec/services/system_note_service_spec.rb
+++ b/spec/services/system_note_service_spec.rb
@@ -454,17 +454,33 @@ 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
describe '.new_merge_request' do
@@ -477,7 +493,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
@@ -750,7 +766,7 @@ describe SystemNoteService do
end
end
- describe 'JIRA integration' do
+ describe 'Jira integration' do
include JiraServiceHelper
let(:project) { create(:jira_project, :repository) }
@@ -946,6 +962,18 @@ describe SystemNoteService do
expect(subject.note).to eq "changed time estimate to 1w 4d 5h"
end
+
+ context 'when time_tracking_limit_to_hours setting is true' do
+ before do
+ stub_application_setting(time_tracking_limit_to_hours: true)
+ end
+
+ it 'sets the note text' do
+ noteable.update_attribute(:time_estimate, 277200)
+
+ expect(subject.note).to eq "changed time estimate to 77h"
+ end
+ end
end
context 'without a time estimate' do
@@ -1022,6 +1050,18 @@ describe SystemNoteService do
end
end
+ context 'when time_tracking_limit_to_hours setting is true' do
+ before do
+ stub_application_setting(time_tracking_limit_to_hours: true)
+ end
+
+ it 'sets the note text' do
+ spend_time!(277200)
+
+ expect(subject.note).to eq "added 77h of time spent"
+ end
+ end
+
def spend_time!(seconds)
noteable.spend_time(duration: seconds, user_id: author.id)
noteable.save!
@@ -1108,7 +1148,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
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index 390a869d93f..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
@@ -218,6 +220,12 @@ RSpec.configure do |config|
ActionController::Base.cache_store = caching_store
end
+ config.around(:each, :use_sql_query_cache) do |example|
+ ActiveRecord::Base.cache do
+ example.run
+ end
+ end
+
# The :each scope runs "inside" the example, so this hook ensures the DB is in the
# correct state before any examples' before hooks are called. This prevents a
# problem where `ScheduleIssuesClosedAtTypeChange` (or any migration that depends
diff --git a/spec/support/api/boards_shared_examples.rb b/spec/support/api/boards_shared_examples.rb
index 592962ebf7c..3abb5096a7a 100644
--- a/spec/support/api/boards_shared_examples.rb
+++ b/spec/support/api/boards_shared_examples.rb
@@ -14,6 +14,16 @@ shared_examples_for 'group and project boards' do |route_definition, ee = false|
end
end
+ it 'avoids N+1 queries' do
+ pat = create(:personal_access_token, user: user)
+ control = ActiveRecord::QueryRecorder.new { get api(root_url, personal_access_token: pat) }
+
+ create(:milestone, "#{board_parent.class.name.underscore}": board_parent)
+ create(:board, "#{board_parent.class.name.underscore}": board_parent)
+
+ expect { get api(root_url, personal_access_token: pat) }.not_to exceed_query_limit(control)
+ end
+
describe "GET #{route_definition}" do
context "when unauthenticated" do
it "returns authentication error" 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/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/graphql_helpers.rb b/spec/support/helpers/graphql_helpers.rb
index bcf6669f37d..1a09d48f4cd 100644
--- a/spec/support/helpers/graphql_helpers.rb
+++ b/spec/support/helpers/graphql_helpers.rb
@@ -4,10 +4,7 @@ module GraphqlHelpers
# makes an underscored string look like a fieldname
# "merge_request" => "mergeRequest"
def self.fieldnamerize(underscored_field_name)
- graphql_field_name = underscored_field_name.to_s.camelize
- graphql_field_name[0] = graphql_field_name[0].downcase
-
- graphql_field_name
+ underscored_field_name.to_s.camelize(:lower)
end
# Run a loader's named resolver
diff --git a/spec/support/helpers/jira_service_helper.rb b/spec/support/helpers/jira_service_helper.rb
index f4d5343c4ed..7e955f3d593 100644
--- a/spec/support/helpers/jira_service_helper.rb
+++ b/spec/support/helpers/jira_service_helper.rb
@@ -4,7 +4,7 @@ module JiraServiceHelper
def jira_service_settings
properties = {
- title: "JIRA tracker",
+ title: "Jira tracker",
url: JIRA_URL,
username: 'jira-user',
password: 'my-secret-password',
@@ -25,7 +25,7 @@ module JiraServiceHelper
\"32x32\":\"http://0.0.0.0:4567/secure/useravatar?size=medium&avatarId=10122\",
\"48x48\":\"http://0.0.0.0:4567/secure/useravatar?avatarId=10122\"},
\"displayName\":\"GitLab\",\"active\":true},
- \"body\":\"[Administrator|http://localhost:3000/u/root] mentioned JIRA-1 in Merge request of [gitlab-org/gitlab-test|http://localhost:3000/gitlab-org/gitlab-test/merge_requests/2].\",
+ \"body\":\"[Administrator|http://localhost:3000/root] mentioned JIRA-1 in Merge request of [gitlab-org/gitlab-test|http://localhost:3000/gitlab-org/gitlab-test/merge_requests/2].\",
\"updateAuthor\":{\"self\":\"http://0.0.0.0:4567/rest/api/2/user?username=gitlab\",\"name\":\"gitlab\",\"emailAddress\":\"gitlab@example.com\",
\"avatarUrls\":{\"16x16\":\"http://0.0.0.0:4567/secure/useravatar?size=xsmall&avatarId=10122\",
\"24x24\":\"http://0.0.0.0:4567/secure/useravatar?size=small&avatarId=10122\",
@@ -40,7 +40,7 @@ module JiraServiceHelper
\"24x24\":\"http://0.0.0.0:4567/secure/useravatar?size=small&avatarId=10122\",
\"32x32\":\"http://0.0.0.0:4567/secure/useravatar?size=medium&avatarId=10122\",
\"48x48\":\"http://0.0.0.0:4567/secure/useravatar?avatarId=10122\"},\"displayName\":\"GitLab\",\"active\":true},
- \"body\":\"[Administrator|http://localhost:3000/u/root] mentioned this issue in [a commit of h5bp/html5-boilerplate|http://localhost:3000/h5bp/html5-boilerplate/commit/2439f77897122fbeee3bfd9bb692d3608848433e].\",
+ \"body\":\"[Administrator|http://localhost:3000/root] mentioned this issue in [a commit of h5bp/html5-boilerplate|http://localhost:3000/h5bp/html5-boilerplate/commit/2439f77897122fbeee3bfd9bb692d3608848433e].\",
\"updateAuthor\":{\"self\":\"http://0.0.0.0:4567/rest/api/2/user?username=gitlab\",\"name\":\"gitlab\",\"emailAddress\":\"gitlab@example.com\",
\"avatarUrls\":{\"16x16\":\"http://0.0.0.0:4567/secure/useravatar?size=xsmall&avatarId=10122\",
\"24x24\":\"http://0.0.0.0:4567/secure/useravatar?size=small&avatarId=10122\",
diff --git a/spec/support/helpers/metrics_dashboard_helpers.rb b/spec/support/helpers/metrics_dashboard_helpers.rb
index 6de00eea474..1511a2f6b49 100644
--- a/spec/support/helpers/metrics_dashboard_helpers.rb
+++ b/spec/support/helpers/metrics_dashboard_helpers.rb
@@ -50,4 +50,12 @@ module MetricsDashboardHelpers
it_behaves_like 'valid dashboard service response for schema'
end
+
+ shared_examples_for 'raises error for users with insufficient permissions' do
+ context 'when the user does not have sufficient access' do
+ let(:user) { build(:user) }
+
+ it_behaves_like 'misconfigured dashboard service response', :unauthorized
+ end
+ end
end
diff --git a/spec/support/helpers/prometheus_helpers.rb b/spec/support/helpers/prometheus_helpers.rb
index 87f825152cf..db662836013 100644
--- a/spec/support/helpers/prometheus_helpers.rb
+++ b/spec/support/helpers/prometheus_helpers.rb
@@ -70,6 +70,10 @@ module PrometheusHelpers
WebMock.stub_request(:get, url).to_raise(exception_type)
end
+ def stub_any_prometheus_request
+ WebMock.stub_request(:any, /prometheus.example.com/)
+ end
+
def stub_all_prometheus_requests(environment_slug, body: nil, status: 200)
stub_prometheus_request(
prometheus_query_with_time_url(prometheus_memory_query(environment_slug), Time.now.utc),
diff --git a/spec/support/helpers/stub_configuration.rb b/spec/support/helpers/stub_configuration.rb
index f6c613ad5aa..c372a3f0e49 100644
--- a/spec/support/helpers/stub_configuration.rb
+++ b/spec/support/helpers/stub_configuration.rb
@@ -81,6 +81,12 @@ module StubConfiguration
allow(Gitlab.config.repositories).to receive(:storages).and_return(Settingslogic.new(messages))
end
+ def stub_sentry_settings
+ allow(Gitlab.config.sentry).to receive(:enabled).and_return(true)
+ allow(Gitlab.config.sentry).to receive(:dsn).and_return('dummy://b44a0828b72421a6d8e99efd68d44fa8@example.com/42')
+ allow(Gitlab.config.sentry).to receive(:clientside_dsn).and_return('dummy://b44a0828b72421a6d8e99efd68d44fa8@example.com/43')
+ end
+
def stub_kerberos_setting(messages)
allow(Gitlab.config.kerberos).to receive_messages(to_settings(messages))
end
@@ -89,6 +95,11 @@ module StubConfiguration
allow(Gitlab.config.gitlab_shell).to receive_messages(to_settings(messages))
end
+ def stub_rack_attack_setting(messages)
+ allow(Gitlab.config.rack_attack).to receive(:git_basic_auth).and_return(messages)
+ allow(Gitlab.config.rack_attack.git_basic_auth).to receive_messages(to_settings(messages))
+ end
+
private
# Modifies stubbed messages to also stub possible predicate versions
diff --git a/spec/support/helpers/test_env.rb b/spec/support/helpers/test_env.rb
index 77f22d9dd24..e63099d89b7 100644
--- a/spec/support/helpers/test_env.rb
+++ b/spec/support/helpers/test_env.rb
@@ -64,7 +64,8 @@ module TestEnv
'with-codeowners' => '219560e',
'submodule_inside_folder' => 'b491b92',
'png-lfs' => 'fe42f41',
- 'sha-starting-with-large-number' => '8426165'
+ 'sha-starting-with-large-number' => '8426165',
+ 'invalid-utf8-diff-paths' => '99e4853'
}.freeze
# gitlab-test-fork is a fork of gitlab-fork, but we don't necessarily
diff --git a/spec/support/inspect_squelch.rb b/spec/support/inspect_squelch.rb
new file mode 100644
index 00000000000..8ee6732370b
--- /dev/null
+++ b/spec/support/inspect_squelch.rb
@@ -0,0 +1,7 @@
+# This class can generate a lot of output if it fails,
+# so squelch the instance variable output.
+class ActiveSupport::Cache::NullStore
+ def inspect
+ "<#{self.class}>"
+ end
+end
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/application_setting_examples.rb b/spec/support/shared_examples/application_setting_examples.rb
index 421303c97be..e7ec24c5b7e 100644
--- a/spec/support/shared_examples/application_setting_examples.rb
+++ b/spec/support/shared_examples/application_setting_examples.rb
@@ -249,43 +249,4 @@ RSpec.shared_examples 'application settings examples' do
expect(setting.password_authentication_enabled_for_web?).to be_falsey
end
-
- describe 'sentry settings' do
- context 'when the sentry settings are not set in gitlab.yml' do
- it 'fallbacks to the settings in the database' do
- setting.sentry_enabled = true
- setting.sentry_dsn = 'https://b44a0828b72421a6d8e99efd68d44fa8@example.com/40'
- setting.clientside_sentry_enabled = true
- setting.clientside_sentry_dsn = 'https://b44a0828b72421a6d8e99efd68d44fa8@example.com/41'
-
- allow(Gitlab.config.sentry).to receive(:enabled).and_return(false)
- allow(Gitlab.config.sentry).to receive(:dsn).and_return(nil)
- allow(Gitlab.config.sentry).to receive(:clientside_dsn).and_return(nil)
-
- expect(setting.sentry_enabled).to eq true
- expect(setting.sentry_dsn).to eq 'https://b44a0828b72421a6d8e99efd68d44fa8@example.com/40'
- expect(setting.clientside_sentry_enabled).to eq true
- expect(setting.clientside_sentry_dsn). to eq 'https://b44a0828b72421a6d8e99efd68d44fa8@example.com/41'
- end
- end
-
- context 'when the sentry settings are set in gitlab.yml' do
- it 'does not fallback to the settings in the database' do
- setting.sentry_enabled = false
- setting.sentry_dsn = 'https://b44a0828b72421a6d8e99efd68d44fa8@example.com/40'
- setting.clientside_sentry_enabled = false
- setting.clientside_sentry_dsn = 'https://b44a0828b72421a6d8e99efd68d44fa8@example.com/41'
-
- allow(Gitlab.config.sentry).to receive(:enabled).and_return(true)
- allow(Gitlab.config.sentry).to receive(:dsn).and_return('https://b44a0828b72421a6d8e99efd68d44fa8@example.com/42')
- allow(Gitlab.config.sentry).to receive(:clientside_dsn).and_return('https://b44a0828b72421a6d8e99efd68d44fa8@example.com/43')
-
- expect(setting).not_to receive(:read_attribute)
- expect(setting.sentry_enabled).to eq true
- expect(setting.sentry_dsn).to eq 'https://b44a0828b72421a6d8e99efd68d44fa8@example.com/42'
- expect(setting.clientside_sentry_enabled).to eq true
- expect(setting.clientside_sentry_dsn). to eq 'https://b44a0828b72421a6d8e99efd68d44fa8@example.com/43'
- end
- end
- end
end
diff --git a/spec/support/shared_examples/ci_trace_shared_examples.rb b/spec/support/shared_examples/ci_trace_shared_examples.rb
index 7993b2870e5..ab0550e2613 100644
--- a/spec/support/shared_examples/ci_trace_shared_examples.rb
+++ b/spec/support/shared_examples/ci_trace_shared_examples.rb
@@ -5,7 +5,7 @@ shared_examples_for 'common trace features' do
end
it "returns formatted html" do
- expect(trace.html).to eq("<span class=\"\">12</span><br/><span class=\"\">34</span>")
+ expect(trace.html).to eq("<span class=\"\">12<br/><span class=\"\">34</span></span>")
end
it "returns last line of formatted html" do
@@ -270,7 +270,7 @@ shared_examples_for 'common trace features' do
include ExclusiveLeaseHelpers
before do
- stub_exclusive_lease_taken("trace:write:lock:#{trace.job.id}", timeout: 1.minute)
+ stub_exclusive_lease_taken("trace:write:lock:#{trace.job.id}", timeout: 10.minutes)
end
it 'blocks concurrent archiving' do
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/graphql/mutation_shared_examples.rb b/spec/support/shared_examples/graphql/mutation_shared_examples.rb
new file mode 100644
index 00000000000..022d41c0bdd
--- /dev/null
+++ b/spec/support/shared_examples/graphql/mutation_shared_examples.rb
@@ -0,0 +1,34 @@
+# frozen_string_literal: true
+
+# Shared example for expecting top-level errors.
+# See https://graphql-ruby.org/mutations/mutation_errors#raising-errors
+#
+# { errors: [] }
+#
+# There must be a method or let called `mutation` defined that executes
+# the mutation.
+RSpec.shared_examples 'a mutation that returns top-level errors' do |errors:|
+ it do
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ error_messages = graphql_errors.map { |e| e['message'] }
+
+ expect(error_messages).to eq(errors)
+ end
+end
+
+# Shared example for expecting schema-level errors.
+# See https://graphql-ruby.org/mutations/mutation_errors#errors-as-data
+#
+# { data: { mutationName: { errors: [] } } }
+#
+# There must be:
+# - a method or let called `mutation` defined that executes the mutation
+# - a `mutation_response` method defined that returns the data of the mutation response.
+RSpec.shared_examples 'a mutation that returns errors in the response' do |errors:|
+ it do
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ expect(mutation_response['errors']).to eq(errors)
+ end
+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/shared_examples/services/boards/issues_move_service.rb b/spec/support/shared_examples/services/boards/issues_move_service.rb
index 9dbd1d8e867..5359831f8f8 100644
--- a/spec/support/shared_examples/services/boards/issues_move_service.rb
+++ b/spec/support/shared_examples/services/boards/issues_move_service.rb
@@ -1,8 +1,17 @@
shared_examples 'issues move service' do |group|
+ shared_examples 'updating timestamps' do
+ it 'updates updated_at' do
+ expect {described_class.new(parent, user, params).execute(issue)}
+ .to change {issue.reload.updated_at}
+ end
+ end
+
context 'when moving an issue between lists' do
let(:issue) { create(:labeled_issue, project: project, labels: [bug, development]) }
let(:params) { { board_id: board1.id, from_list_id: list1.id, to_list_id: list2.id } }
+ it_behaves_like 'updating timestamps'
+
it 'delegates the label changes to Issues::UpdateService' do
service = double(:service)
expect(Issues::UpdateService).to receive(:new).and_return(service)
@@ -24,6 +33,8 @@ shared_examples 'issues move service' do |group|
let(:issue) { create(:labeled_issue, project: project, labels: [bug, development, testing, regression]) }
let(:params) { { board_id: board1.id, from_list_id: list2.id, to_list_id: closed.id } }
+ it_behaves_like 'updating timestamps'
+
it 'delegates the close proceedings to Issues::CloseService' do
expect_any_instance_of(Issues::CloseService).to receive(:execute).with(issue).once
@@ -46,6 +57,8 @@ shared_examples 'issues move service' do |group|
let(:issue) { create(:labeled_issue, project: project, labels: [bug, development, testing, regression], milestone: milestone) }
let(:params) { { board_id: board1.id, from_list_id: list2.id, to_list_id: backlog.id } }
+ it_behaves_like 'updating timestamps'
+
it 'keeps labels and milestone' do
described_class.new(parent, user, params).execute(issue)
issue.reload
@@ -59,6 +72,8 @@ shared_examples 'issues move service' do |group|
let(:issue) { create(:labeled_issue, :closed, project: project, labels: [bug]) }
let(:params) { { board_id: board1.id, from_list_id: closed.id, to_list_id: list2.id } }
+ it_behaves_like 'updating timestamps'
+
it 'delegates the re-open proceedings to Issues::ReopenService' do
expect_any_instance_of(Issues::ReopenService).to receive(:execute).with(issue).once
@@ -75,10 +90,13 @@ shared_examples 'issues move service' do |group|
end
context 'when moving to same list' do
- let(:issue) { create(:labeled_issue, project: project, labels: [bug, development]) }
- let(:issue1) { create(:labeled_issue, project: project, labels: [bug, development]) }
- let(:issue2) { create(:labeled_issue, project: project, labels: [bug, development]) }
- let(:params) { { board_id: board1.id, from_list_id: list1.id, to_list_id: list1.id } }
+ let(:assignee) { create(:user) }
+ let(:params) { { board_id: board1.id, from_list_id: list1.id, to_list_id: list1.id } }
+ let(:issue1) { create(:labeled_issue, project: project, labels: [bug, development]) }
+ let(:issue2) { create(:labeled_issue, project: project, labels: [bug, development]) }
+ let(:issue) do
+ create(:labeled_issue, project: project, labels: [bug, development], assignees: [assignee])
+ end
it 'returns false' do
expect(described_class.new(parent, user, params).execute(issue)).to eq false
@@ -90,18 +108,36 @@ shared_examples 'issues move service' do |group|
expect(issue.reload.labels).to contain_exactly(bug, development)
end
- it 'sorts issues' do
- [issue, issue1, issue2].each do |issue|
- issue.move_to_end && issue.save!
- end
+ it 'keeps issues assignees' do
+ described_class.new(parent, user, params).execute(issue)
+
+ expect(issue.reload.assignees).to contain_exactly(assignee)
+ end
- params.merge!(move_after_id: issue1.id, move_before_id: issue2.id)
+ it 'sorts issues' do
+ reorder_issues(params, issues: [issue, issue1, issue2])
described_class.new(parent, user, params).execute(issue)
expect(issue.relative_position).to be_between(issue1.relative_position, issue2.relative_position)
end
+ it 'does not update updated_at' do
+ reorder_issues(params, issues: [issue, issue1, issue2])
+
+ updated_at = issue.updated_at
+ updated_at1 = issue1.updated_at
+ updated_at2 = issue2.updated_at
+
+ Timecop.travel(1.minute.from_now) do
+ described_class.new(parent, user, params).execute(issue)
+ end
+
+ expect(issue.reload.updated_at.change(usec: 0)).to eq updated_at.change(usec: 0)
+ expect(issue1.reload.updated_at.change(usec: 0)).to eq updated_at1.change(usec: 0)
+ expect(issue2.reload.updated_at.change(usec: 0)).to eq updated_at2.change(usec: 0)
+ end
+
if group
context 'when on a group board' do
it 'sends the board_group_id parameter' do
@@ -114,5 +150,13 @@ shared_examples 'issues move service' do |group|
end
end
end
+
+ def reorder_issues(params, issues: [])
+ issues.each do |issue|
+ issue.move_to_end && issue.save!
+ end
+
+ params.merge!(move_after_id: issues[1].id, move_before_id: issues[2].id)
+ end
end
end
diff --git a/spec/support/sidekiq.rb b/spec/support/sidekiq.rb
index 6c4e11910d3..d1a765f27b9 100644
--- a/spec/support/sidekiq.rb
+++ b/spec/support/sidekiq.rb
@@ -30,6 +30,8 @@ RSpec.configure do |config|
end
config.after(:each, :sidekiq, :redis) do
- Sidekiq.redis { |redis| redis.flushdb }
+ Sidekiq.redis do |connection|
+ connection.redis.flushdb
+ end
end
end
diff --git a/spec/tasks/gitlab/cleanup_rake_spec.rb b/spec/tasks/gitlab/cleanup_rake_spec.rb
index 19794227d9f..92c094f08a4 100644
--- a/spec/tasks/gitlab/cleanup_rake_spec.rb
+++ b/spec/tasks/gitlab/cleanup_rake_spec.rb
@@ -156,4 +156,33 @@ describe 'gitlab:cleanup rake tasks' do
end
end
end
+
+ describe 'gitlab:cleanup:orphan_job_artifact_files' do
+ subject(:rake_task) { run_rake_task('gitlab:cleanup:orphan_job_artifact_files') }
+
+ it 'runs the task without errors' do
+ expect(Gitlab::Cleanup::OrphanJobArtifactFiles)
+ .to receive(:new).and_call_original
+
+ expect { rake_task }.not_to raise_error
+ end
+
+ context 'with DRY_RUN set to false' do
+ before do
+ stub_env('DRY_RUN', 'false')
+ end
+
+ it 'passes dry_run correctly' do
+ expect(Gitlab::Cleanup::OrphanJobArtifactFiles)
+ .to receive(:new)
+ .with(limit: anything,
+ dry_run: false,
+ niceness: anything,
+ logger: anything)
+ .and_call_original
+
+ rake_task
+ end
+ end
+ end
end
diff --git a/spec/tasks/migrate/schema_check_rake_spec.rb b/spec/tasks/migrate/schema_check_rake_spec.rb
new file mode 100644
index 00000000000..1097a43cd8a
--- /dev/null
+++ b/spec/tasks/migrate/schema_check_rake_spec.rb
@@ -0,0 +1,48 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require 'rake'
+
+describe 'schema_version_check rake task' do
+ include StubENV
+
+ before :all do
+ Rake.application.rake_require 'active_record/railties/databases'
+ Rake.application.rake_require 'tasks/migrate/schema_check'
+
+ # empty task as env is already loaded
+ Rake::Task.define_task :environment
+ end
+
+ before do
+ allow(ActiveRecord::Migrator).to receive(:current_version).and_return(Gitlab::Database::MIN_SCHEMA_VERSION)
+
+ # Ensure our check can re-run each time
+ Rake::Task[:schema_version_check].reenable
+ end
+
+ it 'allows migrations on databases meeting the min schema version requirement' do
+ 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('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('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('schema_version_check') }.not_to raise_error
+ end
+
+ def run_rake_task(task_name)
+ Rake::Task[task_name].reenable
+ Rake.application.invoke_task task_name
+ end
+end
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/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/views/layouts/nav/sidebar/_project.html.haml_spec.rb b/spec/views/layouts/nav/sidebar/_project.html.haml_spec.rb
index c6c10001bc5..2befbcb3370 100644
--- a/spec/views/layouts/nav/sidebar/_project.html.haml_spec.rb
+++ b/spec/views/layouts/nav/sidebar/_project.html.haml_spec.rb
@@ -17,7 +17,7 @@ describe 'layouts/nav/sidebar/_project' do
it 'has board tab' do
render
- expect(rendered).to have_css('a[title="Board"]')
+ expect(rendered).to have_css('a[title="Boards"]')
end
end
diff --git a/spec/views/projects/services/_form.haml_spec.rb b/spec/views/projects/services/_form.haml_spec.rb
index 85167bca115..06e159f103b 100644
--- a/spec/views/projects/services/_form.haml_spec.rb
+++ b/spec/views/projects/services/_form.haml_spec.rb
@@ -28,7 +28,7 @@ describe 'projects/services/_form' do
expect(rendered).to have_content('Event will be triggered when a merge request is created/updated/merged')
end
- context 'when service is JIRA' do
+ context 'when service is Jira' do
let(:project) { create(:jira_project) }
before do
@@ -38,8 +38,8 @@ describe 'projects/services/_form' do
it 'display merge_request_events and commit_events descriptions' do
render
- expect(rendered).to have_content('JIRA comments will be created when an issue gets referenced in a commit.')
- expect(rendered).to have_content('JIRA comments will be created when an issue gets referenced in a merge request.')
+ expect(rendered).to have_content('Jira comments will be created when an issue gets referenced in a commit.')
+ expect(rendered).to have_content('Jira comments will be created when an issue gets referenced in a merge request.')
end
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..7432ca12f2a
--- /dev/null
+++ b/spec/workers/namespaces/schedule_aggregation_worker_spec.rb
@@ -0,0 +1,66 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Namespaces::ScheduleAggregationWorker, '#perform' 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
+ 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 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
+
+ context 'when aggregation schedule does not exist' do
+ it 'creates one' do
+ allow_any_instance_of(Namespace::AggregationSchedule)
+ .to receive(:schedule_root_storage_statistics).and_return(nil)
+
+ expect do
+ worker.perform(group.id)
+ end.to change(Namespace::AggregationSchedule, :count).by(1)
+
+ expect(group.aggregation_schedule).to be_present
+ 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
+ allow_any_instance_of(Namespace::AggregationSchedule)
+ .to receive(:schedule_root_storage_statistics).and_return(nil)
+
+ 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
+end
diff --git a/spec/workers/pages_domain_ssl_renewal_cron_worker_spec.rb b/spec/workers/pages_domain_ssl_renewal_cron_worker_spec.rb
new file mode 100644
index 00000000000..08a3511f70b
--- /dev/null
+++ b/spec/workers/pages_domain_ssl_renewal_cron_worker_spec.rb
@@ -0,0 +1,62 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe PagesDomainSslRenewalCronWorker do
+ include LetsEncryptHelpers
+
+ subject(:worker) { described_class.new }
+
+ before do
+ stub_lets_encrypt_settings
+ end
+
+ describe '#perform' do
+ let(:project) { create :project }
+ let!(:domain) { create(:pages_domain, project: project) }
+ let!(:domain_with_enabled_auto_ssl) { create(:pages_domain, project: project, auto_ssl_enabled: true) }
+ let!(:domain_with_obtained_letsencrypt) do
+ create(:pages_domain, :letsencrypt, project: project, auto_ssl_enabled: true)
+ end
+ let!(:domain_without_auto_certificate) do
+ create(:pages_domain, :without_certificate, :without_key, project: project, auto_ssl_enabled: true)
+ end
+
+ let!(:domain_with_expired_auto_ssl) do
+ create(:pages_domain, :letsencrypt, :with_expired_certificate, project: project)
+ end
+
+ it 'enqueues a PagesDomainSslRenewalWorker for domains needing renewal' do
+ [domain_without_auto_certificate,
+ domain_with_enabled_auto_ssl,
+ domain_with_expired_auto_ssl].each do |domain|
+ expect(PagesDomainSslRenewalWorker).to receive(:perform_async).with(domain.id)
+ end
+
+ [domain,
+ domain_with_obtained_letsencrypt].each do |domain|
+ expect(PagesDomainVerificationWorker).not_to receive(:perform_async).with(domain.id)
+ end
+
+ worker.perform
+ end
+
+ shared_examples 'does nothing' do
+ it 'does nothing' do
+ expect(PagesDomainSslRenewalWorker).not_to receive(:perform_async)
+
+ worker.perform
+ end
+ end
+
+ context 'when letsencrypt integration is disabled' do
+ before do
+ stub_application_setting(
+ lets_encrypt_terms_of_service_accepted: false
+ )
+ end
+
+ include_examples 'does nothing'
+ end
+ end
+end
diff --git a/spec/workers/pages_domain_ssl_renewal_worker_spec.rb b/spec/workers/pages_domain_ssl_renewal_worker_spec.rb
new file mode 100644
index 00000000000..3552ff0823a
--- /dev/null
+++ b/spec/workers/pages_domain_ssl_renewal_worker_spec.rb
@@ -0,0 +1,46 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe PagesDomainSslRenewalWorker do
+ include LetsEncryptHelpers
+
+ subject(:worker) { described_class.new }
+
+ let(:project) { create(:project) }
+ let(:domain) { create(:pages_domain, project: project) }
+
+ before do
+ stub_lets_encrypt_settings
+ end
+
+ describe '#perform' do
+ it 'delegates to ObtainLetsEncryptCertificateService' do
+ service = double(:service)
+ expect(::PagesDomains::ObtainLetsEncryptCertificateService).to receive(:new).with(domain).and_return(service)
+ expect(service).to receive(:execute)
+
+ worker.perform(domain.id)
+ end
+
+ shared_examples 'does nothing' do
+ it 'does nothing' do
+ expect(::PagesDomains::ObtainLetsEncryptCertificateService).not_to receive(:new)
+ end
+ end
+
+ context 'when domain was deleted' do
+ before do
+ domain.destroy!
+ end
+
+ include_examples 'does nothing'
+ end
+
+ context 'when domain is disabled' do
+ let(:domain) { create(:pages_domain, :disabled) }
+
+ include_examples 'does nothing'
+ end
+ end
+end
diff --git a/spec/workers/reactive_caching_worker_spec.rb b/spec/workers/reactive_caching_worker_spec.rb
index b8ca6063ccd..ca0e76fc19a 100644
--- a/spec/workers/reactive_caching_worker_spec.rb
+++ b/spec/workers/reactive_caching_worker_spec.rb
@@ -3,17 +3,16 @@
require 'spec_helper'
describe ReactiveCachingWorker do
- let(:service) { project.deployment_platform }
-
describe '#perform' do
context 'when user configured kubernetes from CI/CD > Clusters' do
let!(:cluster) { create(:cluster, :project, :provided_by_gcp) }
let(:project) { cluster.project }
+ let!(:environment) { create(:environment, project: project) }
it 'calls #exclusively_update_reactive_cache!' do
- expect_any_instance_of(Clusters::Platforms::Kubernetes).to receive(:exclusively_update_reactive_cache!)
+ expect_any_instance_of(Environment).to receive(:exclusively_update_reactive_cache!)
- described_class.new.perform("Clusters::Platforms::Kubernetes", service.id)
+ described_class.new.perform("Environment", environment.id)
end
end
end
diff --git a/app/graphql/mutations/.keep b/tmp/prometheus_multiproc_dir/puma/.gitkeep
index e69de29bb2d..e69de29bb2d 100644
--- a/app/graphql/mutations/.keep
+++ 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/vendor/jupyter/values.yaml b/vendor/jupyter/values.yaml
index 0fbf36b39cc..2aadd3dbe1e 100644
--- a/vendor/jupyter/values.yaml
+++ b/vendor/jupyter/values.yaml
@@ -46,7 +46,7 @@ singleuser:
- "-c"
- >
git clone https://gitlab.com/gitlab-org/nurtch-demo.git DevOps-Runbook-Demo || true;
- echo "https://${GITLAB_USER_LOGIN}:${GITLAB_ACCESS_TOKEN}@${GITLAB_HOST}" > ~/.git-credentials;
+ echo "https://oauth2:${GITLAB_ACCESS_TOKEN}@${GITLAB_HOST}" > ~/.git-credentials;
git config --global credential.helper store;
git config --global user.email "${GITLAB_USER_EMAIL}";
git config --global user.name "${GITLAB_USER_NAME}";
diff --git a/yarn.lock b/yarn.lock
index 7bbb8ef0f87..1e04c82df1c 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -700,21 +700,22 @@
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.66.0":
+ version "1.66.0"
+ resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-1.66.0.tgz#3c02da455421ea241f32e915671842435df027ff"
+ integrity sha512-nxOoQPnofMs3BjRr3SVzQcclM0G6QFrLM8L4nnUCN+8Gxq2u8ukfSU5FCrkivXz+FP9Qo/FYilWV7CY8kDkt6A==
-"@gitlab/ui@^4.3.0":
- version "4.3.0"
- resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-4.3.0.tgz#7d6e626e7143febef642a0418ceae1923dfa8f15"
- integrity sha512-+r19vg9KkFhYO1mlC1Lz98ZnXEifJSumfIUvaRFPgw+LtU2SyOsxXp9fleaJVXXBgpQDiNnpe1FyRL0kWVcn3g==
+"@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==
dependencies:
"@babel/standalone" "^7.0.0"
"@gitlab/vue-toasted" "^1.2.1"
bootstrap "4.3.1"
- bootstrap-vue "^2.0.0-rc.11"
+ bootstrap-vue "^2.0.0-rc.24"
copy-to-clipboard "^3.0.8"
+ core-js "^2.6.9"
echarts "^4.2.0-rc.2"
highlight.js "^9.13.1"
js-beautify "^1.8.8"
@@ -887,6 +888,15 @@
resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz#2b5a3ab3f918cca48a8c754c08168e3f03eba61b"
integrity sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==
+"@nuxt/opencollective@^0.2.2":
+ version "0.2.2"
+ resolved "https://registry.yarnpkg.com/@nuxt/opencollective/-/opencollective-0.2.2.tgz#17adc7d380457379cd14cbb64a435ea196cc4a6e"
+ integrity sha512-ie50SpS47L+0gLsW4yP23zI/PtjsDRglyozX2G09jeiUazC1AJlGPZo0JUs9iuCDUoIgsDEf66y7/bSfig0BpA==
+ dependencies:
+ chalk "^2.4.1"
+ consola "^2.3.0"
+ node-fetch "^2.3.0"
+
"@sindresorhus/is@^0.7.0":
version "0.7.0"
resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.7.0.tgz#9a06f4f137ee84d7df0460c1fdb1135ffa6c50fd"
@@ -1234,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=
@@ -1322,11 +1332,6 @@ ansi-colors@^3.0.0:
resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.0.5.tgz#cb9dc64993b64fd6945485f797fc3853137d9a7b"
integrity sha512-VVjWpkfaphxUBFarydrQ3n26zX5nIK7hcbT3/ielrvwDDyBBjuh2vuSw1P9zkPq0cfqvdw7lkYHnu+OLSfIBsg==
-ansi-escapes@^1.1.0:
- version "1.4.0"
- resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e"
- integrity sha1-06ioOzGapneTZisT52HHkRQiMG4=
-
ansi-escapes@^3.0.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b"
@@ -1625,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=
@@ -1686,13 +1691,13 @@ axios-mock-adapter@^1.15.0:
dependencies:
deep-equal "^1.0.1"
-axios@^0.17.1:
- version "0.17.1"
- resolved "https://registry.yarnpkg.com/axios/-/axios-0.17.1.tgz#2d8e3e5d0bdbd7327f91bc814f5c57660f81824d"
- integrity sha1-LY4+XQvb1zJ/kbyBT1xXZg+Bgk0=
+axios@^0.19.0:
+ version "0.19.0"
+ resolved "https://registry.yarnpkg.com/axios/-/axios-0.19.0.tgz#8e09bff3d9122e133f7b8101c8fbdd00ed3d2ab8"
+ integrity sha512-1uvKqKQta3KBxIz14F2v06AEHZ/dIoeKfbTRkK1E5oqjDnuEerLmYTgJB5AiQZHJcljpg1TuRzdjDR06qNk0DQ==
dependencies:
- follow-redirects "^1.2.5"
- is-buffer "^1.1.5"
+ follow-redirects "1.5.10"
+ is-buffer "^2.0.2"
babel-code-frame@^6.26.0:
version "6.26.0"
@@ -1766,15 +1771,6 @@ babel-plugin-rewire@^1.2.0:
resolved "https://registry.yarnpkg.com/babel-plugin-rewire/-/babel-plugin-rewire-1.2.0.tgz#822562d72ed2c84e47c0f95ee232c920853e9d89"
integrity sha512-JBZxczHw3tScS+djy6JPLMjblchGhLI89ep15H3SyjujIzlxo5nr6Yjo7AXotdeVczeBmWs0tF8PgJWDdgzAkQ==
-babel-polyfill@6.23.0:
- version "6.23.0"
- resolved "https://registry.yarnpkg.com/babel-polyfill/-/babel-polyfill-6.23.0.tgz#8364ca62df8eafb830499f699177466c3b03499d"
- integrity sha1-g2TKYt+Or7gwSZ9pkXdGbDsDSZ0=
- dependencies:
- babel-runtime "^6.22.0"
- core-js "^2.4.0"
- regenerator-runtime "^0.10.0"
-
babel-preset-jest@^24.6.0:
version "24.6.0"
resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-24.6.0.tgz#66f06136eefce87797539c0d63f1769cc3915984"
@@ -1783,14 +1779,6 @@ babel-preset-jest@^24.6.0:
"@babel/plugin-syntax-object-rest-spread" "^7.0.0"
babel-plugin-jest-hoist "^24.6.0"
-babel-runtime@^6.22.0:
- version "6.26.0"
- resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe"
- integrity sha1-llxwWGaOgrVde/4E/yM3vItWR/4=
- dependencies:
- core-js "^2.4.0"
- regenerator-runtime "^0.11.0"
-
babylon@7.0.0-beta.19:
version "7.0.0-beta.19"
resolved "https://registry.yarnpkg.com/babylon/-/babylon-7.0.0-beta.19.tgz#e928c7e807e970e0536b078ab3e0c48f9e052503"
@@ -1933,19 +1921,19 @@ bonjour@^3.5.0:
multicast-dns "^6.0.1"
multicast-dns-service-types "^1.1.0"
-bootstrap-vue@^2.0.0-rc.11:
- version "2.0.0-rc.11"
- resolved "https://registry.yarnpkg.com/bootstrap-vue/-/bootstrap-vue-2.0.0-rc.11.tgz#47aaa6d2a8d390477de75e636d8ea652b1d03f59"
- integrity sha512-LxR+oL8yKr1DVoWUWTX+XhiT0xaTMH6142u2VSFDm4tewTH8HIrzN2YIl7HLZrw2DIuE9bRMIdWJqqn3aQe7Hw==
+bootstrap-vue@^2.0.0-rc.24:
+ version "2.0.0-rc.24"
+ resolved "https://registry.yarnpkg.com/bootstrap-vue/-/bootstrap-vue-2.0.0-rc.24.tgz#8ea5bbcd19e0f9b4f87ed4d9ba72abaa35231f32"
+ integrity sha512-8rA/I9tOvpNVIuMKD3rdlrUqgVdPEw4vPI0X8OeFJcG2hHvCHeZDF7FmWqxSeehIrUHGDV17HlTGSuP/v1Sp5g==
dependencies:
- bootstrap "^4.1.1"
- lodash.get "^4.4.2"
- lodash.startcase "^4.4.0"
- opencollective "^1.0.3"
- popper.js "^1.12.9"
- vue-functional-data-merge "^2.0.5"
+ "@nuxt/opencollective" "^0.2.2"
+ bootstrap "^4.3.1"
+ core-js ">=2.6.5 <3.0.0"
+ popper.js "^1.15.0"
+ portal-vue "^2.1.5"
+ vue-functional-data-merge "^3.1.0"
-bootstrap@4.3.1, bootstrap@^4.1.1, bootstrap@^4.1.3:
+bootstrap@4.3.1, bootstrap@^4.1.3, bootstrap@^4.3.1:
version "4.3.1"
resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-4.3.1.tgz#280ca8f610504d99d7b6b4bfc4b68cec601704ac"
integrity sha512-rXqOmH1VilAt2DyPzluTi2blhk17bO7ef+zLLPlWvG494pDxcM234pJ8wTc/6R40UWizAIIMgxjvxZg5kmsbag==
@@ -2231,6 +2219,14 @@ callsites@^3.0.0:
resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.0.0.tgz#fb7eb569b72ad7a45812f93fd9430a3e410b3dd3"
integrity sha512-tWnkwu9YEq2uzlBDI4RcLn8jrFvF9AOi8PxDNU3hZZjJcjkcRAq3vCI+vZcg1SuxISDYe86k9VZFwAxDiJGoAw==
+camel-case@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-3.0.0.tgz#ca3c3688a4e9cf3a4cda777dc4dcbc713249cf73"
+ integrity sha1-yjw2iKTpzzpM2nd9xNy8cTJJz3M=
+ dependencies:
+ no-case "^2.2.0"
+ upper-case "^1.1.1"
+
camelcase-keys@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-2.1.0.tgz#308beeaffdf28119051efa1d932213c91b8f92e7"
@@ -2302,7 +2298,7 @@ ccount@^1.0.0:
resolved "https://registry.yarnpkg.com/ccount/-/ccount-1.0.3.tgz#f1cec43f332e2ea5a569fd46f9f5bde4e6102aff"
integrity sha512-Jt9tIBkRc9POUof7QA/VwWd+58fKkEEfI+/t1/eOlxKM7ZhrczNzMFefge7Ai+39y1pR/pP6cI19guHy3FSLmw==
-chalk@1.1.3, chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3:
+chalk@^1.1.1, chalk@^1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98"
integrity sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=
@@ -2342,11 +2338,6 @@ character-reference-invalid@^1.0.0:
resolved "https://registry.yarnpkg.com/character-reference-invalid/-/character-reference-invalid-1.1.2.tgz#21e421ad3d84055952dab4a43a04e73cd425d3ed"
integrity sha512-7I/xceXfKyUJmSAn/jw8ve/9DyOP7XxufNYLI9Px7CmsKgEUaZLUTax6nZxGQtaoiZCjpu6cHPj20xC/vqRReQ==
-chardet@^0.4.0:
- version "0.4.2"
- resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.4.2.tgz#b5473b33dc97c424e5d98dc87d55d4d8a29c8bf2"
- integrity sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=
-
chardet@^0.5.0:
version "0.5.0"
resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.5.0.tgz#fe3ac73c00c3d865ffcc02a0682e2c20b6a06029"
@@ -2460,6 +2451,13 @@ classlist-polyfill@^1.2.0:
resolved "https://registry.yarnpkg.com/classlist-polyfill/-/classlist-polyfill-1.2.0.tgz#935bc2dfd9458a876b279617514638bcaa964a2e"
integrity sha1-k1vC39lFiodrJ5YXUUY4vKqWSi4=
+clean-css@^4.1.6, clean-css@^4.2.1:
+ version "4.2.1"
+ resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-4.2.1.tgz#2d411ef76b8569b6d0c84068dabe85b0aa5e5c17"
+ integrity sha512-4ZxI6dy4lrY6FHzfiy1aEOXgu4LIsW2MhwG0VBKdcoGoH/XLFgaHSdLTGr4O8Be6A8r3MOphEiI8Gc1n0ecf3g==
+ dependencies:
+ source-map "~0.6.0"
+
cli-boxes@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-1.0.0.tgz#4fa917c3e59c94a004cd61f8ee509da651687143"
@@ -2724,6 +2722,11 @@ connect@^3.6.0:
parseurl "~1.3.2"
utils-merge "1.0.1"
+consola@^2.3.0:
+ version "2.9.0"
+ resolved "https://registry.yarnpkg.com/consola/-/consola-2.9.0.tgz#57760e3a65a53ec27337f4add31505802d902278"
+ integrity sha512-34Iue+LRcWbndFIfZc5boNizWlsrRjqIBJZTe591vImgbnq7nx2EzlrLtANj9TH2Fxm7puFJBJAOk5BhvZOddQ==
+
console-browserify@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.1.0.tgz#f0241c45730a9fc6323b206dbf38edc741d0bb10"
@@ -2824,10 +2827,10 @@ core-js@3.0.1:
resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.0.1.tgz#1343182634298f7f38622f95e73f54e48ddf4738"
integrity sha512-sco40rF+2KlE0ROMvydjkrVMMG1vYilP2ALoRXcYR4obqbYIuV3Bg+51GEDW+HF8n7NRA+iaA4qD0nD9lo9mew==
-core-js@^2.2.0, core-js@^2.4.0:
- version "2.5.7"
- resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.7.tgz#f972608ff0cead68b841a16a932d0b183791814e"
- integrity sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw==
+"core-js@>=2.6.5 <3.0.0", core-js@^2.2.0, core-js@^2.6.9:
+ version "2.6.9"
+ resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.9.tgz#6b4b214620c834152e179323727fc19741b084f2"
+ integrity sha512-HOpZf6eXmnl7la+cUdMnLvUxKNqLUzJvgIziQ0DiF3JwSImNphIqdGqzj6hIKyX04MmV0poclQ7+wjWvxQyR2A==
core-js@^3.1.3:
version "3.1.3"
@@ -2953,6 +2956,11 @@ crypto-random-string@^1.0.0:
resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e"
integrity sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4=
+css-b64-images@~0.2.5:
+ version "0.2.5"
+ resolved "https://registry.yarnpkg.com/css-b64-images/-/css-b64-images-0.2.5.tgz#42005d83204b2b4a5d93b6b1a5644133b5927a02"
+ integrity sha1-QgBdgyBLK0pdk7axpWRBM7WSegI=
+
css-loader@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-1.0.1.tgz#6885bb5233b35ec47b006057da01cc640b6b79fe"
@@ -3410,6 +3418,13 @@ debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.8, debug@^2.6.9:
dependencies:
ms "2.0.0"
+debug@=3.1.0, debug@~3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261"
+ integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==
+ dependencies:
+ ms "2.0.0"
+
debug@^3.1.0, debug@^3.2.5, debug@^3.2.6:
version "3.2.6"
resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b"
@@ -3424,13 +3439,6 @@ debug@^4.0.0, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1:
dependencies:
ms "^2.1.1"
-debug@~3.1.0:
- version "3.1.0"
- resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261"
- integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==
- dependencies:
- ms "2.0.0"
-
decamelize-keys@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/decamelize-keys/-/decamelize-keys-1.1.0.tgz#d171a87933252807eb3cb61dc1c1445d078df2d9"
@@ -3855,13 +3863,6 @@ encodeurl@~1.0.1, encodeurl@~1.0.2:
resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59"
integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=
-encoding@^0.1.11:
- version "0.1.12"
- resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb"
- integrity sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=
- dependencies:
- iconv-lite "~0.4.13"
-
end-of-stream@^1.0.0, end-of-stream@^1.1.0:
version "1.4.1"
resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.1.tgz#ed29634d19baba463b6ce6b80a37213eab71ec43"
@@ -3992,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"
@@ -4212,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"
@@ -4241,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"
@@ -4460,15 +4439,6 @@ extend@^3.0.0, extend@~3.0.2:
resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==
-external-editor@^2.0.1:
- version "2.2.0"
- resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-2.2.0.tgz#045511cfd8d133f3846673d1047c154e214ad3d5"
- integrity sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==
- dependencies:
- chardet "^0.4.0"
- iconv-lite "^0.4.17"
- tmp "^0.0.33"
-
external-editor@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.0.0.tgz#dc35c48c6f98a30ca27a20e9687d7f3c77704bb6"
@@ -4731,12 +4701,12 @@ flush-write-stream@^1.0.0:
inherits "^2.0.1"
readable-stream "^2.0.4"
-follow-redirects@^1.2.5:
- version "1.2.6"
- resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.2.6.tgz#4dcdc7e4ab3dd6765a97ff89c3b4c258117c79bf"
- integrity sha512-FrMqZ/FONtHnbqO651UPpfRUVukIEwJhXMfdr/JWAmrDbeYBu773b1J6gdWDyRIj4hvvzQEHoEOTrdR8o6KLYA==
+follow-redirects@1.5.10:
+ version "1.5.10"
+ resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.5.10.tgz#7b7a9f9aea2fdff36786a94ff643ed07f4ff5e2a"
+ integrity sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==
dependencies:
- debug "^3.1.0"
+ debug "=3.1.0"
for-in@^1.0.2:
version "1.0.2"
@@ -4961,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"
@@ -5171,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==
@@ -5214,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"
@@ -5370,6 +5324,19 @@ html-entities@^1.2.0:
resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.2.0.tgz#41948caf85ce82fed36e4e6a0ed371a6664379e2"
integrity sha1-QZSMr4XOgv7Tbk5qDtNxpmZDeeI=
+html-minifier@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/html-minifier/-/html-minifier-4.0.0.tgz#cca9aad8bce1175e02e17a8c33e46d8988889f56"
+ integrity sha512-aoGxanpFPLg7MkIl/DDFYtb0iWz7jMFGqFhvEDZga6/4QTjneiD8I/NXL1x5aaoCp7FSIT6h/OhykDdPsbtMig==
+ dependencies:
+ camel-case "^3.0.0"
+ clean-css "^4.2.1"
+ commander "^2.19.0"
+ he "^1.2.0"
+ param-case "^2.1.1"
+ relateurl "^0.2.7"
+ uglify-js "^3.5.1"
+
html-tags@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/html-tags/-/html-tags-2.0.0.tgz#10b30a386085f43cede353cc8fa7cb0deeea668b"
@@ -5439,7 +5406,7 @@ https-browserify@^1.0.0:
resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73"
integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=
-iconv-lite@0.4, iconv-lite@0.4.24, iconv-lite@^0.4.17, iconv-lite@^0.4.22, iconv-lite@^0.4.4, iconv-lite@~0.4.13:
+iconv-lite@0.4, iconv-lite@0.4.24, iconv-lite@^0.4.22, iconv-lite@^0.4.4:
version "0.4.24"
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==
@@ -5594,25 +5561,6 @@ ini@^1.3.4, ini@^1.3.5, ini@~1.3.0:
resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927"
integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==
-inquirer@3.0.6:
- version "3.0.6"
- resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-3.0.6.tgz#e04aaa9d05b7a3cb9b0f407d04375f0447190347"
- integrity sha1-4EqqnQW3o8ubD0B9BDdfBEcZA0c=
- dependencies:
- ansi-escapes "^1.1.0"
- chalk "^1.0.0"
- cli-cursor "^2.1.0"
- cli-width "^2.0.0"
- external-editor "^2.0.1"
- figures "^2.0.0"
- lodash "^4.3.0"
- mute-stream "0.0.7"
- run-async "^2.2.0"
- rx "^4.1.0"
- string-width "^2.0.0"
- strip-ansi "^3.0.0"
- through "^2.3.6"
-
inquirer@^6.1.0:
version "6.2.0"
resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.2.0.tgz#51adcd776f661369dc1e894859c2560a224abdd8"
@@ -5734,7 +5682,7 @@ is-buffer@^1.1.5, is-buffer@~1.1.1:
resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==
-is-buffer@^2.0.0:
+is-buffer@^2.0.0, is-buffer@^2.0.2:
version "2.0.3"
resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.3.tgz#4ecf3fcf749cbd1e472689e109ac66261a25e725"
integrity sha512-U15Q7MXTuZlrbymiz95PJpZxu8IlipAp4dtS3wOdgPXx3mqBnslrWU14kxfHB+Py/+2PVKSr37dMAgM2A4uArw==
@@ -5963,7 +5911,7 @@ is-retry-allowed@^1.0.0, is-retry-allowed@^1.1.0:
resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz#11a060568b67339444033d0125a61a20d564fb34"
integrity sha1-EaBgVotnM5REAz0BJaYaINVk+zQ=
-is-stream@^1.0.0, is-stream@^1.0.1, is-stream@^1.1.0:
+is-stream@^1.0.0, is-stream@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ=
@@ -6118,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"
@@ -6566,10 +6494,10 @@ jquery.waitforimages@^2.2.0:
resolved "https://registry.yarnpkg.com/jquery.waitforimages/-/jquery.waitforimages-2.2.0.tgz#63f23131055a1b060dc913e6d874bcc9b9e6b16b"
integrity sha1-Y/IxMQVaGwYNyRPm2HS8ybnmsWs=
-"jquery@>= 1.9.1", jquery@>=1.8.0, jquery@^3.2.1:
- version "3.3.1"
- resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.3.1.tgz#958ce29e81c9790f31be7792df5d4d95fc57fbca"
- integrity sha512-Ubldcmxp5np52/ENotGxlLe6aGMvmF4R8S6tZjsP6Knsaxd/xp3Zrh50cG93lR6nPXyUFwzN3ZSOQI0wRJNdGg==
+"jquery@>= 1.9.1", jquery@>=1.8.0, jquery@^3.4.1:
+ version "3.4.1"
+ resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.4.1.tgz#714f1f8d9dde4bdfa55764ba37ef214630d80ef2"
+ integrity sha512-36+AdBzCL+y6qjw5Tx7HgzeGCzC81MDDgaUP8ld2zhx58HdqXGoBd+tHdrBMiyjGQs0Hxs/MLZTu/eHNJJuWPw==
js-base64@^2.1.8:
version "2.5.1"
@@ -6607,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==
@@ -7053,11 +6981,6 @@ lodash.escaperegexp@^4.1.2:
resolved "https://registry.yarnpkg.com/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz#64762c48618082518ac3df4ccf5d5886dae20347"
integrity sha1-ZHYsSGGAglGKw99Mz11YhtriA0c=
-lodash.get@^4.4.2:
- version "4.4.2"
- resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99"
- integrity sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=
-
lodash.isequal@^4.5.0:
version "4.5.0"
resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0"
@@ -7083,17 +7006,12 @@ lodash.sortby@^4.7.0:
resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438"
integrity sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=
-lodash.startcase@^4.4.0:
- version "4.4.0"
- resolved "https://registry.yarnpkg.com/lodash.startcase/-/lodash.startcase-4.4.0.tgz#9436e34ed26093ed7ffae1936144350915d9add8"
- integrity sha1-lDbjTtJgk+1/+uGTYUQ1CRXZrdg=
-
lodash.upperfirst@4.3.1:
version "4.3.1"
resolved "https://registry.yarnpkg.com/lodash.upperfirst/-/lodash.upperfirst-4.3.1.tgz#1365edf431480481ef0d1c68957a5ed99d49f7ce"
integrity sha1-E2Xt9DFIBIHvDRxolXpe2Z1J984=
-lodash@^4.0.0, lodash@^4.13.1, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.3.0, lodash@^4.5.0, lodash@~4.17.10:
+lodash@^4.0.0, lodash@^4.13.1, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.5.0, lodash@~4.17.10:
version "4.17.11"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d"
integrity sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==
@@ -7141,6 +7059,11 @@ loud-rejection@^1.0.0:
currently-unhandled "^0.4.1"
signal-exit "^3.0.0"
+lower-case@^1.1.1:
+ version "1.1.4"
+ resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-1.1.4.tgz#9a2cabd1b9e8e0ae993a4bf7d5875c39c42e8eac"
+ integrity sha1-miyr0bno4K6ZOkv31YdcOcQujqw=
+
lowercase-keys@1.0.0, lowercase-keys@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.0.tgz#4e3366b39e7f5457e35f1324bdf6f88d0bfc7306"
@@ -7384,10 +7307,10 @@ merge2@^1.2.3:
resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.2.3.tgz#7ee99dbd69bb6481689253f018488a1b902b0ed5"
integrity sha512-gdUU1Fwj5ep4kplwcmftruWofEFt6lfpkkr3h860CXbAB9c3hGb55EOL2ali0Td5oebvW0E1+3Sr+Ur7XfKpRA==
-mermaid@^8.0.0:
- version "8.0.0"
- resolved "https://registry.yarnpkg.com/mermaid/-/mermaid-8.0.0.tgz#8f6c75017e788a8c3997e20c5e5046c2b88d1a8f"
- integrity sha512-vUQRykev0A6RtxIVqQT3a9TDxcSbdZbQF5JDyKgidnYuJy8BE8jp6LM+HKDSQuroKm6buu4NlpMO+qhxIP/cTg==
+mermaid@^8.1.0:
+ version "8.1.0"
+ resolved "https://registry.yarnpkg.com/mermaid/-/mermaid-8.1.0.tgz#f9f4c02cf98d2d9fae230d5ce28f531e605e9b72"
+ integrity sha512-fsCN8bOukYHZT6FlA0eIeLs/O3H2+CWcHnxRrS86Ci1cpJes5/qvoye0xjhe8lbXJCFLM8sXWVg57aMHPtnAaw==
dependencies:
d3 "^5.7.0"
dagre-d3-renderer "^0.5.8"
@@ -7395,7 +7318,8 @@ mermaid@^8.0.0:
graphlibrary "^2.2.0"
he "^1.2.0"
lodash "^4.17.11"
- moment "^2.23.0"
+ minify "^4.1.1"
+ moment-mini "^2.22.1"
scope-css "^1.2.1"
methods@~1.1.2:
@@ -7467,6 +7391,19 @@ mimic-response@^1.0.0:
resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.0.tgz#df3d3652a73fded6b9b0b24146e6fd052353458e"
integrity sha1-3z02Uqc/3ta5sLJBRub9BSNTRY4=
+minify@^4.1.1:
+ version "4.1.2"
+ resolved "https://registry.yarnpkg.com/minify/-/minify-4.1.2.tgz#88755f4faa5f7ab6d0c64fdd659aa34ea658f180"
+ integrity sha512-YY6b6VzV7AY2MTMt1GjoFqKthGWvAr2L7MrzmFyiEsvPX+XAvidHcKqu36LlDT1V4I80ncbV5bsdTnIJq4/Sdw==
+ dependencies:
+ clean-css "^4.1.6"
+ css-b64-images "~0.2.5"
+ debug "^4.1.0"
+ html-minifier "^4.0.0"
+ terser "^4.0.0"
+ try-catch "^2.0.0"
+ try-to-catch "^1.0.2"
+
minimalistic-assert@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.0.tgz#702be2dda6b37f4836bcb3f5db56641b64a1d3d3"
@@ -7477,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==
@@ -7502,7 +7439,7 @@ minimist@1.1.x:
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.1.3.tgz#3bedfd91a92d39016fcfaa1c681e8faa1a1efda8"
integrity sha1-O+39kaktOQFvz6ocaB6Pqhoe/ag=
-minimist@1.2.0, minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0:
+minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=
@@ -7553,7 +7490,12 @@ mkdirp@0.5.x, mkdirp@0.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp
dependencies:
minimist "0.0.8"
-moment@2.x, moment@^2.10.2, moment@^2.23.0:
+moment-mini@^2.22.1:
+ version "2.22.1"
+ resolved "https://registry.yarnpkg.com/moment-mini/-/moment-mini-2.22.1.tgz#bc32d73e43a4505070be6b53494b17623183420d"
+ integrity sha512-OUCkHOz7ehtNMYuZjNciXUfwTuz8vmF1MTbAy59ebf+ZBYZO5/tZKuChVWCX+uDo+4idJBpGltNfV8st+HwsGw==
+
+moment@2.x, moment@^2.10.2:
version "2.24.0"
resolved "https://registry.yarnpkg.com/moment/-/moment-2.24.0.tgz#0d055d53f5052aa653c9f6eb68bb5d12bf5c2b5b"
integrity sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==
@@ -7666,18 +7608,22 @@ nice-try@^1.0.4:
resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366"
integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==
+no-case@^2.2.0:
+ version "2.3.2"
+ resolved "https://registry.yarnpkg.com/no-case/-/no-case-2.3.2.tgz#60b813396be39b3f1288a4c1ed5d1e7d28b464ac"
+ integrity sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==
+ dependencies:
+ lower-case "^1.1.1"
+
node-ensure@^0.0.0:
version "0.0.0"
resolved "https://registry.yarnpkg.com/node-ensure/-/node-ensure-0.0.0.tgz#ecae764150de99861ec5c810fd5d096b183932a7"
integrity sha1-7K52QVDemYYexcgQ/V0Jaxg5Mqc=
-node-fetch@1.6.3:
- version "1.6.3"
- resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.6.3.tgz#dc234edd6489982d58e8f0db4f695029abcd8c04"
- integrity sha1-3CNO3WSJmC1Y6PDbT2lQKavNjAQ=
- dependencies:
- encoding "^0.1.11"
- is-stream "^1.0.1"
+node-fetch@^2.3.0:
+ version "2.6.0"
+ resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.0.tgz#e633456386d4aa55863f676a7ab0daa8fdecb0fd"
+ integrity sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==
node-forge@0.6.33:
version "0.6.33"
@@ -7814,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=
@@ -8015,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=
@@ -8029,31 +7975,11 @@ onetime@^2.0.0:
dependencies:
mimic-fn "^1.0.0"
-opencollective@^1.0.3:
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/opencollective/-/opencollective-1.0.3.tgz#aee6372bc28144583690c3ca8daecfc120dd0ef1"
- integrity sha1-ruY3K8KBRFg2kMPKja7PwSDdDvE=
- dependencies:
- babel-polyfill "6.23.0"
- chalk "1.1.3"
- inquirer "3.0.6"
- minimist "1.2.0"
- node-fetch "1.6.3"
- opn "4.0.2"
-
opener@^1.5.1:
version "1.5.1"
resolved "https://registry.yarnpkg.com/opener/-/opener-1.5.1.tgz#6d2f0e77f1a0af0032aca716c2c1fbb8e7e8abed"
integrity sha512-goYSy5c2UXE4Ra1xixabeVh1guIX/ZV/YokJksb6q2lubWu6UbvPQ20p542/sFIll1nl8JnCyK9oBaOcCWXwvA==
-opn@4.0.2:
- version "4.0.2"
- resolved "https://registry.yarnpkg.com/opn/-/opn-4.0.2.tgz#7abc22e644dff63b0a96d5ab7f2790c0f01abc95"
- integrity sha1-erwi5kTf9jsKltWrfyeQwPAavJU=
- dependencies:
- object-assign "^4.0.1"
- pinkie-promise "^2.0.0"
-
opn@^5.1.0:
version "5.2.0"
resolved "https://registry.yarnpkg.com/opn/-/opn-5.2.0.tgz#71fdf934d6827d676cecbea1531f95d354641225"
@@ -8259,6 +8185,13 @@ parallel-transform@^1.1.0:
inherits "^2.0.3"
readable-stream "^2.1.5"
+param-case@^2.1.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/param-case/-/param-case-2.1.1.tgz#df94fd8cf6531ecf75e6bef9a0858fbc72be2247"
+ integrity sha1-35T9jPZTHs915r75oIWPvHK+Ikc=
+ dependencies:
+ no-case "^2.2.0"
+
parse-asn1@^5.0.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.0.tgz#37c4f9b7ed3ab65c74817b5f2480937fbf97c712"
@@ -8512,10 +8445,15 @@ pofile@^1:
resolved "https://registry.yarnpkg.com/pofile/-/pofile-1.0.11.tgz#35aff58c17491d127a07336d5522ebc9df57c954"
integrity sha512-Vy9eH1dRD9wHjYt/QqXcTz+RnX/zg53xK+KljFSX30PvdDMb2z+c6uDUeblUGqqJgz3QFsdlA0IJvHziPmWtQg==
-popper.js@^1.12.9, popper.js@^1.14.7:
- version "1.14.7"
- resolved "https://registry.yarnpkg.com/popper.js/-/popper.js-1.14.7.tgz#e31ec06cfac6a97a53280c3e55e4e0c860e7738e"
- integrity sha512-4q1hNvoUre/8srWsH7hnoSJ5xVmIL4qgz+s4qf2TnJIMyZFUFMGH+9vE7mXynAlHSZ/NdTmmow86muD0myUkVQ==
+popper.js@^1.14.7, popper.js@^1.15.0:
+ version "1.15.0"
+ resolved "https://registry.yarnpkg.com/popper.js/-/popper.js-1.15.0.tgz#5560b99bbad7647e9faa475c6b8056621f5a4ff2"
+ integrity sha512-w010cY1oCUmI+9KwwlWki+r5jxKfTFDVoadl7MSrIujHU5MJ5OR6HTDj6Xo8aoR/QsA56x8jKjA59qGH4ELtrA==
+
+portal-vue@^2.1.5:
+ version "2.1.5"
+ resolved "https://registry.yarnpkg.com/portal-vue/-/portal-vue-2.1.5.tgz#ecd0997cb32958205151cb72f40fd4f38d175e5c"
+ integrity sha512-vZmdMn0mOo7puvxoMQ5zju6S29aFD+9yygJxyWQtPaMXS9xunAeoYdnx6yzfL9J8HD8pMZYgSieEIbioAKhrSQ==
portfinder@^1.0.9:
version "1.0.13"
@@ -9206,16 +9144,6 @@ regenerate@^1.2.1, regenerate@^1.4.0:
resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.0.tgz#4a856ec4b56e4077c557589cae85e7a4c8869a11"
integrity sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg==
-regenerator-runtime@^0.10.0:
- version "0.10.5"
- resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz#336c3efc1220adcedda2c9fab67b5a7955a33658"
- integrity sha1-M2w+/BIgrc7dosn6tntaeVWjNlg=
-
-regenerator-runtime@^0.11.0:
- version "0.11.1"
- resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9"
- integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==
-
regenerator-transform@^0.13.4:
version "0.13.4"
resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.13.4.tgz#18f6763cf1382c69c36df76c6ce122cc694284fb"
@@ -9305,6 +9233,11 @@ regjsparser@^0.6.0:
dependencies:
jsesc "~0.5.0"
+relateurl@^0.2.7:
+ version "0.2.7"
+ resolved "https://registry.yarnpkg.com/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9"
+ integrity sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=
+
remark-parse@^6.0.0:
version "6.0.3"
resolved "https://registry.yarnpkg.com/remark-parse/-/remark-parse-6.0.3.tgz#c99131052809da482108413f87b0ee7f52180a3a"
@@ -9499,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=
@@ -9580,11 +9513,6 @@ rw@1:
resolved "https://registry.yarnpkg.com/rw/-/rw-1.3.3.tgz#3f862dfa91ab766b14885ef4d01124bfda074fb4"
integrity sha1-P4Yt+pGrdmsUiF700BEkv9oHT7Q=
-rx@^4.1.0:
- version "4.1.0"
- resolved "https://registry.yarnpkg.com/rx/-/rx-4.1.0.tgz#a5f13ff79ef3b740fe30aa803fb09f98805d4782"
- integrity sha1-pfE/957zt0D+MKqAP7CfmIBdR4I=
-
rxjs@^6.1.0:
version "6.2.1"
resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.2.1.tgz#246cebec189a6cbc143a3ef9f62d6f4c91813ca1"
@@ -10027,7 +9955,7 @@ source-map-resolve@^0.5.0, source-map-resolve@^0.5.2:
source-map-url "^0.4.0"
urix "^0.1.0"
-source-map-support@^0.5.6, source-map-support@~0.5.6:
+source-map-support@^0.5.6, source-map-support@~0.5.10, source-map-support@~0.5.6:
version "0.5.12"
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.12.tgz#b4f3b10d51857a5af0138d3ce8003b201613d599"
integrity sha512-4h2Pbvyy15EE02G+JOZpUCmqWJuqrs+sEkzewTm++BPi7Hvn/HwcqLAcNxYAyI0x13CpPPn+kMjl+hplXMHITQ==
@@ -10057,18 +9985,11 @@ source-map@^0.5.0, source-map@^0.5.6:
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=
-source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1:
+source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1:
version "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"
@@ -10470,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"
@@ -10588,6 +10502,15 @@ terser@^3.8.1:
source-map "~0.6.1"
source-map-support "~0.5.6"
+terser@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/terser/-/terser-4.0.0.tgz#ef356f6f359a963e2cc675517f21c1c382877374"
+ integrity sha512-dOapGTU0hETFl1tCo4t56FN+2jffoKyER9qBGoUFyZ6y7WLoKT0bF+lAYi6B6YsILcGF3q1C2FBh8QcKSCgkgA==
+ dependencies:
+ commander "^2.19.0"
+ source-map "~0.6.1"
+ source-map-support "~0.5.10"
+
test-exclude@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-5.0.0.tgz#cdce7cece785e0e829cd5c2b27baf18bc583cfb7"
@@ -10842,6 +10765,16 @@ trough@^1.0.0:
dependencies:
glob "^7.1.2"
+try-catch@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/try-catch/-/try-catch-2.0.0.tgz#a491141d597f8b72b46757fe1c47059341a16aed"
+ integrity sha512-RPXpVjsbtWgymwGq5F/OWDFsjEzdvzwHFaMjWWW6f/p6+uk/N7YSKJHQfIfGqITfj8qH4cBqCLMnhKZBaKk7Kg==
+
+try-to-catch@^1.0.2:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/try-to-catch/-/try-to-catch-1.1.1.tgz#770162dd13b9a0e55da04db5b7f888956072038a"
+ integrity sha512-ikUlS+/BcImLhNYyIgZcEmq4byc31QpC+46/6Jm5ECWkVFhf8SM2Fp/0pMVXPX6vk45SMCwrP4Taxucne8I0VA==
+
tryer@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/tryer/-/tryer-1.0.0.tgz#027b69fa823225e551cace3ef03b11f6ab37c1d7"
@@ -10928,10 +10861,10 @@ uc.micro@^1.0.1, uc.micro@^1.0.5:
resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.5.tgz#0c65f15f815aa08b560a61ce8b4db7ffc3f45376"
integrity sha512-JoLI4g5zv5qNyT09f4YAvEZIIV1oOjqnewYg5D38dkQljIzpPT296dbIGvKro3digYI1bkb7W6EP1y4uDlmzLg==
-uglify-js@^3.1.4:
- version "3.5.15"
- resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.5.15.tgz#fe2b5378fd0b09e116864041437bff889105ce24"
- integrity sha512-fe7aYFotptIddkwcm6YuA0HmknBZ52ZzOsUxZEdhhkSsz7RfjHDX2QDxwKTiv4JQ5t5NhfmpgAK+J7LiDhKSqg==
+uglify-js@^3.1.4, uglify-js@^3.5.1:
+ version "3.6.0"
+ resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.6.0.tgz#704681345c53a8b2079fb6cec294b05ead242ff5"
+ integrity sha512-W+jrUHJr3DXKhrsS7NUVxn3zqMOFn0hL/Ei6v0anCIMoKC93TjcflTagwIHLW7SfMFfiQuktQyFVCFHGUE0+yg==
dependencies:
commander "~2.20.0"
source-map "~0.6.1"
@@ -11128,6 +11061,11 @@ update-notifier@^2.5.0:
semver-diff "^2.0.0"
xdg-basedir "^3.0.0"
+upper-case@^1.1.1:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/upper-case/-/upper-case-1.1.3.tgz#f6b4501c2ec4cdd26ba78be7222961de77621598"
+ integrity sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg=
+
uri-js@^4.2.2:
version "4.2.2"
resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0"
@@ -11318,10 +11256,10 @@ vue-eslint-parser@^4.0.2:
esquery "^1.0.1"
lodash "^4.17.11"
-vue-functional-data-merge@^2.0.5:
- version "2.0.6"
- resolved "https://registry.yarnpkg.com/vue-functional-data-merge/-/vue-functional-data-merge-2.0.6.tgz#f08055adfb92458debcf2ad10c3aa712277f7fc2"
- integrity sha512-eivElFOJwhXJopKlq71/8onDxOKK4quPwWGFF9yIVjpU2sNzxISRpufu18bh674ivSADuEAPU2OhT+vrH0E9Mg==
+vue-functional-data-merge@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/vue-functional-data-merge/-/vue-functional-data-merge-3.1.0.tgz#08a7797583b7f35680587f8a1d51d729aa1dc657"
+ integrity sha512-leT4kdJVQyeZNY1kmnS1xiUlQ9z1B/kdBFCILIjYYQDqZgLqCLa0UhjSSeRX6c3mUe6U5qYeM8LrEqkHJ1B4LA==
vue-hot-reload-api@^2.3.0:
version "2.3.0"
@@ -11625,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==
@@ -11646,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"