Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitlab/CODEOWNERS.disabled4
-rw-r--r--.gitlab/issue_templates/Feature proposal.md2
-rw-r--r--CHANGELOG.md316
-rw-r--r--GITALY_SERVER_VERSION2
-rw-r--r--Gemfile17
-rw-r--r--Gemfile.lock114
-rw-r--r--PROCESS.md12
-rw-r--r--VERSION2
-rw-r--r--app/assets/javascripts/api.js2
-rw-r--r--app/assets/javascripts/boards/components/issue_due_date.vue9
-rw-r--r--app/assets/javascripts/ci_variable_list/ci_variable_list.js4
-rw-r--r--app/assets/javascripts/diffs/components/compare_versions_dropdown.vue2
-rw-r--r--app/assets/javascripts/diffs/components/diff_content.vue8
-rw-r--r--app/assets/javascripts/gfm_auto_complete.js17
-rw-r--r--app/assets/javascripts/lib/utils/text_markdown.js4
-rw-r--r--app/assets/javascripts/notes/components/discussion_filter.vue20
-rw-r--r--app/assets/javascripts/notes/components/noteable_discussion.vue39
-rw-r--r--app/assets/javascripts/notes/constants.js1
-rw-r--r--app/assets/javascripts/pages/users/user_overview_block.js15
-rw-r--r--app/assets/javascripts/pipelines/components/pipeline_url.vue4
-rw-r--r--app/assets/javascripts/releases/components/release_block.vue19
-rw-r--r--app/assets/javascripts/releases/index.js2
-rw-r--r--app/assets/javascripts/right_sidebar.js15
-rw-r--r--app/assets/javascripts/serverless/components/functions.vue2
-rw-r--r--app/assets/javascripts/set_status_modal/emoji_menu_in_modal.js3
-rw-r--r--app/assets/javascripts/sidebar/stores/sidebar_store.js2
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue5
-rw-r--r--app/assets/javascripts/vue_shared/components/user_popover/user_popover.vue21
-rw-r--r--app/assets/stylesheets/framework/files.scss2
-rw-r--r--app/assets/stylesheets/framework/highlight.scss7
-rw-r--r--app/assets/stylesheets/framework/modal.scss4
-rw-r--r--app/assets/stylesheets/framework/variables.scss1
-rw-r--r--app/assets/stylesheets/framework/variables_overrides.scss6
-rw-r--r--app/assets/stylesheets/pages/builds.scss1
-rw-r--r--app/assets/stylesheets/pages/issuable.scss4
-rw-r--r--app/assets/stylesheets/pages/pipelines.scss1
-rw-r--r--app/assets/stylesheets/pages/projects.scss6
-rw-r--r--app/controllers/admin/application_settings_controller.rb2
-rw-r--r--app/controllers/application_controller.rb4
-rw-r--r--app/controllers/concerns/group_tree.rb4
-rw-r--r--app/controllers/concerns/issuable_actions.rb10
-rw-r--r--app/controllers/groups/settings/ci_cd_controller.rb6
-rw-r--r--app/controllers/projects/blob_controller.rb2
-rw-r--r--app/controllers/projects/merge_requests/conflicts_controller.rb8
-rw-r--r--app/controllers/projects/merge_requests_controller.rb12
-rw-r--r--app/controllers/projects/releases_controller.rb6
-rw-r--r--app/controllers/projects/snippets_controller.rb9
-rw-r--r--app/controllers/projects/tags_controller.rb15
-rw-r--r--app/controllers/projects_controller.rb1
-rw-r--r--app/controllers/sherlock/transactions_controller.rb2
-rw-r--r--app/controllers/snippets_controller.rb8
-rw-r--r--app/finders/group_descendants_finder.rb6
-rw-r--r--app/finders/groups_finder.rb4
-rw-r--r--app/finders/releases_finder.rb14
-rw-r--r--app/helpers/appearances_helper.rb4
-rw-r--r--app/helpers/application_settings_helper.rb15
-rw-r--r--app/helpers/blob_helper.rb32
-rw-r--r--app/helpers/ci_variables_helper.rb15
-rw-r--r--app/helpers/diff_helper.rb24
-rw-r--r--app/helpers/emails_helper.rb2
-rw-r--r--app/helpers/groups_helper.rb2
-rw-r--r--app/helpers/issuables_helper.rb109
-rw-r--r--app/helpers/milestones_helper.rb8
-rw-r--r--app/helpers/projects_helper.rb28
-rw-r--r--app/helpers/snippets_helper.rb10
-rw-r--r--app/helpers/sorting_helper.rb2
-rw-r--r--app/helpers/workhorse_helper.rb5
-rw-r--r--app/mailers/emails/issues.rb4
-rw-r--r--app/mailers/emails/merge_requests.rb4
-rw-r--r--app/mailers/notify.rb1
-rw-r--r--app/models/appearance.rb28
-rw-r--r--app/models/application_setting.rb7
-rw-r--r--app/models/blob.rb10
-rw-r--r--app/models/blob_viewer/base.rb6
-rw-r--r--app/models/ci/build.rb5
-rw-r--r--app/models/ci/pipeline.rb13
-rw-r--r--app/models/ci/runner.rb2
-rw-r--r--app/models/clusters/applications/cert_manager.rb2
-rw-r--r--app/models/clusters/applications/runner.rb2
-rw-r--r--app/models/clusters/platforms/kubernetes.rb4
-rw-r--r--app/models/commit.rb4
-rw-r--r--app/models/concerns/blob_like.rb2
-rw-r--r--app/models/concerns/cacheable_attributes.rb7
-rw-r--r--app/models/concerns/descendant.rb11
-rw-r--r--app/models/concerns/discussion_on_diff.rb21
-rw-r--r--app/models/concerns/has_ref.rb17
-rw-r--r--app/models/concerns/noteable.rb4
-rw-r--r--app/models/dashboard_group_milestone.rb1
-rw-r--r--app/models/diff_viewer/base.rb39
-rw-r--r--app/models/diff_viewer/image.rb2
-rw-r--r--app/models/diff_viewer/rich.rb2
-rw-r--r--app/models/diff_viewer/server_side.rb12
-rw-r--r--app/models/diff_viewer/simple.rb2
-rw-r--r--app/models/group.rb5
-rw-r--r--app/models/merge_request.rb22
-rw-r--r--app/models/milestone.rb2
-rw-r--r--app/models/namespace.rb17
-rw-r--r--app/models/note_diff_file.rb15
-rw-r--r--app/models/project.rb34
-rw-r--r--app/models/prometheus_metric.rb84
-rw-r--r--app/models/release.rb28
-rw-r--r--app/models/remote_mirror.rb2
-rw-r--r--app/models/repository.rb13
-rw-r--r--app/models/snippet.rb6
-rw-r--r--app/models/todo.rb5
-rw-r--r--app/models/user.rb10
-rw-r--r--app/policies/concerns/clusterable_actions.rb14
-rw-r--r--app/policies/group_policy.rb12
-rw-r--r--app/policies/issuable_policy.rb2
-rw-r--r--app/policies/project_policy.rb14
-rw-r--r--app/policies/release_policy.rb5
-rw-r--r--app/presenters/clusterable_presenter.rb4
-rw-r--r--app/serializers/diff_viewer_entity.rb3
-rw-r--r--app/serializers/entity_date_helper.rb16
-rw-r--r--app/serializers/issuable_sidebar_basic_entity.rb106
-rw-r--r--app/serializers/issuable_sidebar_extras_entity.rb (renamed from app/serializers/issuable_sidebar_entity.rb)4
-rw-r--r--app/serializers/issuable_sidebar_todo_entity.rb11
-rw-r--r--app/serializers/issue_board_entity.rb2
-rw-r--r--app/serializers/issue_serializer.rb6
-rw-r--r--app/serializers/issue_sidebar_basic_entity.rb6
-rw-r--r--app/serializers/issue_sidebar_extras_entity.rb (renamed from app/serializers/issue_sidebar_entity.rb)2
-rw-r--r--app/serializers/merge_request_basic_entity.rb2
-rw-r--r--app/serializers/merge_request_basic_serializer.rb5
-rw-r--r--app/serializers/merge_request_serializer.rb9
-rw-r--r--app/serializers/merge_request_sidebar_basic_entity.rb11
-rw-r--r--app/services/ci/create_pipeline_service.rb3
-rw-r--r--app/services/ci/register_job_service.rb2
-rw-r--r--app/services/clusters/gcp/finalize_creation_service.rb2
-rw-r--r--app/services/commits/tag_service.rb3
-rw-r--r--app/services/create_release_service.rb35
-rw-r--r--app/services/git_push_service.rb3
-rw-r--r--app/services/git_tag_push_service.rb3
-rw-r--r--app/services/groups/nested_create_service.rb2
-rw-r--r--app/services/groups/transfer_service.rb2
-rw-r--r--app/services/groups/update_service.rb2
-rw-r--r--app/services/issues/update_service.rb2
-rw-r--r--app/services/members/base_service.rb6
-rw-r--r--app/services/members/destroy_service.rb8
-rw-r--r--app/services/members/update_service.rb9
-rw-r--r--app/services/merge_requests/build_service.rb24
-rw-r--r--app/services/merge_requests/update_service.rb6
-rw-r--r--app/services/notification_service.rb2
-rw-r--r--app/services/projects/after_rename_service.rb1
-rw-r--r--app/services/projects/lfs_pointers/lfs_download_service.rb35
-rw-r--r--app/services/projects/transfer_service.rb7
-rw-r--r--app/services/projects/update_service.rb4
-rw-r--r--app/services/releases/concerns.rb48
-rw-r--r--app/services/releases/create_service.rb54
-rw-r--r--app/services/releases/destroy_service.rb25
-rw-r--r--app/services/releases/update_service.rb32
-rw-r--r--app/services/tags/create_service.rb7
-rw-r--r--app/services/tags/destroy_service.rb10
-rw-r--r--app/services/update_release_service.rb28
-rw-r--r--app/services/users/refresh_authorized_projects_service.rb2
-rw-r--r--app/views/admin/appearances/_form.html.haml6
-rw-r--r--app/views/admin/application_settings/_ci_cd.html.haml7
-rw-r--r--app/views/ci/variables/_content.html.haml2
-rw-r--r--app/views/ci/variables/_header.html.haml11
-rw-r--r--app/views/ci/variables/_index.html.haml5
-rw-r--r--app/views/ci/variables/_variable_row.html.haml6
-rw-r--r--app/views/clusters/clusters/_buttons.html.haml3
-rw-r--r--app/views/clusters/clusters/_empty_state.html.haml2
-rw-r--r--app/views/events/_events.html.haml5
-rw-r--r--app/views/groups/settings/ci_cd/show.html.haml8
-rw-r--r--app/views/layouts/_search.html.haml2
-rw-r--r--app/views/layouts/devise.html.haml2
-rw-r--r--app/views/layouts/header/_default.html.haml2
-rw-r--r--app/views/layouts/header/_new_dropdown.haml2
-rw-r--r--app/views/layouts/nav/_dashboard.html.haml4
-rw-r--r--app/views/layouts/nav/sidebar/_group.html.haml26
-rw-r--r--app/views/layouts/nav/sidebar/_project.html.haml2
-rw-r--r--app/views/notify/_note_email.html.haml10
-rw-r--r--app/views/notify/_note_email.text.erb2
-rw-r--r--app/views/notify/changed_milestone_email.html.haml (renamed from app/views/notify/changed_milestone_issue_email.html.haml)2
-rw-r--r--app/views/notify/changed_milestone_email.text.erb1
-rw-r--r--app/views/notify/changed_milestone_issue_email.text.erb1
-rw-r--r--app/views/notify/changed_milestone_merge_request_email.html.haml3
-rw-r--r--app/views/notify/changed_milestone_merge_request_email.text.erb1
-rw-r--r--app/views/projects/buttons/_clone.html.haml17
-rw-r--r--app/views/projects/diffs/_render_error.html.haml6
-rw-r--r--app/views/projects/issues/show.html.haml2
-rw-r--r--app/views/projects/merge_requests/conflicts.html.haml36
-rw-r--r--app/views/projects/merge_requests/conflicts/show.html.haml2
-rw-r--r--app/views/projects/merge_requests/show.html.haml3
-rw-r--r--app/views/projects/settings/ci_cd/show.html.haml8
-rw-r--r--app/views/shared/_mobile_clone_panel.html.haml10
-rw-r--r--app/views/shared/issuable/_sidebar.html.haml165
-rw-r--r--app/views/shared/issuable/_sidebar_assignees.html.haml51
-rw-r--r--app/views/shared/issuable/_sidebar_todo.html.haml18
-rw-r--r--app/views/shared/issuable/form/_metadata.html.haml3
-rw-r--r--app/views/shared/milestones/_sidebar.html.haml2
-rw-r--r--app/views/shared/projects/_project.html.haml4
-rw-r--r--app/views/shared/snippets/_header.html.haml2
-rw-r--r--app/workers/all_queues.yml2
-rw-r--r--app/workers/cluster_configure_worker.rb (renamed from app/workers/cluster_platform_configure_worker.rb)2
-rw-r--r--app/workers/cluster_provision_worker.rb2
-rw-r--r--app/workers/mail_scheduler/notification_service_worker.rb23
-rw-r--r--app/workers/post_receive.rb20
-rw-r--r--changelogs/unreleased/18667-handle-push-opts.yml5
-rw-r--r--changelogs/unreleased/19376-post-bfg-cleanup.yml5
-rw-r--r--changelogs/unreleased/1979-redesign-mr-widget-approvals-ce.yml5
-rw-r--r--changelogs/unreleased/20422-hide-ui-variables-by-default.yml6
-rw-r--r--changelogs/unreleased/22548-reopen-error-message.yml6
-rw-r--r--changelogs/unreleased/33705-merge-request-rebase-api.yml5
-rw-r--r--changelogs/unreleased/34758-deployment-cluster.yml5
-rw-r--r--changelogs/unreleased/34758-extend-can-create-cluster-logic.yml5
-rw-r--r--changelogs/unreleased/34758-group-cluster-controller.yml5
-rw-r--r--changelogs/unreleased/38495-calendar-activities-in-timezone.yml5
-rw-r--r--changelogs/unreleased/39849_controller_sorts.yml5
-rw-r--r--changelogs/unreleased/40085-add-a-create_merge_request-quick-action.yml5
-rw-r--r--changelogs/unreleased/40260-reduce-gitaly-calls-project-pipeline-status.yml5
-rw-r--r--changelogs/unreleased/40270-remove-gitlab-upgrader-completely.yml5
-rw-r--r--changelogs/unreleased/40385-prohibit_impersonation.yml5
-rw-r--r--changelogs/unreleased/41875-allow-pipelines-to-be-deleted-by-project-owners.yml5
-rw-r--r--changelogs/unreleased/42125-extend-override-check-to-also-check-arity.yml5
-rw-r--r--changelogs/unreleased/44984-use-serializer-for-issuable-sidebar.yml5
-rw-r--r--changelogs/unreleased/46544-webide-ctrl-enter-commit-shortcut.yml5
-rw-r--r--changelogs/unreleased/46950-systemcheck-ruby-version.yml5
-rw-r--r--changelogs/unreleased/48475-gitlab-pages-settings-regressions.yml5
-rw-r--r--changelogs/unreleased/48496-merge-request-refactor-does-not-highlight-selected-line.yml5
-rw-r--r--changelogs/unreleased/48889-populate-merge_commit_sha.yml6
-rw-r--r--changelogs/unreleased/49479-hide-unmerged-env-perf-stats.yml5
-rw-r--r--changelogs/unreleased/49565-ssh-push-mirroring.yml5
-rw-r--r--changelogs/unreleased/49713-main-navbar-is-broken-in-certain-viewport-widths.yml5
-rw-r--r--changelogs/unreleased/49726-upgrade-helm-to-2-11.yml5
-rw-r--r--changelogs/unreleased/50157-extended-user-centric-tooltips.yml5
-rw-r--r--changelogs/unreleased/50264-add-border-around-the-repository-file-tree.yml5
-rw-r--r--changelogs/unreleased/50341-cleanup-useless-project-import-attributes.yml6
-rw-r--r--changelogs/unreleased/50626-searching-users-by-the-admin-panel-wipes-query-when-using-sort.yml5
-rw-r--r--changelogs/unreleased/50839-webide-mr-dropdown-filter.yml5
-rw-r--r--changelogs/unreleased/51029-status-emoji-currently-replaces-avatar-on-mobile.yml5
-rw-r--r--changelogs/unreleased/51061-readme-url-n-1-rpc-call-resolved.yml5
-rw-r--r--changelogs/unreleased/51083-fix-move-api.yml5
-rw-r--r--changelogs/unreleased/51101-can-add-an-existing-group-member-into-a-group-project-with-new-permissions-but-permissions-are-not-overridde.yml5
-rw-r--r--changelogs/unreleased/51122-fix-navigating-discussions.yml5
-rw-r--r--changelogs/unreleased/51138-54026-breadcrumb-subgroups-ellipsis.yml5
-rw-r--r--changelogs/unreleased/51243-further-improvements-to-project-overview-ui.yml5
-rw-r--r--changelogs/unreleased/51259-ci-cd-gitlab-ui-1.yml5
-rw-r--r--changelogs/unreleased/51259-ci-cd-tooltips.yml6
-rw-r--r--changelogs/unreleased/51668-fix-line-numbers.yml5
-rw-r--r--changelogs/unreleased/51792-dont-delete-failed-install-pods.yml5
-rw-r--r--changelogs/unreleased/51959-branch-and-tag-name-links.yml5
-rw-r--r--changelogs/unreleased/51970-correct-ordering-of-metrics.yml5
-rw-r--r--changelogs/unreleased/52007-frontmatter-toml-json.yml5
-rw-r--r--changelogs/unreleased/52276-jump-to-top-in-merge-request.yml5
-rw-r--r--changelogs/unreleased/52285-omniauth-jwt-ppk-support.yml5
-rw-r--r--changelogs/unreleased/52370-filter-by-none-any-for-labels-in-issues-mrs-boards.yml5
-rw-r--r--changelogs/unreleased/52371-filter-by-none-any-for-labels-in-issues-mrs-api.yml5
-rw-r--r--changelogs/unreleased/52371-removes-patially-matching-no-label-and-makes-it-case-insensitive.yml5
-rw-r--r--changelogs/unreleased/52385-search-bar-for-dashboard-list.yml5
-rw-r--r--changelogs/unreleased/52453-show-subgroups-in-group-create-issue.yml5
-rw-r--r--changelogs/unreleased/52620-fix-loader-animation-alignment.yml5
-rw-r--r--changelogs/unreleased/52712-further-ui-improvements-to-profile-overview-tab.yml5
-rw-r--r--changelogs/unreleased/52774-fix-svgs-in-ie-11.yml5
-rw-r--r--changelogs/unreleased/52828-inconsistency-in-fonts-used-for-branch-name-and-create-from-fields-when-creating-new-branch-from-ui.yml5
-rw-r--r--changelogs/unreleased/52888-status-emoji-should-not-be-added-to-awards-section-on-issue-page-2.yml5
-rw-r--r--changelogs/unreleased/52940-fix-internal-email-pattern-not-respected.yml5
-rw-r--r--changelogs/unreleased/53289-update-haml_lint-to-0-28-0.yml5
-rw-r--r--changelogs/unreleased/53290-incorrect-project-list-order-select-default-label.yml5
-rw-r--r--changelogs/unreleased/53291-update-ffaker-to-2-10-0.yml5
-rw-r--r--changelogs/unreleased/53326-improve-issues-empty-state.yml5
-rw-r--r--changelogs/unreleased/53400-unstar-icon-button-is-misaligned.yml5
-rw-r--r--changelogs/unreleased/53578-fe-deployment-status.yml5
-rw-r--r--changelogs/unreleased/53626-update-config-map-on-install-retry.yml5
-rw-r--r--changelogs/unreleased/53640-follow-up-from-resolve-redesign-activity-feed.yml4
-rw-r--r--changelogs/unreleased/53659-use-padded-key-for-gcm-ciphers.yml5
-rw-r--r--changelogs/unreleased/53700-hashed-storagemigration.yml5
-rw-r--r--changelogs/unreleased/53728-warn-in-web-editor-when-user-navigates-away.yml5
-rw-r--r--changelogs/unreleased/53816-empty-label-menu-if-not-logged-in.yml5
-rw-r--r--changelogs/unreleased/53874-navbar-lowres.yml5
-rw-r--r--changelogs/unreleased/53907-improve-milestone-links.yml5
-rw-r--r--changelogs/unreleased/53933-include-dates-in-milestone-change-email.yml5
-rw-r--r--changelogs/unreleased/53988-remove-notes-index-on-updated-at.yml5
-rw-r--r--changelogs/unreleased/53992-add-events-index-on-project-id-and-created-at.yml5
-rw-r--r--changelogs/unreleased/53994-add-missing-ci_builds-partial-indices.yml5
-rw-r--r--changelogs/unreleased/54004-update-asana-to-0-8-1.yml5
-rw-r--r--changelogs/unreleased/54010-update-asciidoctor-to-1-5-8.yml5
-rw-r--r--changelogs/unreleased/54015-Markdown-Editor-improve-Cursor-placement.yml5
-rw-r--r--changelogs/unreleased/54021-empty-button.yml5
-rw-r--r--changelogs/unreleased/54032-reply-shortcut-only-discussion-text.yml5
-rw-r--r--changelogs/unreleased/54048-Line-numbers-are-misaligned-in-file-blame-view.yml5
-rw-r--r--changelogs/unreleased/54093-the-default_value_for-gem-doesn-t-handle-actioncontroller-parameters-correctly.yml7
-rw-r--r--changelogs/unreleased/54160-use-reports-syntax-for-sast-in-auto-devops.yml5
-rw-r--r--changelogs/unreleased/54201-update-rack-to-2-0-6.yml5
-rw-r--r--changelogs/unreleased/54206-show-the-activity-filter-dropdown-in-discussion-tab-only.yml5
-rw-r--r--changelogs/unreleased/54218-fix-mergeUrlParams.yml5
-rw-r--r--changelogs/unreleased/54336-include-tags-into-pipeline-detail-view.yml5
-rw-r--r--changelogs/unreleased/54391-tag.yml5
-rw-r--r--changelogs/unreleased/54407-fix-limited-intersection-observers.yml5
-rw-r--r--changelogs/unreleased/54427-label-xss.yml5
-rw-r--r--changelogs/unreleased/54571-runner-tags.yml5
-rw-r--r--changelogs/unreleased/54626-able-to-download-a-single-archive-file-with-api-by-ref-name.yml5
-rw-r--r--changelogs/unreleased/54648-fix-order-by-dropdown-tablet-screens.yml5
-rw-r--r--changelogs/unreleased/54826-use-read_repository-scope-on-read-only-files-endpoints.yml5
-rw-r--r--changelogs/unreleased/54857-fix-templates-path-traversal.yml5
-rw-r--r--changelogs/unreleased/54953-error-500-viewing-merge-request-due-to-nil-commit_email_hostname.yml5
-rw-r--r--changelogs/unreleased/54975-fix-web-hooks-rake-task.yml5
-rw-r--r--changelogs/unreleased/55104-frozenerror-can-t-modify-frozen-string.yml5
-rw-r--r--changelogs/unreleased/55116-runtimeerror-can-t-modify-frozen-string.yml5
-rw-r--r--changelogs/unreleased/55138-fix-mr-discussions-count.yml5
-rw-r--r--changelogs/unreleased/55183-frozenerror-can-t-modify-frozen-string-in-app-mailers-notify-rb.yml5
-rw-r--r--changelogs/unreleased/55266-fix-incorrect-due-date-parsing.yml5
-rw-r--r--changelogs/unreleased/55293-split-bio-into-individual-line-in-extended-user-tooltips.yml5
-rw-r--r--changelogs/unreleased/55369-update-milestone-sort-to-say-say-milestone-due-date.yml5
-rw-r--r--changelogs/unreleased/55402-broken-master-karma-test-failing-in-spec-javascripts-boards-components-issue_due_date_spec-js.yml5
-rw-r--r--changelogs/unreleased/55484-fix-edit-button.yml4
-rw-r--r--changelogs/unreleased/55669-redesign-project-lists-ui-further-improvements.yml5
-rw-r--r--changelogs/unreleased/55716-update-cert-manager-chart-from-v0-5-0-to-v0-5-2.yml5
-rw-r--r--changelogs/unreleased/55755-user-activity-is-stuck-loading-when-there-is-none.yml5
-rw-r--r--changelogs/unreleased/55838-remove-gem-install-bundler-from-docker-based-ruby-environments.yml5
-rw-r--r--changelogs/unreleased/_acet-fix-flash-styling.yml5
-rw-r--r--changelogs/unreleased/ab-approximate-counts.yml5
-rw-r--r--changelogs/unreleased/ac-releases-api.yml5
-rw-r--r--changelogs/unreleased/added-glob-for-ci-changes-detection.yml5
-rw-r--r--changelogs/unreleased/allow_collaboration_status_work.yml5
-rw-r--r--changelogs/unreleased/an-gitaly-version-0-133-0.yml5
-rw-r--r--changelogs/unreleased/ashmckenzie-hmac-token-decode-and-tests.yml5
-rw-r--r--changelogs/unreleased/auto_devops_kubernetes_active.yml5
-rw-r--r--changelogs/unreleased/blackst0ne-add-discord-service.yml5
-rw-r--r--changelogs/unreleased/blackst0ne-bump-rails-cve-2018-16476.yml5
-rw-r--r--changelogs/unreleased/bump_gpgme_gem.yml5
-rw-r--r--changelogs/unreleased/bvl-use-shell-writeref.yml5
-rw-r--r--changelogs/unreleased/ce-52811-fix_namespaces_api_routing.yml5
-rw-r--r--changelogs/unreleased/ce-54109-fix_user_by_any_email.yml5
-rw-r--r--changelogs/unreleased/cert-manager-email.yml5
-rw-r--r--changelogs/unreleased/certmanager-temp.yml5
-rw-r--r--changelogs/unreleased/check-if-fetched-data-does-is-complete.yml5
-rw-r--r--changelogs/unreleased/ci-dropdown-hidden-bug.yml5
-rw-r--r--changelogs/unreleased/commit-badge-style-fix.yml5
-rw-r--r--changelogs/unreleased/define-default-value-for-only-except-keys.yml5
-rw-r--r--changelogs/unreleased/deprecated-insert-sql.yml5
-rw-r--r--changelogs/unreleased/deprecated-instance-find.yml5
-rw-r--r--changelogs/unreleased/deprecated-redirect-back.yml5
-rw-r--r--changelogs/unreleased/diff-expand-commit-file.yml5
-rw-r--r--changelogs/unreleased/diff-fix-expanding.yml5
-rw-r--r--changelogs/unreleased/discussion-perf-improvement.yml5
-rw-r--r--changelogs/unreleased/dm-batch-loader-key.yml5
-rw-r--r--changelogs/unreleased/dm-note-email-image-diff-discussion.yml5
-rw-r--r--changelogs/unreleased/dm-remove-prune-web-hook-logs-worker.yml5
-rw-r--r--changelogs/unreleased/docs-minor-aws-fixes.yml5
-rw-r--r--changelogs/unreleased/document-raw-snippet-api.yml5
-rw-r--r--changelogs/unreleased/drop-default-value-status-deployments.yml5
-rw-r--r--changelogs/unreleased/drop-gcp-cluster-table.yml5
-rw-r--r--changelogs/unreleased/expose-mr-pipeline-variables.yml5
-rw-r--r--changelogs/unreleased/feature-option-to-make-variables-protected.yml5
-rw-r--r--changelogs/unreleased/fix-55448.yml5
-rw-r--r--changelogs/unreleased/fix-gb-encrypt-ci-build-token.yml5
-rw-r--r--changelogs/unreleased/fix-gb-encrypt-runners-tokens.yml5
-rw-r--r--changelogs/unreleased/fix-gb-improve-timeout-inputs-help-sections.yml5
-rw-r--r--changelogs/unreleased/fix-mr-widget-unrelated-deployment-status.yml5
-rw-r--r--changelogs/unreleased/fix-multiple-comments-shade-overlap.yml5
-rw-r--r--changelogs/unreleased/fj-44679-skip-per-commit-validations.yml5
-rw-r--r--changelogs/unreleased/fj-47494-upgrade-git-to-2-18-0.yml5
-rw-r--r--changelogs/unreleased/fj-55781-fix-api-blob-content-disposition.yml5
-rw-r--r--changelogs/unreleased/fj-clean-content-headers.yml5
-rw-r--r--changelogs/unreleased/fj-fix-lfs-image-comments-diffs.yml5
-rw-r--r--changelogs/unreleased/fj-force-content-disposition.yml5
-rw-r--r--changelogs/unreleased/force-reload-arguments-1.yml5
-rw-r--r--changelogs/unreleased/frozen-string-lib-gitlab-even-even-even-more.yml5
-rw-r--r--changelogs/unreleased/frozen-string-lib-gitlab-even-even-more.yml5
-rw-r--r--changelogs/unreleased/frozen-string-lib-gitlab-even-more.yml5
-rw-r--r--changelogs/unreleased/frozen-string-lib-gitlab-more.yml5
-rw-r--r--changelogs/unreleased/frozen-string-lib-rubocop.yml5
-rw-r--r--changelogs/unreleased/gt-add-top-padding-for-nested-environment-items-loading-icon.yml5
-rw-r--r--changelogs/unreleased/gt-align-issue-status-and-confidential-icon.yml5
-rw-r--r--changelogs/unreleased/gt-change-breadcrumb-title-for-contribution-charts.yml5
-rw-r--r--changelogs/unreleased/gt-change-container-width-for-project-import.yml5
-rw-r--r--changelogs/unreleased/gt-externalize-app-views-invites.yml5
-rw-r--r--changelogs/unreleased/gt-externalize-app-views-project-runners.yml5
-rw-r--r--changelogs/unreleased/gt-externalize-app-views-snippets.yml5
-rw-r--r--changelogs/unreleased/gt-fix-typo-in-notebook-props.yml5
-rw-r--r--changelogs/unreleased/gt-fix-typos-in-lib.yml5
-rw-r--r--changelogs/unreleased/gt-remove-instances-of-extend-monospace.yml5
-rw-r--r--changelogs/unreleased/gt-remove-unused-project-method.yml5
-rw-r--r--changelogs/unreleased/gt-rename-diffs-store-variable.yml5
-rw-r--r--changelogs/unreleased/gt-reorder-group-sidebar-menu-items.yml5
-rw-r--r--changelogs/unreleased/gt-show-primary-button-when-all-labels-are-prioritized.yml5
-rw-r--r--changelogs/unreleased/gt-update-env-metrics-empty-state.yml5
-rw-r--r--changelogs/unreleased/gt-use-gl-tooltip-directive.yml5
-rw-r--r--changelogs/unreleased/ide-open-all-mr-files.yml5
-rw-r--r--changelogs/unreleased/ignore-failed-pipeline-creation-on-pipeline-schedule.yml5
-rw-r--r--changelogs/unreleased/improve_auto_devops_migration_debug.yml6
-rw-r--r--changelogs/unreleased/include-new-link-in-breadcrumb.yml5
-rw-r--r--changelogs/unreleased/jivl-add-empty-state-graphs-null-values.yml5
-rw-r--r--changelogs/unreleased/jupyter-tls.yml5
-rw-r--r--changelogs/unreleased/kcj-add-philosophy.yml5
-rw-r--r--changelogs/unreleased/kubernetes-http-response-code.yml5
-rw-r--r--changelogs/unreleased/legacy_fallback_for_project_clusters_only.yml5
-rw-r--r--changelogs/unreleased/lock-trace-writes.yml5
-rw-r--r--changelogs/unreleased/markdown-toolbar-btn-fix.yml (renamed from changelogs/unreleased/fix-deadlock-chunked-io.yml)2
-rw-r--r--changelogs/unreleased/mg-fix-knative-application-row.yml5
-rw-r--r--changelogs/unreleased/move-group-issues-search-cte-up-the-chain.yml5
-rw-r--r--changelogs/unreleased/mr-file-tree-commit.yml5
-rw-r--r--changelogs/unreleased/mr-origin-23218.yml5
-rw-r--r--changelogs/unreleased/mr-pipelines-2.yml5
-rw-r--r--changelogs/unreleased/mr-sticky-headers.yml5
-rw-r--r--changelogs/unreleased/mr-tree-filter-path-name.yml5
-rw-r--r--changelogs/unreleased/multiple-diff-line-discussions-fix.yml5
-rw-r--r--changelogs/unreleased/non-webkit-scrollbar-fixing.yml5
-rw-r--r--changelogs/unreleased/optimise-job-request.yml5
-rw-r--r--changelogs/unreleased/order-of-notification-settings.yml5
-rw-r--r--changelogs/unreleased/osw-cache-discussions-diff-highlighting.yml6
-rw-r--r--changelogs/unreleased/osw-fallback-on-blank-refs.yml5
-rw-r--r--changelogs/unreleased/osw-fix-grouping-by-file-path.yml5
-rw-r--r--changelogs/unreleased/osw-remove-unnused-data-from-diff-discussions.yml5
-rw-r--r--changelogs/unreleased/osw-update-mr-metrics-with-events-data.yml5
-rw-r--r--changelogs/unreleased/profile-fixing.yml5
-rw-r--r--changelogs/unreleased/project_identicon_fix.yml5
-rw-r--r--changelogs/unreleased/rails5-active-record-class-value.yml5
-rw-r--r--changelogs/unreleased/rails5-deprecation-render-nothing.yml6
-rw-r--r--changelogs/unreleased/rails5-env-deprecated.yml5
-rw-r--r--changelogs/unreleased/remove-blob-search-limit.yml5
-rw-r--r--changelogs/unreleased/remove-deployment-status-hack-from-backend.yml5
-rw-r--r--changelogs/unreleased/remove-duplicate-primary-button-in-dashboard-snippets.yml5
-rw-r--r--changelogs/unreleased/render-text-deprecated.yml6
-rw-r--r--changelogs/unreleased/retryable_create_or_update_kubernetes_namespace.yml6
-rw-r--r--changelogs/unreleased/revert-1cccfca1.yml5
-rw-r--r--changelogs/unreleased/rs-cherry-pick-api.yml5
-rw-r--r--changelogs/unreleased/s3-directories-get.yml6
-rw-r--r--changelogs/unreleased/security-182-update-workhorse.yml5
-rw-r--r--changelogs/unreleased/security-2717-xss-username-autocomplete.yml5
-rw-r--r--changelogs/unreleased/security-2736-prometheus-ssrf.yml5
-rw-r--r--changelogs/unreleased/security-2754-fix-lfs-import.yml5
-rw-r--r--changelogs/unreleased/security-48259-private-snippet.yml5
-rw-r--r--changelogs/unreleased/security-53543-user-keeps-access-to-mr-issue-when-removed-from-team.yml5
-rw-r--r--changelogs/unreleased/security-54377-label-milestone-name-xss.yml5
-rw-r--r--changelogs/unreleased/security-bvl-exposure-in-commits-list.yml5
-rw-r--r--changelogs/unreleased/security-bvl-fix-cross-project-mr-exposure.yml5
-rw-r--r--changelogs/unreleased/security-email-change-notification.yml5
-rw-r--r--changelogs/unreleased/security-fix-pat-web-access.yml5
-rw-r--r--changelogs/unreleased/security-fix-ssrf-import-url-remote-mirror.yml5
-rw-r--r--changelogs/unreleased/security-fix-uri-xss-applications.yml5
-rw-r--r--changelogs/unreleased/security-fix-webhook-ssrf-ipv6.yml5
-rw-r--r--changelogs/unreleased/security-fj-crlf-injection.yml5
-rw-r--r--changelogs/unreleased/security-guest-comments.yml5
-rw-r--r--changelogs/unreleased/security-guest-comments_2.yml5
-rw-r--r--changelogs/unreleased/security-issue_51301.yml5
-rw-r--r--changelogs/unreleased/security-master-group-cicd-settings-accessible-to-maintainer.yml5
-rw-r--r--changelogs/unreleased/security-master-guests-jobs-api.yml5
-rw-r--r--changelogs/unreleased/security-master-secret-ci-variables-exposed.yml5
-rw-r--r--changelogs/unreleased/security-master-url-rel.yml5
-rw-r--r--changelogs/unreleased/security-mermaid-xss.yml5
-rw-r--r--changelogs/unreleased/security-pages-toctou-race.yml6
-rw-r--r--changelogs/unreleased/security-private-group.yml6
-rw-r--r--changelogs/unreleased/security-refs-available-to-project-guest.yml5
-rw-r--r--changelogs/unreleased/security-stored-xss-for-environments.yml5
-rw-r--r--changelogs/unreleased/security-todos_not_redacted_for_guests.yml5
-rw-r--r--changelogs/unreleased/security-xss-in-markdown-following-unrecognized-html-element.yml5
-rw-r--r--changelogs/unreleased/set-kubeconfig-nil-when-token-nil.yml5
-rw-r--r--changelogs/unreleased/sh-53180-append-path.yml5
-rw-r--r--changelogs/unreleased/sh-bump-gems-security.yml5
-rw-r--r--changelogs/unreleased/sh-bump-omniauth-google-gem.yml5
-rw-r--r--changelogs/unreleased/sh-bump-ruby-2-5-3.yml5
-rw-r--r--changelogs/unreleased/sh-disable-autocomplete-mirror-settings.yml5
-rw-r--r--changelogs/unreleased/sh-fix-branches-api-timeout.yml5
-rw-r--r--changelogs/unreleased/sh-fix-clone-geo-dropdown.yml5
-rw-r--r--changelogs/unreleased/sh-fix-http-clone-panel.yml5
-rw-r--r--changelogs/unreleased/sh-fix-issue-38317.yml5
-rw-r--r--changelogs/unreleased/sh-fix-issue-51220.yml5
-rw-r--r--changelogs/unreleased/sh-fix-issue-53783-ce.yml5
-rw-r--r--changelogs/unreleased/sh-fix-issue-55822.yml5
-rw-r--r--changelogs/unreleased/sh-fix-mirrors-protected-branches.yml5
-rw-r--r--changelogs/unreleased/sh-handle-invalid-gpg-sig.yml5
-rw-r--r--changelogs/unreleased/sh-handle-string-null-bytes.yml5
-rw-r--r--changelogs/unreleased/sh-ignore-arrays-url-sanitizer.yml5
-rw-r--r--changelogs/unreleased/sh-json-serialize-broadcast-messages.yml5
-rw-r--r--changelogs/unreleased/sh-remove-local-sidekiq-admin-check.yml5
-rw-r--r--changelogs/unreleased/sh-truncate-with-periods.yml5
-rw-r--r--changelogs/unreleased/sh-use-nakayoshi-fork.yml5
-rw-r--r--changelogs/unreleased/sh-use-nokogiri-xml-backend.yml5
-rw-r--r--changelogs/unreleased/spec-positional-arguments.yml5
-rw-r--r--changelogs/unreleased/specs-positional-arguments.yml5
-rw-r--r--changelogs/unreleased/speed-up-relative-positioning.yml5
-rw-r--r--changelogs/unreleased/store-correlation-logs.yml5
-rw-r--r--changelogs/unreleased/suggest-change-to-diff-line.yml5
-rw-r--r--changelogs/unreleased/support-gitaly-tls.yml5
-rw-r--r--changelogs/unreleased/switch-rails.yml5
-rw-r--r--changelogs/unreleased/tc-backfill-full-path-config.yml5
-rw-r--r--changelogs/unreleased/tc-backfill-hashed-project_repositories.yml5
-rw-r--r--changelogs/unreleased/tc-repo-full-path-in-db.yml5
-rw-r--r--changelogs/unreleased/triggermesh-phase2-external-ip.yml5
-rw-r--r--changelogs/unreleased/triggermesh-phase2-knative-description.yml5
-rw-r--r--changelogs/unreleased/triggermesh-phase2-serverless-list.yml5
-rw-r--r--changelogs/unreleased/triggermesh-phase2-serverless.yml5
-rw-r--r--changelogs/unreleased/unicorn-monkey-patch.yml5
-rw-r--r--changelogs/unreleased/update-gitlab-runner-helm-chart-to-0-1-39.yml5
-rw-r--r--changelogs/unreleased/update-gitlab-runner-helm-chart-to-0-1-43.yml5
-rw-r--r--changelogs/unreleased/update-gitlab-runner-helm-chart-version.yml5
-rw-r--r--changelogs/unreleased/upgrade-to-workhorse-7-6-0.yml5
-rw-r--r--changelogs/unreleased/upgrade_kubeclient_400.yml5
-rw-r--r--changelogs/unreleased/usage-count.yml5
-rw-r--r--changelogs/unreleased/validate-foreign-keys-being-indexed.yml5
-rw-r--r--changelogs/unreleased/winh-collapse-discussions.yml5
-rw-r--r--changelogs/unreleased/winh-divider-margin.yml5
-rw-r--r--changelogs/unreleased/winh-dropdown-divider-color.yml5
-rw-r--r--changelogs/unreleased/winh-dropdown-item-padding.yml5
-rw-r--r--changelogs/unreleased/winh-issue-boards-project-dropdown-close.yml5
-rw-r--r--changelogs/unreleased/winh-markdown-preview-lists.yml5
-rw-r--r--changelogs/unreleased/winh-merge-request-commit-context.yml5
-rw-r--r--changelogs/unreleased/winh-merge-request-commit-discussion.yml5
-rw-r--r--changelogs/unreleased/winh-merge-request-diff-discussion-commit-id.yml5
-rw-r--r--changelogs/unreleased/winh-milestone-select.yml5
-rw-r--r--changelogs/unreleased/winh-resolved-discussions-reply-field.yml5
-rw-r--r--changelogs/unreleased/workhorse-7-3-0.yml5
-rw-r--r--changelogs/unreleased/zj-improve-gitaly-pb.yml5
-rw-r--r--changelogs/unreleased/zj-pool-repository-creation.yml5
-rw-r--r--changelogs/unreleased/zj-remove-broken-storage.yml5
-rw-r--r--config/gitlab.yml.example2
-rw-r--r--config/initializers/active_record_avoid_type_casting_in_uniqueness_validator.rb2
-rw-r--r--config/initializers/active_record_locking.rb15
-rw-r--r--config/initializers/carrierwave_patch.rb42
-rw-r--r--config/initializers/zz_metrics.rb (renamed from config/initializers/8_metrics.rb)3
-rw-r--r--config/routes/uploads.rb3
-rw-r--r--db/fixtures/development/24_forks.rb6
-rw-r--r--db/migrate/20180413022611_create_missing_namespace_for_internal_users.rb2
-rw-r--r--db/migrate/20181031145139_add_protected_ci_variables_to_application_settings.rb17
-rw-r--r--db/post_migrate/20181219145520_migrate_cluster_configure_worker_sidekiq_queue.rb15
-rw-r--r--db/schema.rb3
-rw-r--r--doc/administration/gitaly/index.md84
-rw-r--r--doc/api/lint.md2
-rw-r--r--doc/api/templates/gitlab_ci_ymls.md2
-rw-r--r--doc/ci/caching/index.md1
-rw-r--r--doc/ci/docker/using_kaniko.md23
-rw-r--r--doc/ci/examples/devops_and_game_dev_with_gitlab_ci_cd/index.md2
-rw-r--r--doc/ci/quick_start/README.md2
-rw-r--r--doc/ci/services/mysql.md4
-rw-r--r--doc/ci/yaml/README.md9
-rw-r--r--doc/development/contributing/merge_request_workflow.md1
-rw-r--r--doc/development/documentation/feature-change-workflow.md112
-rw-r--r--doc/development/documentation/improvement-workflow.md49
-rw-r--r--doc/development/documentation/index.md226
-rw-r--r--doc/development/documentation/site_architecture/index.md9
-rw-r--r--doc/development/documentation/structure.md168
-rw-r--r--doc/development/documentation/styleguide.md43
-rw-r--r--doc/development/documentation/workflow.md185
-rw-r--r--doc/development/instrumentation.md2
-rw-r--r--doc/install/installation.md2
-rw-r--r--doc/install/kubernetes/gitlab_chart.md3
-rw-r--r--doc/integration/google.md1
-rw-r--r--doc/update/10.0-to-10.1.md2
-rw-r--r--doc/update/10.1-to-10.2.md2
-rw-r--r--doc/update/10.2-to-10.3.md2
-rw-r--r--doc/update/10.3-to-10.4.md2
-rw-r--r--doc/update/10.4-to-10.5.md2
-rw-r--r--doc/update/10.5-to-10.6.md2
-rw-r--r--doc/update/10.6-to-10.7.md2
-rw-r--r--doc/update/10.7-to-10.8.md2
-rw-r--r--doc/update/10.8-to-11.0.md2
-rw-r--r--doc/update/11.0-to-11.1.md2
-rw-r--r--doc/update/11.1-to-11.2.md2
-rw-r--r--doc/update/11.2-to-11.3.md2
-rw-r--r--doc/update/11.3-to-11.4.md2
-rw-r--r--doc/update/11.4-to-11.5.md2
-rw-r--r--doc/update/11.5-to-11.6.md2
-rw-r--r--doc/update/6.9-to-7.0.md2
-rw-r--r--doc/update/6.x-or-7.x-to-7.14.md2
-rw-r--r--doc/update/7.0-to-7.1.md2
-rw-r--r--doc/update/8.10-to-8.11.md2
-rw-r--r--doc/update/8.11-to-8.12.md2
-rw-r--r--doc/update/8.12-to-8.13.md2
-rw-r--r--doc/update/8.13-to-8.14.md2
-rw-r--r--doc/update/8.14-to-8.15.md2
-rw-r--r--doc/update/8.15-to-8.16.md2
-rw-r--r--doc/update/8.16-to-8.17.md2
-rw-r--r--doc/update/8.17-to-9.0.md2
-rw-r--r--doc/update/9.0-to-9.1.md2
-rw-r--r--doc/update/9.1-to-9.2.md2
-rw-r--r--doc/update/9.2-to-9.3.md2
-rw-r--r--doc/update/9.3-to-9.4.md2
-rw-r--r--doc/update/9.4-to-9.5.md2
-rw-r--r--doc/update/9.5-to-10.0.md2
-rw-r--r--doc/update/upgrader.md91
-rw-r--r--doc/user/group/clusters/index.md4
-rw-r--r--doc/user/project/clusters/index.md31
-rw-r--r--doc/user/project/clusters/serverless/img/function-execution.pngbin0 -> 223762 bytes
-rw-r--r--doc/user/project/clusters/serverless/img/serverless-page.pngbin11829 -> 194708 bytes
-rw-r--r--doc/user/project/clusters/serverless/index.md107
-rw-r--r--doc/user/project/repository/index.md2
-rw-r--r--doc/user/snippets.md2
-rw-r--r--doc/workflow/todos.md3
-rw-r--r--lib/api/api.rb1
-rw-r--r--lib/api/branches.rb4
-rw-r--r--lib/api/entities.rb15
-rw-r--r--lib/api/groups.rb2
-rw-r--r--lib/api/helpers.rb16
-rw-r--r--lib/api/internal.rb3
-rw-r--r--lib/api/jobs.rb5
-rw-r--r--lib/api/releases.rb138
-rw-r--r--lib/api/tags.rb70
-rw-r--r--lib/backup/manager.rb2
-rw-r--r--lib/banzai/filter/external_link_filter.rb12
-rw-r--r--lib/banzai/filter/label_reference_filter.rb6
-rw-r--r--lib/gitlab/blob_helper.rb10
-rw-r--r--lib/gitlab/checks/base_checker.rb16
-rw-r--r--lib/gitlab/checks/diff_check.rb24
-rw-r--r--lib/gitlab/checks/lfs_check.rb1
-rw-r--r--lib/gitlab/ci/pipeline/chain/command.rb10
-rw-r--r--lib/gitlab/ci/pipeline/chain/skip.rb7
-rw-r--r--lib/gitlab/ci/pipeline/chain/validate/repository.rb4
-rw-r--r--lib/gitlab/ci/templates/Ruby.gitlab-ci.yml1
-rw-r--r--lib/gitlab/cleanup/remote_uploads.rb2
-rw-r--r--lib/gitlab/current_settings.rb31
-rw-r--r--lib/gitlab/data_builder/push.rb13
-rw-r--r--lib/gitlab/diff/file.rb54
-rw-r--r--lib/gitlab/discussions_diff/file_collection.rb76
-rw-r--r--lib/gitlab/discussions_diff/highlight_cache.rb67
-rw-r--r--lib/gitlab/git.rb4
-rw-r--r--lib/gitlab/git/blob.rb4
-rw-r--r--lib/gitlab/git_post_receive.rb5
-rw-r--r--lib/gitlab/gitaly_client.rb42
-rw-r--r--lib/gitlab/import_export/command_line_util.rb8
-rw-r--r--lib/gitlab/object_hierarchy.rb (renamed from lib/gitlab/group_hierarchy.rb)52
-rw-r--r--lib/gitlab/prometheus/metric_group.rb10
-rw-r--r--lib/gitlab/upgrader.rb111
-rw-r--r--lib/gitlab/utils/override.rb109
-rw-r--r--lib/json_web_token/hmac_token.rb2
-rw-r--r--lib/json_web_token/rsa_token.rb3
-rw-r--r--locale/gitlab.pot64
-rw-r--r--package.json2
-rw-r--r--qa/Dockerfile2
-rw-r--r--qa/qa/page/base.rb12
-rw-r--r--qa/qa/page/main/login.rb12
-rw-r--r--qa/qa/page/main/menu.rb8
-rw-r--r--qa/qa/page/project/issue/show.rb6
-rw-r--r--qa/qa/support/page/logging.rb17
-rw-r--r--qa/spec/page/logging_spec.rb16
-rw-r--r--scripts/prepare_build.sh2
-rw-r--r--spec/controllers/groups/group_members_controller_spec.rb10
-rw-r--r--spec/controllers/groups/settings/ci_cd_controller_spec.rb55
-rw-r--r--spec/controllers/projects/avatars_controller_spec.rb36
-rw-r--r--spec/controllers/projects/ci/lints_controller_spec.rb1
-rw-r--r--spec/controllers/projects/clusters_controller_spec.rb4
-rw-r--r--spec/controllers/projects/issues_controller_spec.rb4
-rw-r--r--spec/controllers/projects/jobs_controller_spec.rb35
-rw-r--r--spec/controllers/projects/merge_requests_controller_spec.rb95
-rw-r--r--spec/controllers/projects/project_members_controller_spec.rb18
-rw-r--r--spec/controllers/projects/raw_controller_spec.rb75
-rw-r--r--spec/controllers/projects/refs_controller_spec.rb14
-rw-r--r--spec/controllers/projects/snippets_controller_spec.rb40
-rw-r--r--spec/controllers/projects/tags/releases_controller_spec.rb7
-rw-r--r--spec/controllers/projects/wikis_controller_spec.rb85
-rw-r--r--spec/controllers/projects_controller_spec.rb24
-rw-r--r--spec/controllers/snippets_controller_spec.rb41
-rw-r--r--spec/db/importers/common_metrics_importer_spec.rb8
-rw-r--r--spec/factories/appearances.rb4
-rw-r--r--spec/factories/notes.rb15
-rw-r--r--spec/factories/releases.rb7
-rw-r--r--spec/features/admin/admin_disables_git_access_protocol_spec.rb59
-rw-r--r--spec/features/group_variables_spec.rb2
-rw-r--r--spec/features/groups/show_spec.rb4
-rw-r--r--spec/features/issues/gfm_autocomplete_spec.rb44
-rw-r--r--spec/features/issues/user_creates_issue_spec.rb6
-rw-r--r--spec/features/merge_request/user_creates_image_diff_notes_spec.rb33
-rw-r--r--spec/features/merge_request/user_sees_diff_spec.rb70
-rw-r--r--spec/features/merge_request/user_sees_versions_spec.rb11
-rw-r--r--spec/features/merge_request/user_tries_to_access_private_repository_through_new_mr_spec.rb37
-rw-r--r--spec/features/profiles/user_edit_profile_spec.rb14
-rw-r--r--spec/features/projects/clusters/gcp_spec.rb2
-rw-r--r--spec/features/projects/commits/user_browses_commits_spec.rb2
-rw-r--r--spec/features/runners_spec.rb3
-rw-r--r--spec/features/users/overview_spec.rb9
-rw-r--r--spec/finders/releases_finder_spec.rb42
-rw-r--r--spec/fixtures/api/schemas/entities/diff_viewer.json16
-rw-r--r--spec/fixtures/api/schemas/entities/issuable_sidebar_todo.json8
-rw-r--r--spec/fixtures/api/schemas/entities/issue_sidebar.json54
-rw-r--r--spec/fixtures/api/schemas/entities/issue_sidebar_extras.json18
-rw-r--r--spec/fixtures/api/schemas/entities/merge_request_basic.json6
-rw-r--r--spec/fixtures/api/schemas/entities/merge_request_sidebar.json56
-rw-r--r--spec/fixtures/api/schemas/entities/merge_request_sidebar_extras.json21
-rw-r--r--spec/fixtures/api/schemas/public_api/v4/milestone.json22
-rw-r--r--spec/fixtures/api/schemas/public_api/v4/milestones.json21
-rw-r--r--spec/fixtures/api/schemas/release.json18
-rw-r--r--spec/fixtures/api/schemas/releases.json4
-rw-r--r--spec/fixtures/gitlab/ci/external_files/.gitlab-ci-template-1.yml1
-rw-r--r--spec/fixtures/symlink_export.tar.gzbin0 -> 435 bytes
-rw-r--r--spec/helpers/diff_helper_spec.rb37
-rw-r--r--spec/helpers/issuables_helper_spec.rb36
-rw-r--r--spec/helpers/projects_helper_spec.rb110
-rw-r--r--spec/initializers/active_record_locking_spec.rb44
-rw-r--r--spec/initializers/zz_metrics_spec.rb (renamed from spec/initializers/8_metrics_spec.rb)2
-rw-r--r--spec/javascripts/ci_variable_list/ci_variable_list_spec.js2
-rw-r--r--spec/javascripts/fixtures/blob.rb9
-rw-r--r--spec/javascripts/fixtures/boards.rb7
-rw-r--r--spec/javascripts/fixtures/branches.rb3
-rw-r--r--spec/javascripts/fixtures/clusters.rb3
-rw-r--r--spec/javascripts/fixtures/commit.rb2
-rw-r--r--spec/javascripts/fixtures/deploy_keys.rb6
-rw-r--r--spec/javascripts/fixtures/groups.rb6
-rw-r--r--spec/javascripts/fixtures/issues.rb6
-rw-r--r--spec/javascripts/fixtures/jobs.rb13
-rw-r--r--spec/javascripts/fixtures/labels.rb12
-rw-r--r--spec/javascripts/fixtures/merge_requests.rb12
-rw-r--r--spec/javascripts/fixtures/merge_requests_diffs.rb4
-rw-r--r--spec/javascripts/fixtures/pipeline_schedules.rb6
-rw-r--r--spec/javascripts/fixtures/pipelines.rb6
-rw-r--r--spec/javascripts/fixtures/projects.rb15
-rw-r--r--spec/javascripts/fixtures/prometheus_service.rb3
-rw-r--r--spec/javascripts/fixtures/services.rb3
-rw-r--r--spec/javascripts/fixtures/snippet.rb2
-rw-r--r--spec/javascripts/fixtures/todos.rb6
-rw-r--r--spec/javascripts/fixtures/u2f.rb2
-rw-r--r--spec/javascripts/notes/components/discussion_filter_spec.js36
-rw-r--r--spec/javascripts/notes/components/noteable_discussion_spec.js73
-rw-r--r--spec/javascripts/releases/components/release_block_spec.js20
-rw-r--r--spec/javascripts/sidebar/mock_data.js4
-rw-r--r--spec/javascripts/sidebar/sidebar_mediator_spec.js4
-rw-r--r--spec/javascripts/vue_mr_widget/mr_widget_options_spec.js49
-rw-r--r--spec/javascripts/vue_shared/components/user_popover/user_popover_spec.js14
-rw-r--r--spec/lib/api/helpers_spec.rb32
-rw-r--r--spec/lib/banzai/filter/external_link_filter_spec.rb8
-rw-r--r--spec/lib/banzai/filter/label_reference_filter_spec.rb18
-rw-r--r--spec/lib/banzai/filter/milestone_reference_filter_spec.rb30
-rw-r--r--spec/lib/gitlab/bare_repository_import/importer_spec.rb2
-rw-r--r--spec/lib/gitlab/blob_helper_spec.rb4
-rw-r--r--spec/lib/gitlab/checks/diff_check_spec.rb38
-rw-r--r--spec/lib/gitlab/ci/config/external/file/local_spec.rb1
-rw-r--r--spec/lib/gitlab/ci/config/external/file/remote_spec.rb1
-rw-r--r--spec/lib/gitlab/ci/config/external/processor_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config_spec.rb1
-rw-r--r--spec/lib/gitlab/ci/pipeline/chain/command_spec.rb20
-rw-r--r--spec/lib/gitlab/ci/pipeline/chain/populate_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/pipeline/chain/validate/repository_spec.rb21
-rw-r--r--spec/lib/gitlab/ci/pipeline/seed/build_spec.rb3
-rw-r--r--spec/lib/gitlab/ci/pipeline/seed/stage_spec.rb3
-rw-r--r--spec/lib/gitlab/cleanup/remote_uploads_spec.rb2
-rw-r--r--spec/lib/gitlab/current_settings_spec.rb80
-rw-r--r--spec/lib/gitlab/diff/file_spec.rb8
-rw-r--r--spec/lib/gitlab/diff/lines_unfolder_spec.rb2
-rw-r--r--spec/lib/gitlab/discussions_diff/file_collection_spec.rb61
-rw-r--r--spec/lib/gitlab/discussions_diff/highlight_cache_spec.rb102
-rw-r--r--spec/lib/gitlab/git/blob_spec.rb8
-rw-r--r--spec/lib/gitlab/git_access_spec.rb18
-rw-r--r--spec/lib/gitlab/gitaly_client/blobs_stitcher_spec.rb4
-rw-r--r--spec/lib/gitlab/gitaly_client_spec.rb82
-rw-r--r--spec/lib/gitlab/import_export/command_line_util_spec.rb38
-rw-r--r--spec/lib/gitlab/import_export/file_importer_spec.rb13
-rw-r--r--spec/lib/gitlab/legacy_github_import/importer_spec.rb2
-rw-r--r--spec/lib/gitlab/object_hierarchy_spec.rb (renamed from spec/lib/gitlab/group_hierarchy_spec.rb)10
-rw-r--r--spec/lib/gitlab/project_authorizations_spec.rb4
-rw-r--r--spec/lib/gitlab/prometheus/metric_group_spec.rb7
-rw-r--r--spec/lib/gitlab/upgrader_spec.rb40
-rw-r--r--spec/lib/gitlab/utils/override_spec.rb32
-rw-r--r--spec/lib/json_web_token/rsa_token_spec.rb4
-rw-r--r--spec/mailers/notify_spec.rb12
-rw-r--r--spec/migrations/migrate_cluster_configure_worker_sidekiq_queue_spec.rb68
-rw-r--r--spec/models/appearance_spec.rb30
-rw-r--r--spec/models/blob_spec.rb22
-rw-r--r--spec/models/ci/build_spec.rb12
-rw-r--r--spec/models/ci/pipeline_spec.rb4
-rw-r--r--spec/models/clusters/applications/cert_manager_spec.rb6
-rw-r--r--spec/models/clusters/applications/runner_spec.rb6
-rw-r--r--spec/models/clusters/platforms/kubernetes_spec.rb7
-rw-r--r--spec/models/concerns/cacheable_attributes_spec.rb8
-rw-r--r--spec/models/concerns/discussion_on_diff_spec.rb10
-rw-r--r--spec/models/concerns/has_ref_spec.rb59
-rw-r--r--spec/models/diff_note_spec.rb17
-rw-r--r--spec/models/diff_viewer/base_spec.rb23
-rw-r--r--spec/models/diff_viewer/server_side_spec.rb20
-rw-r--r--spec/models/event_spec.rb18
-rw-r--r--spec/models/merge_request_spec.rb51
-rw-r--r--spec/models/milestone_spec.rb9
-rw-r--r--spec/models/namespace_spec.rb54
-rw-r--r--spec/models/project_spec.rb194
-rw-r--r--spec/models/prometheus_metric_spec.rb54
-rw-r--r--spec/models/release_spec.rb4
-rw-r--r--spec/models/remote_mirror_spec.rb14
-rw-r--r--spec/models/repository_spec.rb61
-rw-r--r--spec/models/snippet_spec.rb37
-rw-r--r--spec/models/user_spec.rb4
-rw-r--r--spec/policies/group_policy_spec.rb21
-rw-r--r--spec/policies/issuable_policy_spec.rb27
-rw-r--r--spec/policies/project_policy_spec.rb21
-rw-r--r--spec/presenters/clusterable_presenter_spec.rb64
-rw-r--r--spec/requests/api/branches_spec.rb12
-rw-r--r--spec/requests/api/events_spec.rb4
-rw-r--r--spec/requests/api/files_spec.rb14
-rw-r--r--spec/requests/api/internal_spec.rb10
-rw-r--r--spec/requests/api/jobs_spec.rb32
-rw-r--r--spec/requests/api/releases_spec.rb532
-rw-r--r--spec/requests/api/repositories_spec.rb2
-rw-r--r--spec/requests/api/runner_spec.rb2
-rw-r--r--spec/requests/api/tags_spec.rb33
-rw-r--r--spec/requests/lfs_http_spec.rb2
-rw-r--r--spec/requests/openid_connect_spec.rb2
-rw-r--r--spec/requests/rack_attack_global_spec.rb2
-rw-r--r--spec/serializers/entity_date_helper_spec.rb12
-rw-r--r--spec/serializers/issue_serializer_spec.rb10
-rw-r--r--spec/serializers/merge_request_basic_serializer_spec.rb16
-rw-r--r--spec/serializers/merge_request_serializer_spec.rb12
-rw-r--r--spec/services/auth/container_registry_authentication_service_spec.rb2
-rw-r--r--spec/services/ci/create_pipeline_service_spec.rb34
-rw-r--r--spec/services/ci/register_job_service_spec.rb4
-rw-r--r--spec/services/clusters/gcp/finalize_creation_service_spec.rb6
-rw-r--r--spec/services/clusters/update_service_spec.rb2
-rw-r--r--spec/services/create_release_service_spec.rb39
-rw-r--r--spec/services/groups/create_service_spec.rb4
-rw-r--r--spec/services/groups/nested_create_service_spec.rb2
-rw-r--r--spec/services/groups/transfer_service_spec.rb2
-rw-r--r--spec/services/groups/update_service_spec.rb2
-rw-r--r--spec/services/issuable/bulk_update_service_spec.rb27
-rw-r--r--spec/services/issues/update_service_spec.rb2
-rw-r--r--spec/services/members/destroy_service_spec.rb2
-rw-r--r--spec/services/members/update_service_spec.rb17
-rw-r--r--spec/services/merge_requests/build_service_spec.rb55
-rw-r--r--spec/services/notification_service_spec.rb8
-rw-r--r--spec/services/projects/after_rename_service_spec.rb20
-rw-r--r--spec/services/projects/lfs_pointers/lfs_download_service_spec.rb59
-rw-r--r--spec/services/projects/transfer_service_spec.rb20
-rw-r--r--spec/services/projects/update_service_spec.rb4
-rw-r--r--spec/services/releases/create_service_spec.rb72
-rw-r--r--spec/services/releases/destroy_service_spec.rb61
-rw-r--r--spec/services/releases/update_service_spec.rb50
-rw-r--r--spec/services/todo_service_spec.rb1
-rw-r--r--spec/services/update_release_service_spec.rb34
-rw-r--r--spec/spec_helper.rb6
-rw-r--r--spec/support/api/boards_shared_examples.rb15
-rw-r--r--spec/support/api/milestones_shared_examples.rb31
-rw-r--r--spec/support/api/scopes/read_user_shared_examples.rb2
-rw-r--r--spec/support/api/time_tracking_shared_examples.rb22
-rw-r--r--spec/support/controllers/githubish_import_controller_shared_examples.rb34
-rw-r--r--spec/support/features/variable_list_shared_examples.rb46
-rw-r--r--spec/support/gitlab_stubs/gitlab_ci.yml3
-rw-r--r--spec/support/helpers/fake_blob_helpers.rb2
-rw-r--r--spec/support/helpers/git_http_helpers.rb8
-rw-r--r--spec/support/helpers/graphql_helpers.rb2
-rw-r--r--spec/support/helpers/kubernetes_helpers.rb20
-rw-r--r--spec/support/helpers/migrations_helpers.rb16
-rw-r--r--spec/support/helpers/test_env.rb3
-rw-r--r--spec/support/import_export/export_file_helper.rb2
-rw-r--r--spec/support/issuables_requiring_filter_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/controllers/uploads_actions_shared_examples.rb11
-rw-r--r--spec/support/shared_examples/milestone_tabs_examples.rb2
-rw-r--r--spec/support/shared_examples/policies/clusterable_shared_examples.rb37
-rw-r--r--spec/support/shared_examples/requests/api/diff_discussions.rb8
-rw-r--r--spec/support/shared_examples/requests/api/discussions.rb16
-rw-r--r--spec/support/shared_examples/requests/api/merge_requests_list.rb16
-rw-r--r--spec/support/shared_examples/requests/api/notes.rb26
-rw-r--r--spec/support/shared_examples/requests/api/resolvable_discussions.rb16
-rw-r--r--spec/uploaders/file_uploader_spec.rb2
-rw-r--r--spec/uploaders/object_storage_spec.rb2
-rw-r--r--spec/views/notify/changed_milestone_email.html.haml_spec.rb35
-rw-r--r--spec/views/projects/merge_requests/show.html.haml_spec.rb5
-rw-r--r--spec/workers/cluster_configure_worker_spec.rb (renamed from spec/workers/cluster_platform_configure_worker_spec.rb)2
-rw-r--r--spec/workers/cluster_provision_worker_spec.rb4
-rw-r--r--spec/workers/mail_scheduler/notification_service_worker_spec.rb17
-rw-r--r--yarn.lock8
846 files changed, 7468 insertions, 4130 deletions
diff --git a/.gitlab/CODEOWNERS.disabled b/.gitlab/CODEOWNERS.disabled
index 82e914a502f..b9f886c1d47 100644
--- a/.gitlab/CODEOWNERS.disabled
+++ b/.gitlab/CODEOWNERS.disabled
@@ -1,6 +1,6 @@
# Backend Maintainers are the default for all ruby files
-*.rb @ayufan @DouweM @dzaporozhets @grzesiek @nick.thomas @rspeicher @rymai @smcgivern
-*.rake @ayufan @DouweM @dzaporozhets @grzesiek @nick.thomas @rspeicher @rymai @smcgivern
+*.rb @ayufan @dbalexandre @DouweM @dzaporozhets @godfat @grzesiek @nick.thomas @rspeicher @rymai @smcgivern
+*.rake @ayufan @dbalexandre @DouweM @dzaporozhets @godfat @grzesiek @nick.thomas @rspeicher @rymai @smcgivern
# Technical writing team are the default reviewers for everything in `doc/`
/doc/ @axil @marcia
diff --git a/.gitlab/issue_templates/Feature proposal.md b/.gitlab/issue_templates/Feature proposal.md
index ad517f0457d..639a236631d 100644
--- a/.gitlab/issue_templates/Feature proposal.md
+++ b/.gitlab/issue_templates/Feature proposal.md
@@ -4,7 +4,7 @@
### Target audience
-<!--- For whom are we doing this? Include either a persona from https://design.gitlab.com/#/getting-started/personas or define a specific company role. e.a. "Release Manager" or "Security Analyst" -->
+<!--- For whom are we doing this? Include either a persona from https://design.gitlab.com/getting-started/personas or define a specific company role. e.a. "Release Manager" or "Security Analyst" -->
### Further details
diff --git a/CHANGELOG.md b/CHANGELOG.md
index a51ac887aed..a1c928aedf3 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,315 @@
documentation](doc/development/changelog.md) for instructions on adding your own
entry.
+## 11.6.1 (2018-12-28)
+
+### Security (15 changes)
+
+- Escape label and milestone titles to prevent XSS in GFM autocomplete. !2740
+- Prevent private snippets from being embeddable.
+- Add subresources removal to member destroy service.
+- Escape html entities in LabelReferenceFilter when no label found.
+- Allow changing group CI/CD settings only for owners.
+- Authorize before reading job information via API.
+- Prevent leaking protected variables for ambiguous refs.
+- Ensure that build token is only used when running.
+- Issuable no longer is visible to users when project can't be viewed.
+- Don't expose cross project repositories through diffs when creating merge reqeusts.
+- Fix SSRF with import_url and remote mirror url.
+- Fix persistent symlink in project import.
+- Set URL rel attribute for broken URLs.
+- Project guests no longer are able to see refs page.
+- Delete confidential todos for user when downgraded to Guest.
+
+### Other (1 change)
+
+- Fix due date test. !23845
+
+
+## 11.6.0 (2018-12-22)
+
+### Security (24 changes, 1 of them is from the community)
+
+- Fix possible XSS attack in Markdown urls with spaces. !2599
+- Update rack to 2.0.6 (for QA environments). !23171 (Takuya Noguchi)
+- Bump nokogiri, loofah, and rack gems for security updates. !23204
+- Encrypt runners tokens. !23412
+- Encrypt CI/CD builds authentication tokens. !23436
+- Configure mermaid to not render HTML content in diagrams.
+- Fix a possible symlink time of check to time of use race condition in GitLab Pages.
+- Removed ability to see private group names when the group id is entered in the url.
+- Fix stored XSS for Environments.
+- Fix persistent symlink in project import.
+- Fixed ability of guest users to edit/delete comments on locked or confidential issues.
+- Fixed ability to comment on locked/confidential issues.
+- Fix CRLF vulnerability in Project hooks.
+- Fix SSRF in project integrations.
+- Resolve reflected XSS in Ouath authorize window.
+- Restrict Personal Access Tokens to API scope on web requests.
+- Provide email notification when a user changes their email address.
+- Don't expose confidential information in commit message list.
+- Validate LFS hrefs before downloading them.
+- Do not follow redirects in Prometheus service when making http requests to the configured api url.
+- Escape user fullname while rendering autocomplete template to prevent XSS.
+- Redact sensitive information on gitlab-workhorse log.
+- Fix milestone promotion authorization check.
+- Prevent a path traversal attack on global file templates.
+
+### Removed (1 change)
+
+- Remove obsolete gitlab_shell rake tasks. !22417
+
+### Fixed (86 changes, 13 of them are from the community)
+
+- Remove limit of 100 when searching repository code. !8671
+- Show error message when attempting to reopen an MR and there is an open MR for the same branch. !16447 (Akos Gyimesi)
+- Fix a bug where internal email pattern wasn't respected. !22516
+- Fix project selector consistency in groups issues / MRs / boards pages. !22612 (Heinrich Lee Yu)
+- Add empty state for graphs with no values. !22630
+- Fix navigating by unresolved discussions on Merge Request page. !22789
+- Fix "merged with [commit]" info for merge requests being merged automatically by other actions. !22794
+- Fixing regression issues on pages settings and details. !22821
+- Remove duplicate primary button in dashboard snippets on small viewports. !22902 (George Tsiolis)
+- Fix API::Namespaces routing to accept namepaces with dots. !22912
+- Switch kubernetes:active with checking in Auto-DevOps.gitlab-ci.yml. !22929
+- Avoid Gitaly RPC errors when fetching diff stats. !22995
+- Removes promote to group label for anonymous user. !23042 (Jacopo Beschi @jacopo-beschi)
+- Fix enabling project deploy key for admins. !23043
+- Align issue status label and confidential icon. !23046 (George Tsiolis)
+- Fix default sorting for subgroups and projects list. !23058 (Jacopo Beschi @jacopo-beschi)
+- Hashed Storage: allow migration to be retried in partially migrated projects. !23087
+- Fix line height of numbers in file blame view. !23090 (Johann Hubert Sonntagbauer)
+- Fixes an issue where default values from models would override values set in the interface (e.g. users would be set to external even though their emails matches the internal email address pattern). !23114
+- Remove display of local Sidekiq process in /admin/sidekiq. !23118
+- Fix unrelated deployment status in MR widget. !23175
+- Respect confirmed flag on secondary emails. !23181
+- Restrict member access level to be higher than that of any parent group. !23226
+- Return real deployment status to frontend. !23270
+- Handle force_remove_source_branch when creating merge request. !23281
+- Avoid creating invalid refs using rugged, shelling out for writing refs. !23286
+- Remove needless auto-capitalization on Wiki page titles. !23288
+- Modify the wording for the knative cluster application to match upstream. !23289 (Chris Baumbauer)
+- Change container width for project import. !23318 (George Tsiolis)
+- Validate chunk size when persist. !23341
+- Resolve Main navbar is broken in certain viewport widths. !23348
+- Gracefully handle references with null bytes. !23365
+- Display commit ID for commit diff discussion on merge request. !23370
+- Pass commit when posting diff discussions. !23371
+- Fix flash notice styling for fluid layout. !23382
+- Add monkey patch to unicorn to fix eof? problem. !23385
+- Commits API: Preserve file content in move operations if unspecified. !23387
+- Disable password autocomplete in mirror form fill. !23402
+- Fix "protected branches only" checkbox not set properly at init. !23409
+- Support RSA and ECDSA algorithms in Omniauth JWT provider. !23411 (Michael Tsyganov)
+- Make KUBECONFIG nil if KUBE_TOKEN is nil. !23414
+- Allow search and sort users at same time on admin users page. !23439
+- Fix: Unstar icon button is misaligned. !23444
+- Fix error when searching for group issues with priority or popularity sort. !23445
+- Fix Order By dropdown menu styling in tablet and mobile screens. !23446
+- Fix collapsing discussion replies. !23462
+- Gracefully handle unknown/invalid GPG keys. !23492
+- Fix multiple commits shade overlapping vertical discussion line. !23515
+- Use read_repository scope on read-only files API. !23534
+- Avoid 500's when serializing legacy diff notes. !23544
+- Fix web hook functionality when the database encryption key is too short. !23573
+- Hide Knative from group cluster applications until supported. !23577
+- Add top padding for nested environment items loading icon. !23580 (George Tsiolis)
+- Improve help and validation sections of maximum build timeout inputs. !23586
+- Fix milestone select in issue sidebar of issue boards. !23625
+- Fix gitlab:web_hook tasks. !23635
+- Avoid caching BroadcastMessage as an ActiveRecord object. !23662
+- Only allow strings in URL::Sanitizer.valid?. !23675
+- Fix a frozen string error in app/mailers/notify.rb. !23683
+- Fix a frozen string error in lib/gitlab/utils.rb. !23690
+- Fix MR resolved discussion counts being too low. !23710
+- Fix a potential frozen string error in app/mailers/notify.rb. !23728
+- Remove unnecessary div from MarkdownField to apply list styles correctly. !23733
+- Display reply field if resolved discussion has no replies. !23801
+- Restore kubernetes:active in Auto-DevOps.gitlab-ci.yml (reverts 22929). !23826
+- Fix mergeUrlParams with fragment URL. !54218 (Thomas Holder)
+- Fixed multiple diff line discussions not expanding.
+- Fixed diff files expanding not loading commit content.
+- Fixed styling of image comment badges on commits.
+- Resolve possible cherry pick API race condition.
+- When user clicks linenumber in MR changes, highlight that line.
+- Remove old webhook logs after 90 days, as documented, instead of after 2.
+- Add an external IP address to the knative cluster application page. (Chris Baumbauer)
+- Fixed duplicate discussions getting added to diff lines.
+- Fix deadlock on ChunkedIO.
+- Show tree collapse button for merge request commit diffs.
+- Use approximate count for big tables for usage statistics.
+- Lock writes to trace stream.
+- Ensure that SVG sprite icons are properly rendered in IE11.
+- Make new branch form fields' fonts consistent.
+- Open first 10 merge request files in IDE.
+- Prevent user from navigating away from file edit without commit.
+- Prevent empty button being rendered in empty state.
+- Adds margins between tags when a job is stuck.
+- Fix Image Lazy Loader for some older browsers.
+- Correctly styles tags in sidebar for job page.
+
+### Changed (34 changes, 9 of them are from the community)
+
+- Include new link in breadcrumb for issues, merge requests, milestones, and labels. !18515 (George Tsiolis)
+- Allow sorting issues and MRs in reverse order. !21438
+- Design improvements to project overview page. !22196
+- Remove auto deactivation when failed to create a pipeline via pipeline schedules. !22243
+- Use group clusters when deploying (DeploymentPlatform). !22308
+- Improve initial discussion rendering performance. !22607
+- removes partially matching of No Label filter and makes it case-insensitive. !22622 (Jacopo Beschi @jacopo-beschi)
+- Use search bar for filtering in dashboard issues / MRs. !22641 (Heinrich Lee Yu)
+- Show different empty state for filtered issues and MRs. !22775 (Heinrich Lee Yu)
+- Relocate JSONWebToken::HMACToken from EE. !22906
+- Resolve Add border around the repository file tree. !23018
+- Change breadcrumb title for contribution charts. !23071 (George Tsiolis)
+- Update environments metrics empty state. !23074 (George Tsiolis)
+- Refine cursor positioning in Markdown Editor for wrap tags. !23085 (Johann Hubert Sonntagbauer)
+- Use reports syntax for SAST in Auto DevOps. !23163
+- SystemCheck: Use a more reliable way to detect current Ruby version. !23291
+- Changed frontmatter filtering to support YAML, JSON, TOML, and arbitrary languages. !23331 (Travis Miller)
+- Don't remove failed install pods after installing GitLab managed applications. !23350
+- Expose merge request pipeline variables. !23398
+- Scope default MR search in WebIDE dropdown to current project. !23400
+- Show user contributions in correct timezone within user profile. !23419
+- Redesign of MR header sections (CE). !23465
+- Auto DevOps: Add echo for each branch of the deploy() function where we run helm upgrade. !23499
+- Updates service to update Kubernetes project namespaces and restricted service account if present. !23525
+- Adjust divider margin to comply with design specs. !23548
+- Adjust dropdown item and header padding to comply with design specs. !23552
+- Truncate merge request titles with periods instead of ellipsis. !23558
+- Remove close icon from projects dropdown in issue boards. !23567
+- Change dropdown divider color to gray-200 (#dfdfdf). !23592
+- Define the default value for only/except policies. !23765
+- Don't show Memory Usage for unmerged MRs.
+- reorder notification settings by noisy-ness. (C.J. Jameson)
+- Changed merge request filtering to be by path instead of name.
+- Make diff file headers sticky.
+
+### Performance (22 changes, 6 of them are from the community)
+
+- Upgrade to Ruby 2.5.3. !2806
+- Removes all the irrelevant code and columns that were migrated from the Project table over to the ProjectImportState table. !21497
+- Approximate counting strategy with TABLESAMPLE. !22650
+- Replace tooltip directive with gl-tooltip diretive in badges, cycle analytics, and diffs. !22770 (George Tsiolis)
+- Validate foreign keys being created and indexed for column with _id. !22808
+- Remove monospace extend. !23089 (George Tsiolis)
+- Use Nokogiri as the ActiveSupport XML backend. !23136
+- Improve memory performance by reducing dirty pages after fork(). !23169
+- Add partial index for ci_builds on project_id and status. !23268
+- Reduce Gitaly calls in projects dashboard. !23307
+- Batch load only data from same repository when lazy object is accessed. !23309
+- Add index for events on project_id and created_at. !23354
+- Remove index for notes on updated_at. !23356
+- Improves performance of Project#readme_url by caching the README path. !23357
+- Populate MR metrics with events table information (migration). !23564
+- Remove unused data from discussions endpoint. !23570
+- Speed up issue board lists in groups with many projects.
+- Use cached size when passing artifacts to Runner.
+- Enable even more frozen string for lib/gitlab. (gfyoung)
+- Enable even more frozen string in lib/gitlab/**/*.rb. (gfyoung)
+- Enable even more frozen string in lib/gitlab/**/*.rb. (gfyoung)
+- Enable even more frozen string for lib/gitlab. (gfyoung)
+
+### Added (32 changes, 13 of them are from the community)
+
+- Add ability to create group level clusters and install gitlab managed applications. !22450
+- Creates /create_merge_request quickaction. !22485 (Jacopo Beschi @jacopo-beschi)
+- Filter by None/Any for labels in issues/mrs API. !22622 (Jacopo Beschi @jacopo-beschi)
+- Chat message push notifications now include links back to GitLab branches. !22651 (Tony Castrogiovanni)
+- Added feature flag to signal content headers detection by Workhorse. !22667
+- Add Discord integration. !22684 (@blackst0ne)
+- Upgrade helm to 2.11.0 and upgrade on every install. !22693
+- Add knative client to kubeclient library. !22968 (cab105)
+- Allow SSH public-key authentication for push mirroring. !22982
+- Allow deleting a Pipeline via the API. !22988
+- #40635: Adds support for cert-manager. !23036 (Amit Rathi)
+- WebIDE: Pressing Ctrl-Enter while typing on the commit message now performs the commit action. !23049 (Thomas Pathier)
+- Adds Any option to label filters. !23111 (Jacopo Beschi @jacopo-beschi)
+- Added glob for CI changes detection. !23128 (Kirill Zaitsev)
+- Add model and relation to store repo full path in database. !23143
+- Add ability to render suggestions. !23147
+- Introduce Knative and Serverless Components. !23174 (Chris Baumbauer)
+- Use BFG object maps to clean projects. !23189
+- Merge request pipelines. !23217
+- Extended user centric tooltips on issue and MR page. !23231
+- Add a rebase API endpoint for merge requests. !23296
+- Add config to prohibit impersonation. !23338
+- Merge request pipeline tag, and adds tags to pipeline view. !23364
+- #52753: HTTPS for JupyterHub installation. !23479 (Amit Rathi)
+- Fill project_repositories for hashed storage projects. !23482
+- Ability to override email for cert-manager. !23503 (Amit Rathi)
+- Allow public forks to be deduplicated. !23508
+- Pipeline trigger variable values are hidden in the UI by default. Maintainers have the option to reveal them. !23518 (jhampton)
+- Add new endpoint to download single artifact file for a ref. !23538
+- Log and pass correlation-id between Unicorn, Sidekiq and Gitaly.
+- Allow user to scroll to top of tab on MR page.
+- Adds states to the deployment widget.
+
+### Other (54 changes, 30 of them are from the community)
+
+- Switch to Rails 5. !21492
+- Migration to write fullpath in all repository configs. !22322
+- Rails5: env is deprecated and will be removed from Rails 5.1. !22626 (Jasper Maes)
+- Update haml_lint to 0.28.0. !22660 (Takuya Noguchi)
+- Update ffaker to 2.10.0. !22661 (Takuya Noguchi)
+- Drop gcp_clusters table. !22713
+- Upgrade minimum required Git version to 2.18.0. !22803
+- Adds new icon size to Vue icon component. !22899
+- Make sure there's only one slash as path separator. !22954
+- Show HTTP response code for Kubernetes errors. !22964
+- Update config map for gitlab managed application if already present on install. !22969
+- Drop default value on status column in deployments table. !22971
+- UI improvements to user's profile. !22977
+- Update asana to 0.8.1. !23039 (Takuya Noguchi)
+- Update asciidoctor to 1.5.8. !23047 (Takuya Noguchi)
+- Make auto-generated icons for subgroups in the breadcrumb dropdown display as a circle. !23062 (Thomas Pathier)
+- Make reply shortcut only quote selected discussion text. !23096 (Thomas Pathier)
+- Fix typo in notebook props. !23103 (George Tsiolis)
+- Fix typos in lib. !23106 (George Tsiolis)
+- Rename diffs store variable. !23123 (George Tsiolis)
+- Fix overlapping navbar separator and overflowing navbar dropdown on small displays. !23126 (Thomas Pathier)
+- Show what RPC is called in the performance bar. !23140
+- Updated Gitaly to v0.133.0. !23148
+- Rails5: Passing a class as a value in an Active Record query is deprecated. !23164 (Jasper Maes)
+- Fix project identicon aligning Harry Kiselev. !23166 (Harry Kiselev)
+- Fix horizontal scrollbar overlapping on horizontal scrolling-tabs. !23167 (Harry Kiselev)
+- Fix bottom paddings of profile header and some markup updates of profile. !23168 (Harry Kiselev)
+- Fixes to AWS documentation spelling and grammar. !23198 (Brendan O'Leary)
+- Adds a PHILOSOPHY.md which references GitLab Product Handbook. !23200
+- Externalize strings from `/app/views/invites`. !23205 (Tao Wang)
+- Externalize strings from `/app/views/project/runners`. !23208 (Tao Wang)
+- Fix typo for scheduled pipeline. !23218 (Davy Defaud)
+- Force content disposition attachment to several endpoints. !23223
+- Upgrade kubeclient to 4.0.0. !23261 (Praveen Arimbrathodiyil @pravi)
+- Update used version of Runner Helm Chart to 0.1.38. !23304
+- render :nothing option is deprecated, Use head method to respond with empty response body. !23311 (Jasper Maes)
+- Passing an argument to force an association to reload is now deprecated. !23334 (Jasper Maes)
+- Externalize strings from `/app/views/snippets`. !23351 (Tao Wang)
+- Fix deprecation: You are passing an instance of ActiveRecord::Base to. !23369 (Jasper Maes)
+- Resolve status emoji being replaced by avatar on mobile. !23408
+- Fix deprecation: render :text is deprecated because it does not actually render a text/plain response. !23425 (Jasper Maes)
+- Fix lack of documentation on how to fetch a snippet's content using API. !23448 (Colin Leroy)
+- Upgrade GitLab Workhorse to v7.3.0. !23489
+- Fallback to admin KUBE_TOKEN for project clusters only. !23527
+- Update used version of Runner Helm Chart to 0.1.39. !23633
+- Show primary button when all labels are prioritized. !23648 (George Tsiolis)
+- Upgrade workhorse to 7.6.0. !23694
+- Upgrade Gitaly to v1.7.1 for correlation-id logging. !23732
+- Fix due date test. !23845
+- Remove unused project method. !54103 (George Tsiolis)
+- Uses new gitlab-ui components in Jobs and Pipelines components.
+- Replaces tooltip directive with the new gl-tooltip directive for consistency in some ci/cd code.
+- Bump gpgme gem version from 2.0.13 to 2.0.18. (asaparov)
+- Enable Rubocop on lib/gitlab. (gfyoung)
+
+
+## 11.5.5 (2018-12-20)
+
+### Security (1 change)
+
+- Fix persistent symlink in project import.
+
+
## 11.5.3 (2018-12-06)
### Security (1 change)
@@ -628,6 +937,13 @@ entry.
- Check frozen string in style builds. (gfyoung)
+## 11.3.14 (2018-12-20)
+
+### Security (1 change)
+
+- Fix persistent symlink in project import.
+
+
## 11.3.13 (2018-12-13)
### Security (1 change)
diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION
index f8e233b2733..0eed1a29efd 100644
--- a/GITALY_SERVER_VERSION
+++ b/GITALY_SERVER_VERSION
@@ -1 +1 @@
-1.9.0
+1.12.0
diff --git a/Gemfile b/Gemfile
index c41f14e09d2..34e6fd17129 100644
--- a/Gemfile
+++ b/Gemfile
@@ -1,6 +1,6 @@
source 'https://rubygems.org'
-gem 'rails', '5.0.7'
+gem 'rails', '5.0.7.1'
gem 'rails-deprecated_sanitizer', '~> 1.0.3'
# Improves copy-on-write performance for MRI
@@ -34,7 +34,7 @@ gem 'omniauth-cas3', '~> 1.1.4'
gem 'omniauth-facebook', '~> 4.0.0'
gem 'omniauth-github', '~> 1.3'
gem 'omniauth-gitlab', '~> 1.0.2'
-gem 'omniauth-google-oauth2', '~> 0.5.3'
+gem 'omniauth-google-oauth2', '~> 0.6.0'
gem 'omniauth-kerberos', '~> 0.3.0', group: :kerberos
gem 'omniauth-oauth2-generic', '~> 0.2.2'
gem 'omniauth-saml', '~> 1.10'
@@ -43,7 +43,7 @@ gem 'omniauth-twitter', '~> 1.4'
gem 'omniauth_crowd', '~> 2.2.0'
gem 'omniauth-authentiq', '~> 0.3.3'
gem 'rack-oauth2', '~> 1.2.1'
-gem 'jwt', '~> 1.5.6'
+gem 'jwt', '~> 2.1.0'
# Spam and anti-bot protection
gem 'recaptcha', '~> 3.0', require: 'recaptcha/rails'
@@ -89,10 +89,7 @@ gem 'kaminari', '~> 1.0'
gem 'hamlit', '~> 2.8.8'
# Files attachments
-# Locked until https://github.com/carrierwaveuploader/carrierwave/pull/2332 and
-# https://github.com/carrierwaveuploader/carrierwave/pull/2356 are merged.
-# config/initializers/carrierwave_patch.rb can be removed once both changes are released.
-gem 'carrierwave', '= 1.2.3'
+gem 'carrierwave', '~> 1.3'
gem 'mini_magick'
# for backups
@@ -130,7 +127,7 @@ gem 'asciidoctor-plantuml', '0.0.8'
gem 'rouge', '~> 3.1'
gem 'truncato', '~> 0.7.9'
gem 'bootstrap_form', '~> 2.7.0'
-gem 'nokogiri', '~> 1.8.2'
+gem 'nokogiri', '~> 1.8.4'
gem 'escape_utils', '~> 1.1'
# Calendar rendering
@@ -165,7 +162,7 @@ gem 'acts-as-taggable-on', '~> 5.0'
gem 'sidekiq', '~> 5.2.1'
gem 'sidekiq-cron', '~> 0.6.0'
gem 'redis-namespace', '~> 1.6.0'
-gem 'gitlab-sidekiq-fetcher', '~> 0.1.0', require: 'sidekiq-reliable-fetch'
+gem 'gitlab-sidekiq-fetcher', '~> 0.4.0', require: 'sidekiq-reliable-fetch'
# Cron Parser
gem 'rufus-scheduler', '~> 3.4'
@@ -331,7 +328,7 @@ group :development, :test do
gem 'awesome_print', require: false
gem 'fuubar', '~> 2.2.0'
- gem 'database_cleaner', '~> 1.5.0'
+ gem 'database_cleaner', '~> 1.7.0'
gem 'factory_bot_rails', '~> 4.8.2'
gem 'rspec-rails', '~> 3.7.0'
gem 'rspec-retry', '~> 0.4.5'
diff --git a/Gemfile.lock b/Gemfile.lock
index 23a2bbeffdd..1f7f58d59e0 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -4,41 +4,41 @@ GEM
RedCloth (4.3.2)
abstract_type (0.0.7)
ace-rails-ap (4.1.2)
- actioncable (5.0.7)
- actionpack (= 5.0.7)
+ actioncable (5.0.7.1)
+ actionpack (= 5.0.7.1)
nio4r (>= 1.2, < 3.0)
websocket-driver (~> 0.6.1)
- actionmailer (5.0.7)
- actionpack (= 5.0.7)
- actionview (= 5.0.7)
- activejob (= 5.0.7)
+ actionmailer (5.0.7.1)
+ actionpack (= 5.0.7.1)
+ actionview (= 5.0.7.1)
+ activejob (= 5.0.7.1)
mail (~> 2.5, >= 2.5.4)
rails-dom-testing (~> 2.0)
- actionpack (5.0.7)
- actionview (= 5.0.7)
- activesupport (= 5.0.7)
+ actionpack (5.0.7.1)
+ actionview (= 5.0.7.1)
+ activesupport (= 5.0.7.1)
rack (~> 2.0)
rack-test (~> 0.6.3)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.0.2)
- actionview (5.0.7)
- activesupport (= 5.0.7)
+ actionview (5.0.7.1)
+ activesupport (= 5.0.7.1)
builder (~> 3.1)
erubis (~> 2.7.0)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.0.3)
- activejob (5.0.7)
- activesupport (= 5.0.7)
+ activejob (5.0.7.1)
+ activesupport (= 5.0.7.1)
globalid (>= 0.3.6)
- activemodel (5.0.7)
- activesupport (= 5.0.7)
- activerecord (5.0.7)
- activemodel (= 5.0.7)
- activesupport (= 5.0.7)
+ activemodel (5.0.7.1)
+ activesupport (= 5.0.7.1)
+ activerecord (5.0.7.1)
+ activemodel (= 5.0.7.1)
+ activesupport (= 5.0.7.1)
arel (~> 7.0)
activerecord_sane_schema_dumper (1.0)
rails (>= 5, < 6)
- activesupport (5.0.7)
+ activesupport (5.0.7.1)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 0.7, < 2)
minitest (~> 5.1)
@@ -108,7 +108,7 @@ GEM
capybara-screenshot (1.0.14)
capybara (>= 1.0, < 3)
launchy
- carrierwave (1.2.3)
+ carrierwave (1.3.0)
activemodel (>= 4.0.0)
activesupport (>= 4.0.0)
mime-types (>= 1.16)
@@ -140,7 +140,7 @@ GEM
css_parser (1.5.0)
addressable
daemons (1.2.6)
- database_cleaner (1.5.3)
+ database_cleaner (1.7.0)
debug_inspector (0.0.3)
debugger-ruby_core_source (1.3.8)
deckar01-task_list (2.0.0)
@@ -280,7 +280,7 @@ GEM
gitlab-default_value_for (3.1.1)
activerecord (>= 3.2.0, < 6.0)
gitlab-markup (1.6.5)
- gitlab-sidekiq-fetcher (0.1.0)
+ gitlab-sidekiq-fetcher (0.4.0)
sidekiq (~> 5)
gitlab-styles (2.4.1)
rubocop (~> 0.54.0)
@@ -381,7 +381,7 @@ GEM
json (~> 1.8)
multi_xml (>= 0.5.2)
httpclient (2.8.3)
- i18n (1.1.1)
+ i18n (1.2.0)
concurrent-ruby (~> 1.0)
icalendar (2.4.1)
ice_nine (0.11.2)
@@ -403,7 +403,7 @@ GEM
bindata
json-schema (2.8.0)
addressable (>= 2.4)
- jwt (1.5.6)
+ jwt (2.1.0)
kaminari (1.0.1)
activesupport (>= 4.1.0)
kaminari-actionview (= 1.0.1)
@@ -449,7 +449,7 @@ GEM
loofah (2.2.3)
crass (~> 1.0.2)
nokogiri (>= 1.5.9)
- mail (2.7.0)
+ mail (2.7.1)
mini_mime (>= 0.1.1)
mail_room (0.9.1)
memoist (0.16.0)
@@ -483,24 +483,24 @@ GEM
nokogiri
numerizer (0.1.1)
oauth (0.5.4)
- oauth2 (1.4.0)
- faraday (>= 0.8, < 0.13)
- jwt (~> 1.0)
+ oauth2 (1.4.1)
+ faraday (>= 0.8, < 0.16.0)
+ jwt (>= 1.0, < 3.0)
multi_json (~> 1.3)
multi_xml (~> 0.5)
rack (>= 1.2, < 3)
octokit (4.9.0)
sawyer (~> 0.8.0, >= 0.5.3)
- omniauth (1.8.1)
- hashie (>= 3.4.6, < 3.6.0)
+ omniauth (1.9.0)
+ hashie (>= 3.4.6, < 3.7.0)
rack (>= 1.6.2, < 3)
omniauth-auth0 (2.0.0)
omniauth-oauth2 (~> 1.4)
omniauth-authentiq (0.3.3)
jwt (>= 1.5)
omniauth-oauth2 (>= 1.5)
- omniauth-azure-oauth2 (0.0.9)
- jwt (~> 1.0)
+ omniauth-azure-oauth2 (0.0.10)
+ jwt (>= 1.0, < 3.0)
omniauth (~> 1.0)
omniauth-oauth2 (~> 1.4)
omniauth-cas3 (1.1.4)
@@ -515,8 +515,8 @@ GEM
omniauth-gitlab (1.0.3)
omniauth (~> 1.0)
omniauth-oauth2 (~> 1.0)
- omniauth-google-oauth2 (0.5.3)
- jwt (>= 1.5)
+ omniauth-google-oauth2 (0.6.0)
+ jwt (>= 2.0)
omniauth (>= 1.1.1)
omniauth-oauth2 (>= 1.5)
omniauth-kerberos (0.3.0)
@@ -527,9 +527,9 @@ GEM
omniauth-oauth (1.1.0)
oauth
omniauth (~> 1.0)
- omniauth-oauth2 (1.5.0)
+ omniauth-oauth2 (1.6.0)
oauth2 (~> 1.1)
- omniauth (~> 1.2)
+ omniauth (~> 1.9)
omniauth-oauth2-generic (0.2.2)
omniauth-oauth2 (~> 1.0)
omniauth-saml (1.10.0)
@@ -624,17 +624,17 @@ GEM
rack
rack-test (0.6.3)
rack (>= 1.0)
- rails (5.0.7)
- actioncable (= 5.0.7)
- actionmailer (= 5.0.7)
- actionpack (= 5.0.7)
- actionview (= 5.0.7)
- activejob (= 5.0.7)
- activemodel (= 5.0.7)
- activerecord (= 5.0.7)
- activesupport (= 5.0.7)
+ rails (5.0.7.1)
+ actioncable (= 5.0.7.1)
+ actionmailer (= 5.0.7.1)
+ actionpack (= 5.0.7.1)
+ actionview (= 5.0.7.1)
+ activejob (= 5.0.7.1)
+ activemodel (= 5.0.7.1)
+ activerecord (= 5.0.7.1)
+ activesupport (= 5.0.7.1)
bundler (>= 1.3.0)
- railties (= 5.0.7)
+ railties (= 5.0.7.1)
sprockets-rails (>= 2.0.0)
rails-controller-testing (1.0.2)
actionpack (~> 5.x, >= 5.0.1)
@@ -650,15 +650,15 @@ GEM
rails-i18n (5.1.1)
i18n (>= 0.7, < 2)
railties (>= 5.0, < 6)
- railties (5.0.7)
- actionpack (= 5.0.7)
- activesupport (= 5.0.7)
+ railties (5.0.7.1)
+ actionpack (= 5.0.7.1)
+ activesupport (= 5.0.7.1)
method_source
rake (>= 0.8.7)
thor (>= 0.18.1, < 2.0)
rainbow (3.0.0)
raindrops (0.18.0)
- rake (12.3.1)
+ rake (12.3.2)
rb-fsevent (0.10.2)
rb-inotify (0.9.10)
ffi (>= 0.5.0, < 2)
@@ -965,7 +965,7 @@ DEPENDENCIES
bundler-audit (~> 0.5.0)
capybara (~> 2.15)
capybara-screenshot (~> 1.0.0)
- carrierwave (= 1.2.3)
+ carrierwave (~> 1.3)
charlock_holmes (~> 0.7.5)
chronic (~> 0.10.2)
chronic_duration (~> 0.10.6)
@@ -973,7 +973,7 @@ DEPENDENCIES
concurrent-ruby (~> 1.1)
connection_pool (~> 2.0)
creole (~> 0.5.0)
- database_cleaner (~> 1.5.0)
+ database_cleaner (~> 1.7.0)
deckar01-task_list (= 2.0.0)
device_detector
devise (~> 4.4)
@@ -1012,7 +1012,7 @@ DEPENDENCIES
github-markup (~> 1.7.0)
gitlab-default_value_for (~> 3.1.1)
gitlab-markup (~> 1.6.5)
- gitlab-sidekiq-fetcher (~> 0.1.0)
+ gitlab-sidekiq-fetcher (~> 0.4.0)
gitlab-styles (~> 2.4)
gitlab_omniauth-ldap (~> 2.0.4)
gon (~> 6.2)
@@ -1041,7 +1041,7 @@ DEPENDENCIES
jquery-atwho-rails (~> 1.3.2)
js_regex (~> 2.2.1)
json-schema (~> 2.8.0)
- jwt (~> 1.5.6)
+ jwt (~> 2.1.0)
kaminari (~> 1.0)
knapsack (~> 1.17)
kubeclient (~> 4.0.0)
@@ -1059,7 +1059,7 @@ DEPENDENCIES
nakayoshi_fork (~> 0.0.4)
net-ldap
net-ssh (~> 5.0)
- nokogiri (~> 1.8.2)
+ nokogiri (~> 1.8.4)
oauth2 (~> 1.4)
octokit (~> 4.9)
omniauth (~> 1.8)
@@ -1070,7 +1070,7 @@ DEPENDENCIES
omniauth-facebook (~> 4.0.0)
omniauth-github (~> 1.3)
omniauth-gitlab (~> 1.0.2)
- omniauth-google-oauth2 (~> 0.5.3)
+ omniauth-google-oauth2 (~> 0.6.0)
omniauth-kerberos (~> 0.3.0)
omniauth-oauth2-generic (~> 0.2.2)
omniauth-saml (~> 1.10)
@@ -1096,7 +1096,7 @@ DEPENDENCIES
rack-cors (~> 1.0.0)
rack-oauth2 (~> 1.2.1)
rack-proxy (~> 0.6.0)
- rails (= 5.0.7)
+ rails (= 5.0.7.1)
rails-controller-testing
rails-deprecated_sanitizer (~> 1.0.3)
rails-i18n (~> 5.1)
diff --git a/PROCESS.md b/PROCESS.md
index 800b268b2a6..5aafbd33daf 100644
--- a/PROCESS.md
+++ b/PROCESS.md
@@ -58,6 +58,18 @@ their contributions accepted by meeting our [Definition of done][done].
What you can expect from them is described at https://about.gitlab.com/roles/merge-request-coach/.
+### Milestones on community contribution issues
+
+The milestone of an issue that is currently being worked on by a community contributor
+should not be set to a named GitLab milestone (e.g. 11.7, 11.8), until the associated
+merge request is very close to being merged, and we will likely know in which named
+GitLab milestone the issue will land. There are many factors that influence when
+a community contributor finishes an issue, or even at all. So we should set this
+milestone only when we have more certainty.
+
+Note this only applies to issues currently assigned to community contributors. For
+issues assigned to GitLabbers, we are [ambitious in assigning milestones to issues](https://about.gitlab.com/direction/#how-we-plan-releases).
+
## Assigning issues
If an issue is complex and needs the attention of a specific person, assignment is a good option but assigning issues might discourage other people from contributing to that issue. We need all the contributions we can get so this should never be discouraged. Also, an assigned person might not have time for a few weeks, so others should feel free to takeover.
diff --git a/VERSION b/VERSION
index 35167c50c26..74f35bff618 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-11.6.0-pre
+11.7.0-pre
diff --git a/app/assets/javascripts/api.js b/app/assets/javascripts/api.js
index a1310d18c26..d1396b6c4bc 100644
--- a/app/assets/javascripts/api.js
+++ b/app/assets/javascripts/api.js
@@ -29,7 +29,7 @@ const Api = {
commitPipelinesPath: '/:project_id/commit/:sha/pipelines',
branchSinglePath: '/api/:version/projects/:id/repository/branches/:branch',
createBranchPath: '/api/:version/projects/:id/repository/branches',
- releasesPath: '/api/:version/project/:id/releases',
+ releasesPath: '/api/:version/projects/:id/releases',
group(groupId, callback) {
const url = Api.buildUrl(Api.groupPath).replace(':id', groupId);
diff --git a/app/assets/javascripts/boards/components/issue_due_date.vue b/app/assets/javascripts/boards/components/issue_due_date.vue
index e038198e6f0..9c4c6632976 100644
--- a/app/assets/javascripts/boards/components/issue_due_date.vue
+++ b/app/assets/javascripts/boards/components/issue_due_date.vue
@@ -3,7 +3,12 @@ import dateFormat from 'dateformat';
import { GlTooltip } from '@gitlab/ui';
import Icon from '~/vue_shared/components/icon.vue';
import { __ } from '~/locale';
-import { getDayDifference, getTimeago, dateInWords } from '~/lib/utils/datetime_utility';
+import {
+ getDayDifference,
+ getTimeago,
+ dateInWords,
+ parsePikadayDate,
+} from '~/lib/utils/datetime_utility';
export default {
components: {
@@ -54,7 +59,7 @@ export default {
return standardDateFormat;
},
issueDueDate() {
- return new Date(this.date);
+ return parsePikadayDate(this.date);
},
timeDifference() {
const today = new Date();
diff --git a/app/assets/javascripts/ci_variable_list/ci_variable_list.js b/app/assets/javascripts/ci_variable_list/ci_variable_list.js
index ee0f7cda189..5b20fa141cd 100644
--- a/app/assets/javascripts/ci_variable_list/ci_variable_list.js
+++ b/app/assets/javascripts/ci_variable_list/ci_variable_list.js
@@ -36,7 +36,9 @@ export default class VariableList {
},
protected: {
selector: '.js-ci-variable-input-protected',
- default: 'false',
+ // use `attr` instead of `data` as we don't want the value to be
+ // converted. we need the value as a string.
+ default: $('.js-ci-variable-input-protected').attr('data-default'),
},
environment_scope: {
// We can't use a `.js-` class here because
diff --git a/app/assets/javascripts/diffs/components/compare_versions_dropdown.vue b/app/assets/javascripts/diffs/components/compare_versions_dropdown.vue
index 8da02ed0b7c..b9b1ee02697 100644
--- a/app/assets/javascripts/diffs/components/compare_versions_dropdown.vue
+++ b/app/assets/javascripts/diffs/components/compare_versions_dropdown.vue
@@ -129,7 +129,7 @@ export default {
</strong>
</div>
<div>
- <small class="commit-sha"> {{ version.truncated_commit_sha }} </small>
+ <small class="commit-sha"> {{ version.short_commit_sha }} </small>
</div>
<div>
<small>
diff --git a/app/assets/javascripts/diffs/components/diff_content.vue b/app/assets/javascripts/diffs/components/diff_content.vue
index 42d09e44768..ba6dcd63880 100644
--- a/app/assets/javascripts/diffs/components/diff_content.vue
+++ b/app/assets/javascripts/diffs/components/diff_content.vue
@@ -45,6 +45,9 @@ export default {
isTextFile() {
return this.diffFile.viewer.name === 'text';
},
+ errorMessage() {
+ return this.diffFile.viewer.error;
+ },
diffFileCommentForm() {
return this.getCommentFormForDiffFile(this.diffFile.file_hash);
},
@@ -75,7 +78,7 @@ export default {
<template>
<div class="diff-content">
- <div class="diff-viewer">
+ <div v-if="!errorMessage" class="diff-viewer">
<template v-if="isTextFile">
<empty-file-viewer v-if="diffFile.empty" />
<inline-diff-view
@@ -129,5 +132,8 @@ export default {
</div>
</diff-viewer>
</div>
+ <div v-else class="diff-viewer">
+ <div class="nothing-here-block" v-html="errorMessage"></div>
+ </div>
</div>
</template>
diff --git a/app/assets/javascripts/gfm_auto_complete.js b/app/assets/javascripts/gfm_auto_complete.js
index c14eb936930..8178821be3d 100644
--- a/app/assets/javascripts/gfm_auto_complete.js
+++ b/app/assets/javascripts/gfm_auto_complete.js
@@ -256,7 +256,7 @@ class GfmAutoComplete {
displayTpl(value) {
let tmpl = GfmAutoComplete.Loading.template;
if (value.title != null) {
- tmpl = GfmAutoComplete.Milestones.template;
+ tmpl = GfmAutoComplete.Milestones.templateFunction(value.title);
}
return tmpl;
},
@@ -323,7 +323,7 @@ class GfmAutoComplete {
searchKey: 'search',
data: GfmAutoComplete.defaultLoadingData,
displayTpl(value) {
- let tmpl = GfmAutoComplete.Labels.template;
+ let tmpl = GfmAutoComplete.Labels.templateFunction(value.color, value.title);
if (GfmAutoComplete.isLoading(value)) {
tmpl = GfmAutoComplete.Loading.template;
}
@@ -588,9 +588,11 @@ GfmAutoComplete.Members = {
},
};
GfmAutoComplete.Labels = {
- template:
- // eslint-disable-next-line no-template-curly-in-string
- '<li><span class="dropdown-label-box" style="background: ${color}"></span> ${title}</li>',
+ templateFunction(color, title) {
+ return `<li><span class="dropdown-label-box" style="background: ${_.escape(
+ color,
+ )}"></span> ${_.escape(title)}</li>`;
+ },
};
// Issues, MergeRequests and Snippets
GfmAutoComplete.Issues = {
@@ -600,8 +602,9 @@ GfmAutoComplete.Issues = {
};
// Milestones
GfmAutoComplete.Milestones = {
- // eslint-disable-next-line no-template-curly-in-string
- template: '<li>${title}</li>',
+ templateFunction(title) {
+ return `<li>${_.escape(title)}</li>`;
+ },
};
GfmAutoComplete.Loading = {
template:
diff --git a/app/assets/javascripts/lib/utils/text_markdown.js b/app/assets/javascripts/lib/utils/text_markdown.js
index c095a017866..1254ec798a6 100644
--- a/app/assets/javascripts/lib/utils/text_markdown.js
+++ b/app/assets/javascripts/lib/utils/text_markdown.js
@@ -82,7 +82,7 @@ export function insertMarkdownText({
tag,
cursorOffset,
blockTag,
- selected,
+ selected = '',
wrap,
select,
}) {
@@ -212,7 +212,7 @@ export function addMarkdownListeners(form) {
blockTag: $this.data('mdBlock'),
wrap: !$this.data('mdPrepend'),
select: $this.data('mdSelect'),
- tagContent: $this.data('mdTagContent').toString(),
+ tagContent: $this.data('mdTagContent'),
});
});
}
diff --git a/app/assets/javascripts/notes/components/discussion_filter.vue b/app/assets/javascripts/notes/components/discussion_filter.vue
index 86c114a761a..f5c410211b6 100644
--- a/app/assets/javascripts/notes/components/discussion_filter.vue
+++ b/app/assets/javascripts/notes/components/discussion_filter.vue
@@ -2,7 +2,11 @@
import $ from 'jquery';
import { mapGetters, mapActions } from 'vuex';
import Icon from '~/vue_shared/components/icon.vue';
-import { DISCUSSION_FILTERS_DEFAULT_VALUE, HISTORY_ONLY_FILTER_VALUE } from '../constants';
+import {
+ DISCUSSION_FILTERS_DEFAULT_VALUE,
+ HISTORY_ONLY_FILTER_VALUE,
+ DISCUSSION_TAB_LABEL,
+} from '../constants';
export default {
components: {
@@ -23,6 +27,7 @@ export default {
return {
currentValue: this.selectedValue,
defaultValue: DISCUSSION_FILTERS_DEFAULT_VALUE,
+ displayFilters: true,
};
},
computed: {
@@ -32,6 +37,14 @@ export default {
return this.filters.find(filter => filter.value === this.currentValue);
},
},
+ created() {
+ if (window.mrTabs) {
+ const { eventHub, currentTab } = window.mrTabs;
+
+ eventHub.$on('MergeRequestTabChange', this.toggleFilters);
+ this.toggleFilters(currentTab);
+ }
+ },
mounted() {
this.toggleCommentsForm();
},
@@ -51,12 +64,15 @@ export default {
toggleCommentsForm() {
this.setCommentsDisabled(this.currentValue === HISTORY_ONLY_FILTER_VALUE);
},
+ toggleFilters(tab) {
+ this.displayFilters = tab === DISCUSSION_TAB_LABEL;
+ },
},
};
</script>
<template>
- <div class="discussion-filter-container d-inline-block align-bottom">
+ <div v-if="displayFilters" class="discussion-filter-container d-inline-block align-bottom">
<button
id="discussion-filter-dropdown"
ref="dropdownToggle"
diff --git a/app/assets/javascripts/notes/components/noteable_discussion.vue b/app/assets/javascripts/notes/components/noteable_discussion.vue
index d9dd08a7a6b..7c3f5d00308 100644
--- a/app/assets/javascripts/notes/components/noteable_discussion.vue
+++ b/app/assets/javascripts/notes/components/noteable_discussion.vue
@@ -178,31 +178,32 @@ export default {
commitId = `<span class="commit-sha">${truncateSha(commitId)}</span>`;
}
- let text = s__('MergeRequests|started a discussion');
+ const {
+ for_commit: isForCommit,
+ diff_discussion: isDiffDiscussion,
+ active: isActive,
+ } = this.discussion;
- if (this.discussion.for_commit) {
+ let text = s__('MergeRequests|started a discussion');
+ if (isForCommit) {
text = s__(
'MergeRequests|started a discussion on commit %{linkStart}%{commitId}%{linkEnd}',
);
- } else if (this.discussion.diff_discussion) {
- if (this.discussion.active) {
- text = s__('MergeRequests|started a discussion on %{linkStart}the diff%{linkEnd}');
- } else {
- text = s__(
- 'MergeRequests|started a discussion on %{linkStart}an old version of the diff%{linkEnd}',
- );
- }
+ } else if (isDiffDiscussion && commitId) {
+ text = isActive
+ ? s__('MergeRequests|started a discussion on commit %{linkStart}%{commitId}%{linkEnd}')
+ : s__(
+ 'MergeRequests|started a discussion 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 discussion on %{linkStart}an old version of the diff%{linkEnd}',
+ );
}
- return sprintf(
- text,
- {
- commitId,
- linkStart,
- linkEnd,
- },
- false,
- );
+ return sprintf(text, { commitId, linkStart, linkEnd }, false);
},
diffLine() {
if (this.discussion.diff_discussion && this.discussion.truncated_diff_lines) {
diff --git a/app/assets/javascripts/notes/constants.js b/app/assets/javascripts/notes/constants.js
index 3147dc64c27..78d365fe94b 100644
--- a/app/assets/javascripts/notes/constants.js
+++ b/app/assets/javascripts/notes/constants.js
@@ -17,6 +17,7 @@ export const RESOLVE_NOTE_METHOD_NAME = 'post';
export const DESCRIPTION_TYPE = 'changed the description';
export const HISTORY_ONLY_FILTER_VALUE = 2;
export const DISCUSSION_FILTERS_DEFAULT_VALUE = 0;
+export const DISCUSSION_TAB_LABEL = 'show';
export const NOTEABLE_TYPE_MAPPING = {
Issue: ISSUE_NOTEABLE_TYPE,
diff --git a/app/assets/javascripts/pages/users/user_overview_block.js b/app/assets/javascripts/pages/users/user_overview_block.js
index eec2b5ca8e5..e9ecec717d6 100644
--- a/app/assets/javascripts/pages/users/user_overview_block.js
+++ b/app/assets/javascripts/pages/users/user_overview_block.js
@@ -29,18 +29,21 @@ export default class UserOverviewBlock {
render(data) {
const { html, count } = data;
- const contentList = document.querySelector(`${this.container} .overview-content-list`);
+ const containerEl = document.querySelector(this.container);
+ const contentList = containerEl.querySelector('.overview-content-list');
contentList.innerHTML += html;
- const loadingEl = document.querySelector(`${this.container} .loading`);
+ const loadingEl = containerEl.querySelector('.loading');
if (count && count > 0) {
- document.querySelector(`${this.container} .js-view-all`).classList.remove('hide');
+ containerEl.querySelector('.js-view-all').classList.remove('hide');
} else {
- document
- .querySelector(`${this.container} .nothing-here-block`)
- .classList.add('text-left', 'p-0');
+ const nothingHereBlock = containerEl.querySelector('.nothing-here-block');
+
+ if (nothingHereBlock) {
+ nothingHereBlock.classList.add('text-left', 'p-0');
+ }
}
loadingEl.classList.add('hide');
diff --git a/app/assets/javascripts/pipelines/components/pipeline_url.vue b/app/assets/javascripts/pipelines/components/pipeline_url.vue
index 30a5bbf92ce..7d8863dff29 100644
--- a/app/assets/javascripts/pipelines/components/pipeline_url.vue
+++ b/app/assets/javascripts/pipelines/components/pipeline_url.vue
@@ -65,7 +65,7 @@ export default {
v-if="pipeline.flags.latest"
v-gl-tooltip
class="js-pipeline-url-latest badge badge-success"
- title="__('Latest pipeline for this branch')"
+ :title="__('Latest pipeline for this branch')"
>
latest
</span>
@@ -100,7 +100,7 @@ export default {
<span
v-if="pipeline.flags.merge_request"
v-gl-tooltip
- title="__('This pipeline is run in a merge request context')"
+ :title="__('This pipeline is run in a merge request context')"
class="js-pipeline-url-mergerequest badge badge-info"
>
merge request
diff --git a/app/assets/javascripts/releases/components/release_block.vue b/app/assets/javascripts/releases/components/release_block.vue
index 9c2aade51fc..34b97826cdb 100644
--- a/app/assets/javascripts/releases/components/release_block.vue
+++ b/app/assets/javascripts/releases/components/release_block.vue
@@ -1,4 +1,5 @@
<script>
+import _ from 'underscore';
import { GlTooltipDirective, GlLink } from '@gitlab/ui';
import Icon from '~/vue_shared/components/icon.vue';
import UserAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link.vue';
@@ -30,8 +31,8 @@ export default {
});
},
userImageAltDescription() {
- return this.commit.author && this.commit.author.username
- ? sprintf("%{username}'s avatar", { username: this.commit.author.username })
+ return this.author && this.author.username
+ ? sprintf("%{username}'s avatar", { username: this.author.username })
: null;
},
commit() {
@@ -40,6 +41,12 @@ export default {
assets() {
return this.release.assets || {};
},
+ author() {
+ return this.release.author || {};
+ },
+ hasAuthor() {
+ return _.isEmpty(this.author);
+ },
},
};
</script>
@@ -66,14 +73,14 @@ export default {
}}</span>
</div>
- <div v-if="commit.author" class="d-flex">
+ <div v-if="hasAuthor" class="d-flex">
by
<user-avatar-link
class="prepend-left-4"
- :link-href="commit.author.path"
- :img-src="commit.author.avatar_url"
+ :link-href="author.path"
+ :img-src="author.avatar_url"
:img-alt="userImageAltDescription"
- :tooltip-text="commit.author.username"
+ :tooltip-text="author.username"
/>
</div>
</div>
diff --git a/app/assets/javascripts/releases/index.js b/app/assets/javascripts/releases/index.js
index 6fa7298ac5a..adbed3cb8e2 100644
--- a/app/assets/javascripts/releases/index.js
+++ b/app/assets/javascripts/releases/index.js
@@ -14,7 +14,7 @@ export default () => {
render(createElement) {
return createElement('app', {
props: {
- endpoint: element.dataset.endpoint,
+ projectId: element.dataset.projectId,
documentationLink: element.dataset.documentationPath,
illustrationPath: element.dataset.illustrationPath,
},
diff --git a/app/assets/javascripts/right_sidebar.js b/app/assets/javascripts/right_sidebar.js
index 225e21ad322..9a0cdc02952 100644
--- a/app/assets/javascripts/right_sidebar.js
+++ b/app/assets/javascripts/right_sidebar.js
@@ -79,11 +79,12 @@ Sidebar.prototype.sidebarToggleClicked = function(e, triggered) {
Sidebar.prototype.toggleTodo = function(e) {
var $btnText, $this, $todoLoading, ajaxType, url;
$this = $(e.currentTarget);
- ajaxType = $this.attr('data-delete-path') ? 'delete' : 'post';
- if ($this.attr('data-delete-path')) {
- url = '' + $this.attr('data-delete-path');
+ ajaxType = $this.data('deletePath') ? 'delete' : 'post';
+
+ if ($this.data('deletePath')) {
+ url = '' + $this.data('deletePath');
} else {
- url = '' + $this.data('url');
+ url = '' + $this.data('createPath');
}
$this.tooltip('hide');
@@ -119,14 +120,14 @@ Sidebar.prototype.todoUpdateDone = function(data) {
.removeClass('is-loading')
.enable()
.attr('aria-label', $el.data(`${attrPrefix}Text`))
- .attr('data-delete-path', deletePath)
- .attr('title', $el.data(`${attrPrefix}Text`));
+ .attr('title', $el.data(`${attrPrefix}Text`))
+ .data('deletePath', deletePath);
if ($el.hasClass('has-tooltip')) {
$el.tooltip('_fixTitle');
}
- if ($el.data(`${attrPrefix}Icon`)) {
+ if (typeof $el.data('isCollapsed') !== 'undefined') {
$elText.html($el.data(`${attrPrefix}Icon`));
} else {
$elText.text($el.data(`${attrPrefix}Text`));
diff --git a/app/assets/javascripts/serverless/components/functions.vue b/app/assets/javascripts/serverless/components/functions.vue
index 7874a7b6b6a..349e14670b1 100644
--- a/app/assets/javascripts/serverless/components/functions.vue
+++ b/app/assets/javascripts/serverless/components/functions.vue
@@ -81,7 +81,7 @@ export default {
</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>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.
diff --git a/app/assets/javascripts/set_status_modal/emoji_menu_in_modal.js b/app/assets/javascripts/set_status_modal/emoji_menu_in_modal.js
index 14a89ef9293..3a8631a196f 100644
--- a/app/assets/javascripts/set_status_modal/emoji_menu_in_modal.js
+++ b/app/assets/javascripts/set_status_modal/emoji_menu_in_modal.js
@@ -12,9 +12,8 @@ class EmojiMenuInModal extends AwardsHandler {
this.bindEvents();
}
- postEmoji($emojiButton, awardUrl, selectedEmoji, callback) {
+ postEmoji($emojiButton, awardUrl, selectedEmoji) {
this.selectEmojiCallback(selectedEmoji, this.emoji.glEmojiTag(selectedEmoji));
- callback();
}
}
diff --git a/app/assets/javascripts/sidebar/stores/sidebar_store.js b/app/assets/javascripts/sidebar/stores/sidebar_store.js
index f20cc6d8cca..7b8b4c5d856 100644
--- a/app/assets/javascripts/sidebar/stores/sidebar_store.js
+++ b/app/assets/javascripts/sidebar/stores/sidebar_store.js
@@ -71,7 +71,7 @@ export default class SidebarStore {
}
findAssignee(findAssignee) {
- return this.assignees.filter(assignee => assignee.id === findAssignee.id)[0];
+ return this.assignees.find(assignee => assignee.id === findAssignee.id);
}
removeAssignee(removeAssignee) {
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 d8a75388e84..b7f12076958 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
@@ -106,6 +106,9 @@ export default {
(!this.mr.isNothingToMergeState && !this.mr.isMergedState)
);
},
+ shouldRenderCollaborationStatus() {
+ return this.mr.allowCollaboration && this.mr.isOpen;
+ },
shouldRenderMergedPipeline() {
return this.mr.state === 'merged' && !_.isEmpty(this.mr.mergePipeline);
},
@@ -315,7 +318,7 @@ export default {
<div class="mr-widget-section">
<component :is="componentName" :mr="mr" :service="service" />
- <section v-if="mr.allowCollaboration" class="mr-info-list mr-links">
+ <section v-if="shouldRenderCollaborationStatus" class="mr-info-list mr-links">
{{ s__('mrWidget|Allows commits from members who can merge to the target branch') }}
</section>
diff --git a/app/assets/javascripts/vue_shared/components/user_popover/user_popover.vue b/app/assets/javascripts/vue_shared/components/user_popover/user_popover.vue
index fad1a2f3f56..d24fe1b547e 100644
--- a/app/assets/javascripts/vue_shared/components/user_popover/user_popover.vue
+++ b/app/assets/javascripts/vue_shared/components/user_popover/user_popover.vue
@@ -1,6 +1,5 @@
<script>
import { GlPopover, GlSkeletonLoading } from '@gitlab/ui';
-import { __, sprintf } from '~/locale';
import UserAvatarImage from '../user_avatar/user_avatar_image.vue';
import { glEmojiTag } from '../../../emoji';
@@ -28,23 +27,6 @@ export default {
},
},
computed: {
- jobLine() {
- if (this.user.bio && this.user.organization) {
- return sprintf(
- __('%{bio} at %{organization}'),
- {
- bio: this.user.bio,
- organization: this.user.organization,
- },
- false,
- );
- } else if (this.user.bio) {
- return this.user.bio;
- } else if (this.user.organization) {
- return this.user.organization;
- }
- return null;
- },
statusHtml() {
if (this.user.status.emoji && this.user.status.message) {
return `${glEmojiTag(this.user.status.emoji)} ${this.user.status.message}`;
@@ -86,7 +68,8 @@ export default {
<gl-skeleton-loading v-else :lines="1" class="animation-container-small mb-1" />
</div>
<div class="text-secondary">
- {{ jobLine }}
+ <div v-if="user.bio" class="js-bio">{{ user.bio }}</div>
+ <div v-if="user.organization" class="js-organization">{{ user.organization }}</div>
<gl-skeleton-loading
v-if="jobInfoIsLoading"
:lines="1"
diff --git a/app/assets/stylesheets/framework/files.scss b/app/assets/stylesheets/framework/files.scss
index 3ac7b6b704b..037a5adfb7e 100644
--- a/app/assets/stylesheets/framework/files.scss
+++ b/app/assets/stylesheets/framework/files.scss
@@ -24,7 +24,7 @@
}
}
- &:not(.use-csslab) table {
+ table {
@extend .table;
}
diff --git a/app/assets/stylesheets/framework/highlight.scss b/app/assets/stylesheets/framework/highlight.scss
index 73533571a2f..946f575ac13 100644
--- a/app/assets/stylesheets/framework/highlight.scss
+++ b/app/assets/stylesheets/framework/highlight.scss
@@ -42,7 +42,6 @@
padding: 10px;
text-align: right;
float: left;
- line-height: 1;
a {
font-family: $monospace-font;
@@ -69,3 +68,9 @@
}
}
}
+
+// Vertically aligns <table> line numbers (eg. blame view)
+// see https://gitlab.com/gitlab-org/gitlab-ce/issues/54048
+td.line-numbers {
+ line-height: 1;
+}
diff --git a/app/assets/stylesheets/framework/modal.scss b/app/assets/stylesheets/framework/modal.scss
index 7e30747963a..95291b4a9ad 100644
--- a/app/assets/stylesheets/framework/modal.scss
+++ b/app/assets/stylesheets/framework/modal.scss
@@ -25,8 +25,8 @@
&.w-100 {
// after upgrading to Bootstrap 4.2 we can use $modal-header-padding-x here
// https://github.com/twbs/bootstrap/pull/26976
- margin-right: -2rem;
- padding-right: 2rem;
+ margin-right: -28px;
+ padding-right: 28px;
}
}
diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss
index ce5aaa8963c..7e53f1ec48d 100644
--- a/app/assets/stylesheets/framework/variables.scss
+++ b/app/assets/stylesheets/framework/variables.scss
@@ -198,7 +198,6 @@ $well-light-text-color: #5b6169;
$gl-font-size: 14px;
$gl-font-size-xs: 11px;
$gl-font-size-small: 12px;
-$gl-font-size-medium: 1.43rem;
$gl-font-size-large: 16px;
$gl-font-weight-normal: 400;
$gl-font-weight-bold: 600;
diff --git a/app/assets/stylesheets/framework/variables_overrides.scss b/app/assets/stylesheets/framework/variables_overrides.scss
index 5ca76bb6c5a..069f45bff49 100644
--- a/app/assets/stylesheets/framework/variables_overrides.scss
+++ b/app/assets/stylesheets/framework/variables_overrides.scss
@@ -28,3 +28,9 @@ $popover-border-width: 1px;
$popover-border-color: $border-color;
$popover-box-shadow: 0 $border-radius-small $border-radius-default 0 $shadow-color;
$popover-arrow-outer-color: $shadow-color;
+$h1-font-size: 14px * 2.5;
+$h2-font-size: 14px * 2;
+$h3-font-size: 14px * 1.75;
+$h4-font-size: 14px * 1.5;
+$h5-font-size: 14px * 1.25;
+$h6-font-size: 14px;
diff --git a/app/assets/stylesheets/pages/builds.scss b/app/assets/stylesheets/pages/builds.scss
index c7dde2f0f2a..09235661cea 100644
--- a/app/assets/stylesheets/pages/builds.scss
+++ b/app/assets/stylesheets/pages/builds.scss
@@ -135,6 +135,7 @@
.build-loader-animation {
@include build-loader-animation;
float: left;
+ padding-left: $gl-padding-8;
}
}
diff --git a/app/assets/stylesheets/pages/issuable.scss b/app/assets/stylesheets/pages/issuable.scss
index 5b5f486ea63..a1069aa9783 100644
--- a/app/assets/stylesheets/pages/issuable.scss
+++ b/app/assets/stylesheets/pages/issuable.scss
@@ -60,6 +60,10 @@
padding: 0;
margin-bottom: $gl-padding;
border-bottom: 0;
+ word-wrap: break-word;
+ overflow-wrap: break-word;
+ min-width: 0;
+ width: 100%;
}
.btn-edit {
diff --git a/app/assets/stylesheets/pages/pipelines.scss b/app/assets/stylesheets/pages/pipelines.scss
index fdd17af35fb..7a47e0a2836 100644
--- a/app/assets/stylesheets/pages/pipelines.scss
+++ b/app/assets/stylesheets/pages/pipelines.scss
@@ -978,7 +978,6 @@ button.mini-pipeline-graph-dropdown-toggle {
* Top arrow in the dropdown in the mini pipeline graph
*/
.mini-pipeline-graph-dropdown-menu {
- z-index: 200;
&::before,
&::after {
diff --git a/app/assets/stylesheets/pages/projects.scss b/app/assets/stylesheets/pages/projects.scss
index 0ce0db038a7..004c49dd226 100644
--- a/app/assets/stylesheets/pages/projects.scss
+++ b/app/assets/stylesheets/pages/projects.scss
@@ -973,7 +973,7 @@ pre.light-well {
padding: $gl-padding 0;
@include media-breakpoint-up(lg) {
- padding: $gl-padding-24 0;
+ padding: $gl-padding 0;
}
&.no-description {
@@ -990,7 +990,7 @@ pre.light-well {
}
h2 {
- font-size: $gl-font-size-medium;
+ font-size: $gl-font-size-large;
font-weight: $gl-font-weight-bold;
margin-bottom: 0;
@@ -1049,7 +1049,7 @@ pre.light-well {
}
.controls {
- margin-top: $gl-padding;
+ margin-top: $gl-padding-8;
@include media-breakpoint-down(md) {
margin-top: 0;
diff --git a/app/controllers/admin/application_settings_controller.rb b/app/controllers/admin/application_settings_controller.rb
index 8f683ca06ad..8f267eccc8a 100644
--- a/app/controllers/admin/application_settings_controller.rb
+++ b/app/controllers/admin/application_settings_controller.rb
@@ -77,7 +77,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
def reset_health_check_token
@application_setting.reset_health_check_access_token!
flash[:notice] = 'New health check access token has been generated!'
- redirect_to :back
+ redirect_back_or_default
end
def clear_repository_check_states
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index 6f0dc2a3a20..a8fc848c879 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -76,7 +76,7 @@ class ApplicationController < ActionController::Base
end
def redirect_back_or_default(default: root_path, options: {})
- redirect_to request.referer.present? ? :back : default, options
+ redirect_back(fallback_location: default, **options)
end
def not_found
@@ -403,7 +403,7 @@ class ApplicationController < ActionController::Base
end
def manifest_import_enabled?
- Group.supports_nested_groups? && Gitlab::CurrentSettings.import_sources.include?('manifest')
+ Group.supports_nested_objects? && Gitlab::CurrentSettings.import_sources.include?('manifest')
end
# U2F (universal 2nd factor) devices need a unique identifier for the application
diff --git a/app/controllers/concerns/group_tree.rb b/app/controllers/concerns/group_tree.rb
index 4f56346832c..e9a7d6a3152 100644
--- a/app/controllers/concerns/group_tree.rb
+++ b/app/controllers/concerns/group_tree.rb
@@ -32,14 +32,14 @@ module GroupTree
def filtered_groups_with_ancestors(groups)
filtered_groups = groups.search(params[:filter]).page(params[:page])
- if Group.supports_nested_groups?
+ if Group.supports_nested_objects?
# We find the ancestors by ID of the search results here.
# Otherwise the ancestors would also have filters applied,
# which would cause them not to be preloaded.
#
# Pagination needs to be applied before loading the ancestors to
# make sure ancestors are not cut off by pagination.
- Gitlab::GroupHierarchy.new(Group.where(id: filtered_groups.select(:id)))
+ Gitlab::ObjectHierarchy.new(Group.where(id: filtered_groups.select(:id)))
.base_and_ancestors
else
filtered_groups
diff --git a/app/controllers/concerns/issuable_actions.rb b/app/controllers/concerns/issuable_actions.rb
index ad9cc0925b7..3d64ae8b775 100644
--- a/app/controllers/concerns/issuable_actions.rb
+++ b/app/controllers/concerns/issuable_actions.rb
@@ -5,7 +5,6 @@ module IssuableActions
include Gitlab::Utils::StrongMemoize
included do
- before_action :labels, only: [:show, :new, :edit]
before_action :authorize_destroy_issuable!, only: :destroy
before_action :authorize_admin_issuable!, only: :bulk_update
end
@@ -25,7 +24,10 @@ module IssuableActions
def show
respond_to do |format|
- format.html
+ format.html do
+ @issuable_sidebar = serializer.represent(issuable, serializer: 'sidebar') # rubocop:disable Gitlab/ModuleWithInstanceVariables
+ end
+
format.json do
render json: serializer.represent(issuable, serializer: params[:serializer])
end
@@ -168,10 +170,6 @@ module IssuableActions
end
end
- def labels
- @labels ||= LabelsFinder.new(current_user, project_id: @project.id).execute # rubocop:disable Gitlab/ModuleWithInstanceVariables
- end
-
def authorize_destroy_issuable!
unless can?(current_user, :"destroy_#{issuable.to_ability_name}", issuable)
return access_denied!
diff --git a/app/controllers/groups/settings/ci_cd_controller.rb b/app/controllers/groups/settings/ci_cd_controller.rb
index c1dcc463de7..f476f428fdb 100644
--- a/app/controllers/groups/settings/ci_cd_controller.rb
+++ b/app/controllers/groups/settings/ci_cd_controller.rb
@@ -4,7 +4,7 @@ module Groups
module Settings
class CiCdController < Groups::ApplicationController
skip_cross_project_access_check :show
- before_action :authorize_admin_pipeline!
+ before_action :authorize_admin_group!
def show
define_ci_variables
@@ -26,8 +26,8 @@ module Groups
.map { |variable| variable.present(current_user: current_user) }
end
- def authorize_admin_pipeline!
- return render_404 unless can?(current_user, :admin_pipeline, group)
+ def authorize_admin_group!
+ return render_404 unless can?(current_user, :admin_group, group)
end
end
end
diff --git a/app/controllers/projects/blob_controller.rb b/app/controllers/projects/blob_controller.rb
index 60fabd15333..ff286c0ccf0 100644
--- a/app/controllers/projects/blob_controller.rb
+++ b/app/controllers/projects/blob_controller.rb
@@ -260,7 +260,7 @@ class Projects::BlobController < Projects::ApplicationController
extension: blob.extension,
size: blob.raw_size,
mime_type: blob.mime_type,
- binary: blob.raw_binary?,
+ binary: blob.binary?,
simple_viewer: blob.simple_viewer&.class&.partial_name,
rich_viewer: blob.rich_viewer&.class&.partial_name,
show_viewer_switcher: !!blob.show_viewer_switcher?,
diff --git a/app/controllers/projects/merge_requests/conflicts_controller.rb b/app/controllers/projects/merge_requests/conflicts_controller.rb
index ac1969adc6e..045a4e974fe 100644
--- a/app/controllers/projects/merge_requests/conflicts_controller.rb
+++ b/app/controllers/projects/merge_requests/conflicts_controller.rb
@@ -8,7 +8,7 @@ class Projects::MergeRequests::ConflictsController < Projects::MergeRequests::Ap
def show
respond_to do |format|
format.html do
- labels
+ @issuable_sidebar = serializer.represent(@merge_request, serializer: 'sidebar')
end
format.json do
@@ -60,9 +60,15 @@ class Projects::MergeRequests::ConflictsController < Projects::MergeRequests::Ap
end
end
+ private
+
def authorize_can_resolve_conflicts!
@conflicts_list = ::MergeRequests::Conflicts::ListService.new(@merge_request)
return render_404 unless @conflicts_list.can_be_resolved_by?(current_user)
end
+
+ def serializer
+ MergeRequestSerializer.new(current_user: current_user, project: project)
+ end
end
diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb
index da9316d5f22..162c2636641 100644
--- a/app/controllers/projects/merge_requests_controller.rb
+++ b/app/controllers/projects/merge_requests_controller.rb
@@ -22,8 +22,7 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
format.html
format.json do
render json: {
- html: view_to_html_string("projects/merge_requests/_merge_requests"),
- labels: @labels.as_json(methods: :text_color)
+ html: view_to_html_string("projects/merge_requests/_merge_requests")
}
end
end
@@ -43,8 +42,7 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
@noteable = @merge_request
@commits_count = @merge_request.commits_count
-
- labels
+ @issuable_sidebar = serializer.represent(@merge_request, serializer: 'sidebar')
set_pipeline_variables
@@ -220,6 +218,12 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
head :ok
end
+ def discussions
+ merge_request.preload_discussions_diff_highlight
+
+ super
+ end
+
protected
alias_method :subscribable_resource, :merge_request
diff --git a/app/controllers/projects/releases_controller.rb b/app/controllers/projects/releases_controller.rb
index 58d5ea4762f..62bdc84b41a 100644
--- a/app/controllers/projects/releases_controller.rb
+++ b/app/controllers/projects/releases_controller.rb
@@ -3,7 +3,7 @@
class Projects::ReleasesController < Projects::ApplicationController
# Authorize
before_action :require_non_empty_project
- before_action :authorize_download_code!
+ before_action :authorize_read_release!
before_action :check_releases_page_feature_flag
def index
@@ -12,8 +12,8 @@ class Projects::ReleasesController < Projects::ApplicationController
private
def check_releases_page_feature_flag
- return render_404 unless Feature.enabled?(:releases_page)
+ return render_404 unless Feature.enabled?(:releases_page, @project)
- push_frontend_feature_flag(:releases_page)
+ push_frontend_feature_flag(:releases_page, @project)
end
end
diff --git a/app/controllers/projects/snippets_controller.rb b/app/controllers/projects/snippets_controller.rb
index a44acb12bdf..255f1f3569a 100644
--- a/app/controllers/projects/snippets_controller.rb
+++ b/app/controllers/projects/snippets_controller.rb
@@ -75,7 +75,14 @@ class Projects::SnippetsController < Projects::ApplicationController
format.json do
render_blob_json(blob)
end
- format.js { render 'shared/snippets/show'}
+
+ format.js do
+ if @snippet.embeddable?
+ render 'shared/snippets/show'
+ else
+ head :not_found
+ end
+ end
end
end
diff --git a/app/controllers/projects/tags_controller.rb b/app/controllers/projects/tags_controller.rb
index a50a1475eb2..a17c050b696 100644
--- a/app/controllers/projects/tags_controller.rb
+++ b/app/controllers/projects/tags_controller.rb
@@ -43,9 +43,22 @@ class Projects::TagsController < Projects::ApplicationController
def create
result = ::Tags::CreateService.new(@project, current_user)
- .execute(params[:tag_name], params[:ref], params[:message], params[:release_description])
+ .execute(params[:tag_name], params[:ref], params[:message])
if result[:status] == :success
+ # Release creation with Tags was deprecated in GitLab 11.7
+ if params[:release_description].present?
+ release_params = {
+ tag: params[:tag_name],
+ name: params[:tag_name],
+ description: params[:release_description]
+ }
+
+ Releases::CreateService
+ .new(@project, current_user, release_params)
+ .execute
+ end
+
@tag = result[:tag]
redirect_to project_tag_path(@project, @tag.name)
diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb
index 8bf93bfd68d..878816475b2 100644
--- a/app/controllers/projects_controller.rb
+++ b/app/controllers/projects_controller.rb
@@ -19,6 +19,7 @@ class ProjectsController < Projects::ApplicationController
before_action :lfs_blob_ids, only: [:show], if: [:repo_exists?, :project_view_files?]
before_action :project_export_enabled, only: [:export, :download_export, :remove_export, :generate_new_export]
before_action :present_project, only: [:edit]
+ before_action :authorize_download_code!, only: [:refs]
# Authorize
before_action :authorize_admin_project!, only: [:edit, :update, :housekeeping, :download_export, :export, :remove_export, :generate_new_export]
diff --git a/app/controllers/sherlock/transactions_controller.rb b/app/controllers/sherlock/transactions_controller.rb
index 46e382e594e..8d1847507cc 100644
--- a/app/controllers/sherlock/transactions_controller.rb
+++ b/app/controllers/sherlock/transactions_controller.rb
@@ -15,7 +15,7 @@ module Sherlock
def destroy_all
Gitlab::Sherlock.collection.clear
- redirect_to :back, status: :found
+ redirect_back_or_default(options: { status: :found })
end
end
end
diff --git a/app/controllers/snippets_controller.rb b/app/controllers/snippets_controller.rb
index dd9bf17cf0c..8ea5450b4e8 100644
--- a/app/controllers/snippets_controller.rb
+++ b/app/controllers/snippets_controller.rb
@@ -80,7 +80,13 @@ class SnippetsController < ApplicationController
render_blob_json(blob)
end
- format.js { render 'shared/snippets/show' }
+ format.js do
+ if @snippet.embeddable?
+ render 'shared/snippets/show'
+ else
+ head :not_found
+ end
+ end
end
end
diff --git a/app/finders/group_descendants_finder.rb b/app/finders/group_descendants_finder.rb
index a9ce5be13f3..96a36db7ec8 100644
--- a/app/finders/group_descendants_finder.rb
+++ b/app/finders/group_descendants_finder.rb
@@ -112,7 +112,7 @@ class GroupDescendantsFinder
# rubocop: disable CodeReuse/ActiveRecord
def ancestors_of_groups(base_for_ancestors)
group_ids = base_for_ancestors.except(:select, :sort).select(:id)
- Gitlab::GroupHierarchy.new(Group.where(id: group_ids))
+ Gitlab::ObjectHierarchy.new(Group.where(id: group_ids))
.base_and_ancestors(upto: parent_group.id)
end
# rubocop: enable CodeReuse/ActiveRecord
@@ -132,7 +132,7 @@ class GroupDescendantsFinder
end
def subgroups
- return Group.none unless Group.supports_nested_groups?
+ return Group.none unless Group.supports_nested_objects?
# When filtering subgroups, we want to find all matches withing the tree of
# descendants to show to the user
@@ -183,7 +183,7 @@ class GroupDescendantsFinder
# rubocop: disable CodeReuse/ActiveRecord
def hierarchy_for_parent
- @hierarchy ||= Gitlab::GroupHierarchy.new(Group.where(id: parent_group.id))
+ @hierarchy ||= Gitlab::ObjectHierarchy.new(Group.where(id: parent_group.id))
end
# rubocop: enable CodeReuse/ActiveRecord
end
diff --git a/app/finders/groups_finder.rb b/app/finders/groups_finder.rb
index ea954f98220..0080123407d 100644
--- a/app/finders/groups_finder.rb
+++ b/app/finders/groups_finder.rb
@@ -46,7 +46,7 @@ class GroupsFinder < UnionFinder
return [Group.all] if current_user&.full_private_access? && all_available?
groups = []
- groups << Gitlab::GroupHierarchy.new(groups_for_ancestors, groups_for_descendants).all_groups if current_user
+ groups << Gitlab::ObjectHierarchy.new(groups_for_ancestors, groups_for_descendants).all_objects if current_user
groups << Group.unscoped.public_to_user(current_user) if include_public_groups?
groups << Group.none if groups.empty?
groups
@@ -66,7 +66,7 @@ class GroupsFinder < UnionFinder
.groups
.where('members.access_level >= ?', params[:min_access_level])
- Gitlab::GroupHierarchy
+ Gitlab::ObjectHierarchy
.new(groups)
.base_and_descendants
end
diff --git a/app/finders/releases_finder.rb b/app/finders/releases_finder.rb
new file mode 100644
index 00000000000..59e84198fde
--- /dev/null
+++ b/app/finders/releases_finder.rb
@@ -0,0 +1,14 @@
+# frozen_string_literal: true
+
+class ReleasesFinder
+ def initialize(project, current_user = nil)
+ @project = project
+ @current_user = current_user
+ end
+
+ def execute
+ return Release.none unless Ability.allowed?(@current_user, :read_release, @project)
+
+ @project.releases.sorted
+ end
+end
diff --git a/app/helpers/appearances_helper.rb b/app/helpers/appearances_helper.rb
index 3f69af50f25..473c90c882c 100644
--- a/app/helpers/appearances_helper.rb
+++ b/app/helpers/appearances_helper.rb
@@ -11,7 +11,7 @@ module AppearancesHelper
end
def brand_image
- image_tag(current_appearance.logo) if current_appearance&.logo?
+ image_tag(current_appearance.logo_path) if current_appearance&.logo?
end
def brand_text
@@ -28,7 +28,7 @@ module AppearancesHelper
def brand_header_logo
if current_appearance&.header_logo?
- image_tag current_appearance.header_logo
+ image_tag current_appearance.header_logo_path
else
render 'shared/logo.svg'
end
diff --git a/app/helpers/application_settings_helper.rb b/app/helpers/application_settings_helper.rb
index 086bb38ce9a..5a7c005fd06 100644
--- a/app/helpers/application_settings_helper.rb
+++ b/app/helpers/application_settings_helper.rb
@@ -26,6 +26,18 @@ module ApplicationSettingsHelper
end
end
+ def all_protocols_enabled?
+ Gitlab::CurrentSettings.enabled_git_access_protocol.blank?
+ end
+
+ def ssh_enabled?
+ all_protocols_enabled? || enabled_protocol == 'ssh'
+ end
+
+ def http_enabled?
+ all_protocols_enabled? || enabled_protocol == 'http'
+ end
+
def enabled_project_button(project, protocol)
case protocol
when 'ssh'
@@ -218,7 +230,8 @@ module ApplicationSettingsHelper
:version_check_enabled,
:web_ide_clientside_preview_enabled,
:diff_max_patch_bytes,
- :commit_email_hostname
+ :commit_email_hostname,
+ :protected_ci_variables
]
end
diff --git a/app/helpers/blob_helper.rb b/app/helpers/blob_helper.rb
index bd42f00944f..3dea0975beb 100644
--- a/app/helpers/blob_helper.rb
+++ b/app/helpers/blob_helper.rb
@@ -140,36 +140,6 @@ module BlobHelper
Gitlab::Sanitizers::SVG.clean(data)
end
- # Remove once https://gitlab.com/gitlab-org/gitlab-ce/issues/36103 is closed
- # and :workhorse_set_content_type flag is removed
- # If we blindly set the 'real' content type when serving a Git blob we
- # are enabling XSS attacks. An attacker could upload e.g. a Javascript
- # file to a Git repository, trick the browser of a victim into
- # downloading the blob, and then the 'application/javascript' content
- # type would tell the browser to execute the attacker's Javascript. By
- # overriding the content type and setting it to 'text/plain' (in the
- # example of Javascript) we tell the browser of the victim not to
- # execute untrusted data.
- def safe_content_type(blob)
- if blob.extension == 'svg'
- blob.mime_type
- elsif blob.text?
- 'text/plain; charset=utf-8'
- elsif blob.image?
- blob.content_type
- else
- 'application/octet-stream'
- end
- end
-
- def content_disposition(blob, inline)
- # Remove the following line when https://gitlab.com/gitlab-org/gitlab-ce/issues/36103
- # is closed and :workhorse_set_content_type flag is removed
- return 'attachment' if blob.extension == 'svg'
-
- inline ? 'inline' : 'attachment'
- end
-
def ref_project
@ref_project ||= @target_project || @project
end
@@ -223,7 +193,7 @@ module BlobHelper
def open_raw_blob_button(blob)
return if blob.empty?
- return if blob.raw_binary? || blob.stored_externally?
+ return if blob.binary? || blob.stored_externally?
title = 'Open raw'
link_to icon('file-code-o'), blob_raw_path, class: 'btn btn-sm has-tooltip', target: '_blank', rel: 'noopener noreferrer', title: title, data: { container: 'body' }
diff --git a/app/helpers/ci_variables_helper.rb b/app/helpers/ci_variables_helper.rb
new file mode 100644
index 00000000000..e3728804c2a
--- /dev/null
+++ b/app/helpers/ci_variables_helper.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+module CiVariablesHelper
+ def ci_variable_protected_by_default?
+ Gitlab::CurrentSettings.current_application_settings.protected_ci_variables
+ end
+
+ def ci_variable_protected?(variable, only_key_value)
+ if variable && !only_key_value
+ variable.protected
+ else
+ ci_variable_protected_by_default?
+ end
+ end
+end
diff --git a/app/helpers/diff_helper.rb b/app/helpers/diff_helper.rb
index b6844d36052..32431959851 100644
--- a/app/helpers/diff_helper.rb
+++ b/app/helpers/diff_helper.rb
@@ -138,30 +138,6 @@ module DiffHelper
!diff_file.deleted_file? && @merge_request && @merge_request.source_project
end
- def diff_render_error_reason(viewer)
- case viewer.render_error
- when :too_large
- "it is too large"
- when :server_side_but_stored_externally
- case viewer.diff_file.external_storage
- when :lfs
- 'it is stored in LFS'
- else
- 'it is stored externally'
- end
- end
- end
-
- def diff_render_error_options(viewer)
- diff_file = viewer.diff_file
- options = []
-
- blob_url = project_blob_path(@project, tree_join(diff_file.content_sha, diff_file.file_path))
- options << link_to('view the blob', blob_url)
-
- options
- end
-
def diff_file_changed_icon(diff_file)
if diff_file.deleted_file?
"file-deletion"
diff --git a/app/helpers/emails_helper.rb b/app/helpers/emails_helper.rb
index e4c46ceeaa2..fa5d3ae474a 100644
--- a/app/helpers/emails_helper.rb
+++ b/app/helpers/emails_helper.rb
@@ -58,7 +58,7 @@ module EmailsHelper
def header_logo
if current_appearance&.header_logo?
image_tag(
- current_appearance.header_logo,
+ current_appearance.header_logo_path,
style: 'height: 50px'
)
else
diff --git a/app/helpers/groups_helper.rb b/app/helpers/groups_helper.rb
index 866fc555856..4a9ed123161 100644
--- a/app/helpers/groups_helper.rb
+++ b/app/helpers/groups_helper.rb
@@ -126,7 +126,7 @@ module GroupsHelper
end
def supports_nested_groups?
- Group.supports_nested_groups?
+ Group.supports_nested_objects?
end
private
diff --git a/app/helpers/issuables_helper.rb b/app/helpers/issuables_helper.rb
index da991458ea7..5f7147508c7 100644
--- a/app/helpers/issuables_helper.rb
+++ b/app/helpers/issuables_helper.rb
@@ -23,30 +23,41 @@ module IssuablesHelper
end
end
- def sidebar_due_date_tooltip_label(issuable)
- if issuable.due_date
- "#{_('Due date')}<br />#{due_date_remaining_days(issuable)}"
- else
- _('Due date')
- end
+ def sidebar_milestone_tooltip_label(milestone)
+ return _('Milestone') unless milestone.present?
+
+ [milestone[:title], sidebar_milestone_remaining_days(milestone) || _('Milestone')].join('<br/>')
+ end
+
+ def sidebar_milestone_remaining_days(milestone)
+ due_date_with_remaining_days(milestone[:due_date], milestone[:start_date])
+ end
+
+ def sidebar_due_date_tooltip_label(due_date)
+ [_('Due date'), due_date_with_remaining_days(due_date)].compact.join('<br/>')
end
- def due_date_remaining_days(issuable)
- remaining_days_in_words = remaining_days_in_words(issuable)
+ def due_date_with_remaining_days(due_date, start_date = nil)
+ return unless due_date
- "#{issuable.due_date.to_s(:medium)} (#{remaining_days_in_words})"
+ "#{due_date.to_s(:medium)} (#{remaining_days_in_words(due_date, start_date)})"
+ end
+
+ def sidebar_label_filter_path(base_path, label_name)
+ query_params = { label_name: [label_name] }.to_query
+
+ "#{base_path}?#{query_params}"
end
def multi_label_name(current_labels, default_label)
- if current_labels && current_labels.any?
- title = current_labels.first.try(:title)
- if current_labels.size > 1
- "#{title} +#{current_labels.size - 1} more"
- else
- title
- end
+ return default_label if current_labels.blank?
+
+ title = current_labels.first.try(:title) || current_labels.first[:title]
+
+ if current_labels.size > 1
+ "#{title} +#{current_labels.size - 1} more"
else
- default_label
+ title
end
end
@@ -197,19 +208,11 @@ module IssuablesHelper
output.join.html_safe
end
- # rubocop: disable CodeReuse/ActiveRecord
- def issuable_todo(issuable)
- if current_user
- current_user.todos.find_by(target: issuable, state: :pending)
- end
- end
- # rubocop: enable CodeReuse/ActiveRecord
-
def issuable_labels_tooltip(labels, limit: 5)
first, last = labels.partition.with_index { |_, i| i < limit }
if labels && labels.any?
- label_names = first.collect(&:name)
+ label_names = first.collect { |label| label.fetch(:title) }
label_names << "and #{last.size} more" unless last.empty?
label_names.join(', ')
@@ -356,12 +359,6 @@ module IssuablesHelper
issuable.model_name.human.downcase
end
- def selected_labels
- Array(params[:label_name]).map do |label_name|
- Label.new(title: label_name)
- end
- end
-
def has_filter_bar_param?
finder.class.scalar_params.any? { |p| params[p].present? }
end
@@ -386,19 +383,20 @@ module IssuablesHelper
params[:issuable_template] if issuable_templates(issuable).any? { |template| template[:name] == params[:issuable_template] }
end
- def issuable_todo_button_data(issuable, todo, is_collapsed)
+ def issuable_todo_button_data(issuable, is_collapsed)
{
- todo_text: "Add todo",
- mark_text: "Mark todo as done",
- todo_icon: (is_collapsed ? sprite_icon('todo-add') : nil),
- mark_icon: (is_collapsed ? sprite_icon('todo-done', css_class: 'todo-undone') : nil),
- issuable_id: issuable.id,
- issuable_type: issuable.class.name.underscore,
- url: project_todos_path(@project),
- delete_path: (dashboard_todo_path(todo) if todo),
- placement: (is_collapsed ? 'left' : nil),
- container: (is_collapsed ? 'body' : nil),
- boundary: 'viewport'
+ todo_text: _('Add todo'),
+ mark_text: _('Mark todo as done'),
+ todo_icon: sprite_icon('todo-add'),
+ mark_icon: sprite_icon('todo-done', css_class: 'todo-undone'),
+ issuable_id: issuable[:id],
+ issuable_type: issuable[:type],
+ create_path: issuable[:create_todo_path],
+ delete_path: issuable.dig(:current_user, :todo, :delete_path),
+ placement: is_collapsed ? 'left' : nil,
+ container: is_collapsed ? 'body' : nil,
+ boundary: 'viewport',
+ is_collapsed: is_collapsed
}
end
@@ -418,27 +416,20 @@ module IssuablesHelper
end
end
- def issuable_sidebar_options(issuable, can_edit_issuable)
+ def issuable_sidebar_options(issuable)
{
- endpoint: "#{issuable_json_path(issuable)}?serializer=sidebar",
- toggleSubscriptionEndpoint: toggle_subscription_path(issuable),
- moveIssueEndpoint: move_namespace_project_issue_path(namespace_id: issuable.project.namespace.to_param, project_id: issuable.project, id: issuable),
- projectsAutocompleteEndpoint: autocomplete_projects_path(project_id: @project.id),
- editable: can_edit_issuable,
- currentUser: UserSerializer.new.represent(current_user),
+ endpoint: "#{issuable[:issuable_json_path]}?serializer=sidebar_extras",
+ toggleSubscriptionEndpoint: issuable[:toggle_subscription_path],
+ moveIssueEndpoint: issuable[:move_issue_path],
+ projectsAutocompleteEndpoint: issuable[:projects_autocomplete_path],
+ editable: issuable.dig(:current_user, :can_edit),
+ currentUser: issuable[:current_user],
rootPath: root_path,
- fullPath: @project.full_path
+ fullPath: issuable[:project_full_path]
}
end
def parent
@project || @group
end
-
- def issuable_milestone_tooltip_title(issuable)
- if issuable.milestone
- milestone_tooltip = milestone_tooltip_title(issuable.milestone)
- _('Milestone') + (milestone_tooltip ? ': ' + milestone_tooltip : '')
- end
- end
end
diff --git a/app/helpers/milestones_helper.rb b/app/helpers/milestones_helper.rb
index c212e1804dc..50aec83b867 100644
--- a/app/helpers/milestones_helper.rb
+++ b/app/helpers/milestones_helper.rb
@@ -114,12 +114,6 @@ module MilestonesHelper
end
end
- def milestone_tooltip_title(milestone)
- if milestone
- "#{milestone.title}<br />#{milestone_tooltip_due_date(milestone)}"
- end
- end
-
def milestone_time_for(date, date_type)
title = date_type == :start ? "Start date" : "End date"
@@ -173,7 +167,7 @@ module MilestonesHelper
def milestone_tooltip_due_date(milestone)
if milestone.due_date
- "#{milestone.due_date.to_s(:medium)} (#{remaining_days_in_words(milestone)})"
+ "#{milestone.due_date.to_s(:medium)} (#{remaining_days_in_words(milestone.due_date, milestone.start_date)})"
else
_('Milestone')
end
diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb
index aa54172e108..0cfc2db3285 100644
--- a/app/helpers/projects_helper.rb
+++ b/app/helpers/projects_helper.rb
@@ -271,6 +271,20 @@ module ProjectsHelper
params[:legacy_render] ? { markdown_engine: :redcarpet } : {}
end
+ def explore_projects_tab?
+ current_page?(explore_projects_path) ||
+ current_page?(trending_explore_projects_path) ||
+ current_page?(starred_explore_projects_path)
+ end
+
+ def show_merge_request_count?(disabled: false, compact_mode: false)
+ !disabled && !compact_mode && Feature.enabled?(:project_list_show_mr_count, default_enabled: true)
+ end
+
+ def show_issue_count?(disabled: false, compact_mode: false)
+ !disabled && !compact_mode && Feature.enabled?(:project_list_show_issue_count, default_enabled: true)
+ end
+
private
def get_project_nav_tabs(project, current_user)
@@ -515,20 +529,6 @@ module ProjectsHelper
end
end
- def explore_projects_tab?
- current_page?(explore_projects_path) ||
- current_page?(trending_explore_projects_path) ||
- current_page?(starred_explore_projects_path)
- end
-
- def show_merge_request_count?(merge_requests, compact_mode)
- merge_requests && !compact_mode && Feature.enabled?(:project_list_show_mr_count, default_enabled: true)
- end
-
- def show_issue_count?(issues, compact_mode)
- issues && !compact_mode && Feature.enabled?(:project_list_show_issue_count, default_enabled: true)
- end
-
def sidebar_projects_paths
%w[
projects#show
diff --git a/app/helpers/snippets_helper.rb b/app/helpers/snippets_helper.rb
index c7d31f3469d..ecb2b2d707b 100644
--- a/app/helpers/snippets_helper.rb
+++ b/app/helpers/snippets_helper.rb
@@ -110,7 +110,7 @@ module SnippetsHelper
def embedded_snippet_raw_button
blob = @snippet.blob
- return if blob.empty? || blob.raw_binary? || blob.stored_externally?
+ return if blob.empty? || blob.binary? || blob.stored_externally?
snippet_raw_url = if @snippet.is_a?(PersonalSnippet)
raw_snippet_url(@snippet)
@@ -130,12 +130,4 @@ module SnippetsHelper
link_to external_snippet_icon('download'), download_url, class: 'btn', target: '_blank', title: 'Download', rel: 'noopener noreferrer'
end
-
- def public_snippet?
- if @snippet.project_id?
- can?(nil, :read_project_snippet, @snippet)
- else
- can?(nil, :read_personal_snippet, @snippet)
- end
- end
end
diff --git a/app/helpers/sorting_helper.rb b/app/helpers/sorting_helper.rb
index 6ac1f42c321..02762897c89 100644
--- a/app/helpers/sorting_helper.rb
+++ b/app/helpers/sorting_helper.rb
@@ -234,7 +234,7 @@ module SortingHelper
end
def sort_title_milestone
- s_('SortOptions|Milestone')
+ s_('SortOptions|Milestone due date')
end
def sort_title_milestone_later
diff --git a/app/helpers/workhorse_helper.rb b/app/helpers/workhorse_helper.rb
index e9fc39e451b..bb5b1555dc4 100644
--- a/app/helpers/workhorse_helper.rb
+++ b/app/helpers/workhorse_helper.rb
@@ -7,8 +7,7 @@ module WorkhorseHelper
def send_git_blob(repository, blob, inline: true)
headers.store(*Gitlab::Workhorse.send_git_blob(repository, blob))
- headers['Content-Disposition'] = content_disposition(blob, inline)
- headers['Content-Type'] = safe_content_type(blob)
+ headers['Content-Disposition'] = inline ? 'inline' : 'attachment'
# If enabled, this will override the values set above
workhorse_set_content_type!
@@ -47,6 +46,6 @@ module WorkhorseHelper
end
def workhorse_set_content_type!
- headers[Gitlab::Workhorse::DETECT_HEADER] = "true" if Feature.enabled?(:workhorse_set_content_type)
+ headers[Gitlab::Workhorse::DETECT_HEADER] = "true"
end
end
diff --git a/app/mailers/emails/issues.rb b/app/mailers/emails/issues.rb
index 93b51fb1774..370e6d2f90b 100644
--- a/app/mailers/emails/issues.rb
+++ b/app/mailers/emails/issues.rb
@@ -56,7 +56,9 @@ module Emails
@milestone = milestone
@milestone_url = milestone_url(@milestone)
- mail_answer_thread(@issue, issue_thread_options(updated_by_user_id, recipient_id, reason))
+ mail_answer_thread(@issue, issue_thread_options(updated_by_user_id, recipient_id, reason).merge({
+ template_name: 'changed_milestone_email'
+ }))
end
def issue_status_changed_email(recipient_id, issue_id, status, updated_by_user_id, reason = nil)
diff --git a/app/mailers/emails/merge_requests.rb b/app/mailers/emails/merge_requests.rb
index 6524d0c2087..9ba8f92fcbf 100644
--- a/app/mailers/emails/merge_requests.rb
+++ b/app/mailers/emails/merge_requests.rb
@@ -51,7 +51,9 @@ module Emails
@milestone = milestone
@milestone_url = milestone_url(@milestone)
- mail_answer_thread(@merge_request, merge_request_thread_options(updated_by_user_id, recipient_id, reason))
+ mail_answer_thread(@merge_request, merge_request_thread_options(updated_by_user_id, recipient_id, reason).merge({
+ template_name: 'changed_milestone_email'
+ }))
end
def closed_merge_request_email(recipient_id, merge_request_id, updated_by_user_id, reason = nil)
diff --git a/app/mailers/notify.rb b/app/mailers/notify.rb
index 15710bee4d4..efa1233b434 100644
--- a/app/mailers/notify.rb
+++ b/app/mailers/notify.rb
@@ -16,6 +16,7 @@ class Notify < BaseMailer
include Emails::AutoDevops
include Emails::RemoteMirrors
+ helper MilestonesHelper
helper MergeRequestsHelper
helper DiffHelper
helper BlobHelper
diff --git a/app/models/appearance.rb b/app/models/appearance.rb
index bffba3e13fa..e114c435b67 100644
--- a/app/models/appearance.rb
+++ b/app/models/appearance.rb
@@ -28,4 +28,32 @@ class Appearance < ActiveRecord::Base
errors.add(:single_appearance_row, 'Only 1 appearances row can exist')
end
end
+
+ def logo_path
+ logo_system_path(logo, 'logo')
+ end
+
+ def header_logo_path
+ logo_system_path(header_logo, 'header_logo')
+ end
+
+ def favicon_path
+ logo_system_path(favicon, 'favicon')
+ end
+
+ private
+
+ def logo_system_path(logo, mount_type)
+ return unless logo&.upload
+
+ # If we're using a CDN, we need to use the full URL
+ asset_host = ActionController::Base.asset_host
+ local_path = Gitlab::Routing.url_helpers.appearance_upload_path(
+ filename: logo.filename,
+ id: logo.upload.model_id,
+ model: 'appearance',
+ mounted_as: mount_type)
+
+ Gitlab::Utils.append_path(asset_host, local_path)
+ end
end
diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb
index 4319db42019..88746375c67 100644
--- a/app/models/application_setting.rb
+++ b/app/models/application_setting.rb
@@ -302,7 +302,8 @@ class ApplicationSetting < ActiveRecord::Base
user_show_add_ssh_key_message: true,
usage_stats_set_by_user_id: nil,
diff_max_patch_bytes: Gitlab::Git::Diff::DEFAULT_MAX_PATCH_BYTES,
- commit_email_hostname: default_commit_email_hostname
+ commit_email_hostname: default_commit_email_hostname,
+ protected_ci_variables: false
}
end
@@ -311,7 +312,7 @@ class ApplicationSetting < ActiveRecord::Base
end
def self.create_from_defaults
- create(defaults)
+ build_from_defaults.tap(&:save)
end
def self.human_attribute_name(attr, _options = {})
@@ -382,7 +383,7 @@ class ApplicationSetting < ActiveRecord::Base
end
def restricted_visibility_levels=(levels)
- super(levels.map { |level| Gitlab::VisibilityLevel.level_value(level) })
+ super(levels&.map { |level| Gitlab::VisibilityLevel.level_value(level) })
end
def strip_sentry_values
diff --git a/app/models/blob.rb b/app/models/blob.rb
index 66a0925c495..c5766eb0327 100644
--- a/app/models/blob.rb
+++ b/app/models/blob.rb
@@ -102,7 +102,7 @@ class Blob < SimpleDelegator
# If the blob is a text based blob the content is converted to UTF-8 and any
# invalid byte sequences are replaced.
def data
- if binary?
+ if binary_in_repo?
super
else
@data ||= super.encode(Encoding::UTF_8, invalid: :replace, undef: :replace)
@@ -149,7 +149,7 @@ class Blob < SimpleDelegator
# an LFS pointer, we assume the file stored in LFS is binary, unless a
# text-based rich blob viewer matched on the file's extension. Otherwise, this
# depends on the type of the blob itself.
- def raw_binary?
+ def binary?
if stored_externally?
if rich_viewer
rich_viewer.binary?
@@ -161,7 +161,7 @@ class Blob < SimpleDelegator
true
end
else
- binary?
+ binary_in_repo?
end
end
@@ -180,7 +180,7 @@ class Blob < SimpleDelegator
end
def readable_text?
- text? && !stored_externally? && !truncated?
+ text_in_repo? && !stored_externally? && !truncated?
end
def simple_viewer
@@ -220,7 +220,7 @@ class Blob < SimpleDelegator
def simple_viewer_class
if empty?
BlobViewer::Empty
- elsif raw_binary?
+ elsif binary?
BlobViewer::Download
else # text
BlobViewer::Text
diff --git a/app/models/blob_viewer/base.rb b/app/models/blob_viewer/base.rb
index eaaf9af1330..df6b9bb2f0b 100644
--- a/app/models/blob_viewer/base.rb
+++ b/app/models/blob_viewer/base.rb
@@ -16,7 +16,7 @@ module BlobViewer
def initialize(blob)
@blob = blob
- @initially_binary = blob.binary?
+ @initially_binary = blob.binary_in_repo?
end
def self.partial_path
@@ -52,7 +52,7 @@ module BlobViewer
end
def self.can_render?(blob, verify_binary: true)
- return false if verify_binary && binary? != blob.binary?
+ return false if verify_binary && binary? != blob.binary_in_repo?
return true if extensions&.include?(blob.extension)
return true if file_types&.include?(blob.file_type)
@@ -72,7 +72,7 @@ module BlobViewer
end
def binary_detected_after_load?
- !@initially_binary && blob.binary?
+ !@initially_binary && blob.binary_in_repo?
end
# This method is used on the server side to check whether we can attempt to
diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb
index 16a72c680fa..b128a254b96 100644
--- a/app/models/ci/build.rb
+++ b/app/models/ci/build.rb
@@ -10,6 +10,7 @@ module Ci
include Importable
include Gitlab::Utils::StrongMemoize
include Deployable
+ include HasRef
belongs_to :project, inverse_of: :builds
belongs_to :runner
@@ -640,11 +641,11 @@ module Ci
def secret_group_variables
return [] unless project.group
- project.group.ci_variables_for(ref, project)
+ project.group.ci_variables_for(git_ref, project)
end
def secret_project_variables(environment: persisted_environment)
- project.ci_variables_for(ref: ref, environment: environment)
+ project.ci_variables_for(ref: git_ref, environment: environment)
end
def steps
diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb
index 25937065011..1f5017cc3c3 100644
--- a/app/models/ci/pipeline.rb
+++ b/app/models/ci/pipeline.rb
@@ -11,6 +11,7 @@ module Ci
include Gitlab::Utils::StrongMemoize
include AtomicInternalId
include EnumWithNil
+ include HasRef
belongs_to :project, inverse_of: :all_pipelines
belongs_to :user
@@ -380,7 +381,7 @@ module Ci
end
def branch?
- !tag? && !merge_request?
+ super && !merge_request?
end
def stuck?
@@ -580,7 +581,7 @@ module Ci
end
def protected_ref?
- strong_memoize(:protected_ref) { project.protected_for?(ref) }
+ strong_memoize(:protected_ref) { project.protected_for?(git_ref) }
end
def legacy_trigger
@@ -712,14 +713,10 @@ module Ci
end
def git_ref
- if branch?
+ if merge_request?
Gitlab::Git::BRANCH_REF_PREFIX + ref.to_s
- elsif merge_request?
- Gitlab::Git::BRANCH_REF_PREFIX + ref.to_s
- elsif tag?
- Gitlab::Git::TAG_REF_PREFIX + ref.to_s
else
- raise ArgumentError, 'Invalid pipeline type!'
+ super
end
end
diff --git a/app/models/ci/runner.rb b/app/models/ci/runner.rb
index 3e5cedf92b9..8249199e76f 100644
--- a/app/models/ci/runner.rb
+++ b/app/models/ci/runner.rb
@@ -66,7 +66,7 @@ module Ci
scope :belonging_to_parent_group_of_project, -> (project_id) {
project_groups = ::Group.joins(:projects).where(projects: { id: project_id })
- hierarchy_groups = Gitlab::GroupHierarchy.new(project_groups).base_and_ancestors
+ hierarchy_groups = Gitlab::ObjectHierarchy.new(project_groups).base_and_ancestors
joins(:groups).where(namespaces: { id: hierarchy_groups })
}
diff --git a/app/models/clusters/applications/cert_manager.rb b/app/models/clusters/applications/cert_manager.rb
index 74ef7c7e145..c758577815a 100644
--- a/app/models/clusters/applications/cert_manager.rb
+++ b/app/models/clusters/applications/cert_manager.rb
@@ -3,7 +3,7 @@
module Clusters
module Applications
class CertManager < ActiveRecord::Base
- VERSION = 'v0.5.0'.freeze
+ VERSION = 'v0.5.2'.freeze
self.table_name = 'clusters_applications_cert_managers'
diff --git a/app/models/clusters/applications/runner.rb b/app/models/clusters/applications/runner.rb
index c931b340b24..0c0247da1fb 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 < ActiveRecord::Base
- VERSION = '0.1.39'.freeze
+ VERSION = '0.1.43'.freeze
self.table_name = 'clusters_applications_runners'
diff --git a/app/models/clusters/platforms/kubernetes.rb b/app/models/clusters/platforms/kubernetes.rb
index 867f0edcb07..0dc0c4f80d6 100644
--- a/app/models/clusters/platforms/kubernetes.rb
+++ b/app/models/clusters/platforms/kubernetes.rb
@@ -106,7 +106,7 @@ module Clusters
def terminals(environment)
with_reactive_cache do |data|
pods = filter_by_label(data[:pods], app: environment.slug)
- terminals = pods.flat_map { |pod| terminals_for_pod(api_url, actual_namespace, pod) }
+ terminals = pods.flat_map { |pod| terminals_for_pod(api_url, actual_namespace, pod) }.compact
terminals.each { |terminal| add_terminal_auth(terminal, terminal_auth) }
end
end
@@ -228,7 +228,7 @@ module Clusters
return unless namespace_changed?
run_after_commit do
- ClusterPlatformConfigureWorker.perform_async(cluster_id)
+ ClusterConfigureWorker.perform_async(cluster_id)
end
end
end
diff --git a/app/models/commit.rb b/app/models/commit.rb
index a422a0995ff..01f4c58daa1 100644
--- a/app/models/commit.rb
+++ b/app/models/commit.rb
@@ -469,6 +469,10 @@ class Commit
!!merged_merge_request(user)
end
+ def cache_key
+ "commit:#{sha}"
+ end
+
private
def commit_reference(from, referable_commit_id, full: false)
diff --git a/app/models/concerns/blob_like.rb b/app/models/concerns/blob_like.rb
index f20f01486a5..dc80f8d62f4 100644
--- a/app/models/concerns/blob_like.rb
+++ b/app/models/concerns/blob_like.rb
@@ -28,7 +28,7 @@ module BlobLike
nil
end
- def binary?
+ def binary_in_repo?
false
end
diff --git a/app/models/concerns/cacheable_attributes.rb b/app/models/concerns/cacheable_attributes.rb
index 75592bb63e2..3d60f6924c1 100644
--- a/app/models/concerns/cacheable_attributes.rb
+++ b/app/models/concerns/cacheable_attributes.rb
@@ -23,7 +23,12 @@ module CacheableAttributes
end
def build_from_defaults(attributes = {})
- new(defaults.merge(attributes))
+ final_attributes = defaults
+ .merge(attributes)
+ .stringify_keys
+ .slice(*column_names)
+
+ new(final_attributes)
end
def cached
diff --git a/app/models/concerns/descendant.rb b/app/models/concerns/descendant.rb
new file mode 100644
index 00000000000..4c436522122
--- /dev/null
+++ b/app/models/concerns/descendant.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+module Descendant
+ extend ActiveSupport::Concern
+
+ class_methods do
+ def supports_nested_objects?
+ Gitlab::Database.postgresql?
+ end
+ end
+end
diff --git a/app/models/concerns/discussion_on_diff.rb b/app/models/concerns/discussion_on_diff.rb
index 266c37fa3a1..e4e5928f5cf 100644
--- a/app/models/concerns/discussion_on_diff.rb
+++ b/app/models/concerns/discussion_on_diff.rb
@@ -9,7 +9,7 @@ module DiscussionOnDiff
included do
delegate :line_code,
:original_line_code,
- :diff_file,
+ :note_diff_file,
:diff_line,
:active?,
:created_at_diff?,
@@ -39,6 +39,7 @@ module DiscussionOnDiff
# Returns an array of at most 16 highlighted lines above a diff note
def truncated_diff_lines(highlight: true, diff_limit: nil)
+ return [] unless on_text?
return [] if diff_line.nil? && first_note.is_a?(LegacyDiffNote)
diff_limit = [diff_limit, NUMBER_OF_TRUNCATED_DIFF_LINES].compact.min
@@ -59,6 +60,13 @@ module DiscussionOnDiff
prev_lines
end
+ def diff_file
+ strong_memoize(:diff_file) do
+ # Falling back here is important as `note_diff_files` are created async.
+ fetch_preloaded_diff_file || first_note.diff_file
+ end
+ end
+
def line_code_in_diffs(diff_refs)
if active?(diff_refs)
line_code
@@ -66,4 +74,15 @@ module DiscussionOnDiff
original_line_code
end
end
+
+ private
+
+ def fetch_preloaded_diff_file
+ fetch_preloaded_diff =
+ context_noteable &&
+ context_noteable.preloads_discussion_diff_highlighting? &&
+ note_diff_file
+
+ context_noteable.discussions_diffs.find_by_id(note_diff_file.id) if fetch_preloaded_diff
+ end
end
diff --git a/app/models/concerns/has_ref.rb b/app/models/concerns/has_ref.rb
new file mode 100644
index 00000000000..d7089294efc
--- /dev/null
+++ b/app/models/concerns/has_ref.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+module HasRef
+ extend ActiveSupport::Concern
+
+ def branch?
+ !tag?
+ end
+
+ def git_ref
+ if branch?
+ Gitlab::Git::BRANCH_REF_PREFIX + ref.to_s
+ elsif tag?
+ Gitlab::Git::TAG_REF_PREFIX + ref.to_s
+ end
+ end
+end
diff --git a/app/models/concerns/noteable.rb b/app/models/concerns/noteable.rb
index f2cad09e779..29476654bf7 100644
--- a/app/models/concerns/noteable.rb
+++ b/app/models/concerns/noteable.rb
@@ -34,6 +34,10 @@ module Noteable
false
end
+ def preloads_discussion_diff_highlighting?
+ false
+ end
+
def discussion_notes
notes
end
diff --git a/app/models/dashboard_group_milestone.rb b/app/models/dashboard_group_milestone.rb
index c06823184c2..9bcc95e35a5 100644
--- a/app/models/dashboard_group_milestone.rb
+++ b/app/models/dashboard_group_milestone.rb
@@ -5,7 +5,6 @@ class DashboardGroupMilestone < GlobalMilestone
attr_reader :group_name
- override :initialize
def initialize(milestone)
super
diff --git a/app/models/diff_viewer/base.rb b/app/models/diff_viewer/base.rb
index 1176861a827..527ee33b83b 100644
--- a/app/models/diff_viewer/base.rb
+++ b/app/models/diff_viewer/base.rb
@@ -18,7 +18,7 @@ module DiffViewer
def initialize(diff_file)
@diff_file = diff_file
- @initially_binary = diff_file.binary?
+ @initially_binary = diff_file.binary_in_repo?
end
def self.partial_path
@@ -48,7 +48,7 @@ module DiffViewer
def self.can_render_blob?(blob, verify_binary: true)
return true if blob.nil?
- return false if verify_binary && binary? != blob.binary?
+ return false if verify_binary && binary? != blob.binary_in_repo?
return true if extensions&.include?(blob.extension)
return true if file_types&.include?(blob.file_type)
@@ -70,20 +70,49 @@ module DiffViewer
end
def binary_detected_after_load?
- !@initially_binary && diff_file.binary?
+ !@initially_binary && diff_file.binary_in_repo?
end
# This method is used on the server side to check whether we can attempt to
- # render the diff_file at all. Human-readable error messages are found in the
- # `BlobHelper#diff_render_error_reason` helper.
+ # render the diff_file at all. The human-readable error message can be
+ # retrieved by #render_error_message.
def render_error
if too_large?
:too_large
end
end
+ def render_error_message
+ return unless render_error
+
+ _("This %{viewer} could not be displayed because %{reason}. You can %{options} instead.") %
+ {
+ viewer: switcher_title,
+ reason: render_error_reason,
+ options: render_error_options.to_sentence(two_words_connector: _(' or '), last_word_connector: _(', or '))
+ }
+ end
+
def prepare!
# To be overridden by subclasses
end
+
+ private
+
+ def render_error_options
+ options = []
+
+ blob_url = Gitlab::Routing.url_helpers.project_blob_path(diff_file.repository.project,
+ File.join(diff_file.content_sha, diff_file.file_path))
+ options << ActionController::Base.helpers.link_to(_('view the blob'), blob_url)
+
+ options
+ end
+
+ def render_error_reason
+ if render_error == :too_large
+ _("it is too large")
+ end
+ end
end
end
diff --git a/app/models/diff_viewer/image.rb b/app/models/diff_viewer/image.rb
index c356c2ca50e..350bef1d42a 100644
--- a/app/models/diff_viewer/image.rb
+++ b/app/models/diff_viewer/image.rb
@@ -9,6 +9,6 @@ module DiffViewer
self.extensions = UploaderHelper::IMAGE_EXT
self.binary = true
self.switcher_icon = 'picture-o'
- self.switcher_title = 'image diff'
+ self.switcher_title = _('image diff')
end
end
diff --git a/app/models/diff_viewer/rich.rb b/app/models/diff_viewer/rich.rb
index 2faa1be6567..5caefa2031c 100644
--- a/app/models/diff_viewer/rich.rb
+++ b/app/models/diff_viewer/rich.rb
@@ -7,7 +7,7 @@ module DiffViewer
included do
self.type = :rich
self.switcher_icon = 'file-text-o'
- self.switcher_title = 'rendered diff'
+ self.switcher_title = _('rendered diff')
end
end
end
diff --git a/app/models/diff_viewer/server_side.rb b/app/models/diff_viewer/server_side.rb
index 977204e6c97..0877c9dddec 100644
--- a/app/models/diff_viewer/server_side.rb
+++ b/app/models/diff_viewer/server_side.rb
@@ -24,5 +24,17 @@ module DiffViewer
super
end
+
+ private
+
+ def render_error_reason
+ return super unless render_error == :server_side_but_stored_externally
+
+ if diff_file.external_storage == :lfs
+ _('it is stored in LFS')
+ else
+ _('it is stored externally')
+ end
+ end
end
end
diff --git a/app/models/diff_viewer/simple.rb b/app/models/diff_viewer/simple.rb
index 8d28ca5239a..929d8ad5a7e 100644
--- a/app/models/diff_viewer/simple.rb
+++ b/app/models/diff_viewer/simple.rb
@@ -7,7 +7,7 @@ module DiffViewer
included do
self.type = :simple
self.switcher_icon = 'code'
- self.switcher_title = 'source diff'
+ self.switcher_title = _('source diff')
end
end
end
diff --git a/app/models/group.rb b/app/models/group.rb
index 233747cc2c2..edac2444c4d 100644
--- a/app/models/group.rb
+++ b/app/models/group.rb
@@ -10,6 +10,7 @@ class Group < Namespace
include Referable
include SelectForProjectAuthorization
include LoadedInGroupList
+ include Descendant
include GroupDescendant
include TokenAuthenticatable
include WithUploads
@@ -63,10 +64,6 @@ class Group < Namespace
after_update :path_changed_hook, if: :path_changed?
class << self
- def supports_nested_groups?
- Gitlab::Database.postgresql?
- end
-
def sort_by_attribute(method)
if method == 'storage_size_desc'
# storage_size is a virtual column so we need to
diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb
index 944b9f72396..b937bef100b 100644
--- a/app/models/merge_request.rb
+++ b/app/models/merge_request.rb
@@ -408,6 +408,28 @@ class MergeRequest < ActiveRecord::Base
merge_request_diffs.where.not(id: merge_request_diff.id)
end
+ def preloads_discussion_diff_highlighting?
+ true
+ end
+
+ def preload_discussions_diff_highlight
+ preloadable_files = note_diff_files.for_commit_or_unresolved
+
+ discussions_diffs.load_highlight(preloadable_files.pluck(:id))
+ end
+
+ def discussions_diffs
+ strong_memoize(:discussions_diffs) do
+ Gitlab::DiscussionsDiff::FileCollection.new(note_diff_files.to_a)
+ end
+ end
+
+ def note_diff_files
+ NoteDiffFile
+ .where(diff_note: discussion_notes)
+ .includes(diff_note: :project)
+ end
+
def diff_size
# Calling `merge_request_diff.diffs.real_size` will also perform
# highlighting, which we don't need here.
diff --git a/app/models/milestone.rb b/app/models/milestone.rb
index db56533dea5..f55c39d9912 100644
--- a/app/models/milestone.rb
+++ b/app/models/milestone.rb
@@ -216,7 +216,7 @@ class Milestone < ActiveRecord::Base
end
def reference_link_text(from = nil)
- self.title
+ self.class.reference_prefix + self.title
end
def milestoneish_id
diff --git a/app/models/namespace.rb b/app/models/namespace.rb
index 3c9b1d32a53..a0bebc5e9a2 100644
--- a/app/models/namespace.rb
+++ b/app/models/namespace.rb
@@ -175,16 +175,16 @@ class Namespace < ActiveRecord::Base
# Returns all ancestors, self, and descendants of the current namespace.
def self_and_hierarchy
- Gitlab::GroupHierarchy
+ Gitlab::ObjectHierarchy
.new(self.class.where(id: id))
- .all_groups
+ .all_objects
end
# Returns all the ancestors of the current namespaces.
def ancestors
return self.class.none unless parent_id
- Gitlab::GroupHierarchy
+ Gitlab::ObjectHierarchy
.new(self.class.where(id: parent_id))
.base_and_ancestors
end
@@ -192,27 +192,27 @@ class Namespace < ActiveRecord::Base
# returns all ancestors upto but excluding the given namespace
# when no namespace is given, all ancestors upto the top are returned
def ancestors_upto(top = nil, hierarchy_order: nil)
- Gitlab::GroupHierarchy.new(self.class.where(id: id))
+ Gitlab::ObjectHierarchy.new(self.class.where(id: id))
.ancestors(upto: top, hierarchy_order: hierarchy_order)
end
def self_and_ancestors
return self.class.where(id: id) unless parent_id
- Gitlab::GroupHierarchy
+ Gitlab::ObjectHierarchy
.new(self.class.where(id: id))
.base_and_ancestors
end
# Returns all the descendants of the current namespace.
def descendants
- Gitlab::GroupHierarchy
+ Gitlab::ObjectHierarchy
.new(self.class.where(parent_id: id))
.base_and_descendants
end
def self_and_descendants
- Gitlab::GroupHierarchy
+ Gitlab::ObjectHierarchy
.new(self.class.where(id: id))
.base_and_descendants
end
@@ -293,7 +293,7 @@ class Namespace < ActiveRecord::Base
end
def force_share_with_group_lock_on_descendants
- return unless Group.supports_nested_groups?
+ return unless Group.supports_nested_objects?
# We can't use `descendants.update_all` since Rails will throw away the WITH
# RECURSIVE statement. We also can't use WHERE EXISTS since we can't use
@@ -306,6 +306,7 @@ class Namespace < ActiveRecord::Base
def write_projects_repository_config
all_projects.find_each do |project|
project.write_repository_config
+ project.track_project_repository
end
end
end
diff --git a/app/models/note_diff_file.rb b/app/models/note_diff_file.rb
index 27aef7adc48..e369122003e 100644
--- a/app/models/note_diff_file.rb
+++ b/app/models/note_diff_file.rb
@@ -3,7 +3,22 @@
class NoteDiffFile < ActiveRecord::Base
include DiffFile
+ scope :for_commit_or_unresolved, -> do
+ joins(:diff_note).where("resolved_at IS NULL OR noteable_type = 'Commit'")
+ end
+
+ delegate :original_position, :project, to: :diff_note
+
belongs_to :diff_note, inverse_of: :note_diff_file
validates :diff_note, presence: true
+
+ def raw_diff_file
+ raw_diff = Gitlab::Git::Diff.new(to_hash)
+
+ Gitlab::Diff::File.new(raw_diff,
+ repository: project.repository,
+ diff_refs: original_position.diff_refs,
+ unique_identifier: id)
+ end
end
diff --git a/app/models/project.rb b/app/models/project.rb
index e4b8db860a4..cd558752080 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -324,10 +324,9 @@ class Project < ActiveRecord::Base
validates :namespace, presence: true
validates :name, uniqueness: { scope: :namespace_id }
- validates :import_url, url: { protocols: ->(project) { project.persisted? ? VALID_MIRROR_PROTOCOLS : VALID_IMPORT_PROTOCOLS },
- ports: ->(project) { project.persisted? ? VALID_MIRROR_PORTS : VALID_IMPORT_PORTS },
- allow_localhost: false,
- enforce_user: true }, if: [:external_import?, :import_url_changed?]
+ validates :import_url, public_url: { protocols: ->(project) { project.persisted? ? VALID_MIRROR_PROTOCOLS : VALID_IMPORT_PROTOCOLS },
+ ports: ->(project) { project.persisted? ? VALID_MIRROR_PORTS : VALID_IMPORT_PORTS },
+ enforce_user: true }, if: [:external_import?, :import_url_changed?]
validates :star_count, numericality: { greater_than_or_equal_to: 0 }
validate :check_limit, on: :create
validate :check_repository_path_availability, on: :update, if: ->(project) { project.renamed? }
@@ -570,7 +569,7 @@ class Project < ActiveRecord::Base
# returns all ancestor-groups upto but excluding the given namespace
# when no namespace is given, all ancestors upto the top are returned
def ancestors_upto(top = nil, hierarchy_order: nil)
- Gitlab::GroupHierarchy.new(Group.where(id: namespace_id))
+ Gitlab::ObjectHierarchy.new(Group.where(id: namespace_id))
.base_and_ancestors(upto: top, hierarchy_order: hierarchy_order)
end
@@ -1244,10 +1243,8 @@ class Project < ActiveRecord::Base
end
def track_project_repository
- return unless hashed_storage?(:repository)
-
- project_repo = project_repository || build_project_repository
- project_repo.update!(shard_name: repository_storage, disk_path: disk_path)
+ repository = project_repository || build_project_repository
+ repository.update!(shard_name: repository_storage, disk_path: disk_path)
end
def create_repository(force: false)
@@ -1736,10 +1733,21 @@ class Project < ActiveRecord::Base
end
def protected_for?(ref)
- if repository.branch_exists?(ref)
- ProtectedBranch.protected?(self, ref)
- elsif repository.tag_exists?(ref)
- ProtectedTag.protected?(self, ref)
+ raise Repository::AmbiguousRefError if repository.ambiguous_ref?(ref)
+
+ resolved_ref = repository.expand_ref(ref) || ref
+ return false unless Gitlab::Git.tag_ref?(resolved_ref) || Gitlab::Git.branch_ref?(resolved_ref)
+
+ ref_name = if resolved_ref == ref
+ Gitlab::Git.ref_name(resolved_ref)
+ else
+ ref
+ end
+
+ if Gitlab::Git.branch_ref?(resolved_ref)
+ ProtectedBranch.protected?(self, ref_name)
+ elsif Gitlab::Git.tag_ref?(resolved_ref)
+ ProtectedTag.protected?(self, ref_name)
end
end
diff --git a/app/models/prometheus_metric.rb b/app/models/prometheus_metric.rb
index defbade1ed6..5594594a48d 100644
--- a/app/models/prometheus_metric.rb
+++ b/app/models/prometheus_metric.rb
@@ -18,6 +18,54 @@ class PrometheusMetric < ActiveRecord::Base
system: 2
}
+ GROUP_DETAILS = {
+ # built-in groups
+ nginx_ingress_vts: {
+ group_title: _('Response metrics (NGINX Ingress VTS)'),
+ required_metrics: %w(nginx_upstream_responses_total nginx_upstream_response_msecs_avg),
+ priority: 10
+ }.freeze,
+ nginx_ingress: {
+ group_title: _('Response metrics (NGINX Ingress)'),
+ required_metrics: %w(nginx_ingress_controller_requests nginx_ingress_controller_ingress_upstream_latency_seconds_sum),
+ priority: 10
+ }.freeze,
+ ha_proxy: {
+ group_title: _('Response metrics (HA Proxy)'),
+ required_metrics: %w(haproxy_frontend_http_requests_total haproxy_frontend_http_responses_total),
+ priority: 10
+ }.freeze,
+ aws_elb: {
+ group_title: _('Response metrics (AWS ELB)'),
+ required_metrics: %w(aws_elb_request_count_sum aws_elb_latency_average aws_elb_httpcode_backend_5_xx_sum),
+ priority: 10
+ }.freeze,
+ nginx: {
+ group_title: _('Response metrics (NGINX)'),
+ required_metrics: %w(nginx_server_requests nginx_server_requestMsec),
+ priority: 10
+ }.freeze,
+ kubernetes: {
+ group_title: _('System metrics (Kubernetes)'),
+ required_metrics: %w(container_memory_usage_bytes container_cpu_usage_seconds_total),
+ priority: 5
+ }.freeze,
+
+ # custom/user groups
+ business: {
+ group_title: _('Business metrics (Custom)'),
+ priority: 0
+ }.freeze,
+ response: {
+ group_title: _('Response metrics (Custom)'),
+ priority: -5
+ }.freeze,
+ system: {
+ group_title: _('System metrics (Custom)'),
+ priority: -10
+ }.freeze
+ }.freeze
+
validates :title, presence: true
validates :query, presence: true
validates :group, presence: true
@@ -29,36 +77,16 @@ class PrometheusMetric < ActiveRecord::Base
scope :common, -> { where(common: true) }
- GROUP_TITLES = {
- # built-in groups
- nginx_ingress_vts: _('Response metrics (NGINX Ingress VTS)'),
- nginx_ingress: _('Response metrics (NGINX Ingress)'),
- ha_proxy: _('Response metrics (HA Proxy)'),
- aws_elb: _('Response metrics (AWS ELB)'),
- nginx: _('Response metrics (NGINX)'),
- kubernetes: _('System metrics (Kubernetes)'),
-
- # custom/user groups
- business: _('Business metrics (Custom)'),
- response: _('Response metrics (Custom)'),
- system: _('System metrics (Custom)')
- }.freeze
-
- REQUIRED_METRICS = {
- nginx_ingress_vts: %w(nginx_upstream_responses_total nginx_upstream_response_msecs_avg),
- nginx_ingress: %w(nginx_ingress_controller_requests nginx_ingress_controller_ingress_upstream_latency_seconds_sum),
- ha_proxy: %w(haproxy_frontend_http_requests_total haproxy_frontend_http_responses_total),
- aws_elb: %w(aws_elb_request_count_sum aws_elb_latency_average aws_elb_httpcode_backend_5_xx_sum),
- nginx: %w(nginx_server_requests nginx_server_requestMsec),
- kubernetes: %w(container_memory_usage_bytes container_cpu_usage_seconds_total)
- }.freeze
+ def priority
+ group_details(group).fetch(:priority)
+ end
def group_title
- GROUP_TITLES[group.to_sym]
+ group_details(group).fetch(:group_title)
end
def required_metrics
- REQUIRED_METRICS[group.to_sym].to_a.map(&:to_s)
+ group_details(group).fetch(:required_metrics, []).map(&:to_s)
end
def to_query_metric
@@ -89,4 +117,10 @@ class PrometheusMetric < ActiveRecord::Base
}]
end
end
+
+ private
+
+ def group_details(group)
+ GROUP_DETAILS.fetch(group.to_sym)
+ end
end
diff --git a/app/models/release.rb b/app/models/release.rb
index 7a09ee459a6..df3dfe1cf2f 100644
--- a/app/models/release.rb
+++ b/app/models/release.rb
@@ -2,11 +2,39 @@
class Release < ActiveRecord::Base
include CacheMarkdownField
+ include Gitlab::Utils::StrongMemoize
cache_markdown_field :description
belongs_to :project
+ # releases prior to 11.7 have no author
belongs_to :author, class_name: 'User'
validates :description, :project, :tag, presence: true
+
+ scope :sorted, -> { order(created_at: :desc) }
+
+ delegate :repository, to: :project
+
+ def commit
+ strong_memoize(:commit) do
+ repository.commit(actual_sha)
+ end
+ end
+
+ def tag_missing?
+ actual_tag.nil?
+ end
+
+ private
+
+ def actual_sha
+ sha || actual_tag&.dereferenced_target
+ end
+
+ def actual_tag
+ strong_memoize(:actual_tag) do
+ repository.find_tag(tag)
+ end
+ end
end
diff --git a/app/models/remote_mirror.rb b/app/models/remote_mirror.rb
index 5a6895aefab..a3fa67c72bf 100644
--- a/app/models/remote_mirror.rb
+++ b/app/models/remote_mirror.rb
@@ -17,7 +17,7 @@ class RemoteMirror < ActiveRecord::Base
belongs_to :project, inverse_of: :remote_mirrors
- validates :url, presence: true, url: { protocols: %w(ssh git http https), allow_blank: true, enforce_user: true }
+ validates :url, presence: true, public_url: { protocols: %w(ssh git http https), allow_blank: true, enforce_user: true }
before_save :set_new_remote_name, if: :mirror_url_changed?
diff --git a/app/models/repository.rb b/app/models/repository.rb
index 015a179f374..b19ae2e0e6a 100644
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -25,6 +25,7 @@ class Repository
delegate :bundle_to_disk, to: :raw_repository
CreateTreeError = Class.new(StandardError)
+ AmbiguousRefError = Class.new(StandardError)
# Methods that cache data from the Git repository.
#
@@ -181,6 +182,18 @@ class Repository
tags.find { |tag| tag.name == name }
end
+ def ambiguous_ref?(ref)
+ tag_exists?(ref) && branch_exists?(ref)
+ end
+
+ def expand_ref(ref)
+ if tag_exists?(ref)
+ Gitlab::Git::TAG_REF_PREFIX + ref
+ elsif branch_exists?(ref)
+ Gitlab::Git::BRANCH_REF_PREFIX + ref
+ end
+ end
+
def add_branch(user, branch_name, ref)
branch = raw_repository.add_branch(branch_name, user: user, target: ref)
diff --git a/app/models/snippet.rb b/app/models/snippet.rb
index 11856b55902..f9b23bbbf6c 100644
--- a/app/models/snippet.rb
+++ b/app/models/snippet.rb
@@ -175,6 +175,12 @@ class Snippet < ActiveRecord::Base
:visibility_level
end
+ def embeddable?
+ ability = project_id? ? :read_project_snippet : :read_personal_snippet
+
+ Ability.allowed?(nil, ability, self)
+ end
+
def notes_with_associations
notes.includes(:author)
end
diff --git a/app/models/todo.rb b/app/models/todo.rb
index 7b64615f699..d9b86d941b6 100644
--- a/app/models/todo.rb
+++ b/app/models/todo.rb
@@ -4,6 +4,11 @@ class Todo < ActiveRecord::Base
include Sortable
include FromUnion
+ # Time to wait for todos being removed when not visible for user anymore.
+ # Prevents TODOs being removed by mistake, for example, removing access from a user
+ # and giving it back again.
+ WAIT_FOR_DELETE = 1.hour
+
ASSIGNED = 1
MENTIONED = 2
BUILD_FAILED = 3
diff --git a/app/models/user.rb b/app/models/user.rb
index f20756d1cc3..26fd2d903a1 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -709,13 +709,13 @@ class User < ActiveRecord::Base
# Returns the groups a user is a member of, either directly or through a parent group
def membership_groups
- Gitlab::GroupHierarchy.new(groups).base_and_descendants
+ Gitlab::ObjectHierarchy.new(groups).base_and_descendants
end
# Returns a relation of groups the user has access to, including their parent
# and child groups (recursively).
def all_expanded_groups
- Gitlab::GroupHierarchy.new(groups).all_groups
+ Gitlab::ObjectHierarchy.new(groups).all_objects
end
def expanded_groups_requiring_two_factor_authentication
@@ -1153,7 +1153,7 @@ class User < ActiveRecord::Base
end
def manageable_groups
- Gitlab::GroupHierarchy.new(owned_or_maintainers_groups).base_and_descendants
+ Gitlab::ObjectHierarchy.new(owned_or_maintainers_groups).base_and_descendants
end
def namespaces
@@ -1422,6 +1422,10 @@ class User < ActiveRecord::Base
todos.where(id: ids)
end
+ def pending_todo_for(target)
+ todos.find_by(target: target, state: :pending)
+ end
+
# @deprecated
alias_method :owned_or_masters_groups, :owned_or_maintainers_groups
diff --git a/app/policies/concerns/clusterable_actions.rb b/app/policies/concerns/clusterable_actions.rb
new file mode 100644
index 00000000000..08ddd742ea9
--- /dev/null
+++ b/app/policies/concerns/clusterable_actions.rb
@@ -0,0 +1,14 @@
+# frozen_string_literal: true
+
+module ClusterableActions
+ private
+
+ # Overridden on EE module
+ def multiple_clusters_available?
+ false
+ end
+
+ def clusterable_has_clusters?
+ !subject.clusters.empty?
+ end
+end
diff --git a/app/policies/group_policy.rb b/app/policies/group_policy.rb
index d1264559438..c25766a5af8 100644
--- a/app/policies/group_policy.rb
+++ b/app/policies/group_policy.rb
@@ -1,6 +1,8 @@
# frozen_string_literal: true
class GroupPolicy < BasePolicy
+ include ClusterableActions
+
desc "Group is public"
with_options scope: :subject, score: 0
condition(:public_group) { @subject.public? }
@@ -16,7 +18,7 @@ class GroupPolicy < BasePolicy
condition(:maintainer) { access_level >= GroupMember::MAINTAINER }
condition(:reporter) { access_level >= GroupMember::REPORTER }
- condition(:nested_groups_supported, scope: :global) { Group.supports_nested_groups? }
+ condition(:nested_groups_supported, scope: :global) { Group.supports_nested_objects? }
condition(:has_parent, scope: :subject) { @subject.has_parent? }
condition(:share_with_group_locked, scope: :subject) { @subject.share_with_group_lock? }
@@ -27,6 +29,9 @@ class GroupPolicy < BasePolicy
GroupProjectsFinder.new(group: @subject, current_user: @user, options: { include_subgroups: true }).execute.any?
end
+ condition(:has_clusters, scope: :subject) { clusterable_has_clusters? }
+ condition(:can_have_multiple_clusters) { multiple_clusters_available? }
+
with_options scope: :subject, score: 0
condition(:request_access_enabled) { @subject.request_access_enabled }
@@ -45,7 +50,7 @@ class GroupPolicy < BasePolicy
enable :read_label
end
- rule { admin } .enable :read_group
+ rule { admin }.enable :read_group
rule { has_projects }.policy do
enable :read_group
@@ -67,6 +72,7 @@ class GroupPolicy < BasePolicy
enable :admin_pipeline
enable :admin_build
enable :read_cluster
+ enable :add_cluster
enable :create_cluster
enable :update_cluster
enable :admin_cluster
@@ -106,6 +112,8 @@ class GroupPolicy < BasePolicy
rule { owner & (~share_with_group_locked | ~has_parent | ~parent_share_with_group_locked | can_change_parent_share_with_group_lock) }.enable :change_share_with_group_lock
+ rule { ~can_have_multiple_clusters & has_clusters }.prevent :add_cluster
+
def access_level
return GroupMember::NO_ACCESS if @user.nil?
diff --git a/app/policies/issuable_policy.rb b/app/policies/issuable_policy.rb
index 6d8b575102e..ecb2797d1d9 100644
--- a/app/policies/issuable_policy.rb
+++ b/app/policies/issuable_policy.rb
@@ -11,7 +11,7 @@ class IssuablePolicy < BasePolicy
@user && @subject.assignee_or_author?(@user)
end
- rule { assignee_or_author }.policy do
+ rule { can?(:guest_access) & assignee_or_author }.policy do
enable :read_issue
enable :update_issue
enable :reopen_issue
diff --git a/app/policies/project_policy.rb b/app/policies/project_policy.rb
index 1c082945299..3146f26bed5 100644
--- a/app/policies/project_policy.rb
+++ b/app/policies/project_policy.rb
@@ -2,6 +2,7 @@
class ProjectPolicy < BasePolicy
extend ClassMethods
+ include ClusterableActions
READONLY_FEATURES_WHEN_ARCHIVED = %i[
issue
@@ -22,6 +23,7 @@ class ProjectPolicy < BasePolicy
container_image
pages
cluster
+ release
].freeze
desc "User is a project owner"
@@ -103,6 +105,9 @@ class ProjectPolicy < BasePolicy
@subject.feature_available?(:merge_requests, @user)
end
+ condition(:has_clusters, scope: :subject) { clusterable_has_clusters? }
+ condition(:can_have_multiple_clusters) { multiple_clusters_available? }
+
features = %w[
merge_requests
issues
@@ -169,6 +174,7 @@ class ProjectPolicy < BasePolicy
enable :read_cycle_analytics
enable :award_emoji
enable :read_pages_content
+ enable :read_release
end
# These abilities are not allowed to admins that are not members of the project,
@@ -235,6 +241,8 @@ class ProjectPolicy < BasePolicy
enable :update_container_image
enable :create_environment
enable :create_deployment
+ enable :create_release
+ enable :update_release
end
rule { can?(:maintainer_access) }.policy do
@@ -257,10 +265,12 @@ class ProjectPolicy < BasePolicy
enable :read_pages
enable :update_pages
enable :read_cluster
+ enable :add_cluster
enable :create_cluster
enable :update_cluster
enable :admin_cluster
enable :create_environment_terminal
+ enable :destroy_release
end
rule { (mirror_available & can?(:admin_project)) | admin }.enable :admin_remote_mirror
@@ -320,6 +330,7 @@ class ProjectPolicy < BasePolicy
prevent :download_code
prevent :fork_project
prevent :read_commit_status
+ prevent(*create_read_update_admin_destroy(:release))
end
rule { container_registry_disabled }.policy do
@@ -349,6 +360,7 @@ class ProjectPolicy < BasePolicy
enable :read_commit_status
enable :read_container_image
enable :download_code
+ enable :read_release
enable :download_wiki_code
enable :read_cycle_analytics
enable :read_pages_content
@@ -381,6 +393,8 @@ class ProjectPolicy < BasePolicy
(can?(:read_project_for_iids) & merge_requests_visible_to_user) | can?(:read_merge_request)
end.enable :read_merge_request_iid
+ rule { ~can_have_multiple_clusters & has_clusters }.prevent :add_cluster
+
private
def team_member?
diff --git a/app/policies/release_policy.rb b/app/policies/release_policy.rb
new file mode 100644
index 00000000000..d7f9e5d7445
--- /dev/null
+++ b/app/policies/release_policy.rb
@@ -0,0 +1,5 @@
+# frozen_string_literal: true
+
+class ReleasePolicy < BasePolicy
+ delegate { @subject.project }
+end
diff --git a/app/presenters/clusterable_presenter.rb b/app/presenters/clusterable_presenter.rb
index 9cc137aa3bd..d94d9118eee 100644
--- a/app/presenters/clusterable_presenter.rb
+++ b/app/presenters/clusterable_presenter.rb
@@ -12,6 +12,10 @@ class ClusterablePresenter < Gitlab::View::Presenter::Delegated
.fabricate!
end
+ def can_add_cluster?
+ can?(current_user, :add_cluster, clusterable)
+ end
+
def can_create_cluster?
can?(current_user, :create_cluster, clusterable)
end
diff --git a/app/serializers/diff_viewer_entity.rb b/app/serializers/diff_viewer_entity.rb
index 27fba03cb3f..587fa2347fd 100644
--- a/app/serializers/diff_viewer_entity.rb
+++ b/app/serializers/diff_viewer_entity.rb
@@ -4,4 +4,7 @@ class DiffViewerEntity < Grape::Entity
# Partial name refers directly to a Rails feature, let's avoid
# using this on the frontend.
expose :partial_name, as: :name
+ expose :error do |diff_viewer|
+ diff_viewer.render_error_message
+ end
end
diff --git a/app/serializers/entity_date_helper.rb b/app/serializers/entity_date_helper.rb
index cc0c2abf863..f515abe5917 100644
--- a/app/serializers/entity_date_helper.rb
+++ b/app/serializers/entity_date_helper.rb
@@ -44,14 +44,14 @@ module EntityDateHelper
# It returns "Upcoming" for upcoming entities
# If due date is provided, it returns "# days|weeks|months remaining|ago"
# If start date is provided and elapsed, with no due date, it returns "# days elapsed"
- def remaining_days_in_words(entity)
- if entity.try(:expired?)
+ def remaining_days_in_words(due_date, start_date = nil)
+ if due_date&.past?
content_tag(:strong, 'Past due')
- elsif entity.try(:upcoming?)
+ elsif start_date&.future?
content_tag(:strong, 'Upcoming')
- elsif entity.due_date
- is_upcoming = (entity.due_date - Date.today).to_i > 0
- time_ago = time_ago_in_words(entity.due_date)
+ elsif due_date
+ is_upcoming = (due_date - Date.today).to_i > 0
+ time_ago = time_ago_in_words(due_date)
# https://gitlab.com/gitlab-org/gitlab-ce/issues/49440
#
@@ -63,8 +63,8 @@ module EntityDateHelper
remaining_or_ago = is_upcoming ? _("remaining") : _("ago")
"#{content} #{remaining_or_ago}".html_safe
- elsif entity.start_date && entity.start_date.past?
- days = entity.elapsed_days
+ elsif start_date&.past?
+ days = (Date.today - start_date).to_i
"#{content_tag(:strong, days)} #{'day'.pluralize(days)} elapsed".html_safe
end
end
diff --git a/app/serializers/issuable_sidebar_basic_entity.rb b/app/serializers/issuable_sidebar_basic_entity.rb
new file mode 100644
index 00000000000..61de3c93337
--- /dev/null
+++ b/app/serializers/issuable_sidebar_basic_entity.rb
@@ -0,0 +1,106 @@
+# frozen_string_literal: true
+
+class IssuableSidebarBasicEntity < Grape::Entity
+ include RequestAwareEntity
+
+ expose :id
+ expose :type do |issuable|
+ issuable.to_ability_name
+ end
+ expose :author_id
+ expose :project_id do |issuable|
+ issuable.project.id
+ end
+ expose :discussion_locked
+ expose :reference do |issuable|
+ issuable.to_reference(issuable.project, full: true)
+ end
+
+ expose :milestone, using: ::API::Entities::Milestone
+ expose :labels, using: LabelEntity
+
+ expose :current_user, if: lambda { |_issuable| current_user } do
+ expose :current_user, merge: true, using: API::Entities::UserBasic
+
+ expose :todo, using: IssuableSidebarTodoEntity do |issuable|
+ current_user.pending_todo_for(issuable)
+ end
+
+ expose :can_edit do |issuable|
+ can?(current_user, :"admin_#{issuable.to_ability_name}", issuable.project)
+ end
+
+ expose :can_move do |issuable|
+ issuable.can_move?(current_user)
+ end
+
+ expose :can_admin_label do |issuable|
+ can?(current_user, :admin_label, issuable.project)
+ end
+ end
+
+ expose :issuable_json_path do |issuable|
+ if issuable.is_a?(MergeRequest)
+ project_merge_request_path(issuable.project, issuable.iid, :json)
+ else
+ project_issue_path(issuable.project, issuable.iid, :json)
+ end
+ end
+
+ expose :namespace_path do |issuable|
+ issuable.project.namespace.full_path
+ end
+
+ expose :project_path do |issuable|
+ issuable.project.path
+ end
+
+ expose :project_full_path do |issuable|
+ issuable.project.full_path
+ end
+
+ expose :project_issuables_path do |issuable|
+ project = issuable.project
+ namespace = project.namespace
+
+ if issuable.is_a?(MergeRequest)
+ namespace_project_merge_requests_path(namespace, project)
+ else
+ namespace_project_issues_path(namespace, project)
+ end
+ end
+
+ expose :create_todo_path do |issuable|
+ project_todos_path(issuable.project)
+ end
+
+ expose :project_milestones_path do |issuable|
+ project_milestones_path(issuable.project, :json)
+ end
+
+ expose :project_labels_path do |issuable|
+ project_labels_path(issuable.project, :json, include_ancestor_groups: true)
+ end
+
+ expose :toggle_subscription_path do |issuable|
+ toggle_subscription_path(issuable)
+ end
+
+ expose :move_issue_path do |issuable|
+ move_namespace_project_issue_path(
+ namespace_id: issuable.project.namespace.to_param,
+ project_id: issuable.project,
+ id: issuable
+ )
+ end
+
+ expose :projects_autocomplete_path do |issuable|
+ autocomplete_projects_path(project_id: issuable.project.id)
+ end
+
+ private
+
+ def current_user
+ request.current_user
+ end
+end
diff --git a/app/serializers/issuable_sidebar_entity.rb b/app/serializers/issuable_sidebar_extras_entity.rb
index 773d78d324c..d60253564e1 100644
--- a/app/serializers/issuable_sidebar_entity.rb
+++ b/app/serializers/issuable_sidebar_extras_entity.rb
@@ -1,8 +1,8 @@
# frozen_string_literal: true
-class IssuableSidebarEntity < Grape::Entity
- include TimeTrackableEntity
+class IssuableSidebarExtrasEntity < Grape::Entity
include RequestAwareEntity
+ include TimeTrackableEntity
expose :participants, using: ::API::Entities::UserBasic do |issuable|
issuable.participants(request.current_user)
diff --git a/app/serializers/issuable_sidebar_todo_entity.rb b/app/serializers/issuable_sidebar_todo_entity.rb
new file mode 100644
index 00000000000..b2c98433f05
--- /dev/null
+++ b/app/serializers/issuable_sidebar_todo_entity.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+class IssuableSidebarTodoEntity < Grape::Entity
+ include Gitlab::Routing
+
+ expose :id
+
+ expose :delete_path do |todo|
+ dashboard_todo_path(todo) if todo
+ end
+end
diff --git a/app/serializers/issue_board_entity.rb b/app/serializers/issue_board_entity.rb
index e3dc43240c6..f7719447b92 100644
--- a/app/serializers/issue_board_entity.rb
+++ b/app/serializers/issue_board_entity.rb
@@ -37,7 +37,7 @@ class IssueBoardEntity < Grape::Entity
end
expose :issue_sidebar_endpoint, if: -> (issue) { issue.project } do |issue|
- project_issue_path(issue.project, issue, format: :json, serializer: 'sidebar')
+ project_issue_path(issue.project, issue, format: :json, serializer: 'sidebar_extras')
end
expose :toggle_subscription_endpoint, if: -> (issue) { issue.project } do |issue|
diff --git a/app/serializers/issue_serializer.rb b/app/serializers/issue_serializer.rb
index d66f0a5acb7..0fa76f098cd 100644
--- a/app/serializers/issue_serializer.rb
+++ b/app/serializers/issue_serializer.rb
@@ -2,13 +2,15 @@
class IssueSerializer < BaseSerializer
# This overrided method takes care of which entity should be used
- # to serialize the `issue` based on `basic` key in `opts` param.
+ # to serialize the `issue` based on `serializer` key in `opts` param.
# Hence, `entity` doesn't need to be declared on the class scope.
def represent(issue, opts = {})
entity =
case opts[:serializer]
when 'sidebar'
- IssueSidebarEntity
+ IssueSidebarBasicEntity
+ when 'sidebar_extras'
+ IssueSidebarExtrasEntity
when 'board'
IssueBoardEntity
else
diff --git a/app/serializers/issue_sidebar_basic_entity.rb b/app/serializers/issue_sidebar_basic_entity.rb
new file mode 100644
index 00000000000..723875809ec
--- /dev/null
+++ b/app/serializers/issue_sidebar_basic_entity.rb
@@ -0,0 +1,6 @@
+# frozen_string_literal: true
+
+class IssueSidebarBasicEntity < IssuableSidebarBasicEntity
+ expose :due_date
+ expose :confidential
+end
diff --git a/app/serializers/issue_sidebar_entity.rb b/app/serializers/issue_sidebar_extras_entity.rb
index 349ad9d1fef..7b6e860140b 100644
--- a/app/serializers/issue_sidebar_entity.rb
+++ b/app/serializers/issue_sidebar_extras_entity.rb
@@ -1,5 +1,5 @@
# frozen_string_literal: true
-class IssueSidebarEntity < IssuableSidebarEntity
+class IssueSidebarExtrasEntity < IssuableSidebarExtrasEntity
expose :assignees, using: API::Entities::UserBasic
end
diff --git a/app/serializers/merge_request_basic_entity.rb b/app/serializers/merge_request_basic_entity.rb
index f7eb74cf392..084627f9dbe 100644
--- a/app/serializers/merge_request_basic_entity.rb
+++ b/app/serializers/merge_request_basic_entity.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class MergeRequestBasicEntity < IssuableSidebarEntity
+class MergeRequestBasicEntity < Grape::Entity
expose :assignee_id
expose :merge_status
expose :merge_error
diff --git a/app/serializers/merge_request_basic_serializer.rb b/app/serializers/merge_request_basic_serializer.rb
deleted file mode 100644
index a68b48b00db..00000000000
--- a/app/serializers/merge_request_basic_serializer.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-# frozen_string_literal: true
-
-class MergeRequestBasicSerializer < BaseSerializer
- entity MergeRequestBasicEntity
-end
diff --git a/app/serializers/merge_request_serializer.rb b/app/serializers/merge_request_serializer.rb
index 1f8c830e1aa..4cf84336aa4 100644
--- a/app/serializers/merge_request_serializer.rb
+++ b/app/serializers/merge_request_serializer.rb
@@ -7,9 +7,14 @@ class MergeRequestSerializer < BaseSerializer
def represent(merge_request, opts = {})
entity =
case opts[:serializer]
- when 'basic', 'sidebar'
+ when 'sidebar'
+ MergeRequestSidebarBasicEntity
+ when 'sidebar_extras'
+ IssuableSidebarExtrasEntity
+ when 'basic'
MergeRequestBasicEntity
- else # It's 'widget'
+ else
+ # fallback to widget for old poll requests without `serializer` set
MergeRequestWidgetEntity
end
diff --git a/app/serializers/merge_request_sidebar_basic_entity.rb b/app/serializers/merge_request_sidebar_basic_entity.rb
new file mode 100644
index 00000000000..0ae7298a7c1
--- /dev/null
+++ b/app/serializers/merge_request_sidebar_basic_entity.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+class MergeRequestSidebarBasicEntity < IssuableSidebarBasicEntity
+ expose :assignee, if: lambda { |issuable| issuable.assignee } do
+ expose :assignee, merge: true, using: API::Entities::UserBasic
+
+ expose :can_merge do |issuable|
+ issuable.can_be_merged_by?(issuable.assignee)
+ end
+ end
+end
diff --git a/app/services/ci/create_pipeline_service.rb b/app/services/ci/create_pipeline_service.rb
index 19b5552887f..f8d8ef04001 100644
--- a/app/services/ci/create_pipeline_service.rb
+++ b/app/services/ci/create_pipeline_service.rb
@@ -31,7 +31,8 @@ module Ci
seeds_block: block,
variables_attributes: params[:variables_attributes],
project: project,
- current_user: current_user)
+ current_user: current_user,
+ push_options: params[:push_options])
sequence = Gitlab::Ci::Pipeline::Chain::Sequence
.new(pipeline, command, SEQUENCE)
diff --git a/app/services/ci/register_job_service.rb b/app/services/ci/register_job_service.rb
index 13321b2682e..6707a1363d0 100644
--- a/app/services/ci/register_job_service.rb
+++ b/app/services/ci/register_job_service.rb
@@ -118,7 +118,7 @@ module Ci
# Workaround for weird Rails bug, that makes `runner.groups.to_sql` to return `runner_id = NULL`
groups = ::Group.joins(:runner_namespaces).merge(runner.runner_namespaces)
- hierarchy_groups = Gitlab::GroupHierarchy.new(groups).base_and_descendants
+ hierarchy_groups = Gitlab::ObjectHierarchy.new(groups).base_and_descendants
projects = Project.where(namespace_id: hierarchy_groups)
.with_group_runners_enabled
.with_builds_enabled
diff --git a/app/services/clusters/gcp/finalize_creation_service.rb b/app/services/clusters/gcp/finalize_creation_service.rb
index a4e44d009c0..5525c1b9b7f 100644
--- a/app/services/clusters/gcp/finalize_creation_service.rb
+++ b/app/services/clusters/gcp/finalize_creation_service.rb
@@ -13,7 +13,7 @@ module Clusters
configure_kubernetes
cluster.save!
- ClusterPlatformConfigureWorker.perform_async(cluster.id)
+ ClusterConfigureWorker.perform_async(cluster.id)
rescue Google::Apis::ServerError, Google::Apis::ClientError, Google::Apis::AuthorizationError => e
log_service_error(e.class.name, provider.id, e.message)
diff --git a/app/services/commits/tag_service.rb b/app/services/commits/tag_service.rb
index 7961ba4d3c4..bb8cfb63f98 100644
--- a/app/services/commits/tag_service.rb
+++ b/app/services/commits/tag_service.rb
@@ -9,11 +9,10 @@ module Commits
tag_name = params[:tag_name]
message = params[:tag_message]
- release_description = nil
result = Tags::CreateService
.new(commit.project, current_user)
- .execute(tag_name, commit.sha, message, release_description)
+ .execute(tag_name, commit.sha, message)
if result[:status] == :success
tag = result[:tag]
diff --git a/app/services/create_release_service.rb b/app/services/create_release_service.rb
deleted file mode 100644
index ab2dc5337aa..00000000000
--- a/app/services/create_release_service.rb
+++ /dev/null
@@ -1,35 +0,0 @@
-# frozen_string_literal: true
-
-class CreateReleaseService < BaseService
- # rubocop: disable CodeReuse/ActiveRecord
- def execute(tag_name, release_description)
- repository = project.repository
- existing_tag = repository.find_tag(tag_name)
-
- # Only create a release if the tag exists
- if existing_tag
- release = project.releases.find_by(tag: tag_name)
-
- if release
- error('Release already exists', 409)
- else
- release = project.releases.create!(
- tag: tag_name,
- name: tag_name,
- sha: existing_tag.dereferenced_target.sha,
- author: current_user,
- description: release_description
- )
-
- success(release)
- end
- else
- error('Tag does not exist', 404)
- end
- end
- # rubocop: enable CodeReuse/ActiveRecord
-
- def success(release)
- super().merge(release: release)
- end
-end
diff --git a/app/services/git_push_service.rb b/app/services/git_push_service.rb
index f1883877d56..9ecee7c6156 100644
--- a/app/services/git_push_service.rb
+++ b/app/services/git_push_service.rb
@@ -174,7 +174,8 @@ class GitPushService < BaseService
params[:newrev],
params[:ref],
@push_commits,
- commits_count: commits_count)
+ commits_count: commits_count,
+ push_options: params[:push_options] || [])
end
def push_to_existing_branch?
diff --git a/app/services/git_tag_push_service.rb b/app/services/git_tag_push_service.rb
index dbadafc0f52..03fcf614c64 100644
--- a/app/services/git_tag_push_service.rb
+++ b/app/services/git_tag_push_service.rb
@@ -45,7 +45,8 @@ class GitTagPushService < BaseService
params[:newrev],
params[:ref],
commits,
- message)
+ message,
+ push_options: params[:push_options] || [])
end
def build_system_push_data
diff --git a/app/services/groups/nested_create_service.rb b/app/services/groups/nested_create_service.rb
index 50d34d8cb91..f01f5656296 100644
--- a/app/services/groups/nested_create_service.rb
+++ b/app/services/groups/nested_create_service.rb
@@ -18,7 +18,7 @@ module Groups
return namespace
end
- if group_path.include?('/') && !Group.supports_nested_groups?
+ if group_path.include?('/') && !Group.supports_nested_objects?
raise 'Nested groups are not supported on MySQL'
end
diff --git a/app/services/groups/transfer_service.rb b/app/services/groups/transfer_service.rb
index 5efa746dfb9..f64e327416a 100644
--- a/app/services/groups/transfer_service.rb
+++ b/app/services/groups/transfer_service.rb
@@ -40,7 +40,7 @@ module Groups
def ensure_allowed_transfer
raise_transfer_error(:group_is_already_root) if group_is_already_root?
- raise_transfer_error(:database_not_supported) unless Group.supports_nested_groups?
+ raise_transfer_error(:database_not_supported) unless Group.supports_nested_objects?
raise_transfer_error(:same_parent_as_current) if same_parent?
raise_transfer_error(:invalid_policies) unless valid_policies?
raise_transfer_error(:namespace_with_same_path) if namespace_with_same_path?
diff --git a/app/services/groups/update_service.rb b/app/services/groups/update_service.rb
index 31d3c844ad5..de78a3f7b27 100644
--- a/app/services/groups/update_service.rb
+++ b/app/services/groups/update_service.rb
@@ -31,7 +31,7 @@ module Groups
def after_update
if group.previous_changes.include?(:visibility_level) && group.private?
# don't enqueue immediately to prevent todos removal in case of a mistake
- TodosDestroyer::GroupPrivateWorker.perform_in(1.hour, group.id)
+ TodosDestroyer::GroupPrivateWorker.perform_in(Todo::WAIT_FOR_DELETE, group.id)
end
end
diff --git a/app/services/issues/update_service.rb b/app/services/issues/update_service.rb
index a1d0cc0e568..e992d682c79 100644
--- a/app/services/issues/update_service.rb
+++ b/app/services/issues/update_service.rb
@@ -44,7 +44,7 @@ module Issues
if issue.previous_changes.include?('confidential')
# don't enqueue immediately to prevent todos removal in case of a mistake
- TodosDestroyer::ConfidentialIssueWorker.perform_in(1.hour, issue.id) if issue.confidential?
+ TodosDestroyer::ConfidentialIssueWorker.perform_in(Todo::WAIT_FOR_DELETE, issue.id) if issue.confidential?
create_confidentiality_note(issue)
end
diff --git a/app/services/members/base_service.rb b/app/services/members/base_service.rb
index d734571f835..e78affff797 100644
--- a/app/services/members/base_service.rb
+++ b/app/services/members/base_service.rb
@@ -47,5 +47,11 @@ module Members
raise "Unknown action '#{action}' on #{member}!"
end
end
+
+ def enqueue_delete_todos(member)
+ type = member.is_a?(GroupMember) ? 'Group' : 'Project'
+ # don't enqueue immediately to prevent todos removal in case of a mistake
+ TodosDestroyer::EntityLeaveWorker.perform_in(Todo::WAIT_FOR_DELETE, member.user_id, member.source_id, type)
+ end
end
end
diff --git a/app/services/members/destroy_service.rb b/app/services/members/destroy_service.rb
index c186a5971dc..ae0c644e6c0 100644
--- a/app/services/members/destroy_service.rb
+++ b/app/services/members/destroy_service.rb
@@ -15,7 +15,7 @@ module Members
notification_service.decline_access_request(member)
end
- enqeue_delete_todos(member)
+ enqueue_delete_todos(member)
after_execute(member: member)
@@ -24,12 +24,6 @@ module Members
private
- def enqeue_delete_todos(member)
- type = member.is_a?(GroupMember) ? 'Group' : 'Project'
- # don't enqueue immediately to prevent todos removal in case of a mistake
- TodosDestroyer::EntityLeaveWorker.perform_in(1.hour, member.user_id, member.source_id, type)
- end
-
def can_destroy_member?(member)
can?(current_user, destroy_member_permission(member), member)
end
diff --git a/app/services/members/update_service.rb b/app/services/members/update_service.rb
index 1f5618dae53..ff8d5c1d8c9 100644
--- a/app/services/members/update_service.rb
+++ b/app/services/members/update_service.rb
@@ -10,9 +10,18 @@ module Members
if member.update(params)
after_execute(action: permission, old_access_level: old_access_level, member: member)
+
+ # Deletes only confidential issues todos for guests
+ enqueue_delete_todos(member) if downgrading_to_guest?
end
member
end
+
+ private
+
+ def downgrading_to_guest?
+ params[:access_level] == Gitlab::Access::GUEST
+ end
end
end
diff --git a/app/services/merge_requests/build_service.rb b/app/services/merge_requests/build_service.rb
index 36767621d74..48419da98ad 100644
--- a/app/services/merge_requests/build_service.rb
+++ b/app/services/merge_requests/build_service.rb
@@ -18,7 +18,7 @@ module MergeRequests
merge_request.source_project = find_source_project
merge_request.target_project = find_target_project
merge_request.target_branch = find_target_branch
- merge_request.can_be_created = branches_valid?
+ merge_request.can_be_created = projects_and_branches_valid?
# compare branches only if branches are valid, otherwise
# compare_branches may raise an error
@@ -49,15 +49,19 @@ module MergeRequests
to: :merge_request
def find_source_project
- return source_project if source_project.present? && can?(current_user, :read_project, source_project)
+ return source_project if source_project.present? && can?(current_user, :create_merge_request_from, source_project)
project
end
def find_target_project
- return target_project if target_project.present? && can?(current_user, :read_project, target_project)
+ return target_project if target_project.present? && can?(current_user, :create_merge_request_in, target_project)
- project.default_merge_request_target
+ target_project = project.default_merge_request_target
+
+ return target_project if target_project.present? && can?(current_user, :create_merge_request_in, target_project)
+
+ project
end
def find_target_branch
@@ -72,10 +76,11 @@ module MergeRequests
params[:target_branch].present?
end
- def branches_valid?
+ def projects_and_branches_valid?
+ return false if source_project.nil? || target_project.nil?
return false unless source_branch_specified? || target_branch_specified?
- validate_branches
+ validate_projects_and_branches
errors.blank?
end
@@ -94,7 +99,12 @@ module MergeRequests
end
end
- def validate_branches
+ def validate_projects_and_branches
+ merge_request.validate_target_project
+ merge_request.validate_fork
+
+ return if errors.any?
+
add_error('You must select source and target branch') unless branches_present?
add_error('You must select different branches') if same_source_and_target?
add_error("Source branch \"#{source_branch}\" does not exist") unless source_branch_exists?
diff --git a/app/services/merge_requests/update_service.rb b/app/services/merge_requests/update_service.rb
index 33d8299c8b6..86a04587f79 100644
--- a/app/services/merge_requests/update_service.rb
+++ b/app/services/merge_requests/update_service.rb
@@ -46,11 +46,13 @@ module MergeRequests
end
if merge_request.previous_changes.include?('assignee_id')
+ reassigned_merge_request_args = [merge_request, current_user]
+
old_assignee_id = merge_request.previous_changes['assignee_id'].first
- old_assignee = User.find(old_assignee_id) if old_assignee_id
+ reassigned_merge_request_args << User.find(old_assignee_id) if old_assignee_id
create_assignee_note(merge_request)
- notification_service.async.reassigned_merge_request(merge_request, current_user, old_assignee)
+ notification_service.async.reassigned_merge_request(*reassigned_merge_request_args)
todo_service.reassigned_merge_request(merge_request, current_user)
end
diff --git a/app/services/notification_service.rb b/app/services/notification_service.rb
index ff035fea216..e1cf327209b 100644
--- a/app/services/notification_service.rb
+++ b/app/services/notification_service.rb
@@ -188,7 +188,7 @@ class NotificationService
# * merge_request assignee if their notification level is not Disabled
# * users with custom level checked with "reassign merge request"
#
- def reassigned_merge_request(merge_request, current_user, previous_assignee)
+ def reassigned_merge_request(merge_request, current_user, previous_assignee = nil)
recipients = NotificationRecipientService.build_recipients(
merge_request,
current_user,
diff --git a/app/services/projects/after_rename_service.rb b/app/services/projects/after_rename_service.rb
index 4131da44f5a..aa9b253eb20 100644
--- a/app/services/projects/after_rename_service.rb
+++ b/app/services/projects/after_rename_service.rb
@@ -81,6 +81,7 @@ module Projects
def update_repository_configuration
project.reload_repository!
project.write_repository_config
+ project.track_project_repository
end
def rename_transferred_documents
diff --git a/app/services/projects/lfs_pointers/lfs_download_service.rb b/app/services/projects/lfs_pointers/lfs_download_service.rb
index f9b9781ad5f..b5128443435 100644
--- a/app/services/projects/lfs_pointers/lfs_download_service.rb
+++ b/app/services/projects/lfs_pointers/lfs_download_service.rb
@@ -12,28 +12,43 @@ module Projects
return if LfsObject.exists?(oid: oid)
- sanitized_uri = Gitlab::UrlSanitizer.new(url)
- Gitlab::UrlBlocker.validate!(sanitized_uri.sanitized_url, protocols: VALID_PROTOCOLS)
+ sanitized_uri = sanitize_url!(url)
with_tmp_file(oid) do |file|
- size = download_and_save_file(file, sanitized_uri)
- lfs_object = LfsObject.new(oid: oid, size: size, file: file)
+ download_and_save_file(file, sanitized_uri)
+ lfs_object = LfsObject.new(oid: oid, size: file.size, file: file)
project.all_lfs_objects << lfs_object
end
+ rescue Gitlab::UrlBlocker::BlockedUrlError => e
+ Rails.logger.error("LFS file with oid #{oid} couldn't be downloaded: #{e.message}")
rescue StandardError => e
- Rails.logger.error("LFS file with oid #{oid} could't be downloaded from #{sanitized_uri.sanitized_url}: #{e.message}")
+ Rails.logger.error("LFS file with oid #{oid} couldn't be downloaded from #{sanitized_uri.sanitized_url}: #{e.message}")
end
# rubocop: enable CodeReuse/ActiveRecord
private
+ def sanitize_url!(url)
+ Gitlab::UrlSanitizer.new(url).tap do |sanitized_uri|
+ # Just validate that HTTP/HTTPS protocols are used. The
+ # subsequent Gitlab::HTTP.get call will do network checks
+ # based on the settings.
+ Gitlab::UrlBlocker.validate!(sanitized_uri.sanitized_url,
+ protocols: VALID_PROTOCOLS)
+ end
+ end
+
def download_and_save_file(file, sanitized_uri)
- IO.copy_stream(open(sanitized_uri.sanitized_url, headers(sanitized_uri)), file) # rubocop:disable Security/Open
+ response = Gitlab::HTTP.get(sanitized_uri.sanitized_url, headers(sanitized_uri)) do |fragment|
+ file.write(fragment)
+ end
+
+ raise StandardError, "Received error code #{response.code}" unless response.success?
end
def headers(sanitized_uri)
- {}.tap do |headers|
+ query_options.tap do |headers|
credentials = sanitized_uri.credentials
if credentials[:user].present? || credentials[:password].present?
@@ -43,10 +58,14 @@ module Projects
end
end
+ def query_options
+ { stream_body: true }
+ end
+
def with_tmp_file(oid)
create_tmp_storage_dir
- File.open(File.join(tmp_storage_dir, oid), 'w') { |file| yield file }
+ File.open(File.join(tmp_storage_dir, oid), 'wb') { |file| yield file }
end
def create_tmp_storage_dir
diff --git a/app/services/projects/transfer_service.rb b/app/services/projects/transfer_service.rb
index 9db3fd9cf17..5da1e39a1fb 100644
--- a/app/services/projects/transfer_service.rb
+++ b/app/services/projects/transfer_service.rb
@@ -81,7 +81,7 @@ module Projects
project.old_path_with_namespace = @old_path
- write_repository_config(@new_path)
+ update_repository_configuration(@new_path)
execute_system_hooks
end
@@ -106,8 +106,9 @@ module Projects
project.save!
end
- def write_repository_config(full_path)
+ def update_repository_configuration(full_path)
project.write_repository_config(gl_full_path: full_path)
+ project.track_project_repository
end
def refresh_permissions
@@ -123,7 +124,7 @@ module Projects
rollback_folder_move
project.reload
update_namespace_and_visibility(@old_namespace)
- write_repository_config(@old_path)
+ update_repository_configuration(@old_path)
end
def rollback_folder_move
diff --git a/app/services/projects/update_service.rb b/app/services/projects/update_service.rb
index 93e48fc0199..dd1b9680ece 100644
--- a/app/services/projects/update_service.rb
+++ b/app/services/projects/update_service.rb
@@ -61,9 +61,9 @@ module Projects
if project.previous_changes.include?(:visibility_level) && project.private?
# don't enqueue immediately to prevent todos removal in case of a mistake
- TodosDestroyer::ProjectPrivateWorker.perform_in(1.hour, project.id)
+ TodosDestroyer::ProjectPrivateWorker.perform_in(Todo::WAIT_FOR_DELETE, project.id)
elsif (project_changed_feature_keys & todos_features_changes).present?
- TodosDestroyer::PrivateFeaturesWorker.perform_in(1.hour, project.id)
+ TodosDestroyer::PrivateFeaturesWorker.perform_in(Todo::WAIT_FOR_DELETE, project.id)
end
if project.previous_changes.include?('path')
diff --git a/app/services/releases/concerns.rb b/app/services/releases/concerns.rb
new file mode 100644
index 00000000000..a04bb8f9e14
--- /dev/null
+++ b/app/services/releases/concerns.rb
@@ -0,0 +1,48 @@
+# frozen_string_literal: true
+
+module Releases
+ module Concerns
+ extend ActiveSupport::Concern
+ include Gitlab::Utils::StrongMemoize
+
+ included do
+ def tag_name
+ params[:tag]
+ end
+
+ def ref
+ params[:ref]
+ end
+
+ def name
+ params[:name]
+ end
+
+ def description
+ params[:description]
+ end
+
+ def release
+ strong_memoize(:release) do
+ project.releases.find_by_tag(tag_name)
+ end
+ end
+
+ def existing_tag
+ strong_memoize(:existing_tag) do
+ repository.find_tag(tag_name)
+ end
+ end
+
+ def tag_exist?
+ existing_tag.present?
+ end
+
+ def repository
+ strong_memoize(:repository) do
+ project.repository
+ end
+ end
+ end
+ end
+end
diff --git a/app/services/releases/create_service.rb b/app/services/releases/create_service.rb
new file mode 100644
index 00000000000..73fcebf79af
--- /dev/null
+++ b/app/services/releases/create_service.rb
@@ -0,0 +1,54 @@
+# frozen_string_literal: true
+
+module Releases
+ class CreateService < BaseService
+ include Releases::Concerns
+
+ def execute
+ return error('Access Denied', 403) unless allowed?
+ return error('Release already exists', 409) if release
+
+ tag = ensure_tag
+
+ return tag unless tag.is_a?(Gitlab::Git::Tag)
+
+ create_release(tag)
+ end
+
+ private
+
+ def ensure_tag
+ existing_tag || create_tag
+ end
+
+ def create_tag
+ return error('Ref is not specified', 422) unless ref
+
+ result = Tags::CreateService
+ .new(project, current_user)
+ .execute(tag_name, ref, nil)
+
+ return result unless result[:status] == :success
+
+ result[:tag]
+ end
+
+ def allowed?
+ Ability.allowed?(current_user, :create_release, project)
+ end
+
+ def create_release(tag)
+ release = project.releases.create!(
+ name: name,
+ description: description,
+ author: current_user,
+ tag: tag.name,
+ sha: tag.dereferenced_target.sha
+ )
+
+ success(tag: tag, release: release)
+ rescue ActiveRecord::RecordInvalid => e
+ error(e.message, 400)
+ end
+ end
+end
diff --git a/app/services/releases/destroy_service.rb b/app/services/releases/destroy_service.rb
new file mode 100644
index 00000000000..8c2bc3b4e6e
--- /dev/null
+++ b/app/services/releases/destroy_service.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+module Releases
+ class DestroyService < BaseService
+ include Releases::Concerns
+
+ def execute
+ return error('Tag does not exist', 404) unless existing_tag
+ return error('Release does not exist', 404) unless release
+ return error('Access Denied', 403) unless allowed?
+
+ if release.destroy
+ success(tag: existing_tag, release: release)
+ else
+ error(release.errors.messages || '400 Bad request', 400)
+ end
+ end
+
+ private
+
+ def allowed?
+ Ability.allowed?(current_user, :destroy_release, release)
+ end
+ end
+end
diff --git a/app/services/releases/update_service.rb b/app/services/releases/update_service.rb
new file mode 100644
index 00000000000..fabfa398c59
--- /dev/null
+++ b/app/services/releases/update_service.rb
@@ -0,0 +1,32 @@
+# frozen_string_literal: true
+
+module Releases
+ class UpdateService < BaseService
+ include Releases::Concerns
+
+ def execute
+ return error('Tag does not exist', 404) unless existing_tag
+ return error('Release does not exist', 404) unless release
+ return error('Access Denied', 403) unless allowed?
+ return error('params is empty', 400) if empty_params?
+
+ if release.update(params)
+ success(tag: existing_tag, release: release)
+ else
+ error(release.errors.messages || '400 Bad request', 400)
+ end
+ end
+
+ private
+
+ def allowed?
+ Ability.allowed?(current_user, :update_release, release)
+ end
+
+ # rubocop: disable CodeReuse/ActiveRecord
+ def empty_params?
+ params.except(:tag).empty?
+ end
+ # rubocop: enable CodeReuse/ActiveRecord
+ end
+end
diff --git a/app/services/tags/create_service.rb b/app/services/tags/create_service.rb
index 6bb9bb3988e..4de6b2d2774 100644
--- a/app/services/tags/create_service.rb
+++ b/app/services/tags/create_service.rb
@@ -2,7 +2,7 @@
module Tags
class CreateService < BaseService
- def execute(tag_name, target, message, release_description = nil)
+ def execute(tag_name, target, message)
valid_tag = Gitlab::GitRefValidator.validate(tag_name)
return error('Tag name invalid') unless valid_tag
@@ -20,10 +20,7 @@ module Tags
end
if new_tag
- if release_description.present?
- CreateReleaseService.new(@project, @current_user)
- .execute(tag_name, release_description)
- end
+ repository.expire_tags_cache
success.merge(tag: new_tag)
else
diff --git a/app/services/tags/destroy_service.rb b/app/services/tags/destroy_service.rb
index 6bfef09ac54..cab507946b4 100644
--- a/app/services/tags/destroy_service.rb
+++ b/app/services/tags/destroy_service.rb
@@ -2,7 +2,6 @@
module Tags
class DestroyService < BaseService
- # rubocop: disable CodeReuse/ActiveRecord
def execute(tag_name)
repository = project.repository
tag = repository.find_tag(tag_name)
@@ -12,8 +11,12 @@ module Tags
end
if repository.rm_tag(current_user, tag_name)
- release = project.releases.find_by(tag: tag_name)
- release&.destroy
+ ##
+ # When a tag in a repository is destroyed,
+ # release assets will be destroyed too.
+ Releases::DestroyService
+ .new(project, current_user, tag: tag_name)
+ .execute
push_data = build_push_data(tag)
EventCreateService.new.push(project, current_user, push_data)
@@ -27,7 +30,6 @@ module Tags
rescue Gitlab::Git::PreReceiveError => ex
error(ex.message)
end
- # rubocop: enable CodeReuse/ActiveRecord
def error(message, return_code = 400)
super(message).merge(return_code: return_code)
diff --git a/app/services/update_release_service.rb b/app/services/update_release_service.rb
deleted file mode 100644
index e2228ca026c..00000000000
--- a/app/services/update_release_service.rb
+++ /dev/null
@@ -1,28 +0,0 @@
-# frozen_string_literal: true
-
-class UpdateReleaseService < BaseService
- # rubocop: disable CodeReuse/ActiveRecord
- def execute(tag_name, release_description)
- repository = project.repository
- existing_tag = repository.find_tag(tag_name)
-
- if existing_tag
- release = project.releases.find_by(tag: tag_name)
-
- if release
- release.update(description: release_description)
-
- success(release)
- else
- error('Release does not exist', 404)
- end
- else
- error('Tag does not exist', 404)
- end
- end
- # rubocop: enable CodeReuse/ActiveRecord
-
- def success(release)
- super().merge(release: release)
- end
-end
diff --git a/app/services/users/refresh_authorized_projects_service.rb b/app/services/users/refresh_authorized_projects_service.rb
index 23b63aaabdf..fe5a82e23fa 100644
--- a/app/services/users/refresh_authorized_projects_service.rb
+++ b/app/services/users/refresh_authorized_projects_service.rb
@@ -102,7 +102,7 @@ module Users
end
def fresh_authorizations
- klass = if Group.supports_nested_groups?
+ klass = if Group.supports_nested_objects?
Gitlab::ProjectAuthorizations::WithNestedGroups
else
Gitlab::ProjectAuthorizations::WithoutNestedGroups
diff --git a/app/views/admin/appearances/_form.html.haml b/app/views/admin/appearances/_form.html.haml
index cb67079853e..544f09048f5 100644
--- a/app/views/admin/appearances/_form.html.haml
+++ b/app/views/admin/appearances/_form.html.haml
@@ -8,7 +8,7 @@
= f.label :header_logo, 'Header logo', class: 'col-sm-2 col-form-label pt-0'
.col-sm-10
- if @appearance.header_logo?
- = image_tag @appearance.header_logo_url, class: 'appearance-light-logo-preview'
+ = image_tag @appearance.header_logo_path, class: 'appearance-light-logo-preview'
- if @appearance.persisted?
%br
= link_to 'Remove header logo', header_logos_admin_appearances_path, data: { confirm: "Header logo will be removed. Are you sure?"}, method: :delete, class: "btn btn-inverted btn-remove btn-sm remove-logo"
@@ -25,7 +25,7 @@
= f.label :favicon, 'Favicon', class: 'col-sm-2 col-form-label pt-0'
.col-sm-10
- if @appearance.favicon?
- = image_tag @appearance.favicon_url, class: 'appearance-light-logo-preview'
+ = image_tag @appearance.favicon_path, class: 'appearance-light-logo-preview'
- if @appearance.persisted?
%br
= link_to 'Remove favicon', favicon_admin_appearances_path, data: { confirm: "Favicon will be removed. Are you sure?"}, method: :delete, class: "btn btn-inverted btn-remove btn-sm remove-logo"
@@ -54,7 +54,7 @@
= f.label :logo, class: 'col-sm-2 col-form-label pt-0'
.col-sm-10
- if @appearance.logo?
- = image_tag @appearance.logo_url, class: 'appearance-logo-preview'
+ = image_tag @appearance.logo_path, class: 'appearance-logo-preview'
- if @appearance.persisted?
%br
= link_to 'Remove logo', logo_admin_appearances_path, data: { confirm: "Logo will be removed. Are you sure?"}, method: :delete, class: "btn btn-inverted btn-remove btn-sm remove-logo"
diff --git a/app/views/admin/application_settings/_ci_cd.html.haml b/app/views/admin/application_settings/_ci_cd.html.haml
index 0d42094fc89..fdaad1cf181 100644
--- a/app/views/admin/application_settings/_ci_cd.html.haml
+++ b/app/views/admin/application_settings/_ci_cd.html.haml
@@ -49,5 +49,12 @@
Once that time passes, the jobs will be archived and no longer able to be
retried. Make it empty to never expire jobs. It has to be no less than 1 day,
for example: <code>15 days</code>, <code>1 month</code>, <code>2 years</code>.
+ .form-group
+ .form-check
+ = f.check_box :protected_ci_variables, class: 'form-check-input'
+ = f.label :protected_ci_variables, class: 'form-check-label' do
+ = s_('AdminSettings|Environment variables are protected by default')
+ .form-text.text-muted
+ = s_('AdminSettings|When creating a new environment variable it will be protected by default.')
= f.submit 'Save changes', class: "btn btn-success"
diff --git a/app/views/ci/variables/_content.html.haml b/app/views/ci/variables/_content.html.haml
index d355e7799df..fa82611d9c1 100644
--- a/app/views/ci/variables/_content.html.haml
+++ b/app/views/ci/variables/_content.html.haml
@@ -1 +1 @@
-= _('Variables are applied to environments via the runner. They can be protected by only exposing them to protected branches or tags. You can use variables for passwords, secret keys, or whatever you want.')
+= _('Environment variables are applied to environments via the runner. They can be protected by only exposing them to protected branches or tags. You can use environment variables for passwords, secret keys, or whatever you want.')
diff --git a/app/views/ci/variables/_header.html.haml b/app/views/ci/variables/_header.html.haml
new file mode 100644
index 00000000000..cb7779e2175
--- /dev/null
+++ b/app/views/ci/variables/_header.html.haml
@@ -0,0 +1,11 @@
+- expanded = local_assigns.fetch(:expanded)
+
+%h4
+ = _('Environment variables')
+ = link_to icon('question-circle'), help_page_path('ci/variables/README', anchor: 'variables'), target: '_blank', rel: 'noopener noreferrer'
+
+%button.btn.btn-default.js-settings-toggle{ type: 'button' }
+ = expanded ? _('Collapse') : _('Expand')
+
+%p.append-bottom-0
+ = render "ci/variables/content"
diff --git a/app/views/ci/variables/_index.html.haml b/app/views/ci/variables/_index.html.haml
index f34305e94fa..dc9ccb6cc39 100644
--- a/app/views/ci/variables/_index.html.haml
+++ b/app/views/ci/variables/_index.html.haml
@@ -1,5 +1,10 @@
- save_endpoint = local_assigns.fetch(:save_endpoint, nil)
+- if ci_variable_protected_by_default?
+ %p.settings-message.text-center
+ - link_start = '<a href="%{url}">'.html_safe % { url: help_page_path('ci/variables/README', anchor: 'protected-variables') }
+ = s_('Environment variables are configured by your administrator to be %{link_start}protected%{link_end} by default').html_safe % { link_start: link_start, link_end: '</a>'.html_safe }
+
.row
.col-lg-12.js-ci-variable-list-section{ data: { save_endpoint: save_endpoint } }
.hide.alert.alert-danger.js-ci-variable-error-box
diff --git a/app/views/ci/variables/_variable_row.html.haml b/app/views/ci/variables/_variable_row.html.haml
index 6ee55836dd2..16a7527c8ce 100644
--- a/app/views/ci/variables/_variable_row.html.haml
+++ b/app/views/ci/variables/_variable_row.html.haml
@@ -5,7 +5,8 @@
- id = variable&.id
- key = variable&.key
- value = variable&.value
-- is_protected = variable && !only_key_value ? variable.protected : false
+- is_protected_default = ci_variable_protected_by_default?
+- is_protected = ci_variable_protected?(variable, only_key_value)
- id_input_name = "#{form_field}[variables_attributes][][id]"
- destroy_input_name = "#{form_field}[variables_attributes][][_destroy]"
@@ -39,7 +40,8 @@
%input{ type: "hidden",
class: 'js-ci-variable-input-protected js-project-feature-toggle-input',
name: protected_input_name,
- value: is_protected }
+ value: is_protected,
+ data: { default: is_protected_default.to_s } }
%span.toggle-icon
= sprite_icon('status_success_borderless', size: 16, css_class: 'toggle-icon-svg toggle-status-checked')
= sprite_icon('status_failed_borderless', size: 16, css_class: 'toggle-icon-svg toggle-status-unchecked')
diff --git a/app/views/clusters/clusters/_buttons.html.haml b/app/views/clusters/clusters/_buttons.html.haml
index 9238903aa10..c81d1d5b05a 100644
--- a/app/views/clusters/clusters/_buttons.html.haml
+++ b/app/views/clusters/clusters/_buttons.html.haml
@@ -1,6 +1,5 @@
--# This partial is overridden in EE
.nav-controls
- - if clusterable.can_create_cluster? && clusterable.clusters.empty?
+ - if clusterable.can_add_cluster?
= link_to s_('ClusterIntegration|Add Kubernetes cluster'), clusterable.new_path, class: 'btn btn-success js-add-cluster'
- else
%span.btn.btn-add-cluster.disabled.js-add-cluster
diff --git a/app/views/clusters/clusters/_empty_state.html.haml b/app/views/clusters/clusters/_empty_state.html.haml
index c926ec258f0..cfdbfe2dea1 100644
--- a/app/views/clusters/clusters/_empty_state.html.haml
+++ b/app/views/clusters/clusters/_empty_state.html.haml
@@ -9,6 +9,6 @@
= clusterable.empty_state_help_text
= clusterable.learn_more_link
- - if clusterable.can_create_cluster?
+ - if clusterable.can_add_cluster?
.text-center
= link_to s_('ClusterIntegration|Add Kubernetes cluster'), clusterable.new_path, class: 'btn btn-success'
diff --git a/app/views/events/_events.html.haml b/app/views/events/_events.html.haml
index 68c19df092d..6ae4c334f7f 100644
--- a/app/views/events/_events.html.haml
+++ b/app/views/events/_events.html.haml
@@ -1 +1,4 @@
-= render partial: 'events/event', collection: @events
+- if @events.present?
+ = render partial: 'events/event', collection: @events
+- else
+ .nothing-here-block= _("No activities found")
diff --git a/app/views/groups/settings/ci_cd/show.html.haml b/app/views/groups/settings/ci_cd/show.html.haml
index a5e6abdba52..d9332e36ef5 100644
--- a/app/views/groups/settings/ci_cd/show.html.haml
+++ b/app/views/groups/settings/ci_cd/show.html.haml
@@ -5,13 +5,7 @@
%section.settings#ci-variables.no-animate{ class: ('expanded' if expanded) }
.settings-header
- %h4
- = _('Variables')
- = link_to icon('question-circle'), help_page_path('ci/variables/README', anchor: 'variables'), target: '_blank', rel: 'noopener noreferrer'
- %button.btn.btn-default.js-settings-toggle{ type: "button" }
- = expanded ? _('Collapse') : _('Expand')
- %p.append-bottom-0
- = render "ci/variables/content"
+ = render 'ci/variables/header', expanded: expanded
.settings-content
= render 'ci/variables/index', save_endpoint: group_variables_path
diff --git a/app/views/layouts/_search.html.haml b/app/views/layouts/_search.html.haml
index a86972d8cf3..a6023a1cbb9 100644
--- a/app/views/layouts/_search.html.haml
+++ b/app/views/layouts/_search.html.haml
@@ -2,7 +2,7 @@
- group_data_attrs = { group_path: j(@group.path), name: @group.name, issues_path: issues_group_path(j(@group.path)), mr_path: merge_requests_group_path(j(@group.path)) }
- if @project && @project.persisted?
- project_data_attrs = { project_path: j(@project.path), name: j(@project.name), issues_path: project_issues_path(@project), mr_path: project_merge_requests_path(@project), issues_disabled: !@project.issues_enabled? }
-.search.search-form
+.search.search-form{ data: { track_label: "navbar_search", track_event: "activate_form_input" } }
= form_tag search_path, method: :get, class: 'form-inline' do |f|
.search-input-container
.search-input-wrap
diff --git a/app/views/layouts/devise.html.haml b/app/views/layouts/devise.html.haml
index 4f8db74382f..6003d973c88 100644
--- a/app/views/layouts/devise.html.haml
+++ b/app/views/layouts/devise.html.haml
@@ -1,7 +1,7 @@
!!! 5
%html.devise-layout-html{ class: system_message_class }
= render "layouts/head"
- %body.ui-indigo.login-page.application.navless{ data: { page: body_data_page } }
+ %body.ui-indigo.login-page.application.navless.qa-login-page{ data: { page: body_data_page } }
.page-wrap
= render "layouts/header/empty"
.login-page-broadcast
diff --git a/app/views/layouts/header/_default.html.haml b/app/views/layouts/header/_default.html.haml
index e8d0d809181..a9b85889846 100644
--- a/app/views/layouts/header/_default.html.haml
+++ b/app/views/layouts/header/_default.html.haml
@@ -60,7 +60,7 @@
.dropdown-menu.dropdown-menu-right
= render 'layouts/header/help_dropdown'
- if header_link?(:user_dropdown)
- %li.nav-item.header-user.dropdown
+ %li.nav-item.header-user.dropdown{ data: { track_label: "profile_dropdown", track_event: "click_dropdown" } }
= link_to current_user, class: user_dropdown_class, data: { toggle: "dropdown" } do
= image_tag avatar_icon_for_user(current_user, 23), width: 23, height: 23, class: "header-user-avatar qa-user-avatar"
= sprite_icon('angle-down', css_class: 'caret-down')
diff --git a/app/views/layouts/header/_new_dropdown.haml b/app/views/layouts/header/_new_dropdown.haml
index 5cb8aebadb3..e42251f9ec8 100644
--- a/app/views/layouts/header/_new_dropdown.haml
+++ b/app/views/layouts/header/_new_dropdown.haml
@@ -1,4 +1,4 @@
-%li.header-new.dropdown
+%li.header-new.dropdown{ data: { track_label: "new_dropdown", track_event: "click_dropdown" } }
= link_to new_project_path, class: "header-new-dropdown-toggle has-tooltip qa-new-menu-toggle", title: _("New..."), ref: 'tooltip', aria: { label: _("New...") }, data: { toggle: 'dropdown', placement: 'bottom', container: 'body', display: 'static' } do
= sprite_icon('plus-square', size: 16)
= sprite_icon('angle-down', css_class: 'caret-down')
diff --git a/app/views/layouts/nav/_dashboard.html.haml b/app/views/layouts/nav/_dashboard.html.haml
index 7057a5a142f..ddd30efe062 100644
--- a/app/views/layouts/nav/_dashboard.html.haml
+++ b/app/views/layouts/nav/_dashboard.html.haml
@@ -2,7 +2,7 @@
-# https://gitlab.com/gitlab-org/gitlab-ce/issues/49713 for more information.
%ul.list-unstyled.navbar-sub-nav
- if dashboard_nav_link?(:projects)
- = nav_link(path: ['root#index', 'projects#trending', 'projects#starred', 'dashboard/projects#index'], html_options: { id: 'nav-projects-dropdown', class: "home dropdown header-projects qa-projects-dropdown" }) do
+ = nav_link(path: ['root#index', 'projects#trending', 'projects#starred', 'dashboard/projects#index'], html_options: { id: 'nav-projects-dropdown', class: "home dropdown header-projects qa-projects-dropdown", data: { track_label: "projects_dropdown", track_event: "click_dropdown" } }) do
%button{ type: 'button', data: { toggle: "dropdown" } }
= _('Projects')
= sprite_icon('angle-down', css_class: 'caret-down')
@@ -10,7 +10,7 @@
= render "layouts/nav/projects_dropdown/show"
- if dashboard_nav_link?(:groups)
- = nav_link(controller: ['dashboard/groups', 'explore/groups'], html_options: { id: 'nav-groups-dropdown', class: "home dropdown header-groups qa-groups-dropdown" }) do
+ = nav_link(controller: ['dashboard/groups', 'explore/groups'], html_options: { id: 'nav-groups-dropdown', class: "home dropdown header-groups qa-groups-dropdown", data: { track_label: "groups_dropdown", track_event: "click_dropdown" } }) do
%button{ type: 'button', data: { toggle: "dropdown" } }
= _('Groups')
= sprite_icon('angle-down', css_class: 'caret-down')
diff --git a/app/views/layouts/nav/sidebar/_group.html.haml b/app/views/layouts/nav/sidebar/_group.html.haml
index 477030a20c1..bf475c07711 100644
--- a/app/views/layouts/nav/sidebar/_group.html.haml
+++ b/app/views/layouts/nav/sidebar/_group.html.haml
@@ -103,19 +103,6 @@
= _('Merge Requests')
%span.badge.badge-pill.count.merge_counter.js-merge-counter.fly-out-badge= number_with_delimiter(merge_requests_count)
- - if group_sidebar_link?(:group_members)
- = nav_link(path: 'group_members#index') do
- = link_to group_group_members_path(@group) do
- .nav-icon-container
- = sprite_icon('users')
- %span.nav-item-name.qa-group-members-item
- = _('Members')
- %ul.sidebar-sub-level-items.is-fly-out-only
- = nav_link(path: 'group_members#index', html_options: { class: "fly-out-top-item" } ) do
- = link_to group_group_members_path(@group) do
- %strong.fly-out-top-item-name
- = _('Members')
-
- if group_sidebar_link?(:kubernetes)
= nav_link(controller: [:clusters]) do
= link_to group_clusters_path(@group) do
@@ -129,6 +116,19 @@
%strong.fly-out-top-item-name
= _('Kubernetes')
+ - if group_sidebar_link?(:group_members)
+ = nav_link(path: 'group_members#index') do
+ = link_to group_group_members_path(@group) do
+ .nav-icon-container
+ = sprite_icon('users')
+ %span.nav-item-name.qa-group-members-item
+ = _('Members')
+ %ul.sidebar-sub-level-items.is-fly-out-only
+ = nav_link(path: 'group_members#index', html_options: { class: "fly-out-top-item" } ) do
+ = link_to group_group_members_path(@group) do
+ %strong.fly-out-top-item-name
+ = _('Members')
+
- if group_sidebar_link?(:settings)
= nav_link(path: group_nav_link_paths) do
= link_to edit_group_path(@group) do
diff --git a/app/views/layouts/nav/sidebar/_project.html.haml b/app/views/layouts/nav/sidebar/_project.html.haml
index 59557c70904..d8017742c90 100644
--- a/app/views/layouts/nav/sidebar/_project.html.haml
+++ b/app/views/layouts/nav/sidebar/_project.html.haml
@@ -29,7 +29,7 @@
= link_to activity_project_path(@project), title: _('Activity'), class: 'shortcuts-project-activity' do
%span= _('Activity')
- - if project_nav_tab?(:releases) && Feature.enabled?(:releases_page)
+ - if project_nav_tab?(:releases) && Feature.enabled?(:releases_page, @project)
= nav_link(controller: :releases) do
= link_to project_releases_path(@project), title: _('Releases'), class: 'shortcuts-project-releases' do
%span= _('Releases')
diff --git a/app/views/notify/_note_email.html.haml b/app/views/notify/_note_email.html.haml
index 1fbae2f64ed..83c7f548975 100644
--- a/app/views/notify/_note_email.html.haml
+++ b/app/views/notify/_note_email.html.haml
@@ -4,17 +4,13 @@
- note_style = local_assigns.fetch(:note_style, "")
- discussion = note.discussion if note.part_of_discussion?
-- diff_discussion = discussion&.diff_discussion?
-- on_image = discussion.on_image? if diff_discussion
- if discussion
- - phrase_end_char = on_image ? "." : ":"
-
%p{ style: "color: #777777;" }
- = succeed phrase_end_char do
+ = succeed ':' do
= link_to note.author_name, user_url(note.author)
- - if diff_discussion
+ - if discussion&.diff_discussion?
- if discussion.new_discussion?
started a new discussion
- else
@@ -31,7 +27,7 @@
%p.details
#{link_to note.author_name, user_url(note.author)} commented:
-- if diff_discussion && !on_image
+- if discussion&.diff_discussion? && discussion.on_text?
= content_for :head do
= stylesheet_link_tag 'mailers/highlighted_diff_email'
diff --git a/app/views/notify/_note_email.text.erb b/app/views/notify/_note_email.text.erb
index 4bf252b6ce1..50209c46ed1 100644
--- a/app/views/notify/_note_email.text.erb
+++ b/app/views/notify/_note_email.text.erb
@@ -20,7 +20,7 @@
<% end -%>
-<% if discussion&.diff_discussion? -%>
+<% if discussion&.diff_discussion? && discussion.on_text? -%>
<% discussion.truncated_diff_lines(highlight: false, diff_limit: diff_limit).each do |line| -%>
<%= "> #{line.text}\n" -%>
<% end -%>
diff --git a/app/views/notify/changed_milestone_issue_email.html.haml b/app/views/notify/changed_milestone_email.html.haml
index 7d5425fc72d..01d27cac36b 100644
--- a/app/views/notify/changed_milestone_issue_email.html.haml
+++ b/app/views/notify/changed_milestone_email.html.haml
@@ -1,3 +1,5 @@
%p
Milestone changed to
%strong= link_to(@milestone.name, @milestone_url)
+ - if date_range = milestone_date_range(@milestone)
+ = "(#{date_range})"
diff --git a/app/views/notify/changed_milestone_email.text.erb b/app/views/notify/changed_milestone_email.text.erb
new file mode 100644
index 00000000000..a466da4eb19
--- /dev/null
+++ b/app/views/notify/changed_milestone_email.text.erb
@@ -0,0 +1 @@
+Milestone changed to <%= @milestone.name %><% if date_range = milestone_date_range(@milestone) %> (<%= date_range %>)<% end %> ( <%= @milestone_url %> )
diff --git a/app/views/notify/changed_milestone_issue_email.text.erb b/app/views/notify/changed_milestone_issue_email.text.erb
deleted file mode 100644
index c5fc0b61518..00000000000
--- a/app/views/notify/changed_milestone_issue_email.text.erb
+++ /dev/null
@@ -1 +0,0 @@
-Milestone changed to <%= @milestone.name %> ( <%= @milestone_url %> )
diff --git a/app/views/notify/changed_milestone_merge_request_email.html.haml b/app/views/notify/changed_milestone_merge_request_email.html.haml
deleted file mode 100644
index 7d5425fc72d..00000000000
--- a/app/views/notify/changed_milestone_merge_request_email.html.haml
+++ /dev/null
@@ -1,3 +0,0 @@
-%p
- Milestone changed to
- %strong= link_to(@milestone.name, @milestone_url)
diff --git a/app/views/notify/changed_milestone_merge_request_email.text.erb b/app/views/notify/changed_milestone_merge_request_email.text.erb
deleted file mode 100644
index c5fc0b61518..00000000000
--- a/app/views/notify/changed_milestone_merge_request_email.text.erb
+++ /dev/null
@@ -1 +0,0 @@
-Milestone changed to <%= @milestone.name %> ( <%= @milestone_url %> )
diff --git a/app/views/projects/buttons/_clone.html.haml b/app/views/projects/buttons/_clone.html.haml
index d453a3a9dac..159d9e44e17 100644
--- a/app/views/projects/buttons/_clone.html.haml
+++ b/app/views/projects/buttons/_clone.html.haml
@@ -1,16 +1,12 @@
- project = project || @project
.git-clone-holder.js-git-clone-holder.input-group
- - if allowed_protocols_present?
- .input-group-text.clone-dropdown-btn.btn
- %span.js-clone-dropdown-label
- = enabled_project_button(project, enabled_protocol)
- - else
- %a#clone-dropdown.input-group-text.btn.btn-primary.btn-xs.clone-dropdown-btn.qa-clone-dropdown{ href: '#', data: { toggle: 'dropdown' } }
- %span.append-right-4.js-clone-dropdown-label
- = _('Clone')
- = sprite_icon("arrow-down", css_class: "icon")
- %form.p-3.dropdown-menu.dropdown-menu-right.dropdown-menu-large.dropdown-menu-selectable.clone-options-dropdown.qa-clone-options
+ %a#clone-dropdown.input-group-text.btn.btn-primary.btn-xs.clone-dropdown-btn.qa-clone-dropdown{ href: '#', data: { toggle: 'dropdown' } }
+ %span.append-right-4.js-clone-dropdown-label
+ = _('Clone')
+ = sprite_icon("arrow-down", css_class: "icon")
+ %ul.p-3.dropdown-menu.dropdown-menu-right.dropdown-menu-large.dropdown-menu-selectable.clone-options-dropdown.qa-clone-options
+ - if ssh_enabled?
%li.pb-2
%label.label-bold
= _('Clone with SSH')
@@ -19,6 +15,7 @@
.input-group-append
= clipboard_button(target: '#ssh_project_clone', title: _("Copy URL to clipboard"), class: "input-group-text btn-default btn-clipboard")
= render_if_exists 'projects/buttons/geo'
+ - if http_enabled?
%li
%label.label-bold
= _('Clone with %{http_label}') % { http_label: gitlab_config.protocol.upcase }
diff --git a/app/views/projects/diffs/_render_error.html.haml b/app/views/projects/diffs/_render_error.html.haml
index c3dc47a56a7..7dbd9897e83 100644
--- a/app/views/projects/diffs/_render_error.html.haml
+++ b/app/views/projects/diffs/_render_error.html.haml
@@ -1,6 +1,2 @@
.nothing-here-block
- = _("This %{viewer} could not be displayed because %{reason}.") % { viewer: viewer.switcher_title, reason: diff_render_error_reason(viewer) }
-
- You can
- = diff_render_error_options(viewer).to_sentence(two_words_connector: ' or ', last_word_connector: ', or ').html_safe
- instead.
+ = viewer.render_error_message.html_safe
diff --git a/app/views/projects/issues/show.html.haml b/app/views/projects/issues/show.html.haml
index b50b3ca207b..8c2fe2625c7 100644
--- a/app/views/projects/issues/show.html.haml
+++ b/app/views/projects/issues/show.html.haml
@@ -88,4 +88,4 @@
%section.issuable-discussion
= render 'projects/issues/discussion'
-= render 'shared/issuable/sidebar', issuable: @issue
+= render 'shared/issuable/sidebar', issuable_sidebar: @issuable_sidebar, assignees: @issue.assignees
diff --git a/app/views/projects/merge_requests/conflicts.html.haml b/app/views/projects/merge_requests/conflicts.html.haml
deleted file mode 100644
index a6e2565a485..00000000000
--- a/app/views/projects/merge_requests/conflicts.html.haml
+++ /dev/null
@@ -1,36 +0,0 @@
-- page_title "Merge Conflicts", "#{@merge_request.title} (#{@merge_request.to_reference}", "Merge Requests"
-- content_for :page_specific_javascripts do
- = page_specific_javascript_tag('lib/ace.js')
-= render "projects/merge_requests/mr_title"
-
-.merge-request-details.issuable-details
- = render "projects/merge_requests/mr_box"
-
-= render 'shared/issuable/sidebar', issuable: @merge_request
-
-#conflicts{ "v-cloak" => "true", data: { conflicts_path: conflicts_project_merge_request_path(@merge_request.project, @merge_request, format: :json),
- resolve_conflicts_path: resolve_conflicts_project_merge_request_path(@merge_request.project, @merge_request) } }
- .loading{ "v-if" => "isLoading" }
- %i.fa.fa-spinner.fa-spin
-
- .nothing-here-block{ "v-if" => "hasError" }
- {{conflictsData.errorMessage}}
-
- = render partial: "projects/merge_requests/conflicts/commit_stats"
-
- .files-wrapper{ "v-if" => "!isLoading && !hasError" }
- .files
- .diff-file.file-holder.conflict{ "v-for" => "file in conflictsData.files" }
- .js-file-title.file-title
- %i.fa.fa-fw{ ":class" => "file.iconClass" }
- %strong {{file.filePath}}
- = render partial: 'projects/merge_requests/conflicts/file_actions'
- .diff-content.diff-wrap-lines
- .diff-wrap-lines.code.file-content.js-syntax-highlight{ "v-show" => "!isParallel && file.resolveMode === 'interactive' && file.type === 'text'" }
- = render partial: "projects/merge_requests/conflicts/components/inline_conflict_lines"
- .diff-wrap-lines.code.file-content.js-syntax-highlight{ "v-show" => "isParallel && file.resolveMode === 'interactive' && file.type === 'text'" }
- %parallel-conflict-lines{ ":file" => "file" }
- %div{ "v-show" => "file.resolveMode === 'edit' || file.type === 'text-editor'" }
- = render partial: "projects/merge_requests/conflicts/components/diff_file_editor"
-
- = render partial: "projects/merge_requests/conflicts/submit_form"
diff --git a/app/views/projects/merge_requests/conflicts/show.html.haml b/app/views/projects/merge_requests/conflicts/show.html.haml
index a6e2565a485..09aeb81671a 100644
--- a/app/views/projects/merge_requests/conflicts/show.html.haml
+++ b/app/views/projects/merge_requests/conflicts/show.html.haml
@@ -6,7 +6,7 @@
.merge-request-details.issuable-details
= render "projects/merge_requests/mr_box"
-= render 'shared/issuable/sidebar', issuable: @merge_request
+= render 'shared/issuable/sidebar', issuable_sidebar: @issuable_sidebar, assignees: @merge_request.assignees
#conflicts{ "v-cloak" => "true", data: { conflicts_path: conflicts_project_merge_request_path(@merge_request.project, @merge_request, format: :json),
resolve_conflicts_path: resolve_conflicts_project_merge_request_path(@merge_request.project, @merge_request) } }
diff --git a/app/views/projects/merge_requests/show.html.haml b/app/views/projects/merge_requests/show.html.haml
index cc9292b54d7..d6f340d0ee2 100644
--- a/app/views/projects/merge_requests/show.html.haml
+++ b/app/views/projects/merge_requests/show.html.haml
@@ -86,7 +86,8 @@
.mr-loading-status
= spinner
-= render 'shared/issuable/sidebar', issuable: @merge_request
+= render 'shared/issuable/sidebar', issuable_sidebar: @issuable_sidebar, assignees: @merge_request.assignees
+
- if @merge_request.can_be_reverted?(current_user)
= render "projects/commit/change", type: 'revert', commit: @merge_request.merge_commit, title: @merge_request.title
- if @merge_request.can_be_cherry_picked?
diff --git a/app/views/projects/settings/ci_cd/show.html.haml b/app/views/projects/settings/ci_cd/show.html.haml
index 98e2829ba43..6966bf96724 100644
--- a/app/views/projects/settings/ci_cd/show.html.haml
+++ b/app/views/projects/settings/ci_cd/show.html.haml
@@ -43,13 +43,7 @@
%section.qa-variables-settings.settings.no-animate{ class: ('expanded' if expanded) }
.settings-header
- %h4
- = _('Variables')
- = link_to icon('question-circle'), help_page_path('ci/variables/README', anchor: 'variables'), target: '_blank', rel: 'noopener noreferrer'
- %button.btn.js-settings-toggle{ type: 'button' }
- = expanded ? _('Collapse') : _('Expand')
- %p.append-bottom-0
- = render "ci/variables/content"
+ = render 'ci/variables/header', expanded: expanded
.settings-content
= render 'ci/variables/index', save_endpoint: project_variables_path(@project)
diff --git a/app/views/shared/_mobile_clone_panel.html.haml b/app/views/shared/_mobile_clone_panel.html.haml
index b43662947a8..6e2527bd1a1 100644
--- a/app/views/shared/_mobile_clone_panel.html.haml
+++ b/app/views/shared/_mobile_clone_panel.html.haml
@@ -7,7 +7,9 @@
%button.btn.btn-primary.dropdown-toggle.js-dropdown-toggle{ type: "button", data: { toggle: "dropdown" } }
= sprite_icon("arrow-down", css_class: "dropdown-btn-icon icon")
%ul.dropdown-menu.dropdown-menu-selectable.dropdown-menu-right.clone-options-dropdown{ data: { dropdown: true } }
- %li
- = dropdown_item_with_description(ssh_copy_label, project.ssh_url_to_repo, href: project.ssh_url_to_repo, data: { clone_type: 'ssh' }, default: true)
- %li
- = dropdown_item_with_description(http_copy_label, project.http_url_to_repo, href: project.http_url_to_repo, data: { clone_type: 'http' })
+ - if ssh_enabled?
+ %li
+ = dropdown_item_with_description(ssh_copy_label, project.ssh_url_to_repo, href: project.ssh_url_to_repo, data: { clone_type: 'ssh' }, default: true)
+ - if http_enabled?
+ %li
+ = dropdown_item_with_description(http_copy_label, project.http_url_to_repo, href: project.http_url_to_repo, data: { clone_type: 'http' })
diff --git a/app/views/shared/issuable/_sidebar.html.haml b/app/views/shared/issuable/_sidebar.html.haml
index 9eecfa39390..0520eda37a4 100644
--- a/app/views/shared/issuable/_sidebar.html.haml
+++ b/app/views/shared/issuable/_sidebar.html.haml
@@ -1,32 +1,37 @@
-- todo = issuable_todo(issuable)
+-# `assignees` is being passed in for populating selected assignee values in the select box and rendering the assignee link
+ This should be removed when this sidebar is converted to Vue since assignee data is also available in the `issuable_sidebar` hash
-%aside.right-sidebar.js-right-sidebar.js-issuable-sidebar{ data: { signed: { in: current_user.present? } }, class: sidebar_gutter_collapsed_class, 'aria-live' => 'polite' }
- .issuable-sidebar{ data: { endpoint: "#{issuable_json_path(issuable)}" } }
- - can_edit_issuable = can?(current_user, :"admin_#{issuable.to_ability_name}", @project)
+- issuable_type = issuable_sidebar[:type]
+- signed_in = !!issuable_sidebar.dig(:current_user, :id)
+- can_edit_issuable = issuable_sidebar.dig(:current_user, :can_edit)
+
+%aside.right-sidebar.js-right-sidebar.js-issuable-sidebar{ data: { signed: { in: signed_in } }, class: sidebar_gutter_collapsed_class, 'aria-live' => 'polite' }
+ .issuable-sidebar
.block.issuable-sidebar-header
- - if current_user
+ - if signed_in
%span.issuable-header-text.hide-collapsed.float-left
= _('Todo')
%a.gutter-toggle.float-right.js-sidebar-toggle.has-tooltip{ role: "button", href: "#", "aria-label" => "Toggle sidebar", title: sidebar_gutter_tooltip_text, data: { container: 'body', placement: 'left', boundary: 'viewport' } }
= sidebar_gutter_toggle_icon
- - if current_user
- = render "shared/issuable/sidebar_todo", todo: todo, issuable: issuable
+ - if signed_in
+ = render "shared/issuable/sidebar_todo", issuable_sidebar: issuable_sidebar
- = form_for [@project.namespace.becomes(Namespace), @project, issuable], remote: true, format: :json, html: { class: 'issuable-context-form inline-update js-issuable-update' } do |f|
- - if current_user
+ = form_for issuable_type, url: issuable_sidebar[:issuable_json_path], remote: true, html: { class: 'issuable-context-form inline-update js-issuable-update' } do |f|
+ - if signed_in
.block.todo.hide-expanded
- = render "shared/issuable/sidebar_todo", todo: todo, issuable: issuable, is_collapsed: true
+ = render "shared/issuable/sidebar_todo", issuable_sidebar: issuable_sidebar, is_collapsed: true
.block.assignee.qa-assignee-block
- = render "shared/issuable/sidebar_assignees", issuable: issuable, can_edit_issuable: can_edit_issuable, signed_in: current_user.present?
+ = render "shared/issuable/sidebar_assignees", issuable_sidebar: issuable_sidebar, assignees: assignees
- = render_if_exists 'shared/issuable/sidebar_item_epic', issuable: issuable
+ = render_if_exists 'shared/issuable/sidebar_item_epic', issuable_sidebar: issuable_sidebar
+ - milestone = issuable_sidebar[:milestone] || {}
.block.milestone
- .sidebar-collapsed-icon.has-tooltip{ title: milestone_tooltip_title(issuable.milestone), data: { container: 'body', html: 'true', placement: 'left', boundary: 'viewport' } }
+ .sidebar-collapsed-icon.has-tooltip{ title: sidebar_milestone_tooltip_label(milestone), data: { container: 'body', html: 'true', placement: 'left', boundary: 'viewport' } }
= icon('clock-o', 'aria-hidden': 'true')
%span.milestone-title.collapse-truncated-title
- - if issuable.milestone
- = issuable.milestone.title
+ - if milestone.present?
+ = milestone[:title]
- else
= _('None')
.title.hide-collapsed
@@ -35,49 +40,50 @@
- if can_edit_issuable
= link_to _('Edit'), '#', class: 'js-sidebar-dropdown-toggle edit-link float-right'
.value.hide-collapsed
- - if issuable.milestone
- = link_to issuable.milestone.title, milestone_path(issuable.milestone), class: "bold has-tooltip", title: milestone_tooltip_due_date(issuable.milestone), data: { container: "body", html: 'true', boundary: 'viewport' }
+ - if milestone.present?
+ = link_to milestone[:title], milestone[:web_url], class: "bold has-tooltip", title: sidebar_milestone_remaining_days(milestone), data: { container: "body", html: 'true', boundary: 'viewport' }
- else
%span.no-value
= _('None')
.selectbox.hide-collapsed
- = f.hidden_field 'milestone_id', value: issuable.milestone_id, id: nil
- = dropdown_tag('Milestone', options: { title: _('Assign milestone'), toggle_class: 'js-milestone-select js-extra-options', filter: true, dropdown_class: 'dropdown-menu-selectable', placeholder: _('Search milestones'), data: { show_no: true, field_name: "#{issuable.to_ability_name}[milestone_id]", project_id: @project.id, issuable_id: issuable.id, milestones: project_milestones_path(@project, :json), ability_name: issuable.to_ability_name, issue_update: issuable_json_path(issuable), use_id: true, default_no: true, selected: (issuable.milestone.name if issuable.milestone), null_default: true, display: 'static' }})
- - if issuable.has_attribute?(:time_estimate)
- #issuable-time-tracker.block
- // Fallback while content is loading
- .title.hide-collapsed
- = _('Time tracking')
- = icon('spinner spin', 'aria-hidden': 'true')
- - if issuable.has_attribute?(:due_date)
+ = f.hidden_field 'milestone_id', value: milestone[:id], id: nil
+ = dropdown_tag('Milestone', options: { title: _('Assign milestone'), toggle_class: 'js-milestone-select js-extra-options', filter: true, dropdown_class: 'dropdown-menu-selectable', placeholder: _('Search milestones'), data: { show_no: true, field_name: "#{issuable_type}[milestone_id]", project_id: issuable_sidebar[:project_id], issuable_id: issuable_sidebar[:id], milestones: issuable_sidebar[:project_milestones_path], ability_name: issuable_type, issue_update: issuable_sidebar[:issuable_json_path], use_id: true, default_no: true, selected: milestone[:title], null_default: true, display: 'static' }})
+
+ #issuable-time-tracker.block
+ // Fallback while content is loading
+ .title.hide-collapsed
+ = _('Time tracking')
+ = icon('spinner spin', 'aria-hidden': 'true')
+
+ - if issuable_sidebar.has_key?(:due_date)
.block.due_date
- .sidebar-collapsed-icon.has-tooltip{ data: { placement: 'left', container: 'body', html: 'true', boundary: 'viewport' }, title: sidebar_due_date_tooltip_label(issuable) }
+ .sidebar-collapsed-icon.has-tooltip{ data: { placement: 'left', container: 'body', html: 'true', boundary: 'viewport' }, title: sidebar_due_date_tooltip_label(issuable_sidebar[:due_date]) }
= icon('calendar', 'aria-hidden': 'true')
%span.js-due-date-sidebar-value
- = issuable.due_date.try(:to_s, :medium) || 'None'
+ = issuable_sidebar[:due_date].try(:to_s, :medium) || 'None'
.title.hide-collapsed
= _('Due date')
= icon('spinner spin', class: 'hidden block-loading', 'aria-hidden': 'true')
- - if can?(current_user, :"admin_#{issuable.to_ability_name}", @project)
+ - if can_edit_issuable
= link_to _('Edit'), '#', class: 'js-sidebar-dropdown-toggle edit-link float-right'
.value.hide-collapsed
%span.value-content
- - if issuable.due_date
- %span.bold= issuable.due_date.to_s(:medium)
+ - if issuable_sidebar[:due_date]
+ %span.bold= issuable_sidebar[:due_date].to_s(:medium)
- else
%span.no-value
= _('No due date')
- - if can?(current_user, :"admin_#{issuable.to_ability_name}", @project)
- %span.no-value.js-remove-due-date-holder{ class: ("hidden" if issuable.due_date.nil?) }
+ - if can_edit_issuable
+ %span.no-value.js-remove-due-date-holder{ class: ("hidden" if issuable_sidebar[:due_date].nil?) }
\-
%a.js-remove-due-date{ href: "#", role: "button" }
= _('remove due date')
- - if can?(current_user, :"admin_#{issuable.to_ability_name}", @project)
+ - if can_edit_issuable
.selectbox.hide-collapsed
- = f.hidden_field :due_date, value: issuable.due_date.try(:strftime, 'yy-mm-dd')
+ = f.hidden_field :due_date, value: issuable_sidebar[:due_date].try(:strftime, 'yy-mm-dd')
.dropdown
- %button.dropdown-menu-toggle.js-due-date-select{ type: 'button', data: { toggle: 'dropdown', field_name: "#{issuable.to_ability_name}[due_date]", ability_name: issuable.to_ability_name, issue_update: issuable_json_path(issuable), display: 'static' } }
+ %button.dropdown-menu-toggle.js-due-date-select{ type: 'button', data: { toggle: 'dropdown', field_name: "#{issuable_type}[due_date]", ability_name: issuable_type, issue_update: issuable_sidebar[:issuable_json_path], display: 'static' } }
%span.dropdown-toggle-text
= _('Due date')
= icon('chevron-down', 'aria-hidden': 'true')
@@ -86,56 +92,56 @@
= dropdown_content do
.js-due-date-calendar
- - if @labels
- - selected_labels = issuable.labels
- .block.labels
- .sidebar-collapsed-icon.js-sidebar-labels-tooltip{ title: issuable_labels_tooltip(issuable.labels_array), data: { placement: "left", container: "body", boundary: 'viewport' } }
- = icon('tags', 'aria-hidden': 'true')
- %span
- = selected_labels.size
- .title.hide-collapsed
- = _('Labels')
- = icon('spinner spin', class: 'hidden block-loading', 'aria-hidden': 'true')
- - if can_edit_issuable
- = link_to _('Edit'), '#', class: 'js-sidebar-dropdown-toggle edit-link float-right'
- .value.issuable-show-labels.dont-hide.hide-collapsed.qa-labels-block{ class: ("has-labels" if selected_labels.any?) }
- - if selected_labels.any?
- - selected_labels.each do |label|
- = link_to_label(label, subject: issuable.project, type: issuable.to_ability_name)
- - else
- %span.no-value
- = _('None')
- .selectbox.hide-collapsed
+ - selected_labels = issuable_sidebar[:labels]
+ .block.labels
+ .sidebar-collapsed-icon.js-sidebar-labels-tooltip{ title: issuable_labels_tooltip(selected_labels), data: { placement: "left", container: "body", boundary: 'viewport' } }
+ = icon('tags', 'aria-hidden': 'true')
+ %span
+ = selected_labels.size
+ .title.hide-collapsed
+ = _('Labels')
+ = icon('spinner spin', class: 'hidden block-loading', 'aria-hidden': 'true')
+ - if can_edit_issuable
+ = link_to _('Edit'), '#', class: 'js-sidebar-dropdown-toggle edit-link float-right'
+ .value.issuable-show-labels.dont-hide.hide-collapsed.qa-labels-block{ class: ("has-labels" if selected_labels.any?) }
+ - if selected_labels.any?
- selected_labels.each do |label|
- = hidden_field_tag "#{issuable.to_ability_name}[label_names][]", label.id, id: nil
- .dropdown
- %button.dropdown-menu-toggle.js-label-select.js-multiselect.js-label-sidebar-dropdown{ type: "button", data: {toggle: "dropdown", default_label: "Labels", field_name: "#{issuable.to_ability_name}[label_names][]", ability_name: issuable.to_ability_name, show_no: "true", show_any: "true", namespace_path: @project.try(:namespace).try(:full_path), project_path: @project.try(:path), issue_update: issuable_json_path(issuable), labels: (labels_filter_path_with_defaults if @project), display: 'static' } }
- %span.dropdown-toggle-text{ class: ("is-default" if selected_labels.empty?) }
- = multi_label_name(selected_labels, "Labels")
- = icon('chevron-down', 'aria-hidden': 'true')
- .dropdown-menu.dropdown-select.dropdown-menu-paging.dropdown-menu-labels.dropdown-menu-selectable
- = render partial: "shared/issuable/label_page_default"
- - if can? current_user, :admin_label, @project and @project
- = render partial: "shared/issuable/label_page_create"
-
- = render_if_exists 'shared/issuable/sidebar_weight', issuable: issuable
-
- - if issuable.has_attribute?(:confidential)
+ = link_to sidebar_label_filter_path(issuable_sidebar[:project_issuables_path], label[:title]) do
+ %span.badge.color-label.has-tooltip{ style: "background-color: #{label[:color]}; color: #{label[:text_color]}", title: label[:description], data: { container: "body" } }
+ = label[:title]
+ - else
+ %span.no-value
+ = _('None')
+ .selectbox.hide-collapsed
+ - selected_labels.each do |label|
+ = hidden_field_tag "#{issuable_type}[label_names][]", label[:id], id: nil
+ .dropdown
+ %button.dropdown-menu-toggle.js-label-select.js-multiselect.js-label-sidebar-dropdown{ type: "button", data: {toggle: "dropdown", default_label: "Labels", field_name: "#{issuable_type}[label_names][]", ability_name: issuable_type, show_no: "true", show_any: "true", namespace_path: issuable_sidebar[:namespace_path], project_path: issuable_sidebar[:project_path], issue_update: issuable_sidebar[:issuable_json_path], labels: issuable_sidebar[:project_labels_path], display: 'static' } }
+ %span.dropdown-toggle-text{ class: ("is-default" if selected_labels.empty?) }
+ = multi_label_name(selected_labels, "Labels")
+ = icon('chevron-down', 'aria-hidden': 'true')
+ .dropdown-menu.dropdown-select.dropdown-menu-paging.dropdown-menu-labels.dropdown-menu-selectable
+ = render partial: "shared/issuable/label_page_default"
+ - if issuable_sidebar.dig(:current_user, :can_admin_label)
+ = render partial: "shared/issuable/label_page_create"
+
+ = render_if_exists 'shared/issuable/sidebar_weight', issuable_sidebar: issuable_sidebar
+
+ - if issuable_sidebar.has_key?(:confidential)
-# haml-lint:disable InlineJavaScript
- %script#js-confidential-issue-data{ type: "application/json" }= { is_confidential: @issue.confidential, is_editable: can_edit_issuable }.to_json.html_safe
+ %script#js-confidential-issue-data{ type: "application/json" }= { is_confidential: issuable_sidebar[:confidential], is_editable: can_edit_issuable }.to_json.html_safe
#js-confidential-entry-point
- - if issuable.has_attribute?(:discussion_locked)
- -# haml-lint:disable InlineJavaScript
- %script#js-lock-issue-data{ type: "application/json" }= { is_locked: issuable.discussion_locked?, is_editable: can_edit_issuable }.to_json.html_safe
- #js-lock-entry-point
+ -# haml-lint:disable InlineJavaScript
+ %script#js-lock-issue-data{ type: "application/json" }= { is_locked: issuable_sidebar[:discussion_locked], is_editable: can_edit_issuable }.to_json.html_safe
+ #js-lock-entry-point
.js-sidebar-participants-entry-point
- - if current_user
+ - if signed_in
.js-sidebar-subscriptions-entry-point
- - project_ref = cross_project_reference(@project, issuable)
+ - project_ref = issuable_sidebar[:reference]
.block.project-reference
.sidebar-collapsed-icon.dont-change-state
= clipboard_button(text: project_ref, title: _('Copy reference to clipboard'), placement: "left", boundary: 'viewport')
@@ -145,7 +151,8 @@
%cite{ title: project_ref }
= project_ref
= clipboard_button(text: project_ref, title: _('Copy reference to clipboard'), placement: "left", boundary: 'viewport')
- - if current_user && issuable.can_move?(current_user)
+
+ - if issuable_sidebar.dig(:current_user, :can_move)
.block.js-sidebar-move-issue-block
.sidebar-collapsed-icon{ data: { toggle: 'tooltip', placement: 'left', container: 'body', boundary: 'viewport' }, title: _('Move issue') }
= custom_icon('icon_arrow_right')
@@ -164,4 +171,4 @@
= icon('spinner spin', class: 'sidebar-move-issue-confirmation-loading-icon')
-# haml-lint:disable InlineJavaScript
- %script.js-sidebar-options{ type: "application/json" }= issuable_sidebar_options(issuable, can_edit_issuable).to_json.html_safe
+ %script.js-sidebar-options{ type: "application/json" }= issuable_sidebar_options(issuable_sidebar).to_json.html_safe
diff --git a/app/views/shared/issuable/_sidebar_assignees.html.haml b/app/views/shared/issuable/_sidebar_assignees.html.haml
index 8a13c7a3b83..c5cce1823f0 100644
--- a/app/views/shared/issuable/_sidebar_assignees.html.haml
+++ b/app/views/shared/issuable/_sidebar_assignees.html.haml
@@ -1,12 +1,17 @@
-- if issuable.is_a?(Issue)
- #js-vue-sidebar-assignees{ data: { field: "#{issuable.to_ability_name}[assignee_ids]", signed_in: signed_in } }
+- issuable_type = issuable_sidebar[:type]
+- signed_in = !!issuable_sidebar.dig(:current_user, :id)
+- can_edit_issuable = issuable_sidebar.dig(:current_user, :can_edit)
+
+- if issuable_type == "issue"
+ #js-vue-sidebar-assignees{ data: { field: "#{issuable_type}[assignee_ids]", signed_in: signed_in } }
.title.hide-collapsed
= _('Assignee')
= icon('spinner spin')
- else
- .sidebar-collapsed-icon.sidebar-collapsed-user{ data: { toggle: "tooltip", placement: "left", container: "body", boundary: 'viewport' }, title: sidebar_assignee_tooltip_label(issuable) }
- - if issuable.assignee
- = link_to_member(@project, issuable.assignee, size: 24)
+ - assignee = assignees.first
+ .sidebar-collapsed-icon.sidebar-collapsed-user{ data: { toggle: "tooltip", placement: "left", container: "body", boundary: 'viewport' }, title: (issuable_sidebar.dig(:assignee, :name) || _('Assignee')) }
+ - if issuable_sidebar[:assignee]
+ = link_to_member(@project, assignee, size: 24)
- else
= icon('user', 'aria-hidden': 'true')
.title.hide-collapsed
@@ -18,13 +23,13 @@
%a.gutter-toggle.float-right.js-sidebar-toggle{ role: "button", href: "#", "aria-label" => _('Toggle sidebar') }
= sidebar_gutter_toggle_icon
.value.hide-collapsed
- - if issuable.assignee
- = link_to_member(@project, issuable.assignee, size: 32, extra_class: 'bold') do
- - if !issuable.can_be_merged_by?(issuable.assignee)
+ - if issuable_sidebar[:assignee]
+ = link_to_member(@project, assignee, size: 32, extra_class: 'bold') do
+ - if issuable_sidebar[:assignee][:can_merge]
%span.float-right.cannot-be-merged{ data: { toggle: 'tooltip', placement: 'left' }, title: _('Not allowed to merge') }
= icon('exclamation-triangle', 'aria-hidden': 'true')
%span.username
- = issuable.assignee.to_reference
+ @#{issuable_sidebar[:assignee][:username]}
- else
%span.assign-yourself.no-value
= _('No assignee')
@@ -34,19 +39,33 @@
= _('assign yourself')
.selectbox.hide-collapsed
- - issuable.assignees.each do |assignee|
- = hidden_field_tag "#{issuable.to_ability_name}[assignee_ids][]", assignee.id, id: nil, data: { avatar_url: assignee.avatar_url, name: assignee.name, username: assignee.username }
+ - if assignees.none?
+ = hidden_field_tag "#{issuable_type}[assignee_ids][]", 0, id: nil
+ - else
+ - assignees.each do |assignee|
+ = hidden_field_tag "#{issuable_type}[assignee_ids][]", assignee.id, id: nil, data: { avatar_url: assignee.avatar_url, name: assignee.name, username: assignee.username }
- - options = { toggle_class: 'js-user-search js-author-search', title: _('Assign to'), filter: true, dropdown_class: 'dropdown-menu-user dropdown-menu-selectable dropdown-menu-author', placeholder: _('Search users'), data: { first_user: current_user&.username, current_user: true, project_id: @project&.id, author_id: issuable.author_id, field_name: "#{issuable.to_ability_name}[assignee_ids][]", issue_update: issuable_json_path(issuable), ability_name: issuable.to_ability_name, null_user: true, display: 'static' } }
+ - options = { toggle_class: 'js-user-search js-author-search',
+ title: _('Assign to'),
+ filter: true,
+ dropdown_class: 'dropdown-menu-user dropdown-menu-selectable dropdown-menu-author',
+ placeholder: _('Search users'),
+ data: { first_user: issuable_sidebar.dig(:current_user, :username),
+ current_user: true,
+ project_id: issuable_sidebar[:project_id],
+ author_id: issuable_sidebar[:author_id],
+ field_name: "#{issuable_type}[assignee_ids][]",
+ issue_update: issuable_sidebar[:issuable_json_path],
+ ability_name: issuable_type,
+ null_user: true,
+ display: 'static' } }
- title = _('Select assignee')
- - if issuable.is_a?(Issue)
- - unless issuable.assignees.any?
- = hidden_field_tag "#{issuable.to_ability_name}[assignee_ids][]", 0, id: nil
+ - if issuable_type == "issue"
- dropdown_options = issue_assignees_dropdown_options
- title = dropdown_options[:title]
- options[:toggle_class] += ' js-multiselect js-save-user-data'
- - data = { field_name: "#{issuable.to_ability_name}[assignee_ids][]" }
+ - data = { field_name: "#{issuable_type}[assignee_ids][]" }
- data[:multi_select] = true
- data['dropdown-title'] = title
- data['dropdown-header'] = dropdown_options[:data][:'dropdown-header']
diff --git a/app/views/shared/issuable/_sidebar_todo.html.haml b/app/views/shared/issuable/_sidebar_todo.html.haml
index 660ee6d5777..de4df016cfb 100644
--- a/app/views/shared/issuable/_sidebar_todo.html.haml
+++ b/app/views/shared/issuable/_sidebar_todo.html.haml
@@ -1,15 +1,15 @@
- is_collapsed = local_assigns.fetch(:is_collapsed, false)
-- mark_content = is_collapsed ? sprite_icon('todo-done', css_class: 'todo-undone') : _('Mark todo as done')
-- todo_content = is_collapsed ? sprite_icon('todo-add') : _('Add todo')
+- has_todo = !!issuable_sidebar.dig(:current_user, :todo, :id)
+
+- todo_button_data = issuable_todo_button_data(issuable_sidebar, is_collapsed)
+- button_title = has_todo ? todo_button_data[:mark_text] : todo_button_data[:todo_text]
+- button_icon = has_todo ? todo_button_data[:mark_icon] : todo_button_data[:todo_icon]
%button.issuable-todo-btn.js-issuable-todo{ type: 'button',
class: (is_collapsed ? 'btn-blank sidebar-collapsed-icon dont-change-state has-tooltip' : 'btn btn-default issuable-header-btn float-right'),
- title: (todo.nil? ? _('Add todo') : _('Mark todo as done')),
- 'aria-label' => (todo.nil? ? _('Add todo') : _('Mark todo as done')),
- data: issuable_todo_button_data(issuable, todo, is_collapsed) }
+ title: button_title,
+ 'aria-label' => button_title,
+ data: todo_button_data }
%span.issuable-todo-inner.js-issuable-todo-inner<
- - if todo
- = mark_content
- - else
- = todo_content
+ = is_collapsed ? button_icon : button_title
= icon('spin spinner', 'aria-hidden': 'true')
diff --git a/app/views/shared/issuable/form/_metadata.html.haml b/app/views/shared/issuable/form/_metadata.html.haml
index ac8d58c0bfe..e370dff9526 100644
--- a/app/views/shared/issuable/form/_metadata.html.haml
+++ b/app/views/shared/issuable/form/_metadata.html.haml
@@ -19,10 +19,9 @@
.issuable-form-select-holder
= render "shared/issuable/milestone_dropdown", selected: issuable.milestone, name: "#{issuable.class.model_name.param_key}[milestone_id]", show_any: false, show_upcoming: false, show_started: false, extra_class: "qa-issuable-milestone-dropdown js-issuable-form-dropdown js-dropdown-keep-input", dropdown_title: "Select milestone"
.form-group.row
- - has_labels = @labels && @labels.any?
= form.label :label_ids, "Labels", class: "col-form-label #{has_due_date ? "col-md-2 col-lg-4" : "col-sm-2"}"
= form.hidden_field :label_ids, multiple: true, value: ''
- .col-sm-10{ class: "#{"col-md-8" if has_due_date} #{'issuable-form-padding-top' if !has_labels}" }
+ .col-sm-10{ class: "#{"col-md-8" if has_due_date}" }
.issuable-form-select-holder
= render "shared/issuable/label_dropdown", classes: ["js-issuable-form-dropdown"], selected: issuable.labels, data_options: { field_name: "#{issuable.class.model_name.param_key}[label_ids][]", show_any: false }, dropdown_title: "Select label"
diff --git a/app/views/shared/milestones/_sidebar.html.haml b/app/views/shared/milestones/_sidebar.html.haml
index becd1c4884e..b24075c7849 100644
--- a/app/views/shared/milestones/_sidebar.html.haml
+++ b/app/views/shared/milestones/_sidebar.html.haml
@@ -65,7 +65,7 @@
%span.bold= milestone.due_date.to_s(:medium)
- else
%span.no-value No due date
- - remaining_days = remaining_days_in_words(milestone)
+ - remaining_days = remaining_days_in_words(milestone.due_date, milestone.start_date)
- if remaining_days.present?
= surround '(', ')' do
%span.remaining-days= remaining_days
diff --git a/app/views/shared/projects/_project.html.haml b/app/views/shared/projects/_project.html.haml
index 9dde77fccef..fea7e17be3d 100644
--- a/app/views/shared/projects/_project.html.haml
+++ b/app/views/shared/projects/_project.html.haml
@@ -72,13 +72,13 @@
title: _('Forks'), data: { container: 'body', placement: 'top' } do
= sprite_icon('fork', size: 14, css_class: 'append-right-4')
= number_with_delimiter(project.forks_count)
- - if show_merge_request_count?(merge_requests, compact_mode)
+ - if show_merge_request_count?(disabled: !merge_requests, compact_mode: compact_mode)
= link_to project_merge_requests_path(project),
class: "d-none d-lg-flex align-items-center icon-wrapper merge-requests has-tooltip",
title: _('Merge Requests'), data: { container: 'body', placement: 'top' } do
= sprite_icon('git-merge', size: 14, css_class: 'append-right-4')
= number_with_delimiter(project.open_merge_requests_count)
- - if show_issue_count?(issues, compact_mode)
+ - if show_issue_count?(disabled: !issues, compact_mode: compact_mode)
= link_to project_issues_path(project),
class: "d-none d-lg-flex align-items-center icon-wrapper issues has-tooltip",
title: _('Issues'), data: { container: 'body', placement: 'top' } do
diff --git a/app/views/shared/snippets/_header.html.haml b/app/views/shared/snippets/_header.html.haml
index 10bfc30492a..a43296aa806 100644
--- a/app/views/shared/snippets/_header.html.haml
+++ b/app/views/shared/snippets/_header.html.haml
@@ -30,7 +30,7 @@
- if @snippet.updated_at != @snippet.created_at
= edited_time_ago_with_tooltip(@snippet, placement: 'bottom', html_class: 'snippet-edited-ago', exclude_author: true)
- - if public_snippet?
+ - if @snippet.embeddable?
.embed-snippet
.input-group
.input-group-prepend
diff --git a/app/workers/all_queues.yml b/app/workers/all_queues.yml
index f9928362290..d3cf21db335 100644
--- a/app/workers/all_queues.yml
+++ b/app/workers/all_queues.yml
@@ -27,7 +27,7 @@
- gcp_cluster:cluster_wait_for_app_installation
- gcp_cluster:wait_for_cluster_creation
- gcp_cluster:cluster_wait_for_ingress_ip_address
-- gcp_cluster:cluster_platform_configure
+- gcp_cluster:cluster_configure
- gcp_cluster:cluster_project_configure
- github_import_advance_stage
diff --git a/app/workers/cluster_platform_configure_worker.rb b/app/workers/cluster_configure_worker.rb
index aa7570caa79..63e6cc147be 100644
--- a/app/workers/cluster_platform_configure_worker.rb
+++ b/app/workers/cluster_configure_worker.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-class ClusterPlatformConfigureWorker
+class ClusterConfigureWorker
include ApplicationWorker
include ClusterQueue
diff --git a/app/workers/cluster_provision_worker.rb b/app/workers/cluster_provision_worker.rb
index 3d5894b73ec..926ae2b7286 100644
--- a/app/workers/cluster_provision_worker.rb
+++ b/app/workers/cluster_provision_worker.rb
@@ -10,7 +10,7 @@ class ClusterProvisionWorker
Clusters::Gcp::ProvisionService.new.execute(provider) if cluster.gcp?
end
- ClusterPlatformConfigureWorker.perform_async(cluster.id) if cluster.user?
+ ClusterConfigureWorker.perform_async(cluster.id) if cluster.user?
end
end
end
diff --git a/app/workers/mail_scheduler/notification_service_worker.rb b/app/workers/mail_scheduler/notification_service_worker.rb
index 4726e416182..c8ccaf0c487 100644
--- a/app/workers/mail_scheduler/notification_service_worker.rb
+++ b/app/workers/mail_scheduler/notification_service_worker.rb
@@ -8,14 +8,35 @@ module MailScheduler
include MailSchedulerQueue
def perform(meth, *args)
- deserialized_args = ActiveJob::Arguments.deserialize(args)
+ check_arguments!(args)
+ deserialized_args = ActiveJob::Arguments.deserialize(args)
notification_service.public_send(meth, *deserialized_args) # rubocop:disable GitlabSecurity/PublicSend
rescue ActiveJob::DeserializationError
+ # No-op.
+ # This exception gets raised when an argument
+ # is correct (deserializeable), but it still cannot be deserialized.
+ # This can happen when an object has been deleted after
+ # rails passes this job to sidekiq, but before
+ # sidekiq gets it for execution.
+ # In this case just do nothing.
end
def self.perform_async(*args)
super(*ActiveJob::Arguments.serialize(args))
end
+
+ private
+
+ # If an argument is in the ActiveJob::Arguments::TYPE_WHITELIST list,
+ # it means the argument cannot be deserialized.
+ # Which means there's something wrong with our code.
+ def check_arguments!(args)
+ args.each do |arg|
+ if arg.class.in?(ActiveJob::Arguments::TYPE_WHITELIST)
+ raise(ArgumentError, "Argument `#{arg}` cannot be deserialized because of its type")
+ end
+ end
+ end
end
end
diff --git a/app/workers/post_receive.rb b/app/workers/post_receive.rb
index 72a1733a2a8..bbd4ab159e4 100644
--- a/app/workers/post_receive.rb
+++ b/app/workers/post_receive.rb
@@ -3,7 +3,7 @@
class PostReceive
include ApplicationWorker
- def perform(gl_repository, identifier, changes)
+ def perform(gl_repository, identifier, changes, push_options = [])
project, is_wiki = Gitlab::GlRepository.parse(gl_repository)
if project.nil?
@@ -15,7 +15,7 @@ class PostReceive
# Use Sidekiq.logger so arguments can be correlated with execution
# time and thread ID's.
Sidekiq.logger.info "changes: #{changes.inspect}" if ENV['SIDEKIQ_LOG_ARGUMENTS']
- post_received = Gitlab::GitPostReceive.new(project, identifier, changes)
+ post_received = Gitlab::GitPostReceive.new(project, identifier, changes, push_options)
if is_wiki
process_wiki_changes(post_received)
@@ -38,9 +38,21 @@ class PostReceive
post_received.changes_refs do |oldrev, newrev, ref|
if Gitlab::Git.tag_ref?(ref)
- GitTagPushService.new(post_received.project, @user, oldrev: oldrev, newrev: newrev, ref: ref).execute
+ GitTagPushService.new(
+ post_received.project,
+ @user,
+ oldrev: oldrev,
+ newrev: newrev,
+ ref: ref,
+ push_options: post_received.push_options).execute
elsif Gitlab::Git.branch_ref?(ref)
- GitPushService.new(post_received.project, @user, oldrev: oldrev, newrev: newrev, ref: ref).execute
+ GitPushService.new(
+ post_received.project,
+ @user,
+ oldrev: oldrev,
+ newrev: newrev,
+ ref: ref,
+ push_options: post_received.push_options).execute
end
changes << Gitlab::DataBuilder::Repository.single_change(oldrev, newrev, ref)
diff --git a/changelogs/unreleased/18667-handle-push-opts.yml b/changelogs/unreleased/18667-handle-push-opts.yml
new file mode 100644
index 00000000000..204293476f6
--- /dev/null
+++ b/changelogs/unreleased/18667-handle-push-opts.yml
@@ -0,0 +1,5 @@
+---
+title: Handle ci.skip push option
+merge_request: 15643
+author: Jonathon Reinhart
+type: added
diff --git a/changelogs/unreleased/19376-post-bfg-cleanup.yml b/changelogs/unreleased/19376-post-bfg-cleanup.yml
deleted file mode 100644
index fc1bcc30db9..00000000000
--- a/changelogs/unreleased/19376-post-bfg-cleanup.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Use BFG object maps to clean projects
-merge_request: 23189
-author:
-type: added
diff --git a/changelogs/unreleased/1979-redesign-mr-widget-approvals-ce.yml b/changelogs/unreleased/1979-redesign-mr-widget-approvals-ce.yml
deleted file mode 100644
index d05b6054b22..00000000000
--- a/changelogs/unreleased/1979-redesign-mr-widget-approvals-ce.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Redesign of MR header sections (CE)
-merge_request: 23465
-author:
-type: changed
diff --git a/changelogs/unreleased/20422-hide-ui-variables-by-default.yml b/changelogs/unreleased/20422-hide-ui-variables-by-default.yml
deleted file mode 100644
index 60285d49718..00000000000
--- a/changelogs/unreleased/20422-hide-ui-variables-by-default.yml
+++ /dev/null
@@ -1,6 +0,0 @@
----
-title: Pipeline trigger variable values are hidden in the UI by default. Maintainers
- have the option to reveal them.
-merge_request: 23518
-author: jhampton
-type: added
diff --git a/changelogs/unreleased/22548-reopen-error-message.yml b/changelogs/unreleased/22548-reopen-error-message.yml
deleted file mode 100644
index 79c20eccb12..00000000000
--- a/changelogs/unreleased/22548-reopen-error-message.yml
+++ /dev/null
@@ -1,6 +0,0 @@
----
-title: Show error message when attempting to reopen an MR and there is an open MR
- for the same branch
-merge_request: 16447
-author: Akos Gyimesi
-type: fixed
diff --git a/changelogs/unreleased/33705-merge-request-rebase-api.yml b/changelogs/unreleased/33705-merge-request-rebase-api.yml
deleted file mode 100644
index 322fe31ce87..00000000000
--- a/changelogs/unreleased/33705-merge-request-rebase-api.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Add a rebase API endpoint for merge requests
-merge_request: 23296
-author:
-type: added
diff --git a/changelogs/unreleased/34758-deployment-cluster.yml b/changelogs/unreleased/34758-deployment-cluster.yml
deleted file mode 100644
index 06374098343..00000000000
--- a/changelogs/unreleased/34758-deployment-cluster.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Use group clusters when deploying (DeploymentPlatform)
-merge_request: 22308
-author:
-type: changed
diff --git a/changelogs/unreleased/34758-extend-can-create-cluster-logic.yml b/changelogs/unreleased/34758-extend-can-create-cluster-logic.yml
new file mode 100644
index 00000000000..65f5253a271
--- /dev/null
+++ b/changelogs/unreleased/34758-extend-can-create-cluster-logic.yml
@@ -0,0 +1,5 @@
+---
+title: Allow user to add Kubernetes cluster for clusterable when there are ancestor clusters
+merge_request: 23569
+author:
+type: other
diff --git a/changelogs/unreleased/34758-group-cluster-controller.yml b/changelogs/unreleased/34758-group-cluster-controller.yml
deleted file mode 100644
index 88c4c872714..00000000000
--- a/changelogs/unreleased/34758-group-cluster-controller.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Add ability to create group level clusters and install gitlab managed applications
-merge_request: 22450
-author:
-type: added
diff --git a/changelogs/unreleased/38495-calendar-activities-in-timezone.yml b/changelogs/unreleased/38495-calendar-activities-in-timezone.yml
deleted file mode 100644
index 778d637609c..00000000000
--- a/changelogs/unreleased/38495-calendar-activities-in-timezone.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Show user contributions in correct timezone within user profile
-merge_request: 23419
-author:
-type: changed
diff --git a/changelogs/unreleased/39849_controller_sorts.yml b/changelogs/unreleased/39849_controller_sorts.yml
deleted file mode 100644
index 5fad0cb4ede..00000000000
--- a/changelogs/unreleased/39849_controller_sorts.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Allow sorting issues and MRs in reverse order
-merge_request: 21438
-author:
-type: changed
diff --git a/changelogs/unreleased/40085-add-a-create_merge_request-quick-action.yml b/changelogs/unreleased/40085-add-a-create_merge_request-quick-action.yml
deleted file mode 100644
index e1614ac7669..00000000000
--- a/changelogs/unreleased/40085-add-a-create_merge_request-quick-action.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Creates /create_merge_request quickaction
-merge_request: 22485
-author: Jacopo Beschi @jacopo-beschi
-type: added
diff --git a/changelogs/unreleased/40260-reduce-gitaly-calls-project-pipeline-status.yml b/changelogs/unreleased/40260-reduce-gitaly-calls-project-pipeline-status.yml
deleted file mode 100644
index 8ab104e95f5..00000000000
--- a/changelogs/unreleased/40260-reduce-gitaly-calls-project-pipeline-status.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Reduce Gitaly calls in projects dashboard
-merge_request: 23307
-author:
-type: performance
diff --git a/changelogs/unreleased/40270-remove-gitlab-upgrader-completely.yml b/changelogs/unreleased/40270-remove-gitlab-upgrader-completely.yml
new file mode 100644
index 00000000000..9ea2157bfb7
--- /dev/null
+++ b/changelogs/unreleased/40270-remove-gitlab-upgrader-completely.yml
@@ -0,0 +1,5 @@
+---
+title: Removes all instances of deprecated Gitlab Upgrader calls
+merge_request: 23603
+author: '@jwolen'
+type: removed
diff --git a/changelogs/unreleased/40385-prohibit_impersonation.yml b/changelogs/unreleased/40385-prohibit_impersonation.yml
deleted file mode 100644
index dd061b17939..00000000000
--- a/changelogs/unreleased/40385-prohibit_impersonation.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Add config to prohibit impersonation
-merge_request: 23338
-author:
-type: added
diff --git a/changelogs/unreleased/41875-allow-pipelines-to-be-deleted-by-project-owners.yml b/changelogs/unreleased/41875-allow-pipelines-to-be-deleted-by-project-owners.yml
deleted file mode 100644
index 0662ff6f523..00000000000
--- a/changelogs/unreleased/41875-allow-pipelines-to-be-deleted-by-project-owners.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Allow deleting a Pipeline via the API.
-merge_request: 22988
-author:
-type: added
diff --git a/changelogs/unreleased/42125-extend-override-check-to-also-check-arity.yml b/changelogs/unreleased/42125-extend-override-check-to-also-check-arity.yml
new file mode 100644
index 00000000000..9892466ca50
--- /dev/null
+++ b/changelogs/unreleased/42125-extend-override-check-to-also-check-arity.yml
@@ -0,0 +1,5 @@
+---
+title: Extend override check to also check arity
+merge_request: 23498
+author: Jacopo Beschi @jacopo-beschi
+type: added
diff --git a/changelogs/unreleased/44984-use-serializer-for-issuable-sidebar.yml b/changelogs/unreleased/44984-use-serializer-for-issuable-sidebar.yml
new file mode 100644
index 00000000000..ba9edc8740d
--- /dev/null
+++ b/changelogs/unreleased/44984-use-serializer-for-issuable-sidebar.yml
@@ -0,0 +1,5 @@
+---
+title: Refactor issuable sidebar to use serializer
+merge_request: 23379
+author:
+type: other
diff --git a/changelogs/unreleased/46544-webide-ctrl-enter-commit-shortcut.yml b/changelogs/unreleased/46544-webide-ctrl-enter-commit-shortcut.yml
deleted file mode 100644
index 334c9b3ec9e..00000000000
--- a/changelogs/unreleased/46544-webide-ctrl-enter-commit-shortcut.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: "WebIDE: Pressing Ctrl-Enter while typing on the commit message now performs the commit action"
-merge_request: 23049
-author: Thomas Pathier
-type: added
diff --git a/changelogs/unreleased/46950-systemcheck-ruby-version.yml b/changelogs/unreleased/46950-systemcheck-ruby-version.yml
deleted file mode 100644
index e556e14223b..00000000000
--- a/changelogs/unreleased/46950-systemcheck-ruby-version.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: 'SystemCheck: Use a more reliable way to detect current Ruby version'
-merge_request: 23291
-author:
-type: changed
diff --git a/changelogs/unreleased/48475-gitlab-pages-settings-regressions.yml b/changelogs/unreleased/48475-gitlab-pages-settings-regressions.yml
deleted file mode 100644
index f543730a57d..00000000000
--- a/changelogs/unreleased/48475-gitlab-pages-settings-regressions.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fixing regression issues on pages settings and details
-merge_request: 22821
-author:
-type: fixed
diff --git a/changelogs/unreleased/48496-merge-request-refactor-does-not-highlight-selected-line.yml b/changelogs/unreleased/48496-merge-request-refactor-does-not-highlight-selected-line.yml
deleted file mode 100644
index cfc74bef638..00000000000
--- a/changelogs/unreleased/48496-merge-request-refactor-does-not-highlight-selected-line.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: When user clicks linenumber in MR changes, highlight that line
-merge_request:
-author:
-type: fixed
diff --git a/changelogs/unreleased/48889-populate-merge_commit_sha.yml b/changelogs/unreleased/48889-populate-merge_commit_sha.yml
deleted file mode 100644
index 0e25d8ecfb0..00000000000
--- a/changelogs/unreleased/48889-populate-merge_commit_sha.yml
+++ /dev/null
@@ -1,6 +0,0 @@
----
-title: Fix "merged with [commit]" info for merge requests being merged automatically
- by other actions
-merge_request: 22794
-author:
-type: fixed
diff --git a/changelogs/unreleased/49479-hide-unmerged-env-perf-stats.yml b/changelogs/unreleased/49479-hide-unmerged-env-perf-stats.yml
deleted file mode 100644
index 5118949f8a3..00000000000
--- a/changelogs/unreleased/49479-hide-unmerged-env-perf-stats.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Don't show Memory Usage for unmerged MRs
-merge_request:
-author:
-type: changed
diff --git a/changelogs/unreleased/49565-ssh-push-mirroring.yml b/changelogs/unreleased/49565-ssh-push-mirroring.yml
deleted file mode 100644
index 2dfeffa4088..00000000000
--- a/changelogs/unreleased/49565-ssh-push-mirroring.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Allow SSH public-key authentication for push mirroring
-merge_request: 22982
-author:
-type: added
diff --git a/changelogs/unreleased/49713-main-navbar-is-broken-in-certain-viewport-widths.yml b/changelogs/unreleased/49713-main-navbar-is-broken-in-certain-viewport-widths.yml
deleted file mode 100644
index 0b5d1a6b05a..00000000000
--- a/changelogs/unreleased/49713-main-navbar-is-broken-in-certain-viewport-widths.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Resolve Main navbar is broken in certain viewport widths
-merge_request: 23348
-author:
-type: fixed
diff --git a/changelogs/unreleased/49726-upgrade-helm-to-2-11.yml b/changelogs/unreleased/49726-upgrade-helm-to-2-11.yml
deleted file mode 100644
index dd26af875f5..00000000000
--- a/changelogs/unreleased/49726-upgrade-helm-to-2-11.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Upgrade helm to 2.11.0 and upgrade on every install
-merge_request: 22693
-author:
-type: added
diff --git a/changelogs/unreleased/50157-extended-user-centric-tooltips.yml b/changelogs/unreleased/50157-extended-user-centric-tooltips.yml
deleted file mode 100644
index 3b55a867b87..00000000000
--- a/changelogs/unreleased/50157-extended-user-centric-tooltips.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Extended user centric tooltips on issue and MR page
-merge_request: 23231
-author:
-type: added
diff --git a/changelogs/unreleased/50264-add-border-around-the-repository-file-tree.yml b/changelogs/unreleased/50264-add-border-around-the-repository-file-tree.yml
deleted file mode 100644
index 6315c3e7f36..00000000000
--- a/changelogs/unreleased/50264-add-border-around-the-repository-file-tree.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Resolve Add border around the repository file tree
-merge_request: 23018
-author:
-type: changed
diff --git a/changelogs/unreleased/50341-cleanup-useless-project-import-attributes.yml b/changelogs/unreleased/50341-cleanup-useless-project-import-attributes.yml
deleted file mode 100644
index 3893f14e15c..00000000000
--- a/changelogs/unreleased/50341-cleanup-useless-project-import-attributes.yml
+++ /dev/null
@@ -1,6 +0,0 @@
----
-title: Removes all the irrelevant code and columns that were migrated from the Project
- table over to the ProjectImportState table
-merge_request: 21497
-author:
-type: performance
diff --git a/changelogs/unreleased/50626-searching-users-by-the-admin-panel-wipes-query-when-using-sort.yml b/changelogs/unreleased/50626-searching-users-by-the-admin-panel-wipes-query-when-using-sort.yml
deleted file mode 100644
index c3251fea54d..00000000000
--- a/changelogs/unreleased/50626-searching-users-by-the-admin-panel-wipes-query-when-using-sort.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Allow search and sort users at same time on admin users page
-merge_request: 23439
-author:
-type: fixed
diff --git a/changelogs/unreleased/50839-webide-mr-dropdown-filter.yml b/changelogs/unreleased/50839-webide-mr-dropdown-filter.yml
deleted file mode 100644
index 1c6c8747197..00000000000
--- a/changelogs/unreleased/50839-webide-mr-dropdown-filter.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Scope default MR search in WebIDE dropdown to current project
-merge_request: 23400
-author:
-type: changed
diff --git a/changelogs/unreleased/51029-status-emoji-currently-replaces-avatar-on-mobile.yml b/changelogs/unreleased/51029-status-emoji-currently-replaces-avatar-on-mobile.yml
deleted file mode 100644
index dc11ede5c8d..00000000000
--- a/changelogs/unreleased/51029-status-emoji-currently-replaces-avatar-on-mobile.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Resolve status emoji being replaced by avatar on mobile
-merge_request: 23408
-author:
-type: other
diff --git a/changelogs/unreleased/51061-readme-url-n-1-rpc-call-resolved.yml b/changelogs/unreleased/51061-readme-url-n-1-rpc-call-resolved.yml
deleted file mode 100644
index 86f91fcb427..00000000000
--- a/changelogs/unreleased/51061-readme-url-n-1-rpc-call-resolved.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Improves performance of Project#readme_url by caching the README path
-merge_request: 23357
-author:
-type: performance
diff --git a/changelogs/unreleased/51083-fix-move-api.yml b/changelogs/unreleased/51083-fix-move-api.yml
deleted file mode 100644
index 8838f6f267e..00000000000
--- a/changelogs/unreleased/51083-fix-move-api.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: 'Commits API: Preserve file content in move operations if unspecified'
-merge_request: 23387
-author:
-type: fixed
diff --git a/changelogs/unreleased/51101-can-add-an-existing-group-member-into-a-group-project-with-new-permissions-but-permissions-are-not-overridde.yml b/changelogs/unreleased/51101-can-add-an-existing-group-member-into-a-group-project-with-new-permissions-but-permissions-are-not-overridde.yml
deleted file mode 100644
index 96f33a72cc5..00000000000
--- a/changelogs/unreleased/51101-can-add-an-existing-group-member-into-a-group-project-with-new-permissions-but-permissions-are-not-overridde.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Restrict member access level to be higher than that of any parent group
-merge_request: 23226
-author:
-type: fixed
diff --git a/changelogs/unreleased/51122-fix-navigating-discussions.yml b/changelogs/unreleased/51122-fix-navigating-discussions.yml
deleted file mode 100644
index 94d76654589..00000000000
--- a/changelogs/unreleased/51122-fix-navigating-discussions.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fix navigating by unresolved discussions on Merge Request page
-merge_request: 22789
-author:
-type: fixed
diff --git a/changelogs/unreleased/51138-54026-breadcrumb-subgroups-ellipsis.yml b/changelogs/unreleased/51138-54026-breadcrumb-subgroups-ellipsis.yml
deleted file mode 100644
index f695d5aeff8..00000000000
--- a/changelogs/unreleased/51138-54026-breadcrumb-subgroups-ellipsis.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: "Make auto-generated icons for subgroups in the breadcrumb dropdown display as a circle"
-merge_request: 23062
-author: Thomas Pathier
-type: fix \ No newline at end of file
diff --git a/changelogs/unreleased/51243-further-improvements-to-project-overview-ui.yml b/changelogs/unreleased/51243-further-improvements-to-project-overview-ui.yml
deleted file mode 100644
index ddb5eaa89d0..00000000000
--- a/changelogs/unreleased/51243-further-improvements-to-project-overview-ui.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Design improvements to project overview page
-merge_request: 22196
-author:
-type: changed
diff --git a/changelogs/unreleased/51259-ci-cd-gitlab-ui-1.yml b/changelogs/unreleased/51259-ci-cd-gitlab-ui-1.yml
deleted file mode 100644
index 1d761d6299c..00000000000
--- a/changelogs/unreleased/51259-ci-cd-gitlab-ui-1.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Uses new gitlab-ui components in Jobs and Pipelines components
-merge_request:
-author:
-type: other
diff --git a/changelogs/unreleased/51259-ci-cd-tooltips.yml b/changelogs/unreleased/51259-ci-cd-tooltips.yml
deleted file mode 100644
index fc0010dbeba..00000000000
--- a/changelogs/unreleased/51259-ci-cd-tooltips.yml
+++ /dev/null
@@ -1,6 +0,0 @@
----
-title: Replaces tooltip directive with the new gl-tooltip directive for consistency
- in some ci/cd code
-merge_request:
-author:
-type: other
diff --git a/changelogs/unreleased/51668-fix-line-numbers.yml b/changelogs/unreleased/51668-fix-line-numbers.yml
new file mode 100644
index 00000000000..ac6e45e3cc7
--- /dev/null
+++ b/changelogs/unreleased/51668-fix-line-numbers.yml
@@ -0,0 +1,5 @@
+---
+title: Adjust line-height of blame view line numbers
+merge_request:
+author:
+type: fixed
diff --git a/changelogs/unreleased/51792-dont-delete-failed-install-pods.yml b/changelogs/unreleased/51792-dont-delete-failed-install-pods.yml
deleted file mode 100644
index 7a900cbb86e..00000000000
--- a/changelogs/unreleased/51792-dont-delete-failed-install-pods.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Don't remove failed install pods after installing GitLab managed applications
-merge_request: 23350
-author:
-type: changed
diff --git a/changelogs/unreleased/51959-branch-and-tag-name-links.yml b/changelogs/unreleased/51959-branch-and-tag-name-links.yml
deleted file mode 100644
index 64f1522c70d..00000000000
--- a/changelogs/unreleased/51959-branch-and-tag-name-links.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Chat message push notifications now include links back to GitLab branches
-merge_request: 22651
-author: Tony Castrogiovanni
-type: added
diff --git a/changelogs/unreleased/51970-correct-ordering-of-metrics.yml b/changelogs/unreleased/51970-correct-ordering-of-metrics.yml
new file mode 100644
index 00000000000..fbc7b58d901
--- /dev/null
+++ b/changelogs/unreleased/51970-correct-ordering-of-metrics.yml
@@ -0,0 +1,5 @@
+---
+title: Correct the ordering of metrics on the performance dashboard
+merge_request: 23630
+author:
+type: fixed
diff --git a/changelogs/unreleased/52007-frontmatter-toml-json.yml b/changelogs/unreleased/52007-frontmatter-toml-json.yml
deleted file mode 100644
index bdada19f3a7..00000000000
--- a/changelogs/unreleased/52007-frontmatter-toml-json.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Changed frontmatter filtering to support YAML, JSON, TOML, and arbitrary languages
-merge_request: 23331
-author: Travis Miller
-type: changed
diff --git a/changelogs/unreleased/52276-jump-to-top-in-merge-request.yml b/changelogs/unreleased/52276-jump-to-top-in-merge-request.yml
deleted file mode 100644
index 3dc95441eec..00000000000
--- a/changelogs/unreleased/52276-jump-to-top-in-merge-request.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Allow user to scroll to top of tab on MR page
-merge_request:
-author:
-type: added
diff --git a/changelogs/unreleased/52285-omniauth-jwt-ppk-support.yml b/changelogs/unreleased/52285-omniauth-jwt-ppk-support.yml
deleted file mode 100644
index 3ef564238c5..00000000000
--- a/changelogs/unreleased/52285-omniauth-jwt-ppk-support.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Support RSA and ECDSA algorithms in Omniauth JWT provider
-merge_request: 23411
-author: Michael Tsyganov
-type: fixed
diff --git a/changelogs/unreleased/52370-filter-by-none-any-for-labels-in-issues-mrs-boards.yml b/changelogs/unreleased/52370-filter-by-none-any-for-labels-in-issues-mrs-boards.yml
deleted file mode 100644
index 9e1ee3ede5e..00000000000
--- a/changelogs/unreleased/52370-filter-by-none-any-for-labels-in-issues-mrs-boards.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Adds Any option to label filters
-merge_request: 23111
-author: Jacopo Beschi @jacopo-beschi
-type: added
diff --git a/changelogs/unreleased/52371-filter-by-none-any-for-labels-in-issues-mrs-api.yml b/changelogs/unreleased/52371-filter-by-none-any-for-labels-in-issues-mrs-api.yml
deleted file mode 100644
index bb196af3e90..00000000000
--- a/changelogs/unreleased/52371-filter-by-none-any-for-labels-in-issues-mrs-api.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Filter by None/Any for labels in issues/mrs API
-merge_request: 22622
-author: Jacopo Beschi @jacopo-beschi
-type: added
diff --git a/changelogs/unreleased/52371-removes-patially-matching-no-label-and-makes-it-case-insensitive.yml b/changelogs/unreleased/52371-removes-patially-matching-no-label-and-makes-it-case-insensitive.yml
deleted file mode 100644
index c1fc21c641a..00000000000
--- a/changelogs/unreleased/52371-removes-patially-matching-no-label-and-makes-it-case-insensitive.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: removes partially matching of No Label filter and makes it case-insensitive
-merge_request: 22622
-author: Jacopo Beschi @jacopo-beschi
-type: changed
diff --git a/changelogs/unreleased/52385-search-bar-for-dashboard-list.yml b/changelogs/unreleased/52385-search-bar-for-dashboard-list.yml
deleted file mode 100644
index a437ae560cb..00000000000
--- a/changelogs/unreleased/52385-search-bar-for-dashboard-list.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Use search bar for filtering in dashboard issues / MRs
-merge_request: 22641
-author: Heinrich Lee Yu
-type: changed
diff --git a/changelogs/unreleased/52453-show-subgroups-in-group-create-issue.yml b/changelogs/unreleased/52453-show-subgroups-in-group-create-issue.yml
deleted file mode 100644
index d5877e96d07..00000000000
--- a/changelogs/unreleased/52453-show-subgroups-in-group-create-issue.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fix project selector consistency in groups issues / MRs / boards pages
-merge_request: 22612
-author: Heinrich Lee Yu
-type: fixed
diff --git a/changelogs/unreleased/52620-fix-loader-animation-alignment.yml b/changelogs/unreleased/52620-fix-loader-animation-alignment.yml
new file mode 100644
index 00000000000..5cfb7fc019f
--- /dev/null
+++ b/changelogs/unreleased/52620-fix-loader-animation-alignment.yml
@@ -0,0 +1,5 @@
+---
+title: Aligns build loader animation with the job log
+merge_request: 23959
+author:
+type: fixed
diff --git a/changelogs/unreleased/52712-further-ui-improvements-to-profile-overview-tab.yml b/changelogs/unreleased/52712-further-ui-improvements-to-profile-overview-tab.yml
deleted file mode 100644
index 65aa9323d2e..00000000000
--- a/changelogs/unreleased/52712-further-ui-improvements-to-profile-overview-tab.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: UI improvements to user's profile
-merge_request: 22977
-author:
-type: other
diff --git a/changelogs/unreleased/52774-fix-svgs-in-ie-11.yml b/changelogs/unreleased/52774-fix-svgs-in-ie-11.yml
deleted file mode 100644
index 656a915a281..00000000000
--- a/changelogs/unreleased/52774-fix-svgs-in-ie-11.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Ensure that SVG sprite icons are properly rendered in IE11
-merge_request:
-author:
-type: fixed
diff --git a/changelogs/unreleased/52828-inconsistency-in-fonts-used-for-branch-name-and-create-from-fields-when-creating-new-branch-from-ui.yml b/changelogs/unreleased/52828-inconsistency-in-fonts-used-for-branch-name-and-create-from-fields-when-creating-new-branch-from-ui.yml
deleted file mode 100644
index 8132dde8636..00000000000
--- a/changelogs/unreleased/52828-inconsistency-in-fonts-used-for-branch-name-and-create-from-fields-when-creating-new-branch-from-ui.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Make new branch form fields' fonts consistent
-merge_request:
-author:
-type: fixed
diff --git a/changelogs/unreleased/52888-status-emoji-should-not-be-added-to-awards-section-on-issue-page-2.yml b/changelogs/unreleased/52888-status-emoji-should-not-be-added-to-awards-section-on-issue-page-2.yml
new file mode 100644
index 00000000000..501940d6da3
--- /dev/null
+++ b/changelogs/unreleased/52888-status-emoji-should-not-be-added-to-awards-section-on-issue-page-2.yml
@@ -0,0 +1,5 @@
+---
+title: Prevent awards emoji being updated when updating status
+merge_request: 23470
+author:
+type: fixed
diff --git a/changelogs/unreleased/52940-fix-internal-email-pattern-not-respected.yml b/changelogs/unreleased/52940-fix-internal-email-pattern-not-respected.yml
deleted file mode 100644
index 98e15a5cc0a..00000000000
--- a/changelogs/unreleased/52940-fix-internal-email-pattern-not-respected.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fix a bug where internal email pattern wasn't respected
-merge_request: 22516
-author:
-type: fixed
diff --git a/changelogs/unreleased/53289-update-haml_lint-to-0-28-0.yml b/changelogs/unreleased/53289-update-haml_lint-to-0-28-0.yml
deleted file mode 100644
index 9a16666c416..00000000000
--- a/changelogs/unreleased/53289-update-haml_lint-to-0-28-0.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Update haml_lint to 0.28.0
-merge_request: 22660
-author: Takuya Noguchi
-type: other
diff --git a/changelogs/unreleased/53290-incorrect-project-list-order-select-default-label.yml b/changelogs/unreleased/53290-incorrect-project-list-order-select-default-label.yml
deleted file mode 100644
index d076352a27b..00000000000
--- a/changelogs/unreleased/53290-incorrect-project-list-order-select-default-label.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fix default sorting for subgroups and projects list
-merge_request: 23058
-author: Jacopo Beschi @jacopo-beschi
-type: fixed
diff --git a/changelogs/unreleased/53291-update-ffaker-to-2-10-0.yml b/changelogs/unreleased/53291-update-ffaker-to-2-10-0.yml
deleted file mode 100644
index a1b95df5e32..00000000000
--- a/changelogs/unreleased/53291-update-ffaker-to-2-10-0.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Update ffaker to 2.10.0
-merge_request: 22661
-author: Takuya Noguchi
-type: other
diff --git a/changelogs/unreleased/53326-improve-issues-empty-state.yml b/changelogs/unreleased/53326-improve-issues-empty-state.yml
deleted file mode 100644
index 7632db808b5..00000000000
--- a/changelogs/unreleased/53326-improve-issues-empty-state.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Show different empty state for filtered issues and MRs
-merge_request: 22775
-author: Heinrich Lee Yu
-type: changed
diff --git a/changelogs/unreleased/53400-unstar-icon-button-is-misaligned.yml b/changelogs/unreleased/53400-unstar-icon-button-is-misaligned.yml
deleted file mode 100644
index b393795f491..00000000000
--- a/changelogs/unreleased/53400-unstar-icon-button-is-misaligned.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: 'Fix: Unstar icon button is misaligned'
-merge_request: 23444
-author:
-type: fixed
diff --git a/changelogs/unreleased/53578-fe-deployment-status.yml b/changelogs/unreleased/53578-fe-deployment-status.yml
deleted file mode 100644
index b88bd70ee2e..00000000000
--- a/changelogs/unreleased/53578-fe-deployment-status.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Adds states to the deployment widget
-merge_request:
-author:
-type: added
diff --git a/changelogs/unreleased/53626-update-config-map-on-install-retry.yml b/changelogs/unreleased/53626-update-config-map-on-install-retry.yml
deleted file mode 100644
index 38e79c06c89..00000000000
--- a/changelogs/unreleased/53626-update-config-map-on-install-retry.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Update config map for gitlab managed application if already present on install
-merge_request: 22969
-author:
-type: other
diff --git a/changelogs/unreleased/53640-follow-up-from-resolve-redesign-activity-feed.yml b/changelogs/unreleased/53640-follow-up-from-resolve-redesign-activity-feed.yml
deleted file mode 100644
index 66301329c52..00000000000
--- a/changelogs/unreleased/53640-follow-up-from-resolve-redesign-activity-feed.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-title: Adds new icon size to Vue icon component
-merge_request: 22899
-author:
-type: other
diff --git a/changelogs/unreleased/53659-use-padded-key-for-gcm-ciphers.yml b/changelogs/unreleased/53659-use-padded-key-for-gcm-ciphers.yml
deleted file mode 100644
index fe9ac7b3dc7..00000000000
--- a/changelogs/unreleased/53659-use-padded-key-for-gcm-ciphers.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fix web hook functionality when the database encryption key is too short
-merge_request: 23573
-author:
-type: fixed
diff --git a/changelogs/unreleased/53700-hashed-storagemigration.yml b/changelogs/unreleased/53700-hashed-storagemigration.yml
deleted file mode 100644
index 899012ffd22..00000000000
--- a/changelogs/unreleased/53700-hashed-storagemigration.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: 'Hashed Storage: allow migration to be retried in partially migrated projects'
-merge_request: 23087
-author:
-type: fixed
diff --git a/changelogs/unreleased/53728-warn-in-web-editor-when-user-navigates-away.yml b/changelogs/unreleased/53728-warn-in-web-editor-when-user-navigates-away.yml
deleted file mode 100644
index 8377fdc6133..00000000000
--- a/changelogs/unreleased/53728-warn-in-web-editor-when-user-navigates-away.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Prevent user from navigating away from file edit without commit
-merge_request:
-author:
-type: fixed
diff --git a/changelogs/unreleased/53816-empty-label-menu-if-not-logged-in.yml b/changelogs/unreleased/53816-empty-label-menu-if-not-logged-in.yml
deleted file mode 100644
index a9ca56303eb..00000000000
--- a/changelogs/unreleased/53816-empty-label-menu-if-not-logged-in.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Removes promote to group label for anonymous user
-merge_request: 23042
-author: Jacopo Beschi @jacopo-beschi
-type: fixed
diff --git a/changelogs/unreleased/53874-navbar-lowres.yml b/changelogs/unreleased/53874-navbar-lowres.yml
deleted file mode 100644
index 3b31b8f93fe..00000000000
--- a/changelogs/unreleased/53874-navbar-lowres.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: "Fix overlapping navbar separator and overflowing navbar dropdown on small displays"
-merge_request: 23126
-author: Thomas Pathier
-type: fix
diff --git a/changelogs/unreleased/53907-improve-milestone-links.yml b/changelogs/unreleased/53907-improve-milestone-links.yml
new file mode 100644
index 00000000000..8e867e783cc
--- /dev/null
+++ b/changelogs/unreleased/53907-improve-milestone-links.yml
@@ -0,0 +1,5 @@
+---
+title: Add % prefix to milestone reference links
+merge_request: 23928
+author:
+type: changed
diff --git a/changelogs/unreleased/53933-include-dates-in-milestone-change-email.yml b/changelogs/unreleased/53933-include-dates-in-milestone-change-email.yml
new file mode 100644
index 00000000000..5c40a1e900c
--- /dev/null
+++ b/changelogs/unreleased/53933-include-dates-in-milestone-change-email.yml
@@ -0,0 +1,5 @@
+---
+title: Add date range in milestone change email notifications
+merge_request: 23762
+author:
+type: changed
diff --git a/changelogs/unreleased/53988-remove-notes-index-on-updated-at.yml b/changelogs/unreleased/53988-remove-notes-index-on-updated-at.yml
deleted file mode 100644
index f0bbf69736d..00000000000
--- a/changelogs/unreleased/53988-remove-notes-index-on-updated-at.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Remove index for notes on updated_at
-merge_request: 23356
-author:
-type: performance
diff --git a/changelogs/unreleased/53992-add-events-index-on-project-id-and-created-at.yml b/changelogs/unreleased/53992-add-events-index-on-project-id-and-created-at.yml
deleted file mode 100644
index a2a3fa00f01..00000000000
--- a/changelogs/unreleased/53992-add-events-index-on-project-id-and-created-at.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Add index for events on project_id and created_at
-merge_request: 23354
-author:
-type: performance
diff --git a/changelogs/unreleased/53994-add-missing-ci_builds-partial-indices.yml b/changelogs/unreleased/53994-add-missing-ci_builds-partial-indices.yml
deleted file mode 100644
index 4673ba38bae..00000000000
--- a/changelogs/unreleased/53994-add-missing-ci_builds-partial-indices.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Add partial index for ci_builds on project_id and status
-merge_request: 23268
-author:
-type: performance
diff --git a/changelogs/unreleased/54004-update-asana-to-0-8-1.yml b/changelogs/unreleased/54004-update-asana-to-0-8-1.yml
deleted file mode 100644
index a47b4f3c4d9..00000000000
--- a/changelogs/unreleased/54004-update-asana-to-0-8-1.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Update asana to 0.8.1
-merge_request: 23039
-author: Takuya Noguchi
-type: other
diff --git a/changelogs/unreleased/54010-update-asciidoctor-to-1-5-8.yml b/changelogs/unreleased/54010-update-asciidoctor-to-1-5-8.yml
deleted file mode 100644
index f0b0aa0ee1c..00000000000
--- a/changelogs/unreleased/54010-update-asciidoctor-to-1-5-8.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Update asciidoctor to 1.5.8
-merge_request: 23047
-author: Takuya Noguchi
-type: other
diff --git a/changelogs/unreleased/54015-Markdown-Editor-improve-Cursor-placement.yml b/changelogs/unreleased/54015-Markdown-Editor-improve-Cursor-placement.yml
deleted file mode 100644
index 28e3fae01a9..00000000000
--- a/changelogs/unreleased/54015-Markdown-Editor-improve-Cursor-placement.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Refine cursor positioning in Markdown Editor for wrap tags
-merge_request: 23085
-author: Johann Hubert Sonntagbauer
-type: changed
diff --git a/changelogs/unreleased/54021-empty-button.yml b/changelogs/unreleased/54021-empty-button.yml
deleted file mode 100644
index 3b03665cf95..00000000000
--- a/changelogs/unreleased/54021-empty-button.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Prevent empty button being rendered in empty state
-merge_request:
-author:
-type: fixed
diff --git a/changelogs/unreleased/54032-reply-shortcut-only-discussion-text.yml b/changelogs/unreleased/54032-reply-shortcut-only-discussion-text.yml
deleted file mode 100644
index 5c1f6e74b39..00000000000
--- a/changelogs/unreleased/54032-reply-shortcut-only-discussion-text.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Make reply shortcut only quote selected discussion text
-merge_request: 23096
-author: Thomas Pathier
-type: fix
diff --git a/changelogs/unreleased/54048-Line-numbers-are-misaligned-in-file-blame-view.yml b/changelogs/unreleased/54048-Line-numbers-are-misaligned-in-file-blame-view.yml
deleted file mode 100644
index 8ceac4ec869..00000000000
--- a/changelogs/unreleased/54048-Line-numbers-are-misaligned-in-file-blame-view.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fix line height of numbers in file blame view
-merge_request: 23090
-author: Johann Hubert Sonntagbauer
-type: fixed
diff --git a/changelogs/unreleased/54093-the-default_value_for-gem-doesn-t-handle-actioncontroller-parameters-correctly.yml b/changelogs/unreleased/54093-the-default_value_for-gem-doesn-t-handle-actioncontroller-parameters-correctly.yml
deleted file mode 100644
index 3d6fd2d065a..00000000000
--- a/changelogs/unreleased/54093-the-default_value_for-gem-doesn-t-handle-actioncontroller-parameters-correctly.yml
+++ /dev/null
@@ -1,7 +0,0 @@
----
-title: Fixes an issue where default values from models would override values set in
- the interface (e.g. users would be set to external even though their emails matches
- the internal email address pattern)
-merge_request: 23114
-author:
-type: fixed
diff --git a/changelogs/unreleased/54160-use-reports-syntax-for-sast-in-auto-devops.yml b/changelogs/unreleased/54160-use-reports-syntax-for-sast-in-auto-devops.yml
deleted file mode 100644
index 86c5a0c5a95..00000000000
--- a/changelogs/unreleased/54160-use-reports-syntax-for-sast-in-auto-devops.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Use reports syntax for SAST in Auto DevOps
-merge_request: 23163
-author:
-type: changed
diff --git a/changelogs/unreleased/54201-update-rack-to-2-0-6.yml b/changelogs/unreleased/54201-update-rack-to-2-0-6.yml
deleted file mode 100644
index 020b2bc0957..00000000000
--- a/changelogs/unreleased/54201-update-rack-to-2-0-6.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Update rack to 2.0.6 (for QA environments)
-merge_request: 23171
-author: Takuya Noguchi
-type: security
diff --git a/changelogs/unreleased/54206-show-the-activity-filter-dropdown-in-discussion-tab-only.yml b/changelogs/unreleased/54206-show-the-activity-filter-dropdown-in-discussion-tab-only.yml
new file mode 100644
index 00000000000..e29987b0935
--- /dev/null
+++ b/changelogs/unreleased/54206-show-the-activity-filter-dropdown-in-discussion-tab-only.yml
@@ -0,0 +1,5 @@
+---
+title: Discussion filter only displayed in discussions tab for merge requests
+merge_request: 24082
+author:
+type: changed
diff --git a/changelogs/unreleased/54218-fix-mergeUrlParams.yml b/changelogs/unreleased/54218-fix-mergeUrlParams.yml
deleted file mode 100644
index dae06b66e8e..00000000000
--- a/changelogs/unreleased/54218-fix-mergeUrlParams.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: "Fix mergeUrlParams with fragment URL"
-merge_request: 54218
-author: Thomas Holder
-type: fixed
diff --git a/changelogs/unreleased/54336-include-tags-into-pipeline-detail-view.yml b/changelogs/unreleased/54336-include-tags-into-pipeline-detail-view.yml
deleted file mode 100644
index 11f941ab9bb..00000000000
--- a/changelogs/unreleased/54336-include-tags-into-pipeline-detail-view.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Merge request pipeline tag, and adds tags to pipeline view
-merge_request: 23364
-author:
-type: added
diff --git a/changelogs/unreleased/54391-tag.yml b/changelogs/unreleased/54391-tag.yml
deleted file mode 100644
index be571c6b0c3..00000000000
--- a/changelogs/unreleased/54391-tag.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Correctly styles tags in sidebar for job page
-merge_request:
-author:
-type: fixed
diff --git a/changelogs/unreleased/54407-fix-limited-intersection-observers.yml b/changelogs/unreleased/54407-fix-limited-intersection-observers.yml
deleted file mode 100644
index 2c2bedb170b..00000000000
--- a/changelogs/unreleased/54407-fix-limited-intersection-observers.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fix Image Lazy Loader for some older browsers
-merge_request:
-author:
-type: fixed
diff --git a/changelogs/unreleased/54427-label-xss.yml b/changelogs/unreleased/54427-label-xss.yml
new file mode 100644
index 00000000000..090d1832af2
--- /dev/null
+++ b/changelogs/unreleased/54427-label-xss.yml
@@ -0,0 +1,5 @@
+---
+title: Escape html entities in LabelReferenceFilter when no label found
+merge_request:
+author:
+type: security
diff --git a/changelogs/unreleased/54571-runner-tags.yml b/changelogs/unreleased/54571-runner-tags.yml
deleted file mode 100644
index 1bb19d22e9c..00000000000
--- a/changelogs/unreleased/54571-runner-tags.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Adds margins between tags when a job is stuck
-merge_request:
-author:
-type: fixed
diff --git a/changelogs/unreleased/54626-able-to-download-a-single-archive-file-with-api-by-ref-name.yml b/changelogs/unreleased/54626-able-to-download-a-single-archive-file-with-api-by-ref-name.yml
deleted file mode 100644
index fa905b47ca2..00000000000
--- a/changelogs/unreleased/54626-able-to-download-a-single-archive-file-with-api-by-ref-name.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Add new endpoint to download single artifact file for a ref
-merge_request: 23538
-author:
-type: added
diff --git a/changelogs/unreleased/54648-fix-order-by-dropdown-tablet-screens.yml b/changelogs/unreleased/54648-fix-order-by-dropdown-tablet-screens.yml
deleted file mode 100644
index 671d1590991..00000000000
--- a/changelogs/unreleased/54648-fix-order-by-dropdown-tablet-screens.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fix Order By dropdown menu styling in tablet and mobile screens
-merge_request: 23446
-author:
-type: fixed
diff --git a/changelogs/unreleased/54826-use-read_repository-scope-on-read-only-files-endpoints.yml b/changelogs/unreleased/54826-use-read_repository-scope-on-read-only-files-endpoints.yml
deleted file mode 100644
index ef8e93fca43..00000000000
--- a/changelogs/unreleased/54826-use-read_repository-scope-on-read-only-files-endpoints.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Use read_repository scope on read-only files API
-merge_request: 23534
-author:
-type: fixed
diff --git a/changelogs/unreleased/54857-fix-templates-path-traversal.yml b/changelogs/unreleased/54857-fix-templates-path-traversal.yml
deleted file mode 100644
index 0da02432c60..00000000000
--- a/changelogs/unreleased/54857-fix-templates-path-traversal.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Prevent a path traversal attack on global file templates
-merge_request:
-author:
-type: security
diff --git a/changelogs/unreleased/54953-error-500-viewing-merge-request-due-to-nil-commit_email_hostname.yml b/changelogs/unreleased/54953-error-500-viewing-merge-request-due-to-nil-commit_email_hostname.yml
new file mode 100644
index 00000000000..8fd127acf2b
--- /dev/null
+++ b/changelogs/unreleased/54953-error-500-viewing-merge-request-due-to-nil-commit_email_hostname.yml
@@ -0,0 +1,5 @@
+---
+title: Return an ApplicationSetting in CurrentSettings
+merge_request: 23766
+author:
+type: fixed
diff --git a/changelogs/unreleased/54975-fix-web-hooks-rake-task.yml b/changelogs/unreleased/54975-fix-web-hooks-rake-task.yml
deleted file mode 100644
index 107a93e5b12..00000000000
--- a/changelogs/unreleased/54975-fix-web-hooks-rake-task.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fix gitlab:web_hook tasks
-merge_request: 23635
-author:
-type: fixed
diff --git a/changelogs/unreleased/55104-frozenerror-can-t-modify-frozen-string.yml b/changelogs/unreleased/55104-frozenerror-can-t-modify-frozen-string.yml
deleted file mode 100644
index 994859b1d1d..00000000000
--- a/changelogs/unreleased/55104-frozenerror-can-t-modify-frozen-string.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fix a frozen string error in app/mailers/notify.rb
-merge_request: 23683
-author:
-type: fixed
diff --git a/changelogs/unreleased/55116-runtimeerror-can-t-modify-frozen-string.yml b/changelogs/unreleased/55116-runtimeerror-can-t-modify-frozen-string.yml
deleted file mode 100644
index a98e70465b2..00000000000
--- a/changelogs/unreleased/55116-runtimeerror-can-t-modify-frozen-string.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fix a frozen string error in lib/gitlab/utils.rb
-merge_request: 23690
-author:
-type: fixed
diff --git a/changelogs/unreleased/55138-fix-mr-discussions-count.yml b/changelogs/unreleased/55138-fix-mr-discussions-count.yml
deleted file mode 100644
index 667e9b971d8..00000000000
--- a/changelogs/unreleased/55138-fix-mr-discussions-count.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fix MR resolved discussion counts being too low
-merge_request: 23710
-author:
-type: fixed
diff --git a/changelogs/unreleased/55183-frozenerror-can-t-modify-frozen-string-in-app-mailers-notify-rb.yml b/changelogs/unreleased/55183-frozenerror-can-t-modify-frozen-string-in-app-mailers-notify-rb.yml
deleted file mode 100644
index 685a8309c72..00000000000
--- a/changelogs/unreleased/55183-frozenerror-can-t-modify-frozen-string-in-app-mailers-notify-rb.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fix a potential frozen string error in app/mailers/notify.rb
-merge_request: 23728
-author:
-type: fixed
diff --git a/changelogs/unreleased/55266-fix-incorrect-due-date-parsing.yml b/changelogs/unreleased/55266-fix-incorrect-due-date-parsing.yml
new file mode 100644
index 00000000000..62a57085192
--- /dev/null
+++ b/changelogs/unreleased/55266-fix-incorrect-due-date-parsing.yml
@@ -0,0 +1,5 @@
+---
+title: Use 'parsePikadayDate' to parse due date string
+merge_request: 24045
+author:
+type: fixed
diff --git a/changelogs/unreleased/55293-split-bio-into-individual-line-in-extended-user-tooltips.yml b/changelogs/unreleased/55293-split-bio-into-individual-line-in-extended-user-tooltips.yml
new file mode 100644
index 00000000000..c6ff52b0fa1
--- /dev/null
+++ b/changelogs/unreleased/55293-split-bio-into-individual-line-in-extended-user-tooltips.yml
@@ -0,0 +1,5 @@
+---
+title: Split bio into individual line in extended user tooltips
+merge_request: 23940
+author:
+type: other
diff --git a/changelogs/unreleased/55369-update-milestone-sort-to-say-say-milestone-due-date.yml b/changelogs/unreleased/55369-update-milestone-sort-to-say-say-milestone-due-date.yml
new file mode 100644
index 00000000000..7476b9caa93
--- /dev/null
+++ b/changelogs/unreleased/55369-update-milestone-sort-to-say-say-milestone-due-date.yml
@@ -0,0 +1,5 @@
+---
+title: Renames Milestone sort into Milestone due date
+merge_request: 24080
+author: Jacopo Beschi @jacopo-beschi
+type: changed
diff --git a/changelogs/unreleased/55402-broken-master-karma-test-failing-in-spec-javascripts-boards-components-issue_due_date_spec-js.yml b/changelogs/unreleased/55402-broken-master-karma-test-failing-in-spec-javascripts-boards-components-issue_due_date_spec-js.yml
deleted file mode 100644
index d2ff095ce55..00000000000
--- a/changelogs/unreleased/55402-broken-master-karma-test-failing-in-spec-javascripts-boards-components-issue_due_date_spec-js.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fix due date test
-merge_request: 23845
-author:
-type: other
diff --git a/changelogs/unreleased/55484-fix-edit-button.yml b/changelogs/unreleased/55484-fix-edit-button.yml
new file mode 100644
index 00000000000..c8998cba248
--- /dev/null
+++ b/changelogs/unreleased/55484-fix-edit-button.yml
@@ -0,0 +1,4 @@
+title: Fix edit button disappearing in issue title
+merge_request: 23948
+author: Ruben Moya
+type: fixed
diff --git a/changelogs/unreleased/55669-redesign-project-lists-ui-further-improvements.yml b/changelogs/unreleased/55669-redesign-project-lists-ui-further-improvements.yml
new file mode 100644
index 00000000000..a51a08c892a
--- /dev/null
+++ b/changelogs/unreleased/55669-redesign-project-lists-ui-further-improvements.yml
@@ -0,0 +1,5 @@
+---
+title: UI improvements for redesigned project lists
+merge_request: 24011
+author:
+type: other
diff --git a/changelogs/unreleased/55716-update-cert-manager-chart-from-v0-5-0-to-v0-5-2.yml b/changelogs/unreleased/55716-update-cert-manager-chart-from-v0-5-0-to-v0-5-2.yml
new file mode 100644
index 00000000000..a25ace9d76d
--- /dev/null
+++ b/changelogs/unreleased/55716-update-cert-manager-chart-from-v0-5-0-to-v0-5-2.yml
@@ -0,0 +1,5 @@
+---
+title: Update cert-manager chart from v0.5.0 to v0.5.2
+merge_request: 24025
+author: Takuya Noguchi
+type: other
diff --git a/changelogs/unreleased/55755-user-activity-is-stuck-loading-when-there-is-none.yml b/changelogs/unreleased/55755-user-activity-is-stuck-loading-when-there-is-none.yml
new file mode 100644
index 00000000000..5362a781281
--- /dev/null
+++ b/changelogs/unreleased/55755-user-activity-is-stuck-loading-when-there-is-none.yml
@@ -0,0 +1,5 @@
+---
+title: Hide spinner on empty activites list on user profile overview
+merge_request: 24063
+author:
+type: other
diff --git a/changelogs/unreleased/55838-remove-gem-install-bundler-from-docker-based-ruby-environments.yml b/changelogs/unreleased/55838-remove-gem-install-bundler-from-docker-based-ruby-environments.yml
new file mode 100644
index 00000000000..08f60d205df
--- /dev/null
+++ b/changelogs/unreleased/55838-remove-gem-install-bundler-from-docker-based-ruby-environments.yml
@@ -0,0 +1,5 @@
+---
+title: Remove gem install bundler from Docker-based Ruby environments
+merge_request: 24093
+author: Takuya Noguchi
+type: other
diff --git a/changelogs/unreleased/_acet-fix-flash-styling.yml b/changelogs/unreleased/_acet-fix-flash-styling.yml
deleted file mode 100644
index 57354c04899..00000000000
--- a/changelogs/unreleased/_acet-fix-flash-styling.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fix flash notice styling for fluid layout
-merge_request: 23382
-author:
-type: fixed
diff --git a/changelogs/unreleased/ab-approximate-counts.yml b/changelogs/unreleased/ab-approximate-counts.yml
deleted file mode 100644
index 8a67239d031..00000000000
--- a/changelogs/unreleased/ab-approximate-counts.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Approximate counting strategy with TABLESAMPLE.
-merge_request: 22650
-author:
-type: performance
diff --git a/changelogs/unreleased/ac-releases-api.yml b/changelogs/unreleased/ac-releases-api.yml
new file mode 100644
index 00000000000..87217cce371
--- /dev/null
+++ b/changelogs/unreleased/ac-releases-api.yml
@@ -0,0 +1,5 @@
+---
+title: Releases API
+merge_request: 23795
+author:
+type: added
diff --git a/changelogs/unreleased/added-glob-for-ci-changes-detection.yml b/changelogs/unreleased/added-glob-for-ci-changes-detection.yml
deleted file mode 100644
index 887c6ef0346..00000000000
--- a/changelogs/unreleased/added-glob-for-ci-changes-detection.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Added glob for CI changes detection
-merge_request: 23128
-author: Kirill Zaitsev
-type: added
diff --git a/changelogs/unreleased/allow_collaboration_status_work.yml b/changelogs/unreleased/allow_collaboration_status_work.yml
new file mode 100644
index 00000000000..3cf8f13ffea
--- /dev/null
+++ b/changelogs/unreleased/allow_collaboration_status_work.yml
@@ -0,0 +1,5 @@
+---
+title: Update a condition to visibility a merge request collaboration message
+merge_request: 23104
+author: Harry Kiselev
+type: other
diff --git a/changelogs/unreleased/an-gitaly-version-0-133-0.yml b/changelogs/unreleased/an-gitaly-version-0-133-0.yml
deleted file mode 100644
index 4f3943ceacb..00000000000
--- a/changelogs/unreleased/an-gitaly-version-0-133-0.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Updated Gitaly to v0.133.0
-merge_request: 23148
-author:
-type: other
diff --git a/changelogs/unreleased/ashmckenzie-hmac-token-decode-and-tests.yml b/changelogs/unreleased/ashmckenzie-hmac-token-decode-and-tests.yml
deleted file mode 100644
index d15c5654d99..00000000000
--- a/changelogs/unreleased/ashmckenzie-hmac-token-decode-and-tests.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Relocate JSONWebToken::HMACToken from EE
-merge_request: 22906
-author:
-type: changed
diff --git a/changelogs/unreleased/auto_devops_kubernetes_active.yml b/changelogs/unreleased/auto_devops_kubernetes_active.yml
deleted file mode 100644
index 310d37128c9..00000000000
--- a/changelogs/unreleased/auto_devops_kubernetes_active.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Switch kubernetes:active with checking in Auto-DevOps.gitlab-ci.yml
-merge_request: 22929
-author:
-type: fixed
diff --git a/changelogs/unreleased/blackst0ne-add-discord-service.yml b/changelogs/unreleased/blackst0ne-add-discord-service.yml
deleted file mode 100644
index 85dedf6d81f..00000000000
--- a/changelogs/unreleased/blackst0ne-add-discord-service.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Add Discord integration
-merge_request: 22684
-author: "@blackst0ne"
-type: added
diff --git a/changelogs/unreleased/blackst0ne-bump-rails-cve-2018-16476.yml b/changelogs/unreleased/blackst0ne-bump-rails-cve-2018-16476.yml
new file mode 100644
index 00000000000..dfa94c69ce0
--- /dev/null
+++ b/changelogs/unreleased/blackst0ne-bump-rails-cve-2018-16476.yml
@@ -0,0 +1,5 @@
+---
+title: Bump Ruby on Rails to 5.0.7.1
+merge_request: 23396
+author: "@blackst0ne"
+type: security
diff --git a/changelogs/unreleased/bump_gpgme_gem.yml b/changelogs/unreleased/bump_gpgme_gem.yml
deleted file mode 100644
index 4c0067cb824..00000000000
--- a/changelogs/unreleased/bump_gpgme_gem.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Bump gpgme gem version from 2.0.13 to 2.0.18
-merge_request:
-author: asaparov
-type: other
diff --git a/changelogs/unreleased/bvl-use-shell-writeref.yml b/changelogs/unreleased/bvl-use-shell-writeref.yml
deleted file mode 100644
index 682d428e8c5..00000000000
--- a/changelogs/unreleased/bvl-use-shell-writeref.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Avoid creating invalid refs using rugged, shelling out for writing refs
-merge_request: 23286
-author:
-type: fixed
diff --git a/changelogs/unreleased/ce-52811-fix_namespaces_api_routing.yml b/changelogs/unreleased/ce-52811-fix_namespaces_api_routing.yml
deleted file mode 100644
index b5fd99c304f..00000000000
--- a/changelogs/unreleased/ce-52811-fix_namespaces_api_routing.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fix API::Namespaces routing to accept namepaces with dots
-merge_request: 22912
-author:
-type: fixed
diff --git a/changelogs/unreleased/ce-54109-fix_user_by_any_email.yml b/changelogs/unreleased/ce-54109-fix_user_by_any_email.yml
deleted file mode 100644
index eb5d2e3244c..00000000000
--- a/changelogs/unreleased/ce-54109-fix_user_by_any_email.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Respect confirmed flag on secondary emails
-merge_request: 23181
-author:
-type: fixed
diff --git a/changelogs/unreleased/cert-manager-email.yml b/changelogs/unreleased/cert-manager-email.yml
deleted file mode 100644
index 530608d9660..00000000000
--- a/changelogs/unreleased/cert-manager-email.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Ability to override email for cert-manager
-merge_request: 23503
-author: Amit Rathi
-type: added
diff --git a/changelogs/unreleased/certmanager-temp.yml b/changelogs/unreleased/certmanager-temp.yml
deleted file mode 100644
index 3f908d01c9f..00000000000
--- a/changelogs/unreleased/certmanager-temp.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: "#40635: Adds support for cert-manager"
-merge_request: 23036
-author: Amit Rathi
-type: added
diff --git a/changelogs/unreleased/check-if-fetched-data-does-is-complete.yml b/changelogs/unreleased/check-if-fetched-data-does-is-complete.yml
deleted file mode 100644
index 31c131045b9..00000000000
--- a/changelogs/unreleased/check-if-fetched-data-does-is-complete.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Validate chunk size when persist
-merge_request: 23341
-author:
-type: fixed
diff --git a/changelogs/unreleased/ci-dropdown-hidden-bug.yml b/changelogs/unreleased/ci-dropdown-hidden-bug.yml
new file mode 100644
index 00000000000..6910f04a6d5
--- /dev/null
+++ b/changelogs/unreleased/ci-dropdown-hidden-bug.yml
@@ -0,0 +1,5 @@
+---
+title: Don't hide CI dropdown behind diff summary
+merge_request:
+author: gfyoung
+type: fixed
diff --git a/changelogs/unreleased/commit-badge-style-fix.yml b/changelogs/unreleased/commit-badge-style-fix.yml
deleted file mode 100644
index d7b37717853..00000000000
--- a/changelogs/unreleased/commit-badge-style-fix.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fixed styling of image comment badges on commits
-merge_request:
-author:
-type: fixed
diff --git a/changelogs/unreleased/define-default-value-for-only-except-keys.yml b/changelogs/unreleased/define-default-value-for-only-except-keys.yml
deleted file mode 100644
index ed0e982f0fc..00000000000
--- a/changelogs/unreleased/define-default-value-for-only-except-keys.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Define the default value for only/except policies
-merge_request: 23765
-author:
-type: changed
diff --git a/changelogs/unreleased/deprecated-insert-sql.yml b/changelogs/unreleased/deprecated-insert-sql.yml
new file mode 100644
index 00000000000..ad21fbd9dde
--- /dev/null
+++ b/changelogs/unreleased/deprecated-insert-sql.yml
@@ -0,0 +1,5 @@
+---
+title: 'Fix deprecation: insert_sql is deprecated and will be removed'
+merge_request: 23944
+author: Jasper Maes
+type: other
diff --git a/changelogs/unreleased/deprecated-instance-find.yml b/changelogs/unreleased/deprecated-instance-find.yml
deleted file mode 100644
index d2ba821e124..00000000000
--- a/changelogs/unreleased/deprecated-instance-find.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: 'Fix deprecation: You are passing an instance of ActiveRecord::Base to'
-merge_request: 23369
-author: Jasper Maes
-type: other
diff --git a/changelogs/unreleased/deprecated-redirect-back.yml b/changelogs/unreleased/deprecated-redirect-back.yml
new file mode 100644
index 00000000000..7fc567fbdb5
--- /dev/null
+++ b/changelogs/unreleased/deprecated-redirect-back.yml
@@ -0,0 +1,5 @@
+---
+title: 'Fix deprecation: redirect_to :back is deprecated'
+merge_request: 23943
+author: Jasper Maes
+type: other
diff --git a/changelogs/unreleased/diff-expand-commit-file.yml b/changelogs/unreleased/diff-expand-commit-file.yml
deleted file mode 100644
index 8ca784d75c1..00000000000
--- a/changelogs/unreleased/diff-expand-commit-file.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fixed diff files expanding not loading commit content
-merge_request:
-author:
-type: fixed
diff --git a/changelogs/unreleased/diff-fix-expanding.yml b/changelogs/unreleased/diff-fix-expanding.yml
deleted file mode 100644
index 8ba7f87addc..00000000000
--- a/changelogs/unreleased/diff-fix-expanding.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fixed multiple diff line discussions not expanding
-merge_request:
-author:
-type: fixed
diff --git a/changelogs/unreleased/discussion-perf-improvement.yml b/changelogs/unreleased/discussion-perf-improvement.yml
deleted file mode 100644
index defff8a55f5..00000000000
--- a/changelogs/unreleased/discussion-perf-improvement.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Improve initial discussion rendering performance
-merge_request: 22607
-author:
-type: changed
diff --git a/changelogs/unreleased/dm-batch-loader-key.yml b/changelogs/unreleased/dm-batch-loader-key.yml
deleted file mode 100644
index 047fdbc4b3f..00000000000
--- a/changelogs/unreleased/dm-batch-loader-key.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Batch load only data from same repository when lazy object is accessed
-merge_request: 23309
-author:
-type: performance
diff --git a/changelogs/unreleased/dm-note-email-image-diff-discussion.yml b/changelogs/unreleased/dm-note-email-image-diff-discussion.yml
new file mode 100644
index 00000000000..6532052e132
--- /dev/null
+++ b/changelogs/unreleased/dm-note-email-image-diff-discussion.yml
@@ -0,0 +1,5 @@
+---
+title: Fix notification email for image diff notes
+merge_request:
+author:
+type: fixed
diff --git a/changelogs/unreleased/dm-remove-prune-web-hook-logs-worker.yml b/changelogs/unreleased/dm-remove-prune-web-hook-logs-worker.yml
deleted file mode 100644
index fb0c508400c..00000000000
--- a/changelogs/unreleased/dm-remove-prune-web-hook-logs-worker.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Remove old webhook logs after 90 days, as documented, instead of after 2
-merge_request:
-author:
-type: fixed
diff --git a/changelogs/unreleased/docs-minor-aws-fixes.yml b/changelogs/unreleased/docs-minor-aws-fixes.yml
deleted file mode 100644
index 64fa6b12afe..00000000000
--- a/changelogs/unreleased/docs-minor-aws-fixes.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fixes to AWS documentation spelling and grammar
-merge_request: 23198
-author: Brendan O'Leary
-type: other
diff --git a/changelogs/unreleased/document-raw-snippet-api.yml b/changelogs/unreleased/document-raw-snippet-api.yml
deleted file mode 100644
index 3b8818cea5c..00000000000
--- a/changelogs/unreleased/document-raw-snippet-api.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fix lack of documentation on how to fetch a snippet's content using API
-merge_request: 23448
-author: Colin Leroy
-type: other
diff --git a/changelogs/unreleased/drop-default-value-status-deployments.yml b/changelogs/unreleased/drop-default-value-status-deployments.yml
deleted file mode 100644
index fdb826a0507..00000000000
--- a/changelogs/unreleased/drop-default-value-status-deployments.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Drop default value on status column in deployments table
-merge_request: 22971
-author:
-type: other
diff --git a/changelogs/unreleased/drop-gcp-cluster-table.yml b/changelogs/unreleased/drop-gcp-cluster-table.yml
deleted file mode 100644
index 15964ec2eaf..00000000000
--- a/changelogs/unreleased/drop-gcp-cluster-table.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Drop gcp_clusters table
-merge_request: 22713
-author:
-type: other
diff --git a/changelogs/unreleased/expose-mr-pipeline-variables.yml b/changelogs/unreleased/expose-mr-pipeline-variables.yml
deleted file mode 100644
index b77b9a69d5c..00000000000
--- a/changelogs/unreleased/expose-mr-pipeline-variables.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Expose merge request pipeline variables
-merge_request: 23398
-author:
-type: changed
diff --git a/changelogs/unreleased/feature-option-to-make-variables-protected.yml b/changelogs/unreleased/feature-option-to-make-variables-protected.yml
new file mode 100644
index 00000000000..c99c0481c35
--- /dev/null
+++ b/changelogs/unreleased/feature-option-to-make-variables-protected.yml
@@ -0,0 +1,5 @@
+---
+title: Add option to make ci variables protected by default
+merge_request: 22744
+author: Alexis Reigel
+type: added
diff --git a/changelogs/unreleased/fix-55448.yml b/changelogs/unreleased/fix-55448.yml
new file mode 100644
index 00000000000..e0bdbb6eda4
--- /dev/null
+++ b/changelogs/unreleased/fix-55448.yml
@@ -0,0 +1,5 @@
+---
+title: Remove deprecated xhr from specs
+merge_request: 23949
+author: Jasper Maes
+type: other
diff --git a/changelogs/unreleased/fix-gb-encrypt-ci-build-token.yml b/changelogs/unreleased/fix-gb-encrypt-ci-build-token.yml
deleted file mode 100644
index 04fc88bc3d3..00000000000
--- a/changelogs/unreleased/fix-gb-encrypt-ci-build-token.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Encrypt CI/CD builds authentication tokens
-merge_request: 23436
-author:
-type: security
diff --git a/changelogs/unreleased/fix-gb-encrypt-runners-tokens.yml b/changelogs/unreleased/fix-gb-encrypt-runners-tokens.yml
deleted file mode 100644
index 4ce4f96c1dd..00000000000
--- a/changelogs/unreleased/fix-gb-encrypt-runners-tokens.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Encrypt runners tokens
-merge_request: 23412
-author:
-type: security
diff --git a/changelogs/unreleased/fix-gb-improve-timeout-inputs-help-sections.yml b/changelogs/unreleased/fix-gb-improve-timeout-inputs-help-sections.yml
deleted file mode 100644
index 52b431edf2c..00000000000
--- a/changelogs/unreleased/fix-gb-improve-timeout-inputs-help-sections.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Improve help and validation sections of maximum build timeout inputs
-merge_request: 23586
-author:
-type: fixed
diff --git a/changelogs/unreleased/fix-mr-widget-unrelated-deployment-status.yml b/changelogs/unreleased/fix-mr-widget-unrelated-deployment-status.yml
deleted file mode 100644
index ab926fbd43b..00000000000
--- a/changelogs/unreleased/fix-mr-widget-unrelated-deployment-status.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fix unrelated deployment status in MR widget
-merge_request: 23175
-author:
-type: fixed
diff --git a/changelogs/unreleased/fix-multiple-comments-shade-overlap.yml b/changelogs/unreleased/fix-multiple-comments-shade-overlap.yml
deleted file mode 100644
index 20005ba355e..00000000000
--- a/changelogs/unreleased/fix-multiple-comments-shade-overlap.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fix multiple commits shade overlapping vertical discussion line
-merge_request: 23515
-author:
-type: fixed
diff --git a/changelogs/unreleased/fj-44679-skip-per-commit-validations.yml b/changelogs/unreleased/fj-44679-skip-per-commit-validations.yml
new file mode 100644
index 00000000000..3f9754409df
--- /dev/null
+++ b/changelogs/unreleased/fj-44679-skip-per-commit-validations.yml
@@ -0,0 +1,5 @@
+---
+title: Skip per-commit validations already evaluated
+merge_request: 23984
+author:
+type: performance
diff --git a/changelogs/unreleased/fj-47494-upgrade-git-to-2-18-0.yml b/changelogs/unreleased/fj-47494-upgrade-git-to-2-18-0.yml
deleted file mode 100644
index 0f01552ff7e..00000000000
--- a/changelogs/unreleased/fj-47494-upgrade-git-to-2-18-0.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Upgrade minimum required Git version to 2.18.0
-merge_request: 22803
-author:
-type: other
diff --git a/changelogs/unreleased/fj-55781-fix-api-blob-content-disposition.yml b/changelogs/unreleased/fj-55781-fix-api-blob-content-disposition.yml
new file mode 100644
index 00000000000..2e1d9889b22
--- /dev/null
+++ b/changelogs/unreleased/fj-55781-fix-api-blob-content-disposition.yml
@@ -0,0 +1,5 @@
+---
+title: Fix content-disposition in blobs and files API endpoint
+merge_request: 24078
+author:
+type: fixed
diff --git a/changelogs/unreleased/fj-clean-content-headers.yml b/changelogs/unreleased/fj-clean-content-headers.yml
deleted file mode 100644
index 59e25ca6578..00000000000
--- a/changelogs/unreleased/fj-clean-content-headers.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Added feature flag to signal content headers detection by Workhorse
-merge_request: 22667
-author:
-type: added
diff --git a/changelogs/unreleased/fj-fix-lfs-image-comments-diffs.yml b/changelogs/unreleased/fj-fix-lfs-image-comments-diffs.yml
new file mode 100644
index 00000000000..dc1fe5d7417
--- /dev/null
+++ b/changelogs/unreleased/fj-fix-lfs-image-comments-diffs.yml
@@ -0,0 +1,5 @@
+---
+title: Fix bug commenting on LFS images
+merge_request: 23812
+author:
+type: fixed
diff --git a/changelogs/unreleased/fj-force-content-disposition.yml b/changelogs/unreleased/fj-force-content-disposition.yml
deleted file mode 100644
index d84555a489f..00000000000
--- a/changelogs/unreleased/fj-force-content-disposition.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Force content disposition attachment to several endpoints
-merge_request: 23223
-author:
-type: other
diff --git a/changelogs/unreleased/force-reload-arguments-1.yml b/changelogs/unreleased/force-reload-arguments-1.yml
deleted file mode 100644
index 29f34b8bdbe..00000000000
--- a/changelogs/unreleased/force-reload-arguments-1.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Passing an argument to force an association to reload is now deprecated
-merge_request: 23334
-author: Jasper Maes
-type: other
diff --git a/changelogs/unreleased/frozen-string-lib-gitlab-even-even-even-more.yml b/changelogs/unreleased/frozen-string-lib-gitlab-even-even-even-more.yml
deleted file mode 100644
index e718d716647..00000000000
--- a/changelogs/unreleased/frozen-string-lib-gitlab-even-even-even-more.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Enable even more frozen string for lib/gitlab
-merge_request:
-author: gfyoung
-type: performance
diff --git a/changelogs/unreleased/frozen-string-lib-gitlab-even-even-more.yml b/changelogs/unreleased/frozen-string-lib-gitlab-even-even-more.yml
deleted file mode 100644
index e718d716647..00000000000
--- a/changelogs/unreleased/frozen-string-lib-gitlab-even-even-more.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Enable even more frozen string for lib/gitlab
-merge_request:
-author: gfyoung
-type: performance
diff --git a/changelogs/unreleased/frozen-string-lib-gitlab-even-more.yml b/changelogs/unreleased/frozen-string-lib-gitlab-even-more.yml
deleted file mode 100644
index cfbc4ced635..00000000000
--- a/changelogs/unreleased/frozen-string-lib-gitlab-even-more.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Enable even more frozen string in lib/gitlab/**/*.rb
-merge_request:
-author: gfyoung
-type: performance
diff --git a/changelogs/unreleased/frozen-string-lib-gitlab-more.yml b/changelogs/unreleased/frozen-string-lib-gitlab-more.yml
deleted file mode 100644
index cfbc4ced635..00000000000
--- a/changelogs/unreleased/frozen-string-lib-gitlab-more.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Enable even more frozen string in lib/gitlab/**/*.rb
-merge_request:
-author: gfyoung
-type: performance
diff --git a/changelogs/unreleased/frozen-string-lib-rubocop.yml b/changelogs/unreleased/frozen-string-lib-rubocop.yml
deleted file mode 100644
index 9fe342e251b..00000000000
--- a/changelogs/unreleased/frozen-string-lib-rubocop.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Enable Rubocop on lib/gitlab
-merge_request:
-author: gfyoung
-type: other
diff --git a/changelogs/unreleased/gt-add-top-padding-for-nested-environment-items-loading-icon.yml b/changelogs/unreleased/gt-add-top-padding-for-nested-environment-items-loading-icon.yml
deleted file mode 100644
index 606314b5780..00000000000
--- a/changelogs/unreleased/gt-add-top-padding-for-nested-environment-items-loading-icon.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Add top padding for nested environment items loading icon
-merge_request: 23580
-author: George Tsiolis
-type: fixed
diff --git a/changelogs/unreleased/gt-align-issue-status-and-confidential-icon.yml b/changelogs/unreleased/gt-align-issue-status-and-confidential-icon.yml
deleted file mode 100644
index 481ce656dc7..00000000000
--- a/changelogs/unreleased/gt-align-issue-status-and-confidential-icon.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Align issue status label and confidential icon.
-merge_request: 23046
-author: George Tsiolis
-type: fixed
diff --git a/changelogs/unreleased/gt-change-breadcrumb-title-for-contribution-charts.yml b/changelogs/unreleased/gt-change-breadcrumb-title-for-contribution-charts.yml
deleted file mode 100644
index 233cc43117d..00000000000
--- a/changelogs/unreleased/gt-change-breadcrumb-title-for-contribution-charts.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Change breadcrumb title for contribution charts
-merge_request: 23071
-author: George Tsiolis
-type: changed
diff --git a/changelogs/unreleased/gt-change-container-width-for-project-import.yml b/changelogs/unreleased/gt-change-container-width-for-project-import.yml
deleted file mode 100644
index ec2beb15912..00000000000
--- a/changelogs/unreleased/gt-change-container-width-for-project-import.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Change container width for project import
-merge_request: 23318
-author: George Tsiolis
-type: fixed
diff --git a/changelogs/unreleased/gt-externalize-app-views-invites.yml b/changelogs/unreleased/gt-externalize-app-views-invites.yml
deleted file mode 100644
index b5a22177f9b..00000000000
--- a/changelogs/unreleased/gt-externalize-app-views-invites.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Externalize strings from `/app/views/invites`
-merge_request: 23205
-author: Tao Wang
-type: other
diff --git a/changelogs/unreleased/gt-externalize-app-views-project-runners.yml b/changelogs/unreleased/gt-externalize-app-views-project-runners.yml
deleted file mode 100644
index d7d591e2175..00000000000
--- a/changelogs/unreleased/gt-externalize-app-views-project-runners.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Externalize strings from `/app/views/project/runners`
-merge_request: 23208
-author: Tao Wang
-type: other
diff --git a/changelogs/unreleased/gt-externalize-app-views-snippets.yml b/changelogs/unreleased/gt-externalize-app-views-snippets.yml
deleted file mode 100644
index 633aa9f2534..00000000000
--- a/changelogs/unreleased/gt-externalize-app-views-snippets.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Externalize strings from `/app/views/snippets`
-merge_request: 23351
-author: Tao Wang
-type: other
diff --git a/changelogs/unreleased/gt-fix-typo-in-notebook-props.yml b/changelogs/unreleased/gt-fix-typo-in-notebook-props.yml
deleted file mode 100644
index 60603905a2d..00000000000
--- a/changelogs/unreleased/gt-fix-typo-in-notebook-props.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fix typo in notebook props
-merge_request: 23103
-author: George Tsiolis
-type: other
diff --git a/changelogs/unreleased/gt-fix-typos-in-lib.yml b/changelogs/unreleased/gt-fix-typos-in-lib.yml
deleted file mode 100644
index 32ccd03b063..00000000000
--- a/changelogs/unreleased/gt-fix-typos-in-lib.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fix typos in lib
-merge_request: 23106
-author: George Tsiolis
-type: other
diff --git a/changelogs/unreleased/gt-remove-instances-of-extend-monospace.yml b/changelogs/unreleased/gt-remove-instances-of-extend-monospace.yml
deleted file mode 100644
index dc41de61046..00000000000
--- a/changelogs/unreleased/gt-remove-instances-of-extend-monospace.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Remove monospace extend
-merge_request: 23089
-author: George Tsiolis
-type: performance
diff --git a/changelogs/unreleased/gt-remove-unused-project-method.yml b/changelogs/unreleased/gt-remove-unused-project-method.yml
deleted file mode 100644
index 2d60c2fe423..00000000000
--- a/changelogs/unreleased/gt-remove-unused-project-method.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Remove unused project method
-merge_request: 54103
-author: George Tsiolis
-type: other
diff --git a/changelogs/unreleased/gt-rename-diffs-store-variable.yml b/changelogs/unreleased/gt-rename-diffs-store-variable.yml
deleted file mode 100644
index 0aed49f3d60..00000000000
--- a/changelogs/unreleased/gt-rename-diffs-store-variable.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Rename diffs store variable
-merge_request: 23123
-author: George Tsiolis
-type: other
diff --git a/changelogs/unreleased/gt-reorder-group-sidebar-menu-items.yml b/changelogs/unreleased/gt-reorder-group-sidebar-menu-items.yml
new file mode 100644
index 00000000000..b1ecf2bb1ed
--- /dev/null
+++ b/changelogs/unreleased/gt-reorder-group-sidebar-menu-items.yml
@@ -0,0 +1,5 @@
+---
+title: Reorder sidebar menu item for group clusters
+merge_request: 24001
+author: George Tsiolis
+type: changed
diff --git a/changelogs/unreleased/gt-show-primary-button-when-all-labels-are-prioritized.yml b/changelogs/unreleased/gt-show-primary-button-when-all-labels-are-prioritized.yml
deleted file mode 100644
index eed31950a76..00000000000
--- a/changelogs/unreleased/gt-show-primary-button-when-all-labels-are-prioritized.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Show primary button when all labels are prioritized
-merge_request: 23648
-author: George Tsiolis
-type: other
diff --git a/changelogs/unreleased/gt-update-env-metrics-empty-state.yml b/changelogs/unreleased/gt-update-env-metrics-empty-state.yml
deleted file mode 100644
index a05dc07e65c..00000000000
--- a/changelogs/unreleased/gt-update-env-metrics-empty-state.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Update environments metrics empty state
-merge_request: 23074
-author: George Tsiolis
-type: changed
diff --git a/changelogs/unreleased/gt-use-gl-tooltip-directive.yml b/changelogs/unreleased/gt-use-gl-tooltip-directive.yml
deleted file mode 100644
index 91fdb73e3c6..00000000000
--- a/changelogs/unreleased/gt-use-gl-tooltip-directive.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Replace tooltip directive with gl-tooltip diretive in badges, cycle analytics, and diffs
-merge_request: 22770
-author: George Tsiolis
-type: performance
diff --git a/changelogs/unreleased/ide-open-all-mr-files.yml b/changelogs/unreleased/ide-open-all-mr-files.yml
deleted file mode 100644
index 6a5ea8908fc..00000000000
--- a/changelogs/unreleased/ide-open-all-mr-files.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Open first 10 merge request files in IDE
-merge_request:
-author:
-type: fixed
diff --git a/changelogs/unreleased/ignore-failed-pipeline-creation-on-pipeline-schedule.yml b/changelogs/unreleased/ignore-failed-pipeline-creation-on-pipeline-schedule.yml
deleted file mode 100644
index 90f47aa12db..00000000000
--- a/changelogs/unreleased/ignore-failed-pipeline-creation-on-pipeline-schedule.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Remove auto deactivation when failed to create a pipeline via pipeline schedules
-merge_request: 22243
-author:
-type: changed
diff --git a/changelogs/unreleased/improve_auto_devops_migration_debug.yml b/changelogs/unreleased/improve_auto_devops_migration_debug.yml
deleted file mode 100644
index 96a78808361..00000000000
--- a/changelogs/unreleased/improve_auto_devops_migration_debug.yml
+++ /dev/null
@@ -1,6 +0,0 @@
----
-title: 'Auto DevOps: Add echo for each branch of the deploy() function where we run
- helm upgrade'
-merge_request: 23499
-author:
-type: changed
diff --git a/changelogs/unreleased/include-new-link-in-breadcrumb.yml b/changelogs/unreleased/include-new-link-in-breadcrumb.yml
deleted file mode 100644
index 68c808d66d7..00000000000
--- a/changelogs/unreleased/include-new-link-in-breadcrumb.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Include new link in breadcrumb for issues, merge requests, milestones, and labels
-merge_request: 18515
-author: George Tsiolis
-type: changed
diff --git a/changelogs/unreleased/jivl-add-empty-state-graphs-null-values.yml b/changelogs/unreleased/jivl-add-empty-state-graphs-null-values.yml
deleted file mode 100644
index d21254b16d0..00000000000
--- a/changelogs/unreleased/jivl-add-empty-state-graphs-null-values.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Add empty state for graphs with no values
-merge_request: 22630
-author:
-type: fixed
diff --git a/changelogs/unreleased/jupyter-tls.yml b/changelogs/unreleased/jupyter-tls.yml
deleted file mode 100644
index 4111edd34ff..00000000000
--- a/changelogs/unreleased/jupyter-tls.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: "#52753: HTTPS for JupyterHub installation"
-merge_request: 23479
-author: Amit Rathi
-type: added
diff --git a/changelogs/unreleased/kcj-add-philosophy.yml b/changelogs/unreleased/kcj-add-philosophy.yml
deleted file mode 100644
index d164ce165ea..00000000000
--- a/changelogs/unreleased/kcj-add-philosophy.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Adds a PHILOSOPHY.md which references GitLab Product Handbook
-merge_request: 23200
-author:
-type: other
diff --git a/changelogs/unreleased/kubernetes-http-response-code.yml b/changelogs/unreleased/kubernetes-http-response-code.yml
deleted file mode 100644
index 551fe2edc3c..00000000000
--- a/changelogs/unreleased/kubernetes-http-response-code.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Show HTTP response code for Kubernetes errors
-merge_request: 22964
-author:
-type: other
diff --git a/changelogs/unreleased/legacy_fallback_for_project_clusters_only.yml b/changelogs/unreleased/legacy_fallback_for_project_clusters_only.yml
deleted file mode 100644
index c8e959176d0..00000000000
--- a/changelogs/unreleased/legacy_fallback_for_project_clusters_only.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fallback to admin KUBE_TOKEN for project clusters only
-merge_request: 23527
-author:
-type: other
diff --git a/changelogs/unreleased/lock-trace-writes.yml b/changelogs/unreleased/lock-trace-writes.yml
deleted file mode 100644
index 9c5239081b9..00000000000
--- a/changelogs/unreleased/lock-trace-writes.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Lock writes to trace stream
-merge_request:
-author:
-type: fixed
diff --git a/changelogs/unreleased/fix-deadlock-chunked-io.yml b/changelogs/unreleased/markdown-toolbar-btn-fix.yml
index def7a59e86e..eefb4d19f86 100644
--- a/changelogs/unreleased/fix-deadlock-chunked-io.yml
+++ b/changelogs/unreleased/markdown-toolbar-btn-fix.yml
@@ -1,5 +1,5 @@
---
-title: Fix deadlock on ChunkedIO
+title: Fixed markdown toolbar buttons
merge_request:
author:
type: fixed
diff --git a/changelogs/unreleased/mg-fix-knative-application-row.yml b/changelogs/unreleased/mg-fix-knative-application-row.yml
deleted file mode 100644
index 95142d380a4..00000000000
--- a/changelogs/unreleased/mg-fix-knative-application-row.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Hide Knative from group cluster applications until supported
-merge_request: 23577
-author:
-type: fixed
diff --git a/changelogs/unreleased/move-group-issues-search-cte-up-the-chain.yml b/changelogs/unreleased/move-group-issues-search-cte-up-the-chain.yml
deleted file mode 100644
index 0269e7b6196..00000000000
--- a/changelogs/unreleased/move-group-issues-search-cte-up-the-chain.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fix error when searching for group issues with priority or popularity sort
-merge_request: 23445
-author:
-type: fixed
diff --git a/changelogs/unreleased/mr-file-tree-commit.yml b/changelogs/unreleased/mr-file-tree-commit.yml
deleted file mode 100644
index e0d47e6e61f..00000000000
--- a/changelogs/unreleased/mr-file-tree-commit.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Show tree collapse button for merge request commit diffs
-merge_request:
-author:
-type: fixed
diff --git a/changelogs/unreleased/mr-origin-23218.yml b/changelogs/unreleased/mr-origin-23218.yml
deleted file mode 100644
index 49867f04343..00000000000
--- a/changelogs/unreleased/mr-origin-23218.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fix typo for scheduled pipeline
-merge_request: 23218
-author: Davy Defaud
-type: other
diff --git a/changelogs/unreleased/mr-pipelines-2.yml b/changelogs/unreleased/mr-pipelines-2.yml
deleted file mode 100644
index 683c626c3ce..00000000000
--- a/changelogs/unreleased/mr-pipelines-2.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Merge request pipelines
-merge_request: 23217
-author:
-type: added
diff --git a/changelogs/unreleased/mr-sticky-headers.yml b/changelogs/unreleased/mr-sticky-headers.yml
deleted file mode 100644
index c20829bc2d7..00000000000
--- a/changelogs/unreleased/mr-sticky-headers.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Make diff file headers sticky
-merge_request:
-author:
-type: changed
diff --git a/changelogs/unreleased/mr-tree-filter-path-name.yml b/changelogs/unreleased/mr-tree-filter-path-name.yml
deleted file mode 100644
index 152f8a67337..00000000000
--- a/changelogs/unreleased/mr-tree-filter-path-name.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Changed merge request filtering to be by path instead of name
-merge_request:
-author:
-type: changed
diff --git a/changelogs/unreleased/multiple-diff-line-discussions-fix.yml b/changelogs/unreleased/multiple-diff-line-discussions-fix.yml
deleted file mode 100644
index 870a8ab3815..00000000000
--- a/changelogs/unreleased/multiple-diff-line-discussions-fix.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fixed duplicate discussions getting added to diff lines
-merge_request:
-author:
-type: fixed
diff --git a/changelogs/unreleased/non-webkit-scrollbar-fixing.yml b/changelogs/unreleased/non-webkit-scrollbar-fixing.yml
deleted file mode 100644
index 526a9f25486..00000000000
--- a/changelogs/unreleased/non-webkit-scrollbar-fixing.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fix horizontal scrollbar overlapping on horizontal scrolling-tabs
-merge_request: 23167
-author: Harry Kiselev
-type: other
diff --git a/changelogs/unreleased/optimise-job-request.yml b/changelogs/unreleased/optimise-job-request.yml
deleted file mode 100644
index e1265841b48..00000000000
--- a/changelogs/unreleased/optimise-job-request.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Use cached size when passing artifacts to Runner
-merge_request:
-author:
-type: performance
diff --git a/changelogs/unreleased/order-of-notification-settings.yml b/changelogs/unreleased/order-of-notification-settings.yml
deleted file mode 100644
index 0f0243bcb40..00000000000
--- a/changelogs/unreleased/order-of-notification-settings.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: reorder notification settings by noisy-ness
-merge_request:
-author: C.J. Jameson
-type: changed
diff --git a/changelogs/unreleased/osw-cache-discussions-diff-highlighting.yml b/changelogs/unreleased/osw-cache-discussions-diff-highlighting.yml
new file mode 100644
index 00000000000..7abc7d85794
--- /dev/null
+++ b/changelogs/unreleased/osw-cache-discussions-diff-highlighting.yml
@@ -0,0 +1,6 @@
+---
+title: Improve the loading time on merge request's discussion page by caching diff
+ highlight
+merge_request: 23857
+author:
+type: performance
diff --git a/changelogs/unreleased/osw-fallback-on-blank-refs.yml b/changelogs/unreleased/osw-fallback-on-blank-refs.yml
deleted file mode 100644
index 039179f5829..00000000000
--- a/changelogs/unreleased/osw-fallback-on-blank-refs.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Avoid Gitaly RPC errors when fetching diff stats
-merge_request: 22995
-author:
-type: fixed
diff --git a/changelogs/unreleased/osw-fix-grouping-by-file-path.yml b/changelogs/unreleased/osw-fix-grouping-by-file-path.yml
deleted file mode 100644
index dff3116e7c6..00000000000
--- a/changelogs/unreleased/osw-fix-grouping-by-file-path.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Avoid 500's when serializing legacy diff notes
-merge_request: 23544
-author:
-type: fixed
diff --git a/changelogs/unreleased/osw-remove-unnused-data-from-diff-discussions.yml b/changelogs/unreleased/osw-remove-unnused-data-from-diff-discussions.yml
deleted file mode 100644
index 58d9a19d038..00000000000
--- a/changelogs/unreleased/osw-remove-unnused-data-from-diff-discussions.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Remove unused data from discussions endpoint
-merge_request: 23570
-author:
-type: performance
diff --git a/changelogs/unreleased/osw-update-mr-metrics-with-events-data.yml b/changelogs/unreleased/osw-update-mr-metrics-with-events-data.yml
deleted file mode 100644
index 09a10a86adc..00000000000
--- a/changelogs/unreleased/osw-update-mr-metrics-with-events-data.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Populate MR metrics with events table information (migration)
-merge_request: 23564
-author:
-type: performance
diff --git a/changelogs/unreleased/profile-fixing.yml b/changelogs/unreleased/profile-fixing.yml
deleted file mode 100644
index 7e255d997d8..00000000000
--- a/changelogs/unreleased/profile-fixing.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fix bottom paddings of profile header and some markup updates of profile
-merge_request: 23168
-author: Harry Kiselev
-type: other
diff --git a/changelogs/unreleased/project_identicon_fix.yml b/changelogs/unreleased/project_identicon_fix.yml
deleted file mode 100644
index de4876fc4a5..00000000000
--- a/changelogs/unreleased/project_identicon_fix.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fix project identicon aligning Harry Kiselev
-merge_request: 23166
-author: Harry Kiselev
-type: other
diff --git a/changelogs/unreleased/rails5-active-record-class-value.yml b/changelogs/unreleased/rails5-active-record-class-value.yml
deleted file mode 100644
index 9f9fdf10cd1..00000000000
--- a/changelogs/unreleased/rails5-active-record-class-value.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: 'Rails5: Passing a class as a value in an Active Record query is deprecated'
-merge_request: 23164
-author: Jasper Maes
-type: other
diff --git a/changelogs/unreleased/rails5-deprecation-render-nothing.yml b/changelogs/unreleased/rails5-deprecation-render-nothing.yml
deleted file mode 100644
index 32e2d5800c7..00000000000
--- a/changelogs/unreleased/rails5-deprecation-render-nothing.yml
+++ /dev/null
@@ -1,6 +0,0 @@
----
-title: render :nothing option is deprecated, Use head method to respond with empty
- response body.
-merge_request: 23311
-author: Jasper Maes
-type: other
diff --git a/changelogs/unreleased/rails5-env-deprecated.yml b/changelogs/unreleased/rails5-env-deprecated.yml
deleted file mode 100644
index 2f8573e2ff6..00000000000
--- a/changelogs/unreleased/rails5-env-deprecated.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: 'Rails5: env is deprecated and will be removed from Rails 5.1'
-merge_request: 22626
-author: Jasper Maes
-type: other
diff --git a/changelogs/unreleased/remove-blob-search-limit.yml b/changelogs/unreleased/remove-blob-search-limit.yml
deleted file mode 100644
index 5bad3a83dbb..00000000000
--- a/changelogs/unreleased/remove-blob-search-limit.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Remove limit of 100 when searching repository code.
-merge_request: 8671
-author:
-type: fixed
diff --git a/changelogs/unreleased/remove-deployment-status-hack-from-backend.yml b/changelogs/unreleased/remove-deployment-status-hack-from-backend.yml
deleted file mode 100644
index 2348bfab7d9..00000000000
--- a/changelogs/unreleased/remove-deployment-status-hack-from-backend.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Return real deployment status to frontend
-merge_request: 23270
-author:
-type: fixed
diff --git a/changelogs/unreleased/remove-duplicate-primary-button-in-dashboard-snippets.yml b/changelogs/unreleased/remove-duplicate-primary-button-in-dashboard-snippets.yml
deleted file mode 100644
index 3a8b3a0df5d..00000000000
--- a/changelogs/unreleased/remove-duplicate-primary-button-in-dashboard-snippets.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Remove duplicate primary button in dashboard snippets on small viewports
-merge_request: 22902
-author: George Tsiolis
-type: fixed
diff --git a/changelogs/unreleased/render-text-deprecated.yml b/changelogs/unreleased/render-text-deprecated.yml
deleted file mode 100644
index 7dbbd13bcef..00000000000
--- a/changelogs/unreleased/render-text-deprecated.yml
+++ /dev/null
@@ -1,6 +0,0 @@
----
-title: 'Fix deprecation: render :text is deprecated because it does not actually render
- a text/plain response'
-merge_request: 23425
-author: Jasper Maes
-type: other
diff --git a/changelogs/unreleased/retryable_create_or_update_kubernetes_namespace.yml b/changelogs/unreleased/retryable_create_or_update_kubernetes_namespace.yml
deleted file mode 100644
index 607f2709f90..00000000000
--- a/changelogs/unreleased/retryable_create_or_update_kubernetes_namespace.yml
+++ /dev/null
@@ -1,6 +0,0 @@
----
-title: Updates service to update Kubernetes project namespaces and restricted service
- account if present
-merge_request: 23525
-author:
-type: changed
diff --git a/changelogs/unreleased/revert-1cccfca1.yml b/changelogs/unreleased/revert-1cccfca1.yml
deleted file mode 100644
index c1efdaac138..00000000000
--- a/changelogs/unreleased/revert-1cccfca1.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Restore kubernetes:active in Auto-DevOps.gitlab-ci.yml (reverts 22929)
-merge_request: 23826
-author:
-type: fixed
diff --git a/changelogs/unreleased/rs-cherry-pick-api.yml b/changelogs/unreleased/rs-cherry-pick-api.yml
deleted file mode 100644
index ce844dfc939..00000000000
--- a/changelogs/unreleased/rs-cherry-pick-api.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Resolve possible cherry pick API race condition
-merge_request:
-author:
-type: fixed
diff --git a/changelogs/unreleased/s3-directories-get.yml b/changelogs/unreleased/s3-directories-get.yml
new file mode 100644
index 00000000000..9f76af2bb09
--- /dev/null
+++ b/changelogs/unreleased/s3-directories-get.yml
@@ -0,0 +1,6 @@
+---
+title: Allow 'rake gitlab:cleanup:remote_upload_files' to read bucket files without
+ having permissions to see all buckets.
+merge_request: 23981
+author:
+type: fixed
diff --git a/changelogs/unreleased/security-182-update-workhorse.yml b/changelogs/unreleased/security-182-update-workhorse.yml
deleted file mode 100644
index 76850901b68..00000000000
--- a/changelogs/unreleased/security-182-update-workhorse.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Redact sensitive information on gitlab-workhorse log
-merge_request:
-author:
-type: security
diff --git a/changelogs/unreleased/security-2717-xss-username-autocomplete.yml b/changelogs/unreleased/security-2717-xss-username-autocomplete.yml
deleted file mode 100644
index d9b1015eeb4..00000000000
--- a/changelogs/unreleased/security-2717-xss-username-autocomplete.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Escape user fullname while rendering autocomplete template to prevent XSS
-merge_request:
-author:
-type: security
diff --git a/changelogs/unreleased/security-2736-prometheus-ssrf.yml b/changelogs/unreleased/security-2736-prometheus-ssrf.yml
deleted file mode 100644
index 9d0dda8a75f..00000000000
--- a/changelogs/unreleased/security-2736-prometheus-ssrf.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Do not follow redirects in Prometheus service when making http requests to the configured api url
-merge_request:
-author:
-type: security
diff --git a/changelogs/unreleased/security-2754-fix-lfs-import.yml b/changelogs/unreleased/security-2754-fix-lfs-import.yml
deleted file mode 100644
index e8e74c9c3f6..00000000000
--- a/changelogs/unreleased/security-2754-fix-lfs-import.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Validate LFS hrefs before downloading them
-merge_request:
-author:
-type: security
diff --git a/changelogs/unreleased/security-48259-private-snippet.yml b/changelogs/unreleased/security-48259-private-snippet.yml
new file mode 100644
index 00000000000..6cf1e5dc694
--- /dev/null
+++ b/changelogs/unreleased/security-48259-private-snippet.yml
@@ -0,0 +1,5 @@
+---
+title: Prevent private snippets from being embeddable
+merge_request:
+author:
+type: security
diff --git a/changelogs/unreleased/security-53543-user-keeps-access-to-mr-issue-when-removed-from-team.yml b/changelogs/unreleased/security-53543-user-keeps-access-to-mr-issue-when-removed-from-team.yml
new file mode 100644
index 00000000000..ab12ba539c1
--- /dev/null
+++ b/changelogs/unreleased/security-53543-user-keeps-access-to-mr-issue-when-removed-from-team.yml
@@ -0,0 +1,5 @@
+---
+title: Issuable no longer is visible to users when project can't be viewed
+merge_request:
+author:
+type: security
diff --git a/changelogs/unreleased/security-54377-label-milestone-name-xss.yml b/changelogs/unreleased/security-54377-label-milestone-name-xss.yml
new file mode 100644
index 00000000000..76589b2eb4f
--- /dev/null
+++ b/changelogs/unreleased/security-54377-label-milestone-name-xss.yml
@@ -0,0 +1,5 @@
+---
+title: Escape label and milestone titles to prevent XSS in GFM autocomplete
+merge_request: 2693
+author:
+type: security
diff --git a/changelogs/unreleased/security-bvl-exposure-in-commits-list.yml b/changelogs/unreleased/security-bvl-exposure-in-commits-list.yml
deleted file mode 100644
index 0361fb0c041..00000000000
--- a/changelogs/unreleased/security-bvl-exposure-in-commits-list.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Don't expose confidential information in commit message list
-merge_request:
-author:
-type: security
diff --git a/changelogs/unreleased/security-bvl-fix-cross-project-mr-exposure.yml b/changelogs/unreleased/security-bvl-fix-cross-project-mr-exposure.yml
new file mode 100644
index 00000000000..11aae4428fb
--- /dev/null
+++ b/changelogs/unreleased/security-bvl-fix-cross-project-mr-exposure.yml
@@ -0,0 +1,5 @@
+---
+title: Don't expose cross project repositories through diffs when creating merge reqeusts
+merge_request:
+author:
+type: security
diff --git a/changelogs/unreleased/security-email-change-notification.yml b/changelogs/unreleased/security-email-change-notification.yml
deleted file mode 100644
index 45075ff20bb..00000000000
--- a/changelogs/unreleased/security-email-change-notification.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Provide email notification when a user changes their email address
-merge_request:
-author:
-type: security
diff --git a/changelogs/unreleased/security-fix-pat-web-access.yml b/changelogs/unreleased/security-fix-pat-web-access.yml
deleted file mode 100644
index 62ffb908fe5..00000000000
--- a/changelogs/unreleased/security-fix-pat-web-access.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Restrict Personal Access Tokens to API scope on web requests
-merge_request:
-author:
-type: security
diff --git a/changelogs/unreleased/security-fix-ssrf-import-url-remote-mirror.yml b/changelogs/unreleased/security-fix-ssrf-import-url-remote-mirror.yml
new file mode 100644
index 00000000000..7ba7aa21090
--- /dev/null
+++ b/changelogs/unreleased/security-fix-ssrf-import-url-remote-mirror.yml
@@ -0,0 +1,5 @@
+---
+title: Fix SSRF with import_url and remote mirror url
+merge_request:
+author:
+type: security
diff --git a/changelogs/unreleased/security-fix-uri-xss-applications.yml b/changelogs/unreleased/security-fix-uri-xss-applications.yml
deleted file mode 100644
index 0eaa1b1c4a3..00000000000
--- a/changelogs/unreleased/security-fix-uri-xss-applications.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Resolve reflected XSS in Ouath authorize window
-merge_request:
-author:
-type: security
diff --git a/changelogs/unreleased/security-fix-webhook-ssrf-ipv6.yml b/changelogs/unreleased/security-fix-webhook-ssrf-ipv6.yml
deleted file mode 100644
index 32c85a2a7da..00000000000
--- a/changelogs/unreleased/security-fix-webhook-ssrf-ipv6.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fix SSRF in project integrations
-merge_request:
-author:
-type: security
diff --git a/changelogs/unreleased/security-fj-crlf-injection.yml b/changelogs/unreleased/security-fj-crlf-injection.yml
deleted file mode 100644
index 861167b8a6e..00000000000
--- a/changelogs/unreleased/security-fj-crlf-injection.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fix CRLF vulnerability in Project hooks
-merge_request:
-author:
-type: security
diff --git a/changelogs/unreleased/security-guest-comments.yml b/changelogs/unreleased/security-guest-comments.yml
deleted file mode 100644
index 2c99512433b..00000000000
--- a/changelogs/unreleased/security-guest-comments.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fixed ability to comment on locked/confidential issues.
-merge_request:
-author:
-type: security
diff --git a/changelogs/unreleased/security-guest-comments_2.yml b/changelogs/unreleased/security-guest-comments_2.yml
deleted file mode 100644
index be6f2d6a490..00000000000
--- a/changelogs/unreleased/security-guest-comments_2.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fixed ability of guest users to edit/delete comments on locked or confidential issues.
-merge_request:
-author:
-type: security
diff --git a/changelogs/unreleased/security-issue_51301.yml b/changelogs/unreleased/security-issue_51301.yml
deleted file mode 100644
index cf8ebb54b1c..00000000000
--- a/changelogs/unreleased/security-issue_51301.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fix milestone promotion authorization check
-merge_request:
-author:
-type: security
diff --git a/changelogs/unreleased/security-master-group-cicd-settings-accessible-to-maintainer.yml b/changelogs/unreleased/security-master-group-cicd-settings-accessible-to-maintainer.yml
new file mode 100644
index 00000000000..5586fa6cd8e
--- /dev/null
+++ b/changelogs/unreleased/security-master-group-cicd-settings-accessible-to-maintainer.yml
@@ -0,0 +1,5 @@
+---
+title: Allow changing group CI/CD settings only for owners.
+merge_request:
+author:
+type: security
diff --git a/changelogs/unreleased/security-master-guests-jobs-api.yml b/changelogs/unreleased/security-master-guests-jobs-api.yml
new file mode 100644
index 00000000000..83022e91aca
--- /dev/null
+++ b/changelogs/unreleased/security-master-guests-jobs-api.yml
@@ -0,0 +1,5 @@
+---
+title: Authorize before reading job information via API.
+merge_request:
+author:
+type: security
diff --git a/changelogs/unreleased/security-master-secret-ci-variables-exposed.yml b/changelogs/unreleased/security-master-secret-ci-variables-exposed.yml
new file mode 100644
index 00000000000..702181065f5
--- /dev/null
+++ b/changelogs/unreleased/security-master-secret-ci-variables-exposed.yml
@@ -0,0 +1,5 @@
+---
+title: Prevent leaking protected variables for ambiguous refs.
+merge_request:
+author:
+type: security
diff --git a/changelogs/unreleased/security-master-url-rel.yml b/changelogs/unreleased/security-master-url-rel.yml
new file mode 100644
index 00000000000..75f599f6bcd
--- /dev/null
+++ b/changelogs/unreleased/security-master-url-rel.yml
@@ -0,0 +1,5 @@
+---
+title: Set URL rel attribute for broken URLs.
+merge_request:
+author:
+type: security
diff --git a/changelogs/unreleased/security-mermaid-xss.yml b/changelogs/unreleased/security-mermaid-xss.yml
deleted file mode 100644
index bcf93ef37ff..00000000000
--- a/changelogs/unreleased/security-mermaid-xss.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Configure mermaid to not render HTML content in diagrams
-merge_request:
-author:
-type: security
diff --git a/changelogs/unreleased/security-pages-toctou-race.yml b/changelogs/unreleased/security-pages-toctou-race.yml
deleted file mode 100644
index 1c055f6087f..00000000000
--- a/changelogs/unreleased/security-pages-toctou-race.yml
+++ /dev/null
@@ -1,6 +0,0 @@
----
-title: Fix a possible symlink time of check to time of use race condition in GitLab
- Pages
-merge_request:
-author:
-type: security
diff --git a/changelogs/unreleased/security-private-group.yml b/changelogs/unreleased/security-private-group.yml
deleted file mode 100644
index dbb7794dfed..00000000000
--- a/changelogs/unreleased/security-private-group.yml
+++ /dev/null
@@ -1,6 +0,0 @@
----
-title: Removed ability to see private group names when the group id is entered in
- the url.
-merge_request:
-author:
-type: security
diff --git a/changelogs/unreleased/security-refs-available-to-project-guest.yml b/changelogs/unreleased/security-refs-available-to-project-guest.yml
new file mode 100644
index 00000000000..eb6804c52d3
--- /dev/null
+++ b/changelogs/unreleased/security-refs-available-to-project-guest.yml
@@ -0,0 +1,5 @@
+---
+title: Project guests no longer are able to see refs page
+merge_request:
+author:
+type: security
diff --git a/changelogs/unreleased/security-stored-xss-for-environments.yml b/changelogs/unreleased/security-stored-xss-for-environments.yml
deleted file mode 100644
index 5d78ca00942..00000000000
--- a/changelogs/unreleased/security-stored-xss-for-environments.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fix stored XSS for Environments
-merge_request:
-author:
-type: security
diff --git a/changelogs/unreleased/security-todos_not_redacted_for_guests.yml b/changelogs/unreleased/security-todos_not_redacted_for_guests.yml
new file mode 100644
index 00000000000..be0ae9a7193
--- /dev/null
+++ b/changelogs/unreleased/security-todos_not_redacted_for_guests.yml
@@ -0,0 +1,5 @@
+---
+title: Delete confidential todos for user when downgraded to Guest
+merge_request:
+author:
+type: security
diff --git a/changelogs/unreleased/security-xss-in-markdown-following-unrecognized-html-element.yml b/changelogs/unreleased/security-xss-in-markdown-following-unrecognized-html-element.yml
deleted file mode 100644
index 3bd8123a346..00000000000
--- a/changelogs/unreleased/security-xss-in-markdown-following-unrecognized-html-element.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fix possible XSS attack in Markdown urls with spaces
-merge_request: 2599
-author:
-type: security
diff --git a/changelogs/unreleased/set-kubeconfig-nil-when-token-nil.yml b/changelogs/unreleased/set-kubeconfig-nil-when-token-nil.yml
deleted file mode 100644
index 6eac2a0146c..00000000000
--- a/changelogs/unreleased/set-kubeconfig-nil-when-token-nil.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Make KUBECONFIG nil if KUBE_TOKEN is nil
-merge_request: 23414
-author:
-type: fixed
diff --git a/changelogs/unreleased/sh-53180-append-path.yml b/changelogs/unreleased/sh-53180-append-path.yml
deleted file mode 100644
index 64fae5522d8..00000000000
--- a/changelogs/unreleased/sh-53180-append-path.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Make sure there's only one slash as path separator
-merge_request: 22954
-author:
-type: other
diff --git a/changelogs/unreleased/sh-bump-gems-security.yml b/changelogs/unreleased/sh-bump-gems-security.yml
deleted file mode 100644
index 06489f6f979..00000000000
--- a/changelogs/unreleased/sh-bump-gems-security.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Bump nokogiri, loofah, and rack gems for security updates
-merge_request: 23204
-author:
-type: security
diff --git a/changelogs/unreleased/sh-bump-omniauth-google-gem.yml b/changelogs/unreleased/sh-bump-omniauth-google-gem.yml
new file mode 100644
index 00000000000..2b31a55f8b2
--- /dev/null
+++ b/changelogs/unreleased/sh-bump-omniauth-google-gem.yml
@@ -0,0 +1,5 @@
+---
+title: Upgrade Omniauth and JWT gems to switch away from Google+ API
+merge_request: 24068
+author:
+type: changed
diff --git a/changelogs/unreleased/sh-bump-ruby-2-5-3.yml b/changelogs/unreleased/sh-bump-ruby-2-5-3.yml
deleted file mode 100644
index 13cadc73e9c..00000000000
--- a/changelogs/unreleased/sh-bump-ruby-2-5-3.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Upgrade to Ruby 2.5.3
-merge_request: 2806
-author:
-type: performance
diff --git a/changelogs/unreleased/sh-disable-autocomplete-mirror-settings.yml b/changelogs/unreleased/sh-disable-autocomplete-mirror-settings.yml
deleted file mode 100644
index e42906e88f2..00000000000
--- a/changelogs/unreleased/sh-disable-autocomplete-mirror-settings.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Disable password autocomplete in mirror form fill
-merge_request: 23402
-author:
-type: fixed
diff --git a/changelogs/unreleased/sh-fix-branches-api-timeout.yml b/changelogs/unreleased/sh-fix-branches-api-timeout.yml
new file mode 100644
index 00000000000..8cd29a7269d
--- /dev/null
+++ b/changelogs/unreleased/sh-fix-branches-api-timeout.yml
@@ -0,0 +1,5 @@
+---
+title: Fix timeout issues retrieving branches via API
+merge_request: 24034
+author:
+type: performance
diff --git a/changelogs/unreleased/sh-fix-clone-geo-dropdown.yml b/changelogs/unreleased/sh-fix-clone-geo-dropdown.yml
new file mode 100644
index 00000000000..1c0cbdc3a2c
--- /dev/null
+++ b/changelogs/unreleased/sh-fix-clone-geo-dropdown.yml
@@ -0,0 +1,5 @@
+---
+title: Fix clone dropdown parent inheritance issues in HAML
+merge_request: 24029
+author:
+type: fixed
diff --git a/changelogs/unreleased/sh-fix-http-clone-panel.yml b/changelogs/unreleased/sh-fix-http-clone-panel.yml
new file mode 100644
index 00000000000..ab220bd5076
--- /dev/null
+++ b/changelogs/unreleased/sh-fix-http-clone-panel.yml
@@ -0,0 +1,5 @@
+---
+title: Fix missing Git clone button when protocol restriction setting enabled
+merge_request: 24015
+author:
+type: fixed
diff --git a/changelogs/unreleased/sh-fix-issue-38317.yml b/changelogs/unreleased/sh-fix-issue-38317.yml
deleted file mode 100644
index 13fcb5b8f96..00000000000
--- a/changelogs/unreleased/sh-fix-issue-38317.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Remove needless auto-capitalization on Wiki page titles
-merge_request: 23288
-author:
-type: fixed
diff --git a/changelogs/unreleased/sh-fix-issue-51220.yml b/changelogs/unreleased/sh-fix-issue-51220.yml
deleted file mode 100644
index 048f58611cb..00000000000
--- a/changelogs/unreleased/sh-fix-issue-51220.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Handle force_remove_source_branch when creating merge request
-merge_request: 23281
-author:
-type: fixed
diff --git a/changelogs/unreleased/sh-fix-issue-53783-ce.yml b/changelogs/unreleased/sh-fix-issue-53783-ce.yml
deleted file mode 100644
index 10be1d81768..00000000000
--- a/changelogs/unreleased/sh-fix-issue-53783-ce.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fix enabling project deploy key for admins
-merge_request: 23043
-author:
-type: fixed
diff --git a/changelogs/unreleased/sh-fix-issue-55822.yml b/changelogs/unreleased/sh-fix-issue-55822.yml
new file mode 100644
index 00000000000..1267b2ace2f
--- /dev/null
+++ b/changelogs/unreleased/sh-fix-issue-55822.yml
@@ -0,0 +1,5 @@
+---
+title: Fix commit SHA not showing in merge request compare dropdown
+merge_request: 24084
+author:
+type: fixed
diff --git a/changelogs/unreleased/sh-fix-mirrors-protected-branches.yml b/changelogs/unreleased/sh-fix-mirrors-protected-branches.yml
deleted file mode 100644
index 627de25650d..00000000000
--- a/changelogs/unreleased/sh-fix-mirrors-protected-branches.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fix "protected branches only" checkbox not set properly at init
-merge_request: 23409
-author:
-type: fixed
diff --git a/changelogs/unreleased/sh-handle-invalid-gpg-sig.yml b/changelogs/unreleased/sh-handle-invalid-gpg-sig.yml
deleted file mode 100644
index 185e2547e16..00000000000
--- a/changelogs/unreleased/sh-handle-invalid-gpg-sig.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Gracefully handle unknown/invalid GPG keys
-merge_request: 23492
-author:
-type: fixed
diff --git a/changelogs/unreleased/sh-handle-string-null-bytes.yml b/changelogs/unreleased/sh-handle-string-null-bytes.yml
deleted file mode 100644
index edc045274e3..00000000000
--- a/changelogs/unreleased/sh-handle-string-null-bytes.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Gracefully handle references with null bytes
-merge_request: 23365
-author:
-type: fixed
diff --git a/changelogs/unreleased/sh-ignore-arrays-url-sanitizer.yml b/changelogs/unreleased/sh-ignore-arrays-url-sanitizer.yml
deleted file mode 100644
index c010bd1f540..00000000000
--- a/changelogs/unreleased/sh-ignore-arrays-url-sanitizer.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Only allow strings in URL::Sanitizer.valid?
-merge_request: 23675
-author:
-type: fixed
diff --git a/changelogs/unreleased/sh-json-serialize-broadcast-messages.yml b/changelogs/unreleased/sh-json-serialize-broadcast-messages.yml
deleted file mode 100644
index e8bee64f780..00000000000
--- a/changelogs/unreleased/sh-json-serialize-broadcast-messages.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Avoid caching BroadcastMessage as an ActiveRecord object
-merge_request: 23662
-author:
-type: fixed
diff --git a/changelogs/unreleased/sh-remove-local-sidekiq-admin-check.yml b/changelogs/unreleased/sh-remove-local-sidekiq-admin-check.yml
deleted file mode 100644
index 3ec15908fc7..00000000000
--- a/changelogs/unreleased/sh-remove-local-sidekiq-admin-check.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Remove display of local Sidekiq process in /admin/sidekiq
-merge_request: 23118
-author:
-type: fixed
diff --git a/changelogs/unreleased/sh-truncate-with-periods.yml b/changelogs/unreleased/sh-truncate-with-periods.yml
deleted file mode 100644
index b1c6b4f9cbd..00000000000
--- a/changelogs/unreleased/sh-truncate-with-periods.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Truncate merge request titles with periods instead of ellipsis
-merge_request: 23558
-author:
-type: changed
diff --git a/changelogs/unreleased/sh-use-nakayoshi-fork.yml b/changelogs/unreleased/sh-use-nakayoshi-fork.yml
deleted file mode 100644
index 5977d9b0974..00000000000
--- a/changelogs/unreleased/sh-use-nakayoshi-fork.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Improve memory performance by reducing dirty pages after fork()
-merge_request: 23169
-author:
-type: performance
diff --git a/changelogs/unreleased/sh-use-nokogiri-xml-backend.yml b/changelogs/unreleased/sh-use-nokogiri-xml-backend.yml
deleted file mode 100644
index 6a82e32c416..00000000000
--- a/changelogs/unreleased/sh-use-nokogiri-xml-backend.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Use Nokogiri as the ActiveSupport XML backend
-merge_request: 23136
-author:
-type: performance
diff --git a/changelogs/unreleased/spec-positional-arguments.yml b/changelogs/unreleased/spec-positional-arguments.yml
new file mode 100644
index 00000000000..9dc114e5595
--- /dev/null
+++ b/changelogs/unreleased/spec-positional-arguments.yml
@@ -0,0 +1,5 @@
+---
+title: 'Fix deprecation: Using positional arguments in integration tests'
+merge_request: 24009
+author: Jasper Maes
+type: other
diff --git a/changelogs/unreleased/specs-positional-arguments.yml b/changelogs/unreleased/specs-positional-arguments.yml
new file mode 100644
index 00000000000..38b831bd72c
--- /dev/null
+++ b/changelogs/unreleased/specs-positional-arguments.yml
@@ -0,0 +1,5 @@
+---
+title: convert specs in javascripts/ and support/ to new syntax
+merge_request: 23947
+author: Jasper Maes
+type: other
diff --git a/changelogs/unreleased/speed-up-relative-positioning.yml b/changelogs/unreleased/speed-up-relative-positioning.yml
deleted file mode 100644
index 3bd865fb5de..00000000000
--- a/changelogs/unreleased/speed-up-relative-positioning.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Speed up issue board lists in groups with many projects
-merge_request:
-author:
-type: performance
diff --git a/changelogs/unreleased/store-correlation-logs.yml b/changelogs/unreleased/store-correlation-logs.yml
deleted file mode 100644
index d5f6c789a17..00000000000
--- a/changelogs/unreleased/store-correlation-logs.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Log and pass correlation-id between Unicorn, Sidekiq and Gitaly
-merge_request:
-author:
-type: added
diff --git a/changelogs/unreleased/suggest-change-to-diff-line.yml b/changelogs/unreleased/suggest-change-to-diff-line.yml
deleted file mode 100644
index cb949f14e8c..00000000000
--- a/changelogs/unreleased/suggest-change-to-diff-line.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Add ability to render suggestions
-merge_request: 23147
-author:
-type: added
diff --git a/changelogs/unreleased/support-gitaly-tls.yml b/changelogs/unreleased/support-gitaly-tls.yml
new file mode 100644
index 00000000000..2a15500d6da
--- /dev/null
+++ b/changelogs/unreleased/support-gitaly-tls.yml
@@ -0,0 +1,5 @@
+---
+title: Support tls communication in gitaly
+merge_request: 22602
+author:
+type: added
diff --git a/changelogs/unreleased/switch-rails.yml b/changelogs/unreleased/switch-rails.yml
deleted file mode 100644
index 4edf709dbd4..00000000000
--- a/changelogs/unreleased/switch-rails.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Switch to Rails 5
-merge_request: 21492
-author:
-type: other
diff --git a/changelogs/unreleased/tc-backfill-full-path-config.yml b/changelogs/unreleased/tc-backfill-full-path-config.yml
deleted file mode 100644
index 4f06284d0e3..00000000000
--- a/changelogs/unreleased/tc-backfill-full-path-config.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Migration to write fullpath in all repository configs
-merge_request: 22322
-author:
-type: other
diff --git a/changelogs/unreleased/tc-backfill-hashed-project_repositories.yml b/changelogs/unreleased/tc-backfill-hashed-project_repositories.yml
deleted file mode 100644
index 90a5c8c4e2c..00000000000
--- a/changelogs/unreleased/tc-backfill-hashed-project_repositories.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fill project_repositories for hashed storage projects
-merge_request: 23482
-author:
-type: added
diff --git a/changelogs/unreleased/tc-repo-full-path-in-db.yml b/changelogs/unreleased/tc-repo-full-path-in-db.yml
deleted file mode 100644
index ead8feabeb9..00000000000
--- a/changelogs/unreleased/tc-repo-full-path-in-db.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Add model and relation to store repo full path in database
-merge_request: 23143
-author:
-type: added
diff --git a/changelogs/unreleased/triggermesh-phase2-external-ip.yml b/changelogs/unreleased/triggermesh-phase2-external-ip.yml
deleted file mode 100644
index 582c8f6df2e..00000000000
--- a/changelogs/unreleased/triggermesh-phase2-external-ip.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Add an external IP address to the knative cluster application page
-merge_request:
-author: Chris Baumbauer
-type: fixed
diff --git a/changelogs/unreleased/triggermesh-phase2-knative-description.yml b/changelogs/unreleased/triggermesh-phase2-knative-description.yml
deleted file mode 100644
index c6cee1984d5..00000000000
--- a/changelogs/unreleased/triggermesh-phase2-knative-description.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Modify the wording for the knative cluster application to match upstream
-merge_request: 23289
-author: Chris Baumbauer
-type: fixed
diff --git a/changelogs/unreleased/triggermesh-phase2-serverless-list.yml b/changelogs/unreleased/triggermesh-phase2-serverless-list.yml
deleted file mode 100644
index 22e1a35dd90..00000000000
--- a/changelogs/unreleased/triggermesh-phase2-serverless-list.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Introduce Knative and Serverless Components
-merge_request: 23174
-author: Chris Baumbauer
-type: added
diff --git a/changelogs/unreleased/triggermesh-phase2-serverless.yml b/changelogs/unreleased/triggermesh-phase2-serverless.yml
deleted file mode 100644
index bee2b5e1e2c..00000000000
--- a/changelogs/unreleased/triggermesh-phase2-serverless.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Add knative client to kubeclient library
-merge_request: 22968
-author: cab105
-type: added
diff --git a/changelogs/unreleased/unicorn-monkey-patch.yml b/changelogs/unreleased/unicorn-monkey-patch.yml
deleted file mode 100644
index 6b0e00ca291..00000000000
--- a/changelogs/unreleased/unicorn-monkey-patch.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Add monkey patch to unicorn to fix eof? problem
-merge_request: 23385
-author:
-type: fixed
diff --git a/changelogs/unreleased/update-gitlab-runner-helm-chart-to-0-1-39.yml b/changelogs/unreleased/update-gitlab-runner-helm-chart-to-0-1-39.yml
deleted file mode 100644
index dffcdb0bb5a..00000000000
--- a/changelogs/unreleased/update-gitlab-runner-helm-chart-to-0-1-39.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Update used version of Runner Helm Chart to 0.1.39
-merge_request: 23633
-author:
-type: other
diff --git a/changelogs/unreleased/update-gitlab-runner-helm-chart-to-0-1-43.yml b/changelogs/unreleased/update-gitlab-runner-helm-chart-to-0-1-43.yml
new file mode 100644
index 00000000000..24471b028b1
--- /dev/null
+++ b/changelogs/unreleased/update-gitlab-runner-helm-chart-to-0-1-43.yml
@@ -0,0 +1,5 @@
+---
+title: Update GitLab Runner Helm Chart to 0.1.43
+merge_request: 24083
+author:
+type: other
diff --git a/changelogs/unreleased/update-gitlab-runner-helm-chart-version.yml b/changelogs/unreleased/update-gitlab-runner-helm-chart-version.yml
deleted file mode 100644
index 9051e4f79c8..00000000000
--- a/changelogs/unreleased/update-gitlab-runner-helm-chart-version.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Update used version of Runner Helm Chart to 0.1.38
-merge_request: 23304
-author:
-type: other
diff --git a/changelogs/unreleased/upgrade-to-workhorse-7-6-0.yml b/changelogs/unreleased/upgrade-to-workhorse-7-6-0.yml
deleted file mode 100644
index 1389693b9a9..00000000000
--- a/changelogs/unreleased/upgrade-to-workhorse-7-6-0.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Upgrade workhorse to 7.6.0
-merge_request: 23694
-author:
-type: other
diff --git a/changelogs/unreleased/upgrade_kubeclient_400.yml b/changelogs/unreleased/upgrade_kubeclient_400.yml
deleted file mode 100644
index edb38710e6a..00000000000
--- a/changelogs/unreleased/upgrade_kubeclient_400.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Upgrade kubeclient to 4.0.0
-merge_request: 23261
-author: Praveen Arimbrathodiyil @pravi
-type: other
diff --git a/changelogs/unreleased/usage-count.yml b/changelogs/unreleased/usage-count.yml
deleted file mode 100644
index efff2615ce4..00000000000
--- a/changelogs/unreleased/usage-count.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Use approximate count for big tables for usage statistics.
-merge_request:
-author:
-type: fixed
diff --git a/changelogs/unreleased/validate-foreign-keys-being-indexed.yml b/changelogs/unreleased/validate-foreign-keys-being-indexed.yml
deleted file mode 100644
index 6608a93c08f..00000000000
--- a/changelogs/unreleased/validate-foreign-keys-being-indexed.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Validate foreign keys being created and indexed for column with _id
-merge_request: 22808
-author:
-type: performance
diff --git a/changelogs/unreleased/winh-collapse-discussions.yml b/changelogs/unreleased/winh-collapse-discussions.yml
deleted file mode 100644
index 19d04506318..00000000000
--- a/changelogs/unreleased/winh-collapse-discussions.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fix collapsing discussion replies
-merge_request: 23462
-author:
-type: fixed
diff --git a/changelogs/unreleased/winh-divider-margin.yml b/changelogs/unreleased/winh-divider-margin.yml
deleted file mode 100644
index db84090c15c..00000000000
--- a/changelogs/unreleased/winh-divider-margin.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Adjust divider margin to comply with design specs
-merge_request: 23548
-author:
-type: changed
diff --git a/changelogs/unreleased/winh-dropdown-divider-color.yml b/changelogs/unreleased/winh-dropdown-divider-color.yml
deleted file mode 100644
index 6b6ecd831b8..00000000000
--- a/changelogs/unreleased/winh-dropdown-divider-color.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Change dropdown divider color to gray-200 (#dfdfdf)
-merge_request: 23592
-author:
-type: changed
diff --git a/changelogs/unreleased/winh-dropdown-item-padding.yml b/changelogs/unreleased/winh-dropdown-item-padding.yml
deleted file mode 100644
index 9f18abba9d1..00000000000
--- a/changelogs/unreleased/winh-dropdown-item-padding.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Adjust dropdown item and header padding to comply with design specs
-merge_request: 23552
-author:
-type: changed
diff --git a/changelogs/unreleased/winh-issue-boards-project-dropdown-close.yml b/changelogs/unreleased/winh-issue-boards-project-dropdown-close.yml
deleted file mode 100644
index 18f7da56edb..00000000000
--- a/changelogs/unreleased/winh-issue-boards-project-dropdown-close.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Remove close icon from projects dropdown in issue boards
-merge_request: 23567
-author:
-type: changed
diff --git a/changelogs/unreleased/winh-markdown-preview-lists.yml b/changelogs/unreleased/winh-markdown-preview-lists.yml
deleted file mode 100644
index 6e47726283d..00000000000
--- a/changelogs/unreleased/winh-markdown-preview-lists.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Remove unnecessary div from MarkdownField to apply list styles correctly
-merge_request: 23733
-author:
-type: fixed
diff --git a/changelogs/unreleased/winh-merge-request-commit-context.yml b/changelogs/unreleased/winh-merge-request-commit-context.yml
new file mode 100644
index 00000000000..9e12a926af4
--- /dev/null
+++ b/changelogs/unreleased/winh-merge-request-commit-context.yml
@@ -0,0 +1,5 @@
+---
+title: Display commit ID for discussions made on merge request commits
+merge_request: 23837
+author:
+type: fixed
diff --git a/changelogs/unreleased/winh-merge-request-commit-discussion.yml b/changelogs/unreleased/winh-merge-request-commit-discussion.yml
deleted file mode 100644
index b0c6264369b..00000000000
--- a/changelogs/unreleased/winh-merge-request-commit-discussion.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Display commit ID for commit diff discussion on merge request
-merge_request: 23370
-author:
-type: fixed
diff --git a/changelogs/unreleased/winh-merge-request-diff-discussion-commit-id.yml b/changelogs/unreleased/winh-merge-request-diff-discussion-commit-id.yml
deleted file mode 100644
index 2ce16a2b6b7..00000000000
--- a/changelogs/unreleased/winh-merge-request-diff-discussion-commit-id.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Pass commit when posting diff discussions
-merge_request: 23371
-author:
-type: fixed
diff --git a/changelogs/unreleased/winh-milestone-select.yml b/changelogs/unreleased/winh-milestone-select.yml
deleted file mode 100644
index 8464fc6c541..00000000000
--- a/changelogs/unreleased/winh-milestone-select.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fix milestone select in issue sidebar of issue boards
-merge_request: 23625
-author:
-type: fixed
diff --git a/changelogs/unreleased/winh-resolved-discussions-reply-field.yml b/changelogs/unreleased/winh-resolved-discussions-reply-field.yml
deleted file mode 100644
index 01cf35ae8a7..00000000000
--- a/changelogs/unreleased/winh-resolved-discussions-reply-field.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Display reply field if resolved discussion has no replies
-merge_request: 23801
-author:
-type: fixed
diff --git a/changelogs/unreleased/workhorse-7-3-0.yml b/changelogs/unreleased/workhorse-7-3-0.yml
deleted file mode 100644
index 6708b8a3cbb..00000000000
--- a/changelogs/unreleased/workhorse-7-3-0.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Upgrade GitLab Workhorse to v7.3.0
-merge_request: 23489
-author:
-type: other
diff --git a/changelogs/unreleased/zj-improve-gitaly-pb.yml b/changelogs/unreleased/zj-improve-gitaly-pb.yml
deleted file mode 100644
index 506a0303d8a..00000000000
--- a/changelogs/unreleased/zj-improve-gitaly-pb.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Show what RPC is called in the performance bar
-merge_request: 23140
-author:
-type: other
diff --git a/changelogs/unreleased/zj-pool-repository-creation.yml b/changelogs/unreleased/zj-pool-repository-creation.yml
deleted file mode 100644
index a24b96e4924..00000000000
--- a/changelogs/unreleased/zj-pool-repository-creation.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Allow public forks to be deduplicated
-merge_request: 23508
-author:
-type: added
diff --git a/changelogs/unreleased/zj-remove-broken-storage.yml b/changelogs/unreleased/zj-remove-broken-storage.yml
deleted file mode 100644
index 9df87b40e09..00000000000
--- a/changelogs/unreleased/zj-remove-broken-storage.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Remove obsolete gitlab_shell rake tasks
-merge_request: 22417
-author:
-type: removed
diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example
index 1c16b999e55..7fe85f0e0d7 100644
--- a/config/gitlab.yml.example
+++ b/config/gitlab.yml.example
@@ -612,7 +612,7 @@ production: &base
storages: # You must have at least a `default` storage path.
default:
path: /home/git/repositories/
- gitaly_address: unix:/home/git/gitlab/tmp/sockets/private/gitaly.socket # TCP connections are supported too (e.g. tcp://host:port)
+ gitaly_address: unix:/home/git/gitlab/tmp/sockets/private/gitaly.socket # TCP connections are supported too (e.g. tcp://host:port). TLS connections are also supported using the system certificate pool (eg: tls://host:port).
# gitaly_token: 'special token' # Optional: override global gitaly.token for this storage.
## Backup settings
diff --git a/config/initializers/active_record_avoid_type_casting_in_uniqueness_validator.rb b/config/initializers/active_record_avoid_type_casting_in_uniqueness_validator.rb
index 3e765469995..228ced32188 100644
--- a/config/initializers/active_record_avoid_type_casting_in_uniqueness_validator.rb
+++ b/config/initializers/active_record_avoid_type_casting_in_uniqueness_validator.rb
@@ -20,7 +20,7 @@
#
# This bug was fixed in Rails 5.1 by https://github.com/rails/rails/pull/24745/commits/aa062318c451512035c10898a1af95943b1a3803
-if Rails.version.start_with?("5.1")
+if Rails.gem_version >= Gem::Version.new("5.1")
raise "Remove this monkey patch: #{__FILE__}"
end
diff --git a/config/initializers/active_record_locking.rb b/config/initializers/active_record_locking.rb
index bfe41e6029a..1bd1a12e4b7 100644
--- a/config/initializers/active_record_locking.rb
+++ b/config/initializers/active_record_locking.rb
@@ -1,7 +1,10 @@
# rubocop:disable Lint/RescueException
-# Remove this monkey-patch when all lock_version values are converted from NULLs to zeros.
-# See https://gitlab.com/gitlab-org/gitlab-ce/issues/25228
+# Remove this monkey patch when we move to Rails 5.1, because the bug has been fixed in https://github.com/rails/rails/pull/26050.
+if Rails.gem_version >= Gem::Version.new("5.1")
+ raise "Remove this monkey patch: #{__FILE__}"
+end
+
module ActiveRecord
module Locking
module Optimistic
@@ -16,12 +19,7 @@ module ActiveRecord
return 0 if attribute_names.empty?
lock_col = self.class.locking_column
-
previous_lock_value = send(lock_col).to_i
-
- # This line is added as a patch
- previous_lock_value = nil if previous_lock_value == '0' || previous_lock_value == 0
-
increment_lock
attribute_names += [lock_col]
@@ -32,7 +30,8 @@ module ActiveRecord
affected_rows = relation.where(
self.class.primary_key => id,
- lock_col => previous_lock_value
+ # Patched because when `lock_version` is read as `0`, it may actually be `NULL` in the DB.
+ lock_col => previous_lock_value == 0 ? [nil, 0] : previous_lock_value
).update_all(
attributes_for_update(attribute_names).map do |name|
[name, _read_attribute(name)]
diff --git a/config/initializers/carrierwave_patch.rb b/config/initializers/carrierwave_patch.rb
deleted file mode 100644
index c361784491d..00000000000
--- a/config/initializers/carrierwave_patch.rb
+++ /dev/null
@@ -1,42 +0,0 @@
-# This monkey patches CarrierWave 1.2.3 to make Google Cloud Storage work with
-# extra query parameters:
-# https://github.com/carrierwaveuploader/carrierwave/pull/2332/files
-module CarrierWave
- module Storage
- class Fog < Abstract
- class File
- def authenticated_url(options = {})
- if %w(AWS Google Rackspace OpenStack).include?(@uploader.fog_credentials[:provider])
- # avoid a get by using local references
- local_directory = connection.directories.new(key: @uploader.fog_directory)
- local_file = local_directory.files.new(key: path)
- expire_at = ::Fog::Time.now + @uploader.fog_authenticated_url_expiration
- case @uploader.fog_credentials[:provider]
- when 'AWS', 'Google'
- local_file.url(expire_at, options)
- when 'Rackspace'
- connection.get_object_https_url(@uploader.fog_directory, path, expire_at, options)
- when 'OpenStack'
- connection.get_object_https_url(@uploader.fog_directory, path, expire_at)
- else
- local_file.url(expire_at)
- end
- end
- end
-
- # Fix for https://github.com/carrierwaveuploader/carrierwave/pull/2356
- def acl_header
- if fog_provider == 'AWS'
- { 'x-amz-acl' => @uploader.fog_public ? 'public-read' : 'private' }
- else
- {}
- end
- end
-
- def fog_provider
- @uploader.fog_credentials[:provider].to_s
- end
- end
- end
- end
-end
diff --git a/config/initializers/8_metrics.rb b/config/initializers/zz_metrics.rb
index 468f80939d7..462e8c811a6 100644
--- a/config/initializers/8_metrics.rb
+++ b/config/initializers/zz_metrics.rb
@@ -1,3 +1,6 @@
+# This file was prefixed with zz_ because we want to load it the last!
+# See: https://gitlab.com/gitlab-org/gitlab-ce/issues/55611
+
# Autoload all classes that we want to instrument, and instrument the methods we
# need. This takes the Gitlab::Metrics::Instrumentation module as an argument so
# that we can stub it for testing, as it is only called when metrics are
diff --git a/config/routes/uploads.rb b/config/routes/uploads.rb
index 6becadd57ae..b594f55f8a0 100644
--- a/config/routes/uploads.rb
+++ b/config/routes/uploads.rb
@@ -17,7 +17,8 @@ scope path: :uploads do
# Appearance
get "-/system/:model/:mounted_as/:id/:filename",
to: "uploads#show",
- constraints: { model: /appearance/, mounted_as: /logo|header_logo|favicon/, filename: /.+/ }
+ constraints: { model: /appearance/, mounted_as: /logo|header_logo|favicon/, filename: /.+/ },
+ as: 'appearance_upload'
# Project markdown uploads
get ":namespace_id/:project_id/:secret/:filename",
diff --git a/db/fixtures/development/24_forks.rb b/db/fixtures/development/24_forks.rb
index 61e39c871e6..5eb5956ec74 100644
--- a/db/fixtures/development/24_forks.rb
+++ b/db/fixtures/development/24_forks.rb
@@ -4,6 +4,12 @@ Sidekiq::Testing.inline! do
Gitlab::Seeder.quiet do
User.all.sample(10).each do |user|
source_project = Project.public_only.sample
+
+ ##
+ # 04_project.rb might not have created a public project because
+ # we use randomized approach (e.g. `Array#sample`).
+ return unless source_project
+
fork_project = Projects::ForkService.new(source_project, user, namespace: user.namespace).execute
if fork_project.valid?
diff --git a/db/migrate/20180413022611_create_missing_namespace_for_internal_users.rb b/db/migrate/20180413022611_create_missing_namespace_for_internal_users.rb
index 90d869a8c10..8de8b3bcc2e 100644
--- a/db/migrate/20180413022611_create_missing_namespace_for_internal_users.rb
+++ b/db/migrate/20180413022611_create_missing_namespace_for_internal_users.rb
@@ -46,7 +46,7 @@ class CreateMissingNamespaceForInternalUsers < ActiveRecord::Migration[4.2]
end
insert_query = "INSERT INTO namespaces(owner_id, path, name, created_at, updated_at) VALUES(#{user_id}, '#{path}', '#{path}', NOW(), NOW())"
- namespace_id = connection.insert_sql(insert_query)
+ namespace_id = connection.insert(insert_query)
create_route(namespace_id)
end
diff --git a/db/migrate/20181031145139_add_protected_ci_variables_to_application_settings.rb b/db/migrate/20181031145139_add_protected_ci_variables_to_application_settings.rb
new file mode 100644
index 00000000000..85ee34afe1e
--- /dev/null
+++ b/db/migrate/20181031145139_add_protected_ci_variables_to_application_settings.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+class AddProtectedCiVariablesToApplicationSettings < ActiveRecord::Migration[5.0]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def up
+ add_column_with_default(:application_settings, :protected_ci_variables, :boolean, default: false, allow_null: false)
+ end
+
+ def down
+ remove_column(:application_settings, :protected_ci_variables)
+ end
+end
diff --git a/db/post_migrate/20181219145520_migrate_cluster_configure_worker_sidekiq_queue.rb b/db/post_migrate/20181219145520_migrate_cluster_configure_worker_sidekiq_queue.rb
new file mode 100644
index 00000000000..c37f8c039c0
--- /dev/null
+++ b/db/post_migrate/20181219145520_migrate_cluster_configure_worker_sidekiq_queue.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+class MigrateClusterConfigureWorkerSidekiqQueue < ActiveRecord::Migration[5.0]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ def up
+ sidekiq_queue_migrate 'gcp_cluster:cluster_platform_configure', to: 'gcp_cluster:cluster_configure'
+ end
+
+ def down
+ sidekiq_queue_migrate 'gcp_cluster:cluster_configure', to: 'gcp_cluster:cluster_platform_configure'
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 604ed1cd6b0..0af185409a9 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: 20181218192239) do
+ActiveRecord::Schema.define(version: 20181219145520) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -166,6 +166,7 @@ ActiveRecord::Schema.define(version: 20181218192239) do
t.integer "diff_max_patch_bytes", default: 102400, null: false
t.integer "archive_builds_in_seconds"
t.string "commit_email_hostname"
+ t.boolean "protected_ci_variables", default: false, null: false
t.string "runners_registration_token_encrypted"
t.index ["usage_stats_set_by_user_id"], name: "index_application_settings_on_usage_stats_set_by_user_id", using: :btree
end
diff --git a/doc/administration/gitaly/index.md b/doc/administration/gitaly/index.md
index dc6a71e2ebd..cf37eaa0b61 100644
--- a/doc/administration/gitaly/index.md
+++ b/doc/administration/gitaly/index.md
@@ -1,6 +1,6 @@
# Gitaly
-[Gitaly](https://gitlab.com/gitlab-org/gitaly) is the service that
+[Gitaly](https://gitlab.com/gitlab-org/gitaly) is the service that
provides high-level RPC access to Git repositories. Without it, no other
components can read or write Git data.
@@ -23,7 +23,7 @@ gitaly['prometheus_listen_addr'] = 'localhost:9236'
```
To change a Gitaly setting in installations from source you can edit
-`/home/git/gitaly/config.toml`. Changes will be applied when you run
+`/home/git/gitaly/config.toml`. Changes will be applied when you run
`service gitlab restart`.
```toml
@@ -91,13 +91,13 @@ documentation on configuring Gitaly
authentication](https://gitlab.com/gitlab-org/gitaly/blob/master/doc/configuration/README.md#authentication)
.
-Gitaly must trigger some callbacks to GitLab via GitLab Shell. As a result,
+Gitaly must trigger some callbacks to GitLab via GitLab Shell. As a result,
the GitLab Shell secret must be the same between the other GitLab servers and
the Gitaly server. The easiest way to accomplish this is to copy `/etc/gitlab/gitlab-secrets.json`
from an existing GitLab server to the Gitaly server. Without this shared secret,
-Git operations in GitLab will result in an API error.
+Git operations in GitLab will result in an API error.
-> **NOTE:** In most or all cases the storage paths below end in `/repositories` which is
+> **NOTE:** In most or all cases the storage paths below end in `/repositories` which is
different than `path` in `git_data_dirs` of Omnibus installations. Check the
directory layout on your Gitaly server to be sure.
@@ -133,6 +133,11 @@ gitaly['storage'] = [
{ 'name' => 'default', 'path' => '/mnt/gitlab/default/repositories' },
{ 'name' => 'storage1', 'path' => '/mnt/gitlab/storage1/repositories' },
]
+
+# To use tls for gitaly you need to add
+gitaly['tls_listen_addr'] = "0.0.0.0:9999"
+gitaly['certificate_path'] = "path/to/cert.pem"
+gitaly['key_path'] = "path/to/key.pem"
```
Source installations:
@@ -140,6 +145,11 @@ Source installations:
```toml
# /home/git/gitaly/config.toml
listen_addr = '0.0.0.0:8075'
+tls_listen_addr = '0.0.0.0:9999'
+
+[tls]
+certificate_path = /path/to/cert.pem
+key_path = /path/to/key.pem
[auth]
token = 'abc123secret'
@@ -205,6 +215,70 @@ Gitaly logs on your Gitaly server (`sudo gitlab-ctl tail gitaly` or
coming in. One sure way to trigger a Gitaly request is to clone a
repository from your GitLab server over HTTP.
+## TLS support
+
+Gitaly supports TLS credentials for GRPC authentication. 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.
+
+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)
+
+### Example TLS configuration
+
+### Omnibus installations:
+
+#### On client nodes:
+
+```ruby
+# /etc/gitlab/gitlab.rb
+git_data_dirs({
+ 'default' => { 'path' => '/mnt/gitlab/default', 'gitaly_address' => 'tls://gitaly.internal:9999' },
+ 'storage1' => { 'path' => '/mnt/gitlab/storage1', 'gitaly_address' => 'tls://gitaly.internal:9999' },
+})
+
+gitlab_rails['gitaly_token'] = 'abc123secret'
+```
+
+#### On gitaly server nodes:
+
+```ruby
+gitaly['tls_listen_addr'] = "0.0.0.0:9999"
+gitaly['certificate_path'] = "path/to/cert.pem"
+gitaly['key_path'] = "path/to/key.pem"
+```
+
+### Source installations:
+
+#### On client nodes:
+
+```yaml
+# /home/git/gitlab/config/gitlab.yml
+gitlab:
+ repositories:
+ storages:
+ default:
+ path: /mnt/gitlab/default/repositories
+ gitaly_address: tls://gitaly.internal:9999
+ storage1:
+ path: /mnt/gitlab/storage1/repositories
+ gitaly_address: tls://gitaly.internal:9999
+
+ gitaly:
+ token: 'abc123secret'
+```
+
+#### On gitaly server nodes:
+
+```toml
+# /home/git/gitaly/config.toml
+tls_listen_addr = '0.0.0.0:9999'
+
+[tls]
+certificate_path = '/path/to/cert.pem'
+key_path = '/path/to/key.pem'
+```
+
## Disabling or enabling the Gitaly service in a cluster environment
If you are running Gitaly [as a remote
diff --git a/doc/api/lint.md b/doc/api/lint.md
index bd5a216a99d..c37a8bff749 100644
--- a/doc/api/lint.md
+++ b/doc/api/lint.md
@@ -13,7 +13,7 @@ POST /lint
| `content` | string | yes | the .gitlab-ci.yaml content|
```bash
-curl --header "Content-Type: application/json" https://gitlab.example.com/api/v4/ci/lint --data '{"content": "{ \"image\": \"ruby:2.1\", \"services\": [\"postgres\"], \"before_script\": [\"gem install bundler\", \"bundle install\", \"bundle exec rake db:create\"], \"variables\": {\"DB_NAME\": \"postgres\"}, \"types\": [\"test\", \"deploy\", \"notify\"], \"rspec\": { \"script\": \"rake spec\", \"tags\": [\"ruby\", \"postgres\"], \"only\": [\"branches\"]}}"}'
+curl --header "Content-Type: application/json" https://gitlab.example.com/api/v4/ci/lint --data '{"content": "{ \"image\": \"ruby:2.6\", \"services\": [\"postgres\"], \"before_script\": [\"bundle install\", \"bundle exec rake db:create\"], \"variables\": {\"DB_NAME\": \"postgres\"}, \"types\": [\"test\", \"deploy\", \"notify\"], \"rspec\": { \"script\": \"rake spec\", \"tags\": [\"ruby\", \"postgres\"], \"only\": [\"branches\"]}}"}'
```
Be sure to copy paste the exact contents of `.gitlab-ci.yml` as YAML is very picky about indentation and spaces.
diff --git a/doc/api/templates/gitlab_ci_ymls.md b/doc/api/templates/gitlab_ci_ymls.md
index cecfc8cd9b9..11ec7360e06 100644
--- a/doc/api/templates/gitlab_ci_ymls.md
+++ b/doc/api/templates/gitlab_ci_ymls.md
@@ -120,6 +120,6 @@ Example response:
```json
{
"name": "Ruby",
- "content": "# This file is a template, and might need editing before it works on your project.\n# Official language image. Look for the different tagged releases at:\n# https://hub.docker.com/r/library/ruby/tags/\nimage: \"ruby:2.3\"\n\n# Pick zero or more services to be used on all builds.\n# Only needed when using a docker container to run your tests in.\n# Check out: http://docs.gitlab.com/ce/ci/docker/using_docker_images.html#what-is-service\nservices:\n - mysql:latest\n - redis:latest\n - postgres:latest\n\nvariables:\n POSTGRES_DB: database_name\n\n# Cache gems in between builds\ncache:\n paths:\n - vendor/ruby\n\n# This is a basic example for a gem or script which doesn't use\n# services such as redis or postgres\nbefore_script:\n - ruby -v # Print out ruby version for debugging\n # Uncomment next line if your rails app needs a JS runtime:\n # - apt-get update -q && apt-get install nodejs -yqq\n - gem install bundler --no-ri --no-rdoc # Bundler is not installed with the image\n - bundle install -j $(nproc) --path vendor # Install dependencies into ./vendor/ruby\n\n# Optional - Delete if not using `rubocop`\nrubocop:\n script:\n - rubocop\n\nrspec:\n script:\n - rspec spec\n\nrails:\n variables:\n DATABASE_URL: \"postgresql://postgres:postgres@postgres:5432/$POSTGRES_DB\"\n script:\n - bundle exec rake db:migrate\n - bundle exec rake db:seed\n - bundle exec rake test\n"
+ "content": "# This file is a template, and might need editing before it works on your project.\n# Official language image. Look for the different tagged releases at:\n# https://hub.docker.com/r/library/ruby/tags/\nimage: \"ruby:2.5\"\n\n# Pick zero or more services to be used on all builds.\n# Only needed when using a docker container to run your tests in.\n# Check out: http://docs.gitlab.com/ce/ci/docker/using_docker_images.html#what-is-a-service\nservices:\n - mysql:latest\n - redis:latest\n - postgres:latest\n\nvariables:\n POSTGRES_DB: database_name\n\n# Cache gems in between builds\ncache:\n paths:\n - vendor/ruby\n\n# This is a basic example for a gem or script which doesn't use\n# services such as redis or postgres\nbefore_script:\n - ruby -v # Print out ruby version for debugging\n # Uncomment next line if your rails app needs a JS runtime:\n # - apt-get update -q && apt-get install nodejs -yqq\n - bundle install -j $(nproc) --path vendor # Install dependencies into ./vendor/ruby\n\n# Optional - Delete if not using `rubocop`\nrubocop:\n script:\n - rubocop\n\nrspec:\n script:\n - rspec spec\n\nrails:\n variables:\n DATABASE_URL: \"postgresql://postgres:postgres@postgres:5432/$POSTGRES_DB\"\n script:\n - rails db:migrate\n - rails db:seed\n - rails test\n\n# This deploy job uses a simple deploy flow to Heroku, other providers, e.g. AWS Elastic Beanstalk\n# are supported too: https://github.com/travis-ci/dpl\ndeploy:\n type: deploy\n environment: production\n script:\n - gem install dpl\n - dpl --provider=heroku --app=$HEROKU_APP_NAME --api-key=$HEROKU_PRODUCTION_KEY\n"
}
```
diff --git a/doc/ci/caching/index.md b/doc/ci/caching/index.md
index f93ccc4e3c1..495ec099111 100644
--- a/doc/ci/caching/index.md
+++ b/doc/ci/caching/index.md
@@ -300,7 +300,6 @@ cache:
before_script:
- ruby -v # Print out ruby version for debugging
- - gem install bundler --no-ri --no-rdoc # Bundler is not installed with the image
- bundle install -j $(nproc) --path vendor # Install dependencies into ./vendor/ruby
rspec:
diff --git a/doc/ci/docker/using_kaniko.md b/doc/ci/docker/using_kaniko.md
index 66f0d429165..aa6b387bc58 100644
--- a/doc/ci/docker/using_kaniko.md
+++ b/doc/ci/docker/using_kaniko.md
@@ -57,3 +57,26 @@ build:
only:
- tags
```
+
+## Using a registry with a custom certificate
+
+When trying to push to a Docker registry that uses a certificate that is signed
+by a custom CA, you might get the following error:
+
+```sh
+$ /kaniko/executor --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/Dockerfile --no-push
+INFO[0000] Downloading base image registry.gitlab.example.com/group/docker-image
+error building image: getting stage builder for stage 0: Get https://registry.gitlab.example.com/v2/: x509: certificate signed by unknown authority
+```
+
+This can be solved by adding your CA's certificate to the kaniko certificate
+store:
+
+```yaml
+ before_script:
+ - echo "{\"auths\":{\"$CI_REGISTRY\":{\"username\":\"$CI_REGISTRY_USER\",\"password\":\"$CI_REGISTRY_PASSWORD\"}}}" > /kaniko/.docker/config.json
+ - |
+ echo "-----BEGIN CERTIFICATE-----
+ ...
+ -----END CERTIFICATE-----" >> /kaniko/ssl/certs/ca-certificates.crt
+```
diff --git a/doc/ci/examples/devops_and_game_dev_with_gitlab_ci_cd/index.md b/doc/ci/examples/devops_and_game_dev_with_gitlab_ci_cd/index.md
index cae051daa56..1e2be2e8475 100644
--- a/doc/ci/examples/devops_and_game_dev_with_gitlab_ci_cd/index.md
+++ b/doc/ci/examples/devops_and_game_dev_with_gitlab_ci_cd/index.md
@@ -254,7 +254,7 @@ To ensure our changes don't break the build and all tests still pass, we utilize
Continuous Integration (CI) to run these checks automatically for every push.
Read through this article to understand [Continuous Integration, Continuous Delivery, and Continuous Deployment](https://about.gitlab.com/2016/08/05/continuous-integration-delivery-and-deployment-with-gitlab/),
and how these methods are leveraged by GitLab.
-From the [last tutorial](https://ryanhallcs.wordpress.com/2017/03/15/devops-and-game-dev/) we already have a `gitlab-ci.yml` file set up for building our app from
+From the [last tutorial](https://ryanhallcs.wordpress.com/2017/03/15/devops-and-game-dev/) we already have a `.gitlab-ci.yml` file set up for building our app from
every push. We need to set up a new CI job for testing, which GitLab CI/CD will run after the build job using our generated artifacts from gulp.
Please read through the [documentation on CI/CD configuration](../../../ci/yaml/README.md) file to explore its contents and adjust it to your needs.
diff --git a/doc/ci/quick_start/README.md b/doc/ci/quick_start/README.md
index bdc593493ea..1ec8a8c89c9 100644
--- a/doc/ci/quick_start/README.md
+++ b/doc/ci/quick_start/README.md
@@ -77,7 +77,7 @@ before_script:
- apt-get update -qq && apt-get install -y -qq sqlite3 libsqlite3-dev nodejs
- ruby -v
- which ruby
- - gem install bundler --no-ri --no-rdoc
+ - gem install bundler --no-document
- bundle install --jobs $(nproc) "${FLAGS[@]}"
rspec:
diff --git a/doc/ci/services/mysql.md b/doc/ci/services/mysql.md
index b76f9618fc9..2902c30c7c0 100644
--- a/doc/ci/services/mysql.md
+++ b/doc/ci/services/mysql.md
@@ -16,7 +16,7 @@ services:
- mysql:latest
variables:
- # Configure mysql environment variables (https://hub.docker.com/r/_/mysql/)
+ # Configure mysql environment variables (https://hub.docker.com/_/mysql/)
MYSQL_DATABASE: el_duderino
MYSQL_ROOT_PASSWORD: mysql_strong_password
```
@@ -114,5 +114,5 @@ available [shared runners](../runners/README.md).
Want to hack on it? Simply fork it, commit and push your changes. Within a few
moments the changes will be picked by a public runner and the job will begin.
-[hub-mysql]: https://hub.docker.com/r/_/mysql/
+[hub-mysql]: https://hub.docker.com/_/mysql/
[mysql-example-repo]: https://gitlab.com/gitlab-examples/mysql
diff --git a/doc/ci/yaml/README.md b/doc/ci/yaml/README.md
index 440254e58bd..5d87a5c0a1f 100644
--- a/doc/ci/yaml/README.md
+++ b/doc/ci/yaml/README.md
@@ -1660,7 +1660,7 @@ automatically fetched and evaluated along with the content of `.gitlab-ci.yml`:
before_script:
- apt-get update -qq && apt-get install -y -qq sqlite3 libsqlite3-dev nodejs
- - gem install bundler --no-ri --no-rdoc
+ - gem install bundler --no-document
- bundle install --jobs $(nproc) "${FLAGS[@]}"
```
@@ -2200,6 +2200,12 @@ with an API call.
If your commit message contains `[ci skip]` or `[skip ci]`, using any
capitalization, the commit will be created but the pipeline will be skipped.
+Alternatively, one can pass the `ci.skip` [Git push option][push-option] if
+using Git 2.10 or newer:
+```
+$ git push -o ci.skip
+```
+
## Validate the .gitlab-ci.yml
Each instance of GitLab CI has an embedded debug tool called Lint, which validates the
@@ -2224,3 +2230,4 @@ GitLab CI/CD with various languages.
[environment]: ../environments.md "CI/CD environments"
[schedules]: ../../user/project/pipelines/schedules.md "Pipelines schedules"
[variables]: ../variables/README.md "CI/CD variables"
+[push-option]: https://git-scm.com/docs/git-push#git-push--oltoptiongt
diff --git a/doc/development/contributing/merge_request_workflow.md b/doc/development/contributing/merge_request_workflow.md
index 5b32b5cd46f..6bcee74a3dd 100644
--- a/doc/development/contributing/merge_request_workflow.md
+++ b/doc/development/contributing/merge_request_workflow.md
@@ -179,7 +179,6 @@ merge request:
1. Note the addition in the release blog post (create one if it doesn't exist yet) https://gitlab.com/gitlab-com/www-gitlab-com/merge_requests/
1. Upgrade guide, for example https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/update/7.5-to-7.6.md
-1. Upgrader https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/update/upgrader.md#2-run-gitlab-upgrade-tool
1. Installation guide https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/install/installation.md#1-packages-dependencies
1. GitLab Development Kit https://gitlab.com/gitlab-org/gitlab-development-kit
1. Test suite https://gitlab.com/gitlab-org/gitlab-ce/blob/master/scripts/prepare_build.sh
diff --git a/doc/development/documentation/feature-change-workflow.md b/doc/development/documentation/feature-change-workflow.md
new file mode 100644
index 00000000000..b5b325683a3
--- /dev/null
+++ b/doc/development/documentation/feature-change-workflow.md
@@ -0,0 +1,112 @@
+---
+description: How to add docs for new or enhanced GitLab features.
+---
+
+# Documentation process at GitLab
+
+At GitLab, developers contribute new or updated documentation along with their code, but product managers and technical writers also have essential roles in the process.
+
+- **Developers**: Author/update documentation in the same MR as their code, and
+merge it by the feature freeze for the assigned milestone. Request technical writer
+assistance if needed.
+- **Product Managers** (PMs): In the issue for all new and enhanced features,
+confirm the documentation requirements, plus the mentioned feature description
+and use cases, which can be reused in docs. They can bring in a technical
+writer for discussion or help, and can be called upon themselves as a doc reviewer.
+- **Technical Writers**: Review doc requirements in issues, track issues and MRs
+that contain docs changes, help with any questions throughout the authoring/editing process,
+and review all new and updated docs content after it's merged (unless a pre-merge
+review request is made).
+
+Beyond this process, any member of the GitLab community can also author documentation
+improvements that are not associated with a new or changed feature. See the [Documentation improvement workflow](improvement-workflow.md).
+
+## When documentation is required
+
+Documentation must be delivered whenever:
+
+- A new or enhanced feature is shipped that impacts the user/admin experience
+- There are changes to the UI or API
+- A process, workflow, or previously documented feature is changed
+- A feature is deprecated or removed
+
+Documentation is not required when a feature is changed on the backend
+only and does not directly affect the way that any user or
+administrator would interact with GitLab. For example, a UI restyling that offers
+no difference in functionality may require documentation updates if screenshots
+are now needed, or need to be updated.
+
+NOTE: **Note:**
+When revamping documentation, if unrelated to the feature change, this should be submitted
+in its own MR (using the [documentation improvement workflow](improvement-workflow.md))
+so that we can ensure the more time-sensitive doc updates are merged with code by the freeze.
+
+## Documenting a new or changed feature
+
+To follow a consistent workflow every month, documentation changes
+involve the Product Managers, the developer who shipped the feature,
+and the Technical Writing team. Each role is described below.
+
+### 1. Product Manager's role
+
+The Product Manager (PM) should confirm or add the following items in the issue:
+
+- New or updated feature name, overview/description, and use cases, all required per the [Documentation structure and template](structure.md).
+- The documentation requirements for the developer working on the docs.
+ - What new page, new subsection of an existing page, or other update to an existing page/subsection is needed.
+ - Just one page/section/update or multiple (perhaps there's an end user and admin change needing docs, or we need to update a previously recommended workflow, or we want to link the new feature from various places; consider and mention all ways documentation should be affected.
+ - Suggested title of any page or subsection, if applicable.
+- Label the issue with `Documentation` and `docs:P1` in addition to the `Deliverable` label and correct milestone.
+
+Anyone is welcome to draft the items above in the issue, but a product manager must review and update them whenever the issue is assigned a specific milestone.
+
+### 2. Developer's role
+
+As a developer, you must ship the documentation with the code of the feature that
+you are creating or updating. The documentation is an essential part of the product.
+
+- New and edited docs should be included in the MR introducing the code, and planned
+in the issue that proposed the feature. However, if the new or changed doc requires
+extensive collaboration or conversation, a separate, linked issue can be used for the planning process.
+- Use the [Documentation guidelines](index.md), as well as other resources linked from there,
+including the [Structure and template](structure.md) page, [Style Guide](styleguide.md), and [Markdown Guide](https://about.gitlab.com/handbook/product/technical-writing/markdown-guide/).
+- If you need any help to choose the correct place for a doc, discuss a documentation
+idea or outline, or request any other help, ping the Technical Writer for the relevant
+[DevOps stage](https://about.gitlab.com/handbook/product/categories/#devops-stages)
+in your issue or MR, or write within `#docs` on the GitLab Slack.
+- The docs must be merged with the code **by the feature freeze date**, otherwise
+- the feature cannot be included with the release.<!-- TODO: Policy/process for feature-flagged issues -->
+
+Prior to merge, documentation changes commited by the developer must be reviewed by:
+* the person reviewing the code and merging the MR.
+* optionally: others involved in the work (such as other devs, the PM, or a technical writer), if requested.
+
+After merging, documentation changing are reviewed by:
+* a technical writer (for clarity, structure, grammar, etc).
+* optionally: by the PM (for accuracy and to ensure it's consistent with the vision for how the product will be used).
+Any party can raise the item to the PM for review at any point: the dev, the technical writer, or the PM, who can request/plan a review at the outset.
+
+### 3. Technical Writer's role
+
+**Planning**
+- Once an issue contains a Documentation label and an upcoming milestone, a
+technical writer reviews the listed documentation requirements, which should have
+already been reviewed by the PM. (These are non-blocking reviews; developers should
+not wait to work on docs.)
+- Monitor the documentation needs of issues assigned to the current and next milestone,
+and participate in any needed discussion on docs planning with the dev, PM, and others.
+
+**Review**
+- Techncial writers provide non-blocking reviews of all documentation changes,
+typically after the change is merged. However, if the docs are ready in the MR while
+we are awaiting other work in order to merge, the technical writer's review can commence early.
+- The technical writer will confirm that the doc is clear, grammatically correct,
+and discoverable, while avoiding redundancy, bad file locations, typos, broken links,
+etc. The technical writer will review the documentation for the following, which
+the developer and code reviewer should have already made a good-faith effort to ensure:
+ - Clarity.
+ - Relevance (make sure the content is appropriate given the impact of the feature).
+ - Location (make sure the doc is in the correct dir and has the correct name).
+ - Syntax, typos, and broken links.
+ - Improvements to the content.
+ - Accordance to the [Documentation Style Guide](styleguide.md) and [structure/template](structure.md).
diff --git a/doc/development/documentation/improvement-workflow.md b/doc/development/documentation/improvement-workflow.md
new file mode 100644
index 00000000000..ef6392c6f7f
--- /dev/null
+++ b/doc/development/documentation/improvement-workflow.md
@@ -0,0 +1,49 @@
+---
+description: How to improve GitLab's documentation.
+---
+
+# Documentation improvement workflow
+
+Anyone can contribute a merge request or create an issue for GitLab's documentation.
+
+This page covers the process for any contributions to GitLab's docs that are
+not part of feature development. If you are looking for information on updating
+GitLab's docs as is required with the development and release of a new feature
+or feature enhancement, see the [feature-change documentation workflow](feature-change-workflow.md).
+
+## Who updates the docs
+
+Anyone can contribute! You can create a merge request with documentation
+when you find errors or other room for improvement in an existing doc, or when you
+have an idea for all-new documentation that would help a GitLab user or admin
+to achieve or improve their DevOps workflows.
+
+## How to update the docs
+
+- Follow the described standards and processes listed on the [GitLab Documentation guidelines](index.md) page,
+including linked resources: the [Structure and template](structure.md) page, [Style Guide](styleguide.md), and [Markdown Guide](https://about.gitlab.com/handbook/product/technical-writing/markdown-guide/).
+- Follow GitLab's [Merge Request Guidelines](../contributing/merge_request_workflow.md#merge-request-guidelines).
+- If you need any help to choose the correct place for a doc, discuss a documentation
+idea or outline, or request any other help, ping the Technical Writer for the relevant
+[DevOps stage](https://about.gitlab.com/handbook/product/categories/#devops-stages)
+in your issue or MR, or write within `#docs` if you are a member of GitLab's Slack workspace.
+
+## Merging
+
+Anyone with master access to the affected GitLab project can merge documentation changes.
+This person must make a good-faith effort to ensure that the content is clear
+(sufficiently easy for the intended audience to navigate and understand) and
+that it meets the [Documentation Guidelines](index.md) and [Style Guide](styleguide.md).
+
+If the author or reviewer has any questions, or would like a techncial writer's review
+before merging, mention the writer who is assigned to the relevant [DevOps stage](https://about.gitlab.com/handbook/product/categories/#devops-stages).
+
+## Technical Writer review
+
+The technical writing team reviews changes after they are merged, unless a prior
+review is requested.
+
+## Other ways to help
+
+If you have ideas for further documentation resources that would be best
+considered/handled by technical writers, devs, and other SMEs, please create an issue.
diff --git a/doc/development/documentation/index.md b/doc/development/documentation/index.md
index 4e5b4a85a97..256e0476c2f 100644
--- a/doc/development/documentation/index.md
+++ b/doc/development/documentation/index.md
@@ -4,48 +4,49 @@ description: Learn how to contribute to GitLab Documentation.
# GitLab Documentation guidelines
-- **General Documentation**: written by the [developers responsible by creating features](#contributing-to-docs). Should be submitted in the same merge request containing code. Feature proposals (by GitLab contributors) should also be accompanied by its respective documentation. They can be later improved by PMs and Technical Writers.
-- **[Technical Articles](#technical-articles)**: written by any [GitLab Team](https://about.gitlab.com/team/) member, GitLab contributors, or [Community Writers](https://about.gitlab.com/handbook/product/technical-writing/community-writers/).
-- **Indexes per topic**: initially prepared by the Technical Writing Team, and kept up-to-date by developers and PMs in the same merge request containing code. They gather all resources for that topic in a single page (user and admin documentation, articles, and third-party docs).
+GitLab's documentation is [intended as the single source of truth (SSOT)](https://about.gitab.com/handbook/documentation/) for information about how to configure, use, and troubleshoot GitLab. The documentation contains use cases and usage instructions covering every GitLab feature, organized by product area and subject. This includes topics and workflows that span multiple GitLab features, as well as the use of GitLab with other applications.
-## Contributing to docs
+In addition to this page, the following resources to help craft and contribute documentation are available:
+
+- [Style Guide](styleguide.md) - What belongs in the docs, language guidelines, and more.
+- [Structure and template](structure.md) - Learn the typical parts of a doc page and how to write each one.
+- [Workflow](workflow.md) - A landing page for our key workflows:
+ - [Feature-change documentation workflow](feature-change-workflow.md) - Adding required documentation when developing a GitLab feature.
+ - [Documentation improvement worflow](improvement-workflow.md) - New content not associated with a new feature.
+- [Markdown Guide](https://about.gitlab.com/handbook/product/technical-writing/markdown-guide/) - A reference for the markdown implementation used by GitLab's documentation site and about.gitlab.com.
+- [Site architecture](/doc/development/documentation/site_architecture/index.md) - How docs.gitlab.com is built.
+
+## Source and rendered locations
-Whenever a feature is changed, updated, introduced, or deprecated, the merge
-request introducing these changes must be accompanied by the documentation
-(either updating existing ones or creating new ones). This is also valid when
-changes are introduced to the UI.
+Documentation for GitLab Community Edition (CE) and Enterprise Edition (EE), along with GitLab Runner and Omnibus, is published to [docs.gitlab.com](https://docs.gitlab.com). The documentation for CE and EE is also published within the application at `/help` on the domain of the GitLab instance.
-The one responsible for writing the first piece of documentation is the developer who
-wrote the code. It's the job of the Product Manager to ensure all features are
-shipped with its docs, whether is a small or big change. At the pace GitLab evolves,
-this is the only way to keep the docs up-to-date. If you have any questions about it,
-ask a Technical Writer. Otherwise, when your content is ready, assign one of
-them to review it for you.
+At `/help`, only content for your current edition and version is included, whereas multiple versions' content is available at docs.gitlab.com.
-We use the [monthly release blog post](https://about.gitlab.com/handbook/marketing/blog/release-posts/#monthly-releases) as a changelog checklist to ensure everything
-is documented.
+The source of the documentation is maintained in the following repository locations:
-Whenever you submit a merge request for the documentation, use the
-"Documentation" MR description template. If you're changing documentation
-location, use the MR description template called "Change documentation
-location" instead.
+| Project | Path |
+| --- | --- |
+| [GitLab Community Edition](https://gitlab.com/gitlab-org/gitlab-ce/) | [`/doc`](https://gitlab.com/gitlab-org/gitlab-ce/tree/master/doc) |
+| [GitLab Enterprise Edition](https://gitlab.com/gitlab-org/gitlab-ce/) | [`/doc`](https://gitlab.com/gitlab-org/gitlab-ee/tree/master/doc) |
+| [GitLab Runner](https://gitlab.com/gitlab-org/gitlab-runner/) | [`/docs`](https://gitlab.com/gitlab-org/gitlab-runner/tree/master/docs) |
+| [Omnibus GitLab](https://gitlab.com/gitlab-org/omnibus-gitlab/) | [`/doc`](https://gitlab.com/gitlab-org/gitlab-ee/tree/master/doc) |
-## Documentation workflow
+Documentation issues and merge requests are part of their respective repositories and all have the label `Documentation`.
-Please read through the [documentation workflow](workflow.md) before getting started.
+## Contributing to docs
+
+[Contributions to GitLab docs](workflow.md) are welcome from the entire GitLab community.
-## Documentation structure
+To ensure that GitLab docs keep up with changes to the product, special processes and responsibilities are in place concerning all [feature changes](feature-change-workflow.md)—i.e. development work that impacts the appearance, usage, or administration of a feature.
-Follow through the [documentation structure guide](structure.md) for learning
-how to structure GitLab docs.
+Meanwhile, anyone can contribute [documentation improvements](improvement-workflow.md) large or small that are not associated with a feature change. For example, adding a new doc on how to accomplish a use case that's already possible with GitLab or with third-party tools and GitLab.
## Markdown and styles
[GitLab docs](https://gitlab.com/gitlab-com/gitlab-docs) uses [GitLab Kramdown](https://gitlab.com/gitlab-org/gitlab_kramdown)
-as markdown engine. Check the [GitLab Markdown Kramdown Guide](https://about.gitlab.com/handbook/product/technical-writing/markdown-guide/)
-for a complete Kramdown reference.
+as its markdown rendering engine. See the [GitLab Markdown Guide](https://about.gitlab.com/handbook/product/technical-writing/markdown-guide/) for a complete Kramdown reference.
-Follow the [documentation style guidelines](styleguide.md) strictly.
+Adhere to the [Documentation Style Guide](styleguide.md). If a style standard is missing, you are welcome to suggest one via a merge request.
## Documentation directory structure
@@ -58,7 +59,7 @@ all docs should be linked. Every new document should be cross-linked to its rela
The directories `/workflow/`, `/gitlab-basics/`, `/university/`, and `/articles/` have
been **deprecated** and the majority their docs have been moved to their correct location
-in small iterations. Please don't create new docs in these folders.
+in small iterations. Please do not create new docs in these folders. Organize docs by product area and subject, not type.
### Documentation files
@@ -71,18 +72,23 @@ in small iterations. Please don't create new docs in these folders.
### Location and naming documents
-The documentation hierarchy can be vastly improved by providing a better layout
-and organization of directories.
-
-Having a structured document layout, we will be able to have meaningful URLs
-like `docs.gitlab.com/user/project/merge_requests/index.html`. With this pattern,
-you can immediately tell that you are navigating a user related documentation
-and is about the project and its merge requests.
-
-Do not create summaries of similar types of content (e.g. an index of all articles, videos, etc.),
-rather organize content by its subject (e.g. everything related to CI goes together)
+Our goal is to have a clear hierarchical structure with meaningful URLs
+like `docs.gitlab.com/user/project/merge_requests/`. With this pattern,
+you can immediately tell that you are navigating to user-related documentation
+about project features; specifically about merge requests. Our site's paths match
+those of our repository, so the clear structure also makes documentation easier to update.
+
+While the documentation is home to a variety of content types, we do not organize by content type.
+For example, do not create groupings of similar media types (e.g. indexes of all articles, videos, etc.).
+Similarly, we do not use glossaries or FAQs. Such grouping of content by type makes
+it difficult to browse for the information you need and difficult to maintain up-to-date content.
+Instead, organize content by its subject (e.g. everything related to CI goes together)
and cross-link between any related content.
+Do not simply link out to GitLab technical blog posts. There should be an up-to-date
+single source of truth on the topic within the documentation, and the top of the
+blog post should be updated to link to that doc.
+
The table below shows what kind of documentation goes where.
| Directory | What belongs here |
@@ -90,14 +96,12 @@ The table below shows what kind of documentation goes where.
| `doc/user/` | User related documentation. Anything that can be done within the GitLab UI goes here including `/admin`. |
| `doc/administration/` | Documentation that requires the user to have access to the server where GitLab is installed. The admin settings that can be accessed via GitLab's interface go under `doc/user/admin_area/`. |
| `doc/api/` | API related documentation. |
-| `doc/development/` | Documentation related to the development of GitLab. Any styleguides should go here. |
+| `doc/development/` | Documentation related to the development of GitLab. Related process and style guides should go here. |
| `doc/legal/` | Legal documents about contributing to GitLab. |
| `doc/install/` | Probably the most visited directory, since `installation.md` is there. Ideally this should go under `doc/administration/`, but it's best to leave it as-is in order to avoid confusion (still debated though). |
| `doc/update/` | Same with `doc/install/`. Should be under `administration/`, but this is a well known location, better leave as-is, at least for now. |
| `doc/topics/` | Indexes per Topic (`doc/topics/topic-name/index.md`): all resources for that topic (user and admin documentation, articles, and third-party docs) |
----
-
**General rules & best practices:**
1. When creating a new document and it has more than one word in its name,
@@ -126,18 +130,23 @@ 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.
-If you are unsure where a document should live, you can ping `@axil` or `@marcia` in your
-merge request.
+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
+changes, regardless, and can move content if there is a better place for it.
### Changing document location
-Changing a document's location is not to be taken lightly. Remember that the
-documentation is available to all installations under `help/` and not only to
-GitLab.com or <http://docs.gitlab.com>. Make sure this is discussed with the
-Documentation team beforehand.
+Changing a document's location requires specific steps to be followed to ensure that
+users can seamlessly access the new doc page, whether they are accesing content
+on a GitLab instance domain at `/help` or at docs.gitlab.com. Be sure to ping a
+GitLab technical writer if you have any questions during the process (such as
+whether the move is necessary), and ensure that a technical writer reviews this
+change prior to merging.
-If you indeed need to change a document's location, do NOT remove the old
-document, but rather replace all of its contents with a new line:
+If you indeed need to change a document's location, do not remove the old
+document, but rather replace all of its content with a new line:
```md
This document was moved to [another location](path/to/new_doc.md).
@@ -175,6 +184,7 @@ Things to note:
- Since we also use inline documentation, except for the documentation itself,
the document might also be referenced in the views of GitLab (`app/`) which will
render when visiting `/help`, and sometimes in the testing suite (`spec/`).
+ You must search these paths for references to the doc and update them as well.
- The above `git grep` command will search recursively in the directory you run
it in for `workflow/lfs/lfs_administration` and `lfs/lfs_administration`
and will print the file and the line where this file is mentioned.
@@ -202,7 +212,7 @@ This redirection method will not provide a redirect fallback on GitLab `/help`.
it, make sure to add a link to the new page on the doc, otherwise it's a dead end for users that
land on the doc via `/help`.
-### Redirections for pages with Disqus comments
+#### Redirections for pages with Disqus comments
If the documentation page being relocated already has any Disqus comments,
we need to preserve the Disqus thread.
@@ -240,20 +250,26 @@ choices:
| Ending in `-docs` | `123-update-api-issues-docs` |
If your branch name matches any of the above, it will run only the docs
-tests. If it doesn't, the whole test suite will run (including docs).
+tests. If it does not, the whole application test suite will run (including docs tests).
## Merge requests for GitLab documentation
Before getting started, make sure you read the introductory section
"[contributing to docs](#contributing-to-docs)" above and the
-[tech writing workflow](https://about.gitlab.com/handbook/product/technical-writing/workflow/)
-for GitLab Team members.
+[documentation workflow](workflow.md).
- Use the current [merge request description template](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/.gitlab/merge_request_templates/Documentation.md)
- Use the correct [branch name](#branch-naming)
- Label the MR `Documentation`
- Assign the correct milestone (see note below)
+Documentation will be merged if it is an improvement on existing content,
+represents a good-faith effort to follow the template and style standards,
+and is believed to be accurate.
+
+Further needs for what would make the doc even better should be immediately addressed
+in a follow-up MR or issue.
+
NOTE: **Note:**
If the release version you want to add the documentation to has already been
frozen or released, use the label `Pick into X.Y` to get it merged into
@@ -380,80 +396,14 @@ to merge changes that will break `master` from a merge request with a successful
## Docs site architecture
-Read through [docs architecture](site_architecture/index.md) to learn
-how we architecture, build, and deploy the docs site, <https://docs.gitlab.com>, and
-to check all the assets and libraries available.
+See the [Docs site architecture](site_architecture/index.md) page to learn
+how we build and deploy the site at [docs.gitlab.com](https://docs.gitlab.com), and
+to review all the assets and libraries in use.
### Global navigation
-Read through the [global navigation](site_architecture/global_nav.md) doc.
-
-## General Documentation vs Technical Articles
-
-### General documentation
-
-General documentation is categorized by _User_, _Admin_, and _Contributor_, and describe what that feature is, what it does, and its available settings.
-
-### Technical Articles
-
-Technical articles replace technical content that once lived in the [GitLab Blog](https://about.gitlab.com/blog/), where they got out-of-date and weren't easily found.
-
-They are topic-related documentation, written with an user-friendly approach and language, aiming to provide the community with guidance on specific processes to achieve certain objectives.
-
-A technical article guides users and/or admins to achieve certain objectives (within guides and tutorials), or provide an overview of that particular topic or feature (within technical overviews). It can also describe the use, implementation, or integration of third-party tools with GitLab.
-
-They should be placed in a new directory named `/article-title/index.md` under a topic-related folder, and their images should be placed in `/article-title/img/`. For example, a new article on GitLab Pages should be placed in `doc/user/project/pages/article-title/` and a new article on GitLab CI/CD should be placed in `doc/ci/examples/article-title/`.
-
-#### Types of Technical Articles
-
-- **User guides**: technical content to guide regular users from point A to point B
-- **Admin guides**: technical content to guide administrators of GitLab instances from point A to point B
-- **Technical Overviews**: technical content describing features, solutions, and third-party integrations
-- **Tutorials**: technical content provided step-by-step on how to do things, or how to reach specific objectives
-
-#### Understanding guides, tutorials, and technical overviews
-
-Suppose there's a process to go from point A to point B in 5 steps: `(A) 1 > 2 > 3 > 4 > 5 (B)`.
-
-A **guide** can be understood as a description of certain processes to achieve a particular objective. A guide brings you from A to B describing the characteristics of that process, but not necessarily going over each step. It can mention, for example, steps 2 and 3, but does not necessarily explain how to accomplish them.
-
-- Live example: "[Static sites and GitLab Pages domains (Part 1)](../../user/project/pages/getting_started_part_one.md) to [Creating and Tweaking GitLab CI/CD for GitLab Pages (Part 4)](../../user/project/pages/getting_started_part_four.md)"
-
-A **tutorial** requires a clear **step-by-step** guidance to achieve a singular objective. It brings you from A to B, describing precisely all the necessary steps involved in that process, showing each of the 5 steps to go from A to B.
-It does not only describes steps 2 and 3, but also shows you how to accomplish them.
-
-- Live example (on the blog): [Hosting on GitLab.com with GitLab Pages](https://about.gitlab.com/2016/04/07/gitlab-pages-setup/)
-
-A **technical overview** is a description of what a certain feature is, and what it does, but does not walk
-through the process of how to use it systematically.
-
-- Live example (on the blog): [GitLab Workflow, an overview](https://about.gitlab.com/2016/10/25/gitlab-workflow-an-overview/)
-
-#### Special format
-
-Every **Technical Article** contains a frontmatter at the beginning of the doc
-with the following information:
-
-- **Type of article** (user guide, admin guide, technical overview, tutorial)
-- **Knowledge level** expected from the reader to be able to follow through (beginner, intermediate, advanced)
-- **Author's name** and **GitLab.com handle**
-- **Publication date** (ISO format YYYY-MM-DD)
-
-For example:
-
-```yaml
----
-author: John Doe
-author_gitlab: johnDoe
-level: beginner
-article_type: user guide
-date: 2017-02-01
----
-```
-
-#### Technical Articles - Writing Method
-
-Use the [writing method](https://about.gitlab.com/handbook/product/technical-writing/#writing-method) defined by the Technical Writing team.
+See the [Global navigation](site_architecture/global_nav.md) doc for information
+on how the left-side navigation menu is built and updated.
## Previewing the changes live
@@ -468,13 +418,13 @@ The live preview is currently enabled for the following projects:
- <https://gitlab.com/gitlab-org/gitlab-runner>
If your branch contains only documentation changes, you can use
-[special branch names](#branch-naming) to avoid long running pipelines.
+[special branch names](#branch-naming) to avoid long-running pipelines.
For [docs-only changes](#branch-naming), the review app is run automatically.
For all other branches, you can use the manual `review-docs-deploy-manual` job
in your merge request. You will need at least Maintainer permissions to be able
-to run it. In the mini pipeline graph, you should see an `>>` icon. Clicking on it will
-reveal the `review-docs-deploy-manual` job. Hit the play button for the job to start.
+to run it. In the mini pipeline graph, you should see a `>>` icon. Clicking it will
+reveal the `review-docs-deploy-manual` job. Click the play button to start the job.
![Manual trigger a docs build](img/manual_build_docs.png)
@@ -630,9 +580,10 @@ A file with `proselint` configuration must be placed in a
#### `markdownlint`
`markdownlint` checks that certain rules ([example](https://github.com/DavidAnson/markdownlint/blob/master/README.md#rules--aliases))
- are followed for Markdown syntax. Our [style guidelines](styleguide.md) elaborate on which choices
- must be made when selecting Markdown syntax for GitLab documentation and this tool helps
- catch deviations from those guidelines.
+ are followed for Markdown syntax.
+ Our [Documentation Style Guide](styleguide.md) and [Markdown Guide](https://about.gitlab.com/handbook/product/technical-writing/markdown-guide/)
+ elaborate on which choices must be made when selecting Markdown syntax for
+ GitLab documentation. This tool helps catch deviations from those guidelines.
`markdownlint` can be used [on the command line](https://github.com/igorshubovych/markdownlint-cli#markdownlint-cli--),
either on a single Markdown file or on all Markdown files in a project. For example, to run
@@ -655,7 +606,7 @@ markdownlint **/*.md
The following sample `markdownlint` configuration modifies the available default rules to:
-- Adhere to the [style guidelines](styleguide.md).
+- Adhere to the [Documentation Style Guide](styleguide.md).
- Apply conventions found in the GitLab documentation.
- Allow the flexibility of using some inline HTML.
@@ -694,9 +645,10 @@ For [`markdownlint`](https://github.com/DavidAnson/markdownlint/), this configur
placed in a [valid location](https://github.com/igorshubovych/markdownlint-cli#configuration). For
example, `~/.markdownlintrc`.
-## Danger bot
+## Danger Bot
-GitLab uses [danger bot](https://github.com/danger/danger) for some elements in
-code review. For docs changes in merge requests, whenever a change under `/doc`
-is made, the bot leaves a comment for the author to mention `@gl-docsteam`, so
-that the docs can be properly reviewed.
+GitLab uses [Danger](https://github.com/danger/danger) for some elements in
+code review. For docs changes in merge requests, whenever a change to files under `/doc`
+is made, Danger Bot leaves a comment with further instructions about the documentation
+process. This is configured in the Dangerfile in the GitLab CE and EE repo under
+[/danger/documentation/](https://gitlab.com/gitlab-org/gitlab-ce/tree/master/danger/documentation).
diff --git a/doc/development/documentation/site_architecture/index.md b/doc/development/documentation/site_architecture/index.md
index 956bf90a5d9..9d4d2d3a28b 100644
--- a/doc/development/documentation/site_architecture/index.md
+++ b/doc/development/documentation/site_architecture/index.md
@@ -2,11 +2,18 @@
description: "Learn how GitLab's documentation website is architectured."
---
-# Docs site architecture
+# Documentation site architecture
Learn how we build and architecture [`gitlab-docs`](https://gitlab.com/gitlab-com/gitlab-docs)
and deploy it to <https://docs.gitlab.com>.
+## Repository
+
+While the source of the documentation content is stored in GitLab's respective product
+repositories, the source that is used to build the documentation site _from that content_
+is located at https://gitlab.com/gitlab-com/gitlab-docs. See the README there for
+detailed information.
+
## Assets
To provide an optimized site structure, design, and a search-engine friendly
diff --git a/doc/development/documentation/structure.md b/doc/development/documentation/structure.md
index 607ad21d459..ee3bd5606a5 100644
--- a/doc/development/documentation/structure.md
+++ b/doc/development/documentation/structure.md
@@ -1,147 +1,121 @@
---
-description: Learn the how to correctly structure GitLab documentation.
+description: What to include in GitLab documentation pages.
---
-# Documentation structure
+# Documentation structure and template
-For consistency throughout the documentation, it's important to maintain the same
-structure among the docs.
+This document will help you determine how to structure a page within GitLab's
+documentation and what content to include. These standards help ensure consistency
+and completeness throughout the documentation, and they make it easier to contribute.
-Before getting started, read through the following docs:
+Before getting started, familiarize yourself with [GitLab's Documentation guidelines](index.md)
+and the section on Content in the [Style Guide](styleguide.md).
-- [Contributing to GitLab documentation](index.md#contributing-to-docs)
-- [Merge requests for GitLab documentation](index.md#merge-requests-for-gitlab-documentation)
-- [Branch naming for docs-only changes](index.md#branch-naming)
-- [Documentation directory structure](index.md#documentation-directory-structure)
-- [Documentation style guidelines](styleguide.md)
-- [Documentation workflow](workflow.md)
+## Components of a documentation page
-## Documentation blurb
+Most pages will be dedicated to a specifig GitLab feature or to a use case that involves
+one or more features, potentially in conjunction with third-party tools.
-Every document should include the following content in the following sequence:
+Every feature or use case document should include the following content in the following sequence,
+with exceptions and details noted below and in the template included on this page.
-- **Feature name**: defines an intuitive name for the feature that clearly
- states what it is and is consistent with any relevant UI text.
-- **Feature overview** and description: describe what it is, what it does, and in what context it should be used.
-- **Use cases**: describes real use case scenarios for that feature.
-- **Requirements**: describes what software and/or configuration is required to be able to
- use the feature and, if applicable, prerequisite knowledge for being able to follow/implement the tutorial.
- For example, familiarity with GitLab CI/CD, an account on a third-party service, dependencies installed, etc.
- Link each one to its most relevant resource; i.e., where the reader can go to begin to fullfil that requirement.
- (Another doc page, a third party application's site, etc.)
-- **Instructions**: clearly describes the steps to use the feature, leaving no gaps.
-- **Troubleshooting** guide (recommended but not required): if you know beforehand what issues
- one might have when setting it 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 in the
- docs. This is important to minimize requests for support, and to avoid doc comments with
- questions that you know someone might ask. Answering them beforehand only makes your
- document better and more approachable.
+- **Title**: Top-level heading with the feature name, or a use case name, which would start with
+a verb, like Configuring, Enabling, etc.
+- **Introduction**: A couple sentences about the subject matter and what's to be found on this page.
+- **Overview** Describe what it is, what it does, and in what context it should be used.
+- **Use cases**: describes real use case scenarios for that feature/configuration.
+- **Requirements**: describes what software, configuration, account, or knowledge is required.
+- **Instructions**: One or more sets of detailed instructions to follow.
+- **Troubleshooting** guide (recommended but not required).
-For additional details, see the subsections below, as well as the [Documentation template for new docs](#Documentation-template-for-new-docs).
+For additional details on each, see the [template for new docs](#template-for-new-docs),
+below.
-### Feature overview and use cases
+Note that you can include additional subsections, as appropriate, such as 'How it Works', 'Architecture',
+and other logicial divisions such as pre- and post-deployment steps.
-Every major feature (regardless if present in GitLab Community or Enterprise editions)
-should present, at the beginning of the document, two main sections: **overview** and
-**use cases**. Every GitLab EE-only feature should also contain these sections.
-
-**Overview**: as the name suggests, the goal here is to provide an overview of the feature.
-Describe what is it, what it does, why it is important/cool/nice-to-have,
-what problem it solves, and what you can do with this feature that you couldn't
-do before.
-
-**Use cases**: provide at least two, ideally three, use cases for every major feature.
-You should answer this question: what can you do with this feature/change? Use cases
-are examples of how this feature or change can be used in real life.
-
-Examples:
-
-- CE and EE: [Issues](../../user/project/issues/index.md#use-cases)
-- CE and EE: [Merge Requests](../../user/project/merge_requests/index.md)
-- EE-only: [Geo](https://docs.gitlab.com/ee/administration/geo/replication/index.html)
-- EE-only: [Jenkins integration](https://docs.gitlab.com/ee/integration/jenkins.html)
-
-Note that if you don't have anything to add between the doc title (`<h1>`) and
-the header `## Overview`, you can omit the header, but keep the content of the
-overview there.
-
-> **Overview** and **use cases** are required to **every** Enterprise Edition feature,
-and for every **major** feature present in Community Edition.
-
-### Discoverability
-
-Your new document will be discoverable by the user only if:
-
-- Crosslinked from the higher-level index (e.g., Issue Boards docs
- should be linked from Issues; Prometheus docs should be linked from
- Monitoring; CI/CD tutorials should be linked from CI/CD examples).
- - When referencing other GitLab products and features, link to their
- respective docs; when referencing third-party products or technologies,
- link out to their external sites, documentation, and resources.
-- The headings are clear. E.g., "App testing" is a bad heading, "Testing
- an application with GitLab CI/CD" is much better. Think of something
- someone will search for and use these keywords in the headings.
-
-## Documentation template for new docs
+## Template for new docs
To start a new document, respect the file tree and file name guidelines,
as well as the style guidelines. Use the following template:
```md
+<!--Follow the Style Guide when working on this document. https://docs.gitlab.com/ee/development/documentation/styleguide.html
+When done, remove all of this commented-out text, except a commented-out Troubleshooting section,
+which, if empty, can be left in place to encourage future use.-->
---
-description: "short document description." # Up to ~200 chars long. They will be displayed in Google Search Snippets.
+description: "Short document description." # Up to ~200 chars long. They will be displayed in Google Search snippets. It may help to write the page intro first, and then reuse it here.
---
-# Feature Name **[TIER]** (1)
+# Feature Name or Use Case Name **[TIER]** (1)
+<!--If writing about a use case, drop the tier, and start with a verb, e.g. 'Configuring', 'Implementing', + the goal/scenario-->
-> [Introduced](link_to_issue_or_mr) in GitLab Tier X.Y (2).
+<!--For pages on newly introduced features, add the following line. If only some aspects of the feature have been introduced, specify what parts of the feature.-->
+> [Introduced](link_to_issue_or_mr) in GitLab (Tier) X.Y (2).
-A short description for the feature (can be the same used in the frontmatter's
-`description`).
+An introduction -- without its own additional header -- goes here.
+Offer a very short description of the feature or use case, and what to expect on this page.
+(You can reuse this content, or part of it, for the front matter's `description` at the top of this file).
## Overview
-To write the feature overview, you should consider answering the following questions:
+The feature overview should answer the following questions:
-- What is it?
+- What is this feature or use case?
- Who is it for?
- What is the context in which it is used and are there any prerequisites/requirements?
-- What can the user do with it? (Be sure to consider multiple audiences, like GitLab admin and developer-user.)
-- What are the benefits to using it over any alternatives?
+- What can the audience do with this? (Be sure to consider all applicable audiences, like GitLab admin and developer-user.)
+- What are the benefits to using this over any alternatives?
## Use cases
-Describe one to three use cases for that feature. Give real-life examples.
+Describe some use cases, typically in bulleted form. Include real-life examples for each.
+
+If the page itself is dedicated to a use case, this section can usually include more specific scenarios
+for use (e.g. variations on the main use case), but if that's not applicable, the section can be omitted.
+
+Examples of use cases on feature pages:
+- CE and EE: [Issues](../../user/project/issues/index.md#use-cases)
+- CE and EE: [Merge Requests](../../user/project/merge_requests/index.md)
+- EE-only: [Geo](https://docs.gitlab.com/ee/administration/geo/replication/index.html)
+- EE-only: [Jenkins integration](https://docs.gitlab.com/ee/integration/jenkins.html)
## Requirements
-State any requirements, if any, for using the feature and/or following along with the tutorial.
+State any requirements for using the feature and/or following along with the instructions.
-The only assumption that is redundant and doesn't need to be mentioned is having an account
-on GitLab.
+These can include both:
+- technical requirements (e.g. an account on a third party service, an amount of storage space, prior configuration of another feature)
+- prerequisite knowledge (e.g. familiarity with certain GitLab features, cloud technologies)
+
+Link each one to an appropriate place for more information.
## Instructions
-("Instructions" is not necessarily the name of the heading)
+"Instructions" is usually not the name of the heading.
+This is the part of the document where you can include one or more sets of instructions, each to accomplish a specific task.
+Headers should describe the task the reader will achieve by following the instructions within, typically starting with a verb.
+Larger instruction sets may have subsections covering specific phases of the process.
- Write a step-by-step guide, with no gaps between the steps.
- Start with an h2 (`##`), break complex steps into small steps using
-subheadings h3 > h4 > h5 > h6. _Never skip the hierarchy level, such
+subheadings h3 > h4 > h5 > h6. _Never skip a hierarchy level, such
as h2 > h4_, as it will break the TOC and may affect the breadcrumbs.
- Use short and descriptive headings (up to ~50 chars). You can use one
-single heading `## How it works` for the instructions when the feature
+single heading like `## Configuring X` for instructions when the feature
is simple and the document is short.
-- Be clear, concise, and stick to the goal of the doc: explain how to
-use that feature.
-- Use inclusive language and avoid jargons, as well as uncommon and
-fancy words. The docs should be clear and easy to understand.
-- Write in the 3rd person (use "we", "you", "us", "one", instead of "I" or "me").
-- Always provide internal and external reference links.
-- Always link the doc from its higher-level index.
<!-- ## Troubleshooting
-Add a troubleshooting guide when possible/applicable. -->
+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/development/documentation/styleguide.md b/doc/development/documentation/styleguide.md
index 8309ba9a72c..8760cd194d4 100644
--- a/doc/development/documentation/styleguide.md
+++ b/doc/development/documentation/styleguide.md
@@ -1,16 +1,16 @@
---
-description: 'Writing styles, markup, formatting, and reusing regular expressions throughout the GitLab Documentation.'
+description: 'Writing styles, markup, formatting, and other standards for GitLab Documentation.'
---
-# Documentation style guidelines
+# Documentation Style Guide
The documentation style guide defines the markup structure used in
GitLab documentation. Check the
[documentation guidelines](index.md) for general development instructions.
-Check the GitLab handbook for the [writing styles guidelines](https://about.gitlab.com/handbook/communication/#writing-style-guidelines).
+See the GitLab handbook for the [writing style guidelines](https://about.gitlab.com/handbook/communication/#writing-style-guidelines).
-For help adhering to the guidelines, see [linting](index.md#linting).
+For programmatic help adhering to the guidelines, see [linting](index.md#linting).
## Files
@@ -40,13 +40,36 @@ Use Kramdown markup wisely: do not overuse its specific markup (e.g., `{:.class}
## Content
-- Make sure that the documentation is added in the correct
- [directory](index.md#documentation-directory-structure), linked from its
- higher-level index, and linked from other related pages.
+These guidelines help toward the goal of having every user's search of documentation
+yield a useful result, and ensuring content is helpful and easy to consume.
+
+- What to include:
+ - Any and all helpful information, processes, and tips for implementing,
+using, and troubleshooting GitLab features. [The documentation is the single source of truth](https://about.gitlab.com/handbook/documentation/#documentation-as-single-source-of-truth-ssot)
+for this information.
+ - 'Risky' or niche problem-solving steps. There is no reason to withhold these or
+store them elsewhere; simply include them along with the rest of the docs including all necessary
+detail, such as specific warnings and caveats about potential ramifications.
+ - Any content types/sources, if relevant to users or admins. You can freely
+include presentations, videos, etc.; no matter who it was originally written for,
+if it is helpful to any of our audiences, we can include it. If an outside source
+that's under copyright, rephrase, or summarize and link out; do not copy and paste.
+ - All applicable subsections as described on the [structure and template](structure.md) page,
+with files organized in the [correct directory](index.md#documentation-directory-structure).
+- To ensure discoverability, link to each doc from its higher-level index page and other related pages.
+- When referencing other GitLab products and features, link to their
+ respective docs; when referencing third-party products or technologies,
+ link out to their external sites, documentation, and resources.
- Do not duplicate information.
-- Be brief and clear.
-- Unless there's a logical reason not to, structure the document in alphabetical order
-(headings, tables, and lists).
+- Structure content in alphabetical order in tables, lists, etc., unless there is
+a logical reason not to (for example, when mirroring the UI or an ordered sequence).
+
+## Language
+
+- Use inclusive language and avoid jargon, as well as uncommon
+words. The docs should be clear and easy to understand.
+- Write in the 3rd person (use "we", "you", "us", "one", instead of "I" or "me").
+- Be clear, concise, and stick to the goal of the doc.
- Write in US English.
- Capitalize "G" and "L" in GitLab.
- Use title case when referring to [features](https://about.gitlab.com/features/) or
diff --git a/doc/development/documentation/workflow.md b/doc/development/documentation/workflow.md
index 75ce8640e87..7c32c92b147 100644
--- a/doc/development/documentation/workflow.md
+++ b/doc/development/documentation/workflow.md
@@ -1,185 +1,10 @@
---
-description: Learn the process of shipping documentation for GitLab.
+description: Learn the processes for contributing to GitLab's documentation.
---
-# Documentation process at GitLab
+# Documentation workflows at GitLab
-At GitLab, developers contribute new or updated documentation along with their code, but product managers and technical writers also have essential roles in the process.
+Documentation workflows at GitLab differ depending on the reason for the change. The two types of documentation changes are:
-- Product Managers (PMs): in the issue for all new and updated features,
- PMs include specific documentation requirements that the developer who is
- writing or updating the docs must meet, along with feature descriptions
- and use cases. They call out any specific areas where collaborating with
- a technical writer is recommended, and usually act as the first reviewer
- of the docs.
-- Developers: author documentation and merge it on time (up to a week after
- the feature freeze).
-- Technical Writers: review each issue to ensure PM's requirements are complete,
- help developers with any questions throughout the process, and act as the final
- reviewer of all new and updated docs content before it's merged.
-
-## Requirements
-
-Documentation must be delivered whenever:
-
-- A new feature is shipped
-- There are changes to the UI
-- A process, workflow, or previously documented feature is changed
-
-Documentation is not required when a feature is changed on the backend
-only and does not directly affect the way that any regular user or
-administrator would interact with GitLab.
-
-NOTE: **Note:**
-When refactoring documentation, it should be submitted in its own MR.
-**Do not** join new features' MRs with refactoring existing docs, as they might have
-different priorities.
-
-NOTE: **Note:**
-[Smaller MRs are better](https://gitlab.com/gitlab-com/blog-posts/issues/185#note_4401010)! Do not mix subjects, and ship the smallest MR possible.
-
-### Documentation review process
-
-The docs shipped by the developer should be reviewed by the PM (for accuracy) and a Technical Writer (for clarity and structure).
-
-#### Documentation updates that require Technical Writer review
-
-Every documentation change that meets the criteria below must be reviewed by a Technical Writer
-to ensure clarity and discoverability, and avoid redundancy, bad file locations, typos, broken links, etc.
-Within the GitLab issue or MR, ping the relevant technical writer for the subject area. If you're not sure who that is,
-ping any of them or all of them (`@gl\-docsteam`).
-
-A Technical Writer must review documentation updates that involve:
-
-- Docs introducing new features
-- Changing documentation location
-- Refactoring existing documentation
-- Creating new documentation files
-
-If you need any help to choose the correct place for a doc, discuss a documentation
-idea or outline, or request any other help, ping a Technical Writer on your issue, MR,
-or on Slack in `#docs`.
-
-#### Skip the PM's review
-
-When there's a non-significant change to the docs, you can skip the review
-of the PM. Add the same labels as you would for a regular doc change and
-assign the correct milestone. In these cases, assign a Technical Writer
-for approval/merge, or mention `@gl\-docsteam` in case you don't know
-which Tech Writer to assign for.
-
-#### Skip the entire review
-
-When the MR only contains corrections to the content (typos, grammar,
-broken links, etc), it can be merged without the PM's and Tech Writer's review.
-
-## Documentation structure
-
-Read through the [documentation structure](structure.md) docs for an overview.
-
-## Documentation workflow
-
-To follow a consistent workflow every month, documentation changes
-involve the Product Managers, the developer who shipped the feature,
-and the Technical Writing team. Each role is described below.
-
-### 1. Product Manager's role in the documentation process
-
-The Product Manager (PM) should add to the feature issue:
-
-- Feature name, overview/description, and use cases, for the [documentation blurb](structure.md#documentation-blurb)
-- The documentation requirements for the developer working on the docs
- - What new page, new subsection of an existing page, or other update to an existing page/subsection is needed.
- - Just one page/section/update or multiple (perhaps there's an end user and admin change needing docs, or we need to update a previously recommended workflow, or we want to link the new feature from various places; consider and mention all ways documentation should be affected
- - Suggested title of any page or subsection, if applicable
-- Label the issue with `Documentation`, `Deliverable`, `docs:P1`, and assign
- the correct milestone
-
-### 2. Developer's role in the documentation process
-
-As a developer, or as a community contributor, you should ship the documentation
-with the feature, as in GitLab the documentation is part of the product.
-
-The docs can either be shipped along with the MR introducing the code, or,
-alternatively, created from a follow-up issue and MR.
-
-The docs should be shipped **by the feature freeze date**. Justified
-exceptions are accepted, as long as the [following process](#documentation-shipped-late)
-and the missed-deliverable due date (the 14th of each month) are both respected.
-
-#### Documentation shipped in the feature MR
-
-The developer should add to the feature MR the documentation containing:
-
-- The [documentation blurb](structure.md#documentation-blurb): copy the
- feature name, overview/description, and use cases from the feature issue
-- Instructions: write how to use the feature, step by step, with no gaps.
-- [Crosslink for discoverability](structure.md#discoverability): link with
- internal docs and external resources (if applicable)
-- Index: link the new doc or the new heading from the higher-level index
- for [discoverability](#discoverability)
-- [Screenshots](styleguide.md#images): when necessary, add screenshots for:
- - Illustrating a step of the process
- - Indicating the location of a navigation menu
-- Label the MR with `Documentation`, `Deliverable`, `docs-P1`, and assign
- the correct milestone
-- Assign the PM for review
-- When done, mention the `@gl\-docsteam` in the MR asking for review
-- **Due date**: feature freeze date and time
-
-#### Documentation shipped in a follow-up MR
-
-If the docs aren't being shipped within the feature MR:
-
-- Create a new issue mentioning "docs" or "documentation" in the title (use the Documentation issue description template)
-- Label the issue with: `Documentation`, `Deliverable`, `docs-P1`, `<product-label>`
- (product label == CI/CD, Pages, Prometheus, etc)
-- Add the correct milestone
-- Create a new MR for shipping the docs changes and follow the same
- process [described above](#documentation-shipped-in-the-feature-mr)
-- Use the MR description template called "Documentation"
-- Add the same labels and milestone as you did for the issue
-- Assign the PM for review
-- When done, mention the `@gl\-docsteam` in the MR asking for review
-- **Due date**: feature freeze date and time
-
-#### Documentation shipped late
-
-Shipping late means that you are affecting the whole feature workflow
-as well as other teams' priorities (PMs, tech writers, release managers,
-release post reviewers), so every effort should be made to avoid this.
-
-If you did not ship the docs within the feature freeze, proceed as
-[described above](#documentation-shipped-in-a-follow-up-mr) and,
-besides the regular labels, include the labels `Pick into X.Y` and
-`missed-deliverable` in the issue and the MR, and assign them the correct
-milestone.
-
-The **due date** for **merging** `missed-deliverable` MRs is on the
-**14th** of each month.
-
-### 3. Technical Writer's role in the documentation process
-
-- **Planning**
- - Once an issue contains a Documentation label and the current milestone, a
- technical writer reviews the Product Manager's documentation requirements.
- - Once the documentation requirements are approved, the technical writer can
- work with the developer to discuss any documentation questions and plans/outlines, as needed.
-
-- **Review** - A technical writer must review the documentation for:
- - Clarity
- - Relevance (make sure the content is appropriate given the impact of the feature)
- - Location (make sure the doc is in the correct dir and has the correct name)
- - Syntax, typos, and broken links
- - Improvements to the content
- - Accordance to the [docs style guide](styleguide.md)
-
-<!-- TBA: issue and MR description templates as part of the process -->
-
-<!--
-## New features vs feature updates
-
-- TBA:
- - Describe the difference between new features and feature updates
- - Creating a new doc vs updating an existing doc
--->
+- [Feature-change documentation workflow](feature-change-workflow.md) - The documentation is being created or updated as part of the development and release of a new or enhanced feature. This process involves the developer of the feature (who includes new/updated documentation files as part of the same merge request containing the feature's code) and also involves the product manager and technical writer who are listed for the feature's [DevOps stage](https://about.gitlab.com/handbook/product/categories/#devops-stages).
+- [Documentation improvement workflow](improvement-workflow.md) - All documentation additions not associated with a feature release. Documentation is being created or updated to improve accuracy, completeness, ease of use, or any reason other than a feature change. Anyone (and everyone) can contribute a merge request for this type of change at any time.
diff --git a/doc/development/instrumentation.md b/doc/development/instrumentation.md
index bef166f2aec..a36dc6424a7 100644
--- a/doc/development/instrumentation.md
+++ b/doc/development/instrumentation.md
@@ -35,7 +35,7 @@ Using this method is in general preferred over directly calling the various
instrumentation methods.
Method instrumentation should be added in the initializer
-`config/initializers/8_metrics.rb`.
+`config/initializers/zz_metrics.rb`.
### Examples
diff --git a/doc/install/installation.md b/doc/install/installation.md
index d041bfa863a..b7781dea384 100644
--- a/doc/install/installation.md
+++ b/doc/install/installation.md
@@ -142,7 +142,7 @@ Download Ruby and compile it:
Then install the Bundler Gem:
- sudo gem install bundler --no-ri --no-rdoc
+ sudo gem install bundler --no-document
## 3. Go
diff --git a/doc/install/kubernetes/gitlab_chart.md b/doc/install/kubernetes/gitlab_chart.md
index 74e2598f860..26ced45de7b 100644
--- a/doc/install/kubernetes/gitlab_chart.md
+++ b/doc/install/kubernetes/gitlab_chart.md
@@ -47,8 +47,9 @@ In order to deploy GitLab on Kubernetes, the following are required:
1. `helm` and `kubectl` [installed on your computer](preparation/tools_installation.md).
1. A Kubernetes cluster, version 1.8 or higher. 6vCPU and 16GB of RAM is recommended.
- - [Google GKE](https://cloud.google.com/kubernetes-engine/docs/how-to/creating-a-container-cluster)
- [Amazon EKS](https://docs.aws.amazon.com/eks/latest/userguide/getting-started.html)
+ - [Google GKE](https://cloud.google.com/kubernetes-engine/docs/how-to/creating-a-container-cluster)
+ - [IBM IKS](https://console.bluemix.net/docs/tutorials/scalable-webapp-kubernetes.html#create_kube_cluster)
- [Microsoft AKS](https://docs.microsoft.com/en-us/azure/aks/kubernetes-walkthrough-portal)
1. A [wildcard DNS entry and external IP address](preparation/networking.md)
1. [Authenticate and connect](preparation/connect.md) to the cluster
diff --git a/doc/integration/google.md b/doc/integration/google.md
index b91d40d4bd4..d2b4e119978 100644
--- a/doc/integration/google.md
+++ b/doc/integration/google.md
@@ -35,7 +35,6 @@ In Google's side:
1. You should now be able to see a Client ID and Client secret. Note them down
or keep this page open as you will need them later.
-1. From the **Dashboard** select **ENABLE APIS AND SERVICES > Social > Google+ API > Enable**
1. To enable projects to access [Google Kubernetes Engine](../user/project/clusters/index.md), you must also
enable these APIs:
- Google Kubernetes Engine API
diff --git a/doc/update/10.0-to-10.1.md b/doc/update/10.0-to-10.1.md
index af815d26a74..10cf02a984f 100644
--- a/doc/update/10.0-to-10.1.md
+++ b/doc/update/10.0-to-10.1.md
@@ -49,7 +49,7 @@ sudo make install
Install Bundler:
```bash
-sudo gem install bundler --no-ri --no-rdoc
+sudo gem install bundler --no-document
```
### 4. Update Node
diff --git a/doc/update/10.1-to-10.2.md b/doc/update/10.1-to-10.2.md
index 632e8befa74..20895a05567 100644
--- a/doc/update/10.1-to-10.2.md
+++ b/doc/update/10.1-to-10.2.md
@@ -49,7 +49,7 @@ sudo make install
Install Bundler:
```bash
-sudo gem install bundler --no-ri --no-rdoc
+sudo gem install bundler --no-document
```
### 4. Update Node
diff --git a/doc/update/10.2-to-10.3.md b/doc/update/10.2-to-10.3.md
index f8fe4a4b6bf..441a241d053 100644
--- a/doc/update/10.2-to-10.3.md
+++ b/doc/update/10.2-to-10.3.md
@@ -49,7 +49,7 @@ sudo make install
Install Bundler:
```bash
-sudo gem install bundler --no-ri --no-rdoc
+sudo gem install bundler --no-document
```
### 4. Update Node
diff --git a/doc/update/10.3-to-10.4.md b/doc/update/10.3-to-10.4.md
index 083f6090a8a..9f3efdd790e 100644
--- a/doc/update/10.3-to-10.4.md
+++ b/doc/update/10.3-to-10.4.md
@@ -51,7 +51,7 @@ sudo make install
Install Bundler:
```bash
-sudo gem install bundler --no-ri --no-rdoc
+sudo gem install bundler --no-document
```
### 4. Update Node
diff --git a/doc/update/10.4-to-10.5.md b/doc/update/10.4-to-10.5.md
index 313419ed13d..3766645a141 100644
--- a/doc/update/10.4-to-10.5.md
+++ b/doc/update/10.4-to-10.5.md
@@ -51,7 +51,7 @@ sudo make install
Install Bundler:
```bash
-sudo gem install bundler --no-ri --no-rdoc
+sudo gem install bundler --no-document
```
### 4. Update Node
diff --git a/doc/update/10.5-to-10.6.md b/doc/update/10.5-to-10.6.md
index 2f90fb62c4a..986ecbf5ef0 100644
--- a/doc/update/10.5-to-10.6.md
+++ b/doc/update/10.5-to-10.6.md
@@ -51,7 +51,7 @@ sudo make install
Install Bundler:
```bash
-sudo gem install bundler --no-ri --no-rdoc
+sudo gem install bundler --no-document
```
### 4. Update Node
diff --git a/doc/update/10.6-to-10.7.md b/doc/update/10.6-to-10.7.md
index b9c14395a3a..10d29837bfb 100644
--- a/doc/update/10.6-to-10.7.md
+++ b/doc/update/10.6-to-10.7.md
@@ -51,7 +51,7 @@ sudo make install
Install Bundler:
```bash
-sudo gem install bundler --no-ri --no-rdoc
+sudo gem install bundler --no-document
```
### 4. Update Node
diff --git a/doc/update/10.7-to-10.8.md b/doc/update/10.7-to-10.8.md
index 7bb628f9740..0cc46fc5aa9 100644
--- a/doc/update/10.7-to-10.8.md
+++ b/doc/update/10.7-to-10.8.md
@@ -52,7 +52,7 @@ sudo make install
Install Bundler:
```bash
-sudo gem install bundler --no-ri --no-rdoc
+sudo gem install bundler --no-document
```
### 4. Update Node
diff --git a/doc/update/10.8-to-11.0.md b/doc/update/10.8-to-11.0.md
index 22a0c9f950c..ad3305d8ebd 100644
--- a/doc/update/10.8-to-11.0.md
+++ b/doc/update/10.8-to-11.0.md
@@ -51,7 +51,7 @@ sudo make install
Install Bundler:
```bash
-sudo gem install bundler --no-ri --no-rdoc
+sudo gem install bundler --no-document
```
### 4. Update Node
diff --git a/doc/update/11.0-to-11.1.md b/doc/update/11.0-to-11.1.md
index 3f10a7edb8a..5b2dd48a744 100644
--- a/doc/update/11.0-to-11.1.md
+++ b/doc/update/11.0-to-11.1.md
@@ -51,7 +51,7 @@ sudo make install
Install Bundler:
```bash
-sudo gem install bundler --no-ri --no-rdoc
+sudo gem install bundler --no-document
```
### 4. Update Node
diff --git a/doc/update/11.1-to-11.2.md b/doc/update/11.1-to-11.2.md
index 3edc7e6923e..cb09d0a2505 100644
--- a/doc/update/11.1-to-11.2.md
+++ b/doc/update/11.1-to-11.2.md
@@ -51,7 +51,7 @@ sudo make install
Install Bundler:
```bash
-sudo gem install bundler --no-ri --no-rdoc
+sudo gem install bundler --no-document
```
### 4. Update Node
diff --git a/doc/update/11.2-to-11.3.md b/doc/update/11.2-to-11.3.md
index f2b8efc3e6e..228ff6cb70e 100644
--- a/doc/update/11.2-to-11.3.md
+++ b/doc/update/11.2-to-11.3.md
@@ -51,7 +51,7 @@ sudo make install
Install Bundler:
```bash
-sudo gem install bundler --no-ri --no-rdoc
+sudo gem install bundler --no-document
```
### 4. Update Node
diff --git a/doc/update/11.3-to-11.4.md b/doc/update/11.3-to-11.4.md
index fddec45e57a..5f64bf81127 100644
--- a/doc/update/11.3-to-11.4.md
+++ b/doc/update/11.3-to-11.4.md
@@ -51,7 +51,7 @@ sudo make install
Install Bundler:
```bash
-sudo gem install bundler --no-ri --no-rdoc
+sudo gem install bundler --no-document
```
### 4. Update Node
diff --git a/doc/update/11.4-to-11.5.md b/doc/update/11.4-to-11.5.md
index 44105348d14..fd7a8e5c2ae 100644
--- a/doc/update/11.4-to-11.5.md
+++ b/doc/update/11.4-to-11.5.md
@@ -51,7 +51,7 @@ sudo make install
Install Bundler:
```bash
-sudo gem install bundler --no-ri --no-rdoc
+sudo gem install bundler --no-document
```
### 4. Update Node
diff --git a/doc/update/11.5-to-11.6.md b/doc/update/11.5-to-11.6.md
index 031abc434ca..2e9ec5d71de 100644
--- a/doc/update/11.5-to-11.6.md
+++ b/doc/update/11.5-to-11.6.md
@@ -51,7 +51,7 @@ sudo make install
Install Bundler:
```bash
-sudo gem install bundler --no-ri --no-rdoc
+sudo gem install bundler --no-document
```
### 4. Update Node
diff --git a/doc/update/6.9-to-7.0.md b/doc/update/6.9-to-7.0.md
index 27063948028..781c90e4198 100644
--- a/doc/update/6.9-to-7.0.md
+++ b/doc/update/6.9-to-7.0.md
@@ -47,7 +47,7 @@ sudo make install
Install Bundler:
```bash
-sudo gem install bundler --no-ri --no-rdoc
+sudo gem install bundler --no-document
```
### 3. Get latest code
diff --git a/doc/update/6.x-or-7.x-to-7.14.md b/doc/update/6.x-or-7.x-to-7.14.md
index 61854b91aa2..6fcec5b7974 100644
--- a/doc/update/6.x-or-7.x-to-7.14.md
+++ b/doc/update/6.x-or-7.x-to-7.14.md
@@ -67,7 +67,7 @@ sudo make install
Install Bundler:
```bash
-sudo gem install bundler --no-ri --no-rdoc
+sudo gem install bundler --no-document
```
## 3. Get latest code
diff --git a/doc/update/7.0-to-7.1.md b/doc/update/7.0-to-7.1.md
index 308e8aeb985..fb4710faad5 100644
--- a/doc/update/7.0-to-7.1.md
+++ b/doc/update/7.0-to-7.1.md
@@ -47,7 +47,7 @@ sudo make install
Install Bundler:
```bash
-sudo gem install bundler --no-ri --no-rdoc
+sudo gem install bundler --no-document
```
### 3. Get latest code
diff --git a/doc/update/8.10-to-8.11.md b/doc/update/8.10-to-8.11.md
index df3e34f5cc6..12a465e1602 100644
--- a/doc/update/8.10-to-8.11.md
+++ b/doc/update/8.10-to-8.11.md
@@ -47,7 +47,7 @@ sudo make install
Install Bundler:
```bash
-sudo gem install bundler --no-ri --no-rdoc
+sudo gem install bundler --no-document
```
### 4. Get latest code
diff --git a/doc/update/8.11-to-8.12.md b/doc/update/8.11-to-8.12.md
index 9d6a1f42375..b9a7986d5ba 100644
--- a/doc/update/8.11-to-8.12.md
+++ b/doc/update/8.11-to-8.12.md
@@ -47,7 +47,7 @@ sudo make install
Install Bundler:
```bash
-sudo gem install bundler --no-ri --no-rdoc
+sudo gem install bundler --no-document
```
### 4. Get latest code
diff --git a/doc/update/8.12-to-8.13.md b/doc/update/8.12-to-8.13.md
index 6225dee9802..37e61794e7e 100644
--- a/doc/update/8.12-to-8.13.md
+++ b/doc/update/8.12-to-8.13.md
@@ -47,7 +47,7 @@ sudo make install
Install Bundler:
```bash
-sudo gem install bundler --no-ri --no-rdoc
+sudo gem install bundler --no-document
```
### 4. Get latest code
diff --git a/doc/update/8.13-to-8.14.md b/doc/update/8.13-to-8.14.md
index d2508e3f980..927f453b9bf 100644
--- a/doc/update/8.13-to-8.14.md
+++ b/doc/update/8.13-to-8.14.md
@@ -47,7 +47,7 @@ sudo make install
Install Bundler:
```bash
-sudo gem install bundler --no-ri --no-rdoc
+sudo gem install bundler --no-document
```
### 4. Get latest code
diff --git a/doc/update/8.14-to-8.15.md b/doc/update/8.14-to-8.15.md
index daf8d0f2ca6..d98a60d31c8 100644
--- a/doc/update/8.14-to-8.15.md
+++ b/doc/update/8.14-to-8.15.md
@@ -50,7 +50,7 @@ sudo make install
Install Bundler:
```bash
-sudo gem install bundler --no-ri --no-rdoc
+sudo gem install bundler --no-document
```
### 4. Get latest code
diff --git a/doc/update/8.15-to-8.16.md b/doc/update/8.15-to-8.16.md
index 3668142edd2..94b0102ed48 100644
--- a/doc/update/8.15-to-8.16.md
+++ b/doc/update/8.15-to-8.16.md
@@ -50,7 +50,7 @@ sudo make install
Install Bundler:
```bash
-sudo gem install bundler --no-ri --no-rdoc
+sudo gem install bundler --no-document
```
### 4. Get latest code
diff --git a/doc/update/8.16-to-8.17.md b/doc/update/8.16-to-8.17.md
index ee2e31c2aec..5a4f620a164 100644
--- a/doc/update/8.16-to-8.17.md
+++ b/doc/update/8.16-to-8.17.md
@@ -50,7 +50,7 @@ sudo make install
Install Bundler:
```bash
-sudo gem install bundler --no-ri --no-rdoc
+sudo gem install bundler --no-document
```
### 4. Update Node
diff --git a/doc/update/8.17-to-9.0.md b/doc/update/8.17-to-9.0.md
index 3c73bc573a6..38f7d22437a 100644
--- a/doc/update/8.17-to-9.0.md
+++ b/doc/update/8.17-to-9.0.md
@@ -49,7 +49,7 @@ sudo make install
Install Bundler:
```bash
-sudo gem install bundler --no-ri --no-rdoc
+sudo gem install bundler --no-document
```
### 4. Update Node
diff --git a/doc/update/9.0-to-9.1.md b/doc/update/9.0-to-9.1.md
index 7c9dacc9b90..a4d2e7be23c 100644
--- a/doc/update/9.0-to-9.1.md
+++ b/doc/update/9.0-to-9.1.md
@@ -49,7 +49,7 @@ sudo make install
Install Bundler:
```bash
-sudo gem install bundler --no-ri --no-rdoc
+sudo gem install bundler --no-document
```
### 4. Update Node
diff --git a/doc/update/9.1-to-9.2.md b/doc/update/9.1-to-9.2.md
index b815242ab4e..dd808c51985 100644
--- a/doc/update/9.1-to-9.2.md
+++ b/doc/update/9.1-to-9.2.md
@@ -49,7 +49,7 @@ sudo make install
Install Bundler:
```bash
-sudo gem install bundler --no-ri --no-rdoc
+sudo gem install bundler --no-document
```
### 4. Update Node
diff --git a/doc/update/9.2-to-9.3.md b/doc/update/9.2-to-9.3.md
index a58b12cb81c..d2bcf45a28e 100644
--- a/doc/update/9.2-to-9.3.md
+++ b/doc/update/9.2-to-9.3.md
@@ -49,7 +49,7 @@ sudo make install
Install Bundler:
```bash
-sudo gem install bundler --no-ri --no-rdoc
+sudo gem install bundler --no-document
```
### 4. Update Node
diff --git a/doc/update/9.3-to-9.4.md b/doc/update/9.3-to-9.4.md
index 0c87468334b..dae2162a964 100644
--- a/doc/update/9.3-to-9.4.md
+++ b/doc/update/9.3-to-9.4.md
@@ -49,7 +49,7 @@ sudo make install
Install Bundler:
```bash
-sudo gem install bundler --no-ri --no-rdoc
+sudo gem install bundler --no-document
```
### 4. Update Node
diff --git a/doc/update/9.4-to-9.5.md b/doc/update/9.4-to-9.5.md
index 6a655f77a55..f2811e9471f 100644
--- a/doc/update/9.4-to-9.5.md
+++ b/doc/update/9.4-to-9.5.md
@@ -49,7 +49,7 @@ sudo make install
Install Bundler:
```bash
-sudo gem install bundler --no-ri --no-rdoc
+sudo gem install bundler --no-document
```
### 4. Update Node
diff --git a/doc/update/9.5-to-10.0.md b/doc/update/9.5-to-10.0.md
index 7790d192a82..333a6e35714 100644
--- a/doc/update/9.5-to-10.0.md
+++ b/doc/update/9.5-to-10.0.md
@@ -49,7 +49,7 @@ sudo make install
Install Bundler:
```bash
-sudo gem install bundler --no-ri --no-rdoc
+sudo gem install bundler --no-document
```
### 4. Update Node
diff --git a/doc/update/upgrader.md b/doc/update/upgrader.md
deleted file mode 100644
index 746d6bf93e7..00000000000
--- a/doc/update/upgrader.md
+++ /dev/null
@@ -1,91 +0,0 @@
----
-comments: false
----
-
-# GitLab Upgrader (deprecated)
-
-*DEPRECATED* We recommend to [switch to the Omnibus package and repository server](https://about.gitlab.com/update/) instead of using this script.
-
-Although deprecated, if someone wants to make this script into a gem or otherwise improve it merge requests are welcome.
-
-*Make sure you view this [upgrade guide from the 'master' branch](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/update/upgrader.md) for the most up to date instructions.*
-
-GitLab Upgrader - a ruby script that allows you easily upgrade GitLab to latest minor version.
-
-For example it can update your application from 6.4 to latest GitLab 6 version (like 6.6.1).
-
-You still need to create a backup and manually restart GitLab after running the script but all other operations are done by this upgrade script.
-
-If you have local changes to your GitLab repository the script will stash them and you need to use `git stash pop` after running the script.
-
-**GitLab Upgrader is available only for GitLab version 6.4.2 or higher.**
-
-**This script does NOT update gitlab-shell, it needs manual update. See step 5 below.**
-
-## 0. Backup
-
- cd /home/git/gitlab
- sudo -u git -H bundle exec rake gitlab:backup:create RAILS_ENV=production
-
-## 1. Stop server
-
- sudo service gitlab stop
-
-## 2. Run GitLab upgrade tool
-
-Please replace X.X.X with the [latest GitLab release](https://packages.gitlab.com/gitlab/gitlab-ce).
-
-GitLab 7.9 adds `nodejs` as a dependency. GitLab 7.6 adds `libkrb5-dev` as a dependency (installed by default on Ubuntu and OSX). GitLab 7.2 adds `pkg-config` and `cmake` as dependency. Please check the dependencies in the [installation guide.](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/install/installation.md#1-packages-dependencies)
-
- cd /home/git/gitlab
- sudo -u git -H ruby -Ilib -e 'require "gitlab/upgrader"' -e 'class Gitlab::Upgrader' -e 'def latest_version_raw' -e '"vX.X.X"' -e 'end' -e 'end' -e 'Gitlab::Upgrader.new.execute'
-
- # to perform a non-interactive install (no user input required) you can add -y
- # sudo -u git -H ruby -Ilib -e 'require "gitlab/upgrader"' -e 'class Gitlab::Upgrader' -e 'def latest_version_raw' -e '"vX.X.X"' -e 'end' -e 'end' -e 'Gitlab::Upgrader.new.execute' -- -y
-
-## 3. Start application
-
- sudo service gitlab start
- sudo service nginx restart
-
-## 4. Check application status
-
-Check if GitLab and its dependencies are configured correctly:
-
- sudo -u git -H bundle exec rake gitlab:check RAILS_ENV=production
-
-If all items are green, then congratulations upgrade is complete!
-
-## 5. Upgrade GitLab Shell
-
-GitLab Shell might be outdated, running the commands below ensures you're using a compatible version:
-
-```
-cd /home/git/gitlab-shell
-sudo -u git -H git fetch
-sudo -u git -H git checkout v`cat /home/git/gitlab/GITLAB_SHELL_VERSION`
-sudo -u git -H sh -c 'if [ -x bin/compile ] ; then bin/compile ; fi'
-```
-
-## One line upgrade command
-
-You've read through the entire guide and probably already did all the steps one by one.
-
-Below is a one line command with step 1 to 5 for the next time you upgrade.
-
-Please replace X.X.X with the [latest GitLab release](https://packages.gitlab.com/gitlab/gitlab-ce).
-
-```bash
-cd /home/git/gitlab; \
- sudo -u git -H bundle exec rake gitlab:backup:create RAILS_ENV=production; \
- sudo service gitlab stop; \
- sudo -u git -H ruby -Ilib -e 'require "gitlab/upgrader"' -e 'class Gitlab::Upgrader' -e 'def latest_version_raw' -e '"vX.X.X"' -e 'end' -e 'end' -e 'Gitlab::Upgrader.new.execute' -- -y; \
- cd /home/git/gitlab-shell; \
- sudo -u git -H git fetch; \
- sudo -u git -H git checkout v`cat /home/git/gitlab/GITLAB_SHELL_VERSION`; \
- sudo -u git -H sh -c 'if [ -x bin/compile ] ; then bin/compile ; fi'; \
- cd /home/git/gitlab; \
- sudo service gitlab start; \
- sudo service nginx restart; \
- sudo -u git -H bundle exec rake gitlab:check RAILS_ENV=production
-``` \ No newline at end of file
diff --git a/doc/user/group/clusters/index.md b/doc/user/group/clusters/index.md
index 8e03d116b81..9f9b2da23e1 100644
--- a/doc/user/group/clusters/index.md
+++ b/doc/user/group/clusters/index.md
@@ -1,9 +1,7 @@
# Group-level Kubernetes clusters
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/issues/34758) in GitLab 11.6.
-
-CAUTION: **Warning:**
-Group Cluster integration is currently in **Beta**.
+> Group Cluster integration is currently in [Beta](https://about.gitlab.com/handbook/product/#alpha-beta-ga).
## Overview
diff --git a/doc/user/project/clusters/index.md b/doc/user/project/clusters/index.md
index db48388e90d..6f334af4fb7 100644
--- a/doc/user/project/clusters/index.md
+++ b/doc/user/project/clusters/index.md
@@ -60,7 +60,7 @@ new Kubernetes cluster to your project:
**Sign in with Google** button.
1. From there on, choose your cluster's settings:
- **Kubernetes cluster name** - The name you wish to give the cluster.
- - **Environment scope** - The [associated environment](#setting-the-environment-scope) to this cluster.
+ - **Environment scope** - The [associated environment](#setting-the-environment-scope-premium) to this cluster.
- **Google Cloud Platform project** - Choose the project you created in your GCP
console that will host the Kubernetes cluster. Learn more about
[Google Cloud Platform projects](https://cloud.google.com/resource-manager/docs/creating-managing-projects).
@@ -254,15 +254,19 @@ install it manually.
GitLab provides a one-click install for various applications which can
be added directly to your configured cluster. Those applications are
needed for [Review Apps](../../../ci/review_apps/index.md) and
-[deployments](../../../ci/environments.md).
+[deployments](../../../ci/environments.md). You can install them after you
+[create a cluster](#adding-and-creating-a-new-gke-cluster-via-gitlab).
+
+To see a list of available applications to install:
+
+1. Navigate to your project's **Operations > Kubernetes**.
+1. Select your cluster.
+
+Install Helm Tiller first because it's used to install other applications.
NOTE: **Note:**
-With the exception of Knative, the applications will be installed in a dedicated namespace called
-`gitlab-managed-apps`. In case you have added an existing Kubernetes cluster
-with Tiller already installed, you should be careful as GitLab cannot
-detect it. In this event, installing Tiller via the applications will
-result in the cluster having it twice. This can lead to confusion during
-deployments.
+As of GitLab 11.6, Helm Tiller will be upgraded to the latest version supported
+by GitLab before installing any of the applications.
| Application | GitLab version | Description | Helm Chart |
| ----------- | :------------: | ----------- | --------------- |
@@ -274,9 +278,14 @@ deployments.
| [JupyterHub](http://jupyter.org/) | 11.0+ | [JupyterHub](https://jupyterhub.readthedocs.io/en/stable/) is a multi-user service for managing notebooks across a team. [Jupyter Notebooks](https://jupyter-notebook.readthedocs.io/en/latest/) provide a web-based interactive programming environment used for data analysis, visualization, and machine learning. We use a [custom Jupyter image](https://gitlab.com/gitlab-org/jupyterhub-user-image/blob/master/Dockerfile) that installs additional useful packages on top of the base Jupyter. You will also see ready-to-use DevOps Runbooks built with Nurtch's [Rubix library](https://github.com/amit1rrr/rubix). More information on creating executable runbooks can be found in [our Nurtch documentation](runbooks/index.md#nurtch-executable-runbooks). **Note**: Authentication will be enabled for any user of the GitLab server via OAuth2. HTTPS will be supported in a future release. | [jupyter/jupyterhub](https://jupyterhub.github.io/helm-chart/) |
| [Knative](https://cloud.google.com/knative) | 11.5+ | Knative provides a platform to create, deploy, and manage serverless workloads from a Kubernetes cluster. It is used in conjunction with, and includes [Istio](https://istio.io) to provide an external IP address for all programs hosted by Knative. You will be prompted to enter a wildcard domain where your applications will be exposed. Configure your DNS server to use the external IP address for that domain. For any application created and installed, they will be accessible as `<program_name>.<kubernetes_namespace>.<domain_name>`. This will require your kubernetes cluster to have [RBAC enabled](#role-based-access-control-rbac). | [knative/knative](https://storage.googleapis.com/triggermesh-charts)
-NOTE: **Note:**
-As of GitLab 11.6 Helm Tiller will be upgraded to the latest version supported
-by GitLab before installing any of the above applications.
+With the exception of Knative, the applications will be installed in a dedicated
+namespace called `gitlab-managed-apps`.
+
+CAUTION: **Caution:**
+If you have an existing Kubernetes cluster with Tiller already installed,
+you should be careful as GitLab cannot detect it. In this case, installing
+Tiller via the applications will result in the cluster having it twice, which
+can lead to confusion during deployments.
## Getting the external IP address
diff --git a/doc/user/project/clusters/serverless/img/function-execution.png b/doc/user/project/clusters/serverless/img/function-execution.png
new file mode 100644
index 00000000000..93b0b6d802d
--- /dev/null
+++ b/doc/user/project/clusters/serverless/img/function-execution.png
Binary files differ
diff --git a/doc/user/project/clusters/serverless/img/serverless-page.png b/doc/user/project/clusters/serverless/img/serverless-page.png
index 5d808fc2d4f..960d6e736d6 100644
--- a/doc/user/project/clusters/serverless/img/serverless-page.png
+++ b/doc/user/project/clusters/serverless/img/serverless-page.png
Binary files differ
diff --git a/doc/user/project/clusters/serverless/index.md b/doc/user/project/clusters/serverless/index.md
index c1f2e844362..a423212a879 100644
--- a/doc/user/project/clusters/serverless/index.md
+++ b/doc/user/project/clusters/serverless/index.md
@@ -1,9 +1,7 @@
# Serverless
> Introduced in GitLab 11.5.
-
-CAUTION: **Caution:**
-Serverless is currently in [alpha](https://about.gitlab.com/handbook/product/#alpha).
+> Serverless is currently in [alpha](https://about.gitlab.com/handbook/product/#alpha).
Run serverless workloads on Kubernetes using [Knative](https://cloud.google.com/knative/).
@@ -31,13 +29,13 @@ To run Knative on Gitlab, you will need:
external IP address for all the applications served by Knative. You will be prompted to enter a
wildcard domain where your applications will be served. Configure your DNS server to use the
external IP address for that domain.
-1. **`gitlab-ci.yml`:** GitLab uses [Kaniko](https://github.com/GoogleContainerTools/kaniko)
+1. **`.gitlab-ci.yml`:** GitLab uses [Kaniko](https://github.com/GoogleContainerTools/kaniko)
to build the application and the [TriggerMesh CLI](https://github.com/triggermesh/tm) to simplify the
deployment of knative services and functions.
-1. **`serverless.yml`** (for [functions only](#deploying-functions)): When using serverless to deploy functions, the `serverless.yml` file
+1. **`serverless.yaml`** (for [functions only](#deploying-functions)): When using serverless to deploy functions, the `serverless.yaml` file
will contain the information for all the functions being hosted in the repository as well as a reference to the
runtime being used.
-1. **`Dockerfile`:** Knative requires a `Dockerfile` in order to build your application. It should be included
+1. **`Dockerfile`** (for [applications only](#deploying-serverless-applications): Knative requires a `Dockerfile` in order to build your application. It should be included
at the root of your project's repo and expose port `8080`.
## Installing Knative via GitLab's Kubernetes integration
@@ -75,13 +73,18 @@ The minimum recommended cluster size to run Knative is 3-nodes, 6 vCPUs, and 22.
> Introduced in GitLab 11.6.
-Using functions is useful for initiating, responding, or triggering independent
+Using functions is useful for dealing with independent
events without needing to maintain a complex unified infrastructure. This allows
you to focus on a single task that can be executed/scaled automatically and independently.
-In order to deploy functions to your Knative instance, the following templates must be present:
+Currently the following [runtimes](https://gitlab.com/triggermesh/runtimes) are offered:
+
+- node.js
+- kaniko
+
+In order to deploy functions to your Knative instance, the following files must be present:
-1. `gitlab-ci.yml`: This template allows to define the stage, environment, and
+1. `.gitlab-ci.yml`: This template allows to define the stage, environment, and
image to be used for your functions. It must be included at the root of your repository:
```yaml
@@ -91,17 +94,22 @@ In order to deploy functions to your Knative instance, the following templates m
functions:
stage: deploy
environment: test
- image: gcr.io/triggermesh/tm:v0.0.6
+ image: gcr.io/triggermesh/tm:v0.0.7
script:
- tm -n "$KUBE_NAMESPACE" set registry-auth gitlab-registry --registry "$CI_REGISTRY" --username "$CI_REGISTRY_USER" --password "$CI_JOB_TOKEN"
- tm -n "$KUBE_NAMESPACE" --registry-host "$CI_REGISTRY_IMAGE" deploy --wait
```
-2. `serverless.yml`: This template contains the metadata for your functions,
- such as name, runtime, and environment. It must be included at the root of your repository:
+ The `gitlab-ci.yml` template creates a `Deploy` stage with a `functions` job that invokes the `tm` CLI with the required parameters.
+
+2. `serverless.yaml`: This file contains the metadata for your functions,
+ such as name, runtime, and environment. It must be included at the root of your repository. The following is a sample `echo` function which shows the required structure for the file.
+
+ NOTE: **Note:**
+ The file extension for the `serverless.yaml` file must be specified as `.yaml` in order to the file to be parsed properly. Specifying the extension as `.yml` will not work.
```yaml
- service: knative-test
+ service: my-functions
description: "Deploying functions from GitLab using Knative"
provider:
@@ -111,27 +119,51 @@ In order to deploy functions to your Knative instance, the following templates m
FOO: BAR
functions:
- container:
- handler: simple
- description: "knative canonical sample"
- runtime: https://gitlab.com/triggermesh/runtimes/raw/master/kaniko.yaml
+ echo:
+ handler: echo
+ runtime: https://gitlab.com/triggermesh/runtimes/raw/master/nodejs.yaml
+ description: "echo function using node.js runtime"
buildargs:
- - DIRECTORY=simple
- environment:
- SIMPLE_MSG: Hello
-
- nodejs:
- handler: nodejs
- runtime: https://gitlab.com/triggermesh/runtimes/raw/master/nodejs.yaml
- description: "nodejs fragment"
- buildargs:
- - DIRECTORY=nodejs
+ - DIRECTORY=echo
environment:
- FUNCTION: nodejs
+ FUNCTION: echo
```
-After the templates have been created, each function must be defined as a single
-file in your repository. Committing a function to your project will result in a
+
+The `serverless.yaml` file contains three sections with distinct parameters:
+
+### `service`
+
+| Parameter | Description |
+|-----------|-------------|
+| `service` | Name for the Knative service which will serve the function. |
+| `description` | A short description of the `service`. |
+
+
+### `provider`
+
+| Parameter | Description |
+|-----------|-------------|
+| `name` | Indicates which provider is used to execute the `serverless.yaml` file. In this case, the TriggerMesh `tm` CLI. |
+| `registry-secret` | Indicates which registry will be used to store docker images. The sample function is using the GitLab Registry (`gitlab-registry`). A different registry host may be specified using `registry` key in the `provider` object. If changing the default, update the permission and the secret value on the `gitlab-ci.yml` file |
+| `environment` | Includes the environment variables to be passed as part of function execution for **all** functions in the file, where `FOO` is the variable name and `BAR` are he variable contents. You may replace this with you own variables. |
+
+### `functions`
+
+In the `serverless.yaml` example above, the function name is `echo` and the subsequent lines contain the function attributes.
+
+
+| Parameter | Description |
+|-----------|-------------|
+| `handler` | The function's file name. In the example above, both the function name and the handler are the same. |
+| `runtime` | The runtime to be used to execute the function. |
+| `description` | A short description of the function. |
+| `buildargs` | Pointer to the function file in the repo. In the sample the function is located in the `echo` directory. |
+| `environment` | Sets an environment variable for the specific function only. |
+
+After the `gitlab-ci.yml` template has been added and the `serverless.yaml` file has been
+created, each function must be defined as a single file in your repository. Committing a
+function to your project will result in a
CI pipeline being executed which will deploy each function as a Knative service.
Once the deploy stage has finished, additional details for the function will
appear under **Operations > Serverless**.
@@ -149,6 +181,10 @@ The function details can be retrieved directly from Knative on the cluster:
kubectl -n "$KUBE_NAMESPACE" get services.serving.knative.dev
```
+The sample function can now be triggered from any HTTP client using a simple `POST` call.
+
+![function exection](img/function-execution.png)
+
Currently, the Serverless page presents all functions available in all clusters registered for the project with Knative installed.
## Deploying Serverless applications
@@ -190,17 +226,12 @@ deploy:
## Deploy the application with Knative
-With all the pieces in place, you can create a new CI pipeline to deploy the Knative application. Navigate to
-**CI/CD > Pipelines** and click the **Run Pipeline** button at the upper-right part of the screen. Then, on the
-Pipelines page, click **Create pipeline**.
+With all the pieces in place, the next time a CI pipeline runs, the Knative application will be deployed. Navigate to
+**CI/CD > Pipelines** and click the most recent pipeline.
## Obtain the URL for the Knative deployment
-There are two ways to obtain the URL for the Knative deployment.
-
-### Using the CI/CD deployment job output
-
-Once all the stages of the pipeline finish, click the **deploy** stage.
+Use the CI/CD deployment job output to obtain the deployment URL. Once all the stages of the pipeline finish, click the **deploy** stage.
![deploy stage](img/deploy-stage.png)
diff --git a/doc/user/project/repository/index.md b/doc/user/project/repository/index.md
index 1710bba2fd0..fac5975a0dc 100644
--- a/doc/user/project/repository/index.md
+++ b/doc/user/project/repository/index.md
@@ -29,7 +29,7 @@ You can either use the user interface (UI), or connect your local computer
with GitLab [through the command line](../../../gitlab-basics/command-line-commands.md#start-working-on-your-project).
To configure [GitLab CI/CD](../../../ci/README.md) to build, test, and deploy
-you code, add a file called [.`gitlab-ci.yml`](../../../ci/quick_start/README.md)
+you code, add a file called [`.gitlab-ci.yml`](../../../ci/quick_start/README.md)
to your repository's root.
**From the user interface:**
diff --git a/doc/user/snippets.md b/doc/user/snippets.md
index 7efb6bafee7..5c9f6ffb163 100644
--- a/doc/user/snippets.md
+++ b/doc/user/snippets.md
@@ -15,7 +15,7 @@ and private. See [Public access](../public_access/public_access.md) for more inf
## Project snippets
Project snippets are always related to a specific project.
-See [Project's features](project/index.md#project-39-s-features) for more information.
+See [Project's features](project/index.md#projects-features) for more information.
## Discover snippets
diff --git a/doc/workflow/todos.md b/doc/workflow/todos.md
index f94d592d0db..830f17aa7f2 100644
--- a/doc/workflow/todos.md
+++ b/doc/workflow/todos.md
@@ -35,6 +35,9 @@ A Todo appears in your Todos dashboard when:
- the author, or
- have set it to automatically merge once pipeline succeeds.
+NOTE: **Note:**
+When an user no longer has access to a resource related to a Todo like an issue, merge request, project or group the related Todos, for security reasons, gets deleted within the next hour. The delete is delayed to prevent data loss in case user got their access revoked by mistake.
+
### Directly addressed Todos
> [Introduced][ce-7926] in GitLab 9.0.
diff --git a/lib/api/api.rb b/lib/api/api.rb
index f1448da7403..19da0b2c434 100644
--- a/lib/api/api.rb
+++ b/lib/api/api.rb
@@ -139,6 +139,7 @@ module API
mount ::API::ProjectTemplates
mount ::API::ProtectedBranches
mount ::API::ProtectedTags
+ mount ::API::Releases
mount ::API::Repositories
mount ::API::Runner
mount ::API::Runners
diff --git a/lib/api/branches.rb b/lib/api/branches.rb
index e7e58ad0e66..07f529b01bb 100644
--- a/lib/api/branches.rb
+++ b/lib/api/branches.rb
@@ -34,11 +34,11 @@ module API
repository = user_project.repository
branches = BranchesFinder.new(repository, declared_params(include_missing: false)).execute
-
+ branches = ::Kaminari.paginate_array(branches)
merged_branch_names = repository.merged_branch_names(branches.map(&:name))
present(
- paginate(::Kaminari.paginate_array(branches)),
+ paginate(branches),
with: Entities::Branch,
current_user: current_user,
project: user_project,
diff --git a/lib/api/entities.rb b/lib/api/entities.rb
index b83a5c14190..7116ab2882b 100644
--- a/lib/api/entities.rb
+++ b/lib/api/entities.rb
@@ -323,7 +323,7 @@ module API
expose :request_access_enabled
expose :full_name, :full_path
- if ::Group.supports_nested_groups?
+ if ::Group.supports_nested_objects?
expose :parent_id
end
@@ -1087,11 +1087,20 @@ module API
expose :password_authentication_enabled_for_web, as: :signin_enabled
end
- class Release < Grape::Entity
+ # deprecated old Release representation
+ class TagRelease < Grape::Entity
expose :tag, as: :tag_name
expose :description
end
+ class Release < TagRelease
+ expose :name
+ expose :description_html
+ expose :created_at
+ expose :author, using: Entities::UserBasic, if: -> (release, _) { release.author.present? }
+ expose :commit, using: Entities::Commit
+ end
+
class Tag < Grape::Entity
expose :name, :message, :target
@@ -1100,7 +1109,7 @@ module API
end
# rubocop: disable CodeReuse/ActiveRecord
- expose :release, using: Entities::Release do |repo_tag, options|
+ expose :release, using: Entities::TagRelease do |repo_tag, options|
options[:project].releases.find_by(tag: repo_tag.name)
end
# rubocop: enable CodeReuse/ActiveRecord
diff --git a/lib/api/groups.rb b/lib/api/groups.rb
index 626a2008dee..64958ff982a 100644
--- a/lib/api/groups.rb
+++ b/lib/api/groups.rb
@@ -113,7 +113,7 @@ module API
requires :name, type: String, desc: 'The name of the group'
requires :path, type: String, desc: 'The path of the group'
- if ::Group.supports_nested_groups?
+ if ::Group.supports_nested_objects?
optional :parent_id, type: Integer, desc: 'The parent group id for creating nested group'
end
diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb
index a7d67a6300e..6c1a730935a 100644
--- a/lib/api/helpers.rb
+++ b/lib/api/helpers.rb
@@ -163,9 +163,11 @@ module API
end
def find_branch!(branch_name)
- user_project.repository.find_branch(branch_name) || not_found!('Branch')
- rescue Gitlab::Git::CommandError
- render_api_error!('The branch refname is invalid', 400)
+ if Gitlab::GitRefValidator.validate(branch_name)
+ user_project.repository.find_branch(branch_name) || not_found!('Branch')
+ else
+ render_api_error!('The branch refname is invalid', 400)
+ end
end
def find_project_label(id)
@@ -494,7 +496,7 @@ module API
def send_git_blob(repository, blob)
env['api.format'] = :txt
content_type 'text/plain'
- header['Content-Disposition'] = "attachment; filename=#{blob.name.inspect}"
+ header['Content-Disposition'] = content_disposition('attachment', blob.name)
header(*Gitlab::Workhorse.send_git_blob(repository, blob))
end
@@ -527,5 +529,11 @@ module API
params[:archived]
end
+
+ def content_disposition(disposition, filename)
+ disposition += %(; filename=#{filename.inspect}) if filename.present?
+
+ disposition
+ end
end
end
diff --git a/lib/api/internal.rb b/lib/api/internal.rb
index ae40b5f7557..9488b3469d9 100644
--- a/lib/api/internal.rb
+++ b/lib/api/internal.rb
@@ -256,8 +256,9 @@ module API
post '/post_receive' do
status 200
+
PostReceive.perform_async(params[:gl_repository], params[:identifier],
- params[:changes])
+ params[:changes], params[:push_options].to_a)
broadcast_message = BroadcastMessage.current&.last&.message
reference_counter_decreased = Gitlab::ReferenceCounter.new(params[:gl_repository]).decrease
diff --git a/lib/api/jobs.rb b/lib/api/jobs.rb
index 80a5cbd6b19..45c694b6448 100644
--- a/lib/api/jobs.rb
+++ b/lib/api/jobs.rb
@@ -38,6 +38,8 @@ module API
end
# rubocop: disable CodeReuse/ActiveRecord
get ':id/jobs' do
+ authorize_read_builds!
+
builds = user_project.builds.order('id DESC')
builds = filter_builds(builds, params[:scope])
@@ -56,7 +58,10 @@ module API
end
# rubocop: disable CodeReuse/ActiveRecord
get ':id/pipelines/:pipeline_id/jobs' do
+ authorize!(:read_pipeline, user_project)
pipeline = user_project.ci_pipelines.find(params[:pipeline_id])
+ authorize!(:read_build, pipeline)
+
builds = pipeline.builds
builds = filter_builds(builds, params[:scope])
builds = builds.preload(:job_artifacts_archive, :job_artifacts, project: [:namespace])
diff --git a/lib/api/releases.rb b/lib/api/releases.rb
new file mode 100644
index 00000000000..37d06988e64
--- /dev/null
+++ b/lib/api/releases.rb
@@ -0,0 +1,138 @@
+# frozen_string_literal: true
+
+module API
+ class Releases < Grape::API
+ include PaginationParams
+
+ RELEASE_ENDPOINT_REQUIREMETS = API::NAMESPACE_OR_PROJECT_REQUIREMENTS
+ .merge(tag_name: API::NO_SLASH_URL_PART_REGEX)
+
+ before { error!('404 Not Found', 404) unless Feature.enabled?(:releases_page, user_project) }
+ before { authorize_read_releases! }
+
+ params do
+ requires :id, type: String, desc: 'The ID of a project'
+ end
+ resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
+ desc 'Get a project releases' do
+ detail 'This feature was introduced in GitLab 11.7.'
+ success Entities::Release
+ end
+ params do
+ use :pagination
+ end
+ get ':id/releases' do
+ releases = ::ReleasesFinder.new(user_project, current_user).execute
+
+ present paginate(releases), with: Entities::Release
+ end
+
+ desc 'Get a single project release' do
+ detail 'This feature was introduced in GitLab 11.7.'
+ success Entities::Release
+ end
+ params do
+ requires :tag_name, type: String, desc: 'The name of the tag', as: :tag
+ end
+ get ':id/releases/:tag_name', requirements: RELEASE_ENDPOINT_REQUIREMETS do
+ authorize_read_release!
+
+ present release, with: Entities::Release
+ end
+
+ desc 'Create a new release' do
+ detail 'This feature was introduced in GitLab 11.7.'
+ success Entities::Release
+ end
+ params do
+ requires :tag_name, type: String, desc: 'The name of the tag', as: :tag
+ requires :name, type: String, desc: 'The name of the release'
+ requires :description, type: String, desc: 'The release notes'
+ optional :ref, type: String, desc: 'The commit sha or branch name'
+ end
+ post ':id/releases' do
+ authorize_create_release!
+
+ result = ::Releases::CreateService
+ .new(user_project, current_user, declared_params(include_missing: false))
+ .execute
+
+ if result[:status] == :success
+ present result[:release], with: Entities::Release
+ else
+ render_api_error!(result[:message], result[:http_status])
+ end
+ end
+
+ desc 'Update a release' do
+ detail 'This feature was introduced in GitLab 11.7.'
+ success Entities::Release
+ end
+ params do
+ 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'
+ end
+ put ':id/releases/:tag_name', requirements: RELEASE_ENDPOINT_REQUIREMETS do
+ authorize_update_release!
+
+ result = ::Releases::UpdateService
+ .new(user_project, current_user, declared_params(include_missing: false))
+ .execute
+
+ if result[:status] == :success
+ present result[:release], with: Entities::Release
+ else
+ render_api_error!(result[:message], result[:http_status])
+ end
+ end
+
+ desc 'Delete a release' do
+ detail 'This feature was introduced in GitLab 11.7.'
+ success Entities::Release
+ end
+ params do
+ requires :tag_name, type: String, desc: 'The name of the tag', as: :tag
+ end
+ delete ':id/releases/:tag_name', requirements: RELEASE_ENDPOINT_REQUIREMETS do
+ authorize_destroy_release!
+
+ result = ::Releases::DestroyService
+ .new(user_project, current_user, declared_params(include_missing: false))
+ .execute
+
+ if result[:status] == :success
+ present result[:release], with: Entities::Release
+ else
+ render_api_error!(result[:message], result[:http_status])
+ end
+ end
+ end
+
+ helpers do
+ def authorize_create_release!
+ authorize! :create_release, user_project
+ end
+
+ def authorize_read_releases!
+ authorize! :read_release, user_project
+ end
+
+ def authorize_read_release!
+ authorize! :read_release, release
+ end
+
+ def authorize_update_release!
+ authorize! :update_release, release
+ end
+
+ def authorize_destroy_release!
+ authorize! :destroy_release, release
+ end
+
+ def release
+ @release ||= user_project.releases.find_by_tag(params[:tag])
+ end
+ end
+ end
+end
diff --git a/lib/api/tags.rb b/lib/api/tags.rb
index b18eec7d796..aacdca3871a 100644
--- a/lib/api/tags.rb
+++ b/lib/api/tags.rb
@@ -42,21 +42,35 @@ module API
end
desc 'Create a new repository tag' do
+ detail 'This optional release_description parameter was deprecated in GitLab 11.7.'
success Entities::Tag
end
params do
requires :tag_name, type: String, desc: 'The name of the tag'
requires :ref, type: String, desc: 'The commit sha or branch name'
optional :message, type: String, desc: 'Specifying a message creates an annotated tag'
- optional :release_description, type: String, desc: 'Specifying release notes stored in the GitLab database'
+ optional :release_description, type: String, desc: 'Specifying release notes stored in the GitLab database (deprecated in GitLab 11.7)'
end
post ':id/repository/tags' do
authorize_push_project
result = ::Tags::CreateService.new(user_project, current_user)
- .execute(params[:tag_name], params[:ref], params[:message], params[:release_description])
+ .execute(params[:tag_name], params[:ref], params[:message])
if result[:status] == :success
+ # Release creation with Tags API was deprecated in GitLab 11.7
+ if params[:release_description].present?
+ release_create_params = {
+ tag: params[:tag_name],
+ name: params[:tag_name], # Name can be specified in new API
+ description: params[:release_description]
+ }
+
+ ::Releases::CreateService
+ .new(user_project, current_user, release_create_params)
+ .execute
+ end
+
present result[:tag],
with: Entities::Tag,
project: user_project
@@ -88,44 +102,72 @@ module API
end
desc 'Add a release note to a tag' do
- success Entities::Release
+ detail 'This feature was deprecated in GitLab 11.7.'
+ success Entities::TagRelease
end
params do
- requires :tag_name, type: String, desc: 'The name of the tag'
+ requires :tag_name, type: String, desc: 'The name of the tag', as: :tag
requires :description, type: String, desc: 'Release notes with markdown support'
end
post ':id/repository/tags/:tag_name/release', requirements: TAG_ENDPOINT_REQUIREMENTS do
- authorize_push_project
+ authorize_create_release!
+
+ ##
+ # Legacy API does not support tag auto creation.
+ not_found!('Tag') unless user_project.repository.find_tag(params[:tag])
- result = CreateReleaseService.new(user_project, current_user)
- .execute(params[:tag_name], params[:description])
+ release_create_params = {
+ tag: params[:tag],
+ name: params[:tag], # Name can be specified in new API
+ description: params[:description]
+ }
+
+ result = ::Releases::CreateService
+ .new(user_project, current_user, release_create_params)
+ .execute
if result[:status] == :success
- present result[:release], with: Entities::Release
+ present result[:release], with: Entities::TagRelease
else
render_api_error!(result[:message], result[:http_status])
end
end
desc "Update a tag's release note" do
- success Entities::Release
+ detail 'This feature was deprecated in GitLab 11.7.'
+ success Entities::TagRelease
end
params do
- requires :tag_name, type: String, desc: 'The name of the tag'
+ requires :tag_name, type: String, desc: 'The name of the tag', as: :tag
requires :description, type: String, desc: 'Release notes with markdown support'
end
put ':id/repository/tags/:tag_name/release', requirements: TAG_ENDPOINT_REQUIREMENTS do
- authorize_push_project
+ authorize_update_release!
- result = UpdateReleaseService.new(user_project, current_user)
- .execute(params[:tag_name], params[:description])
+ result = ::Releases::UpdateService
+ .new(user_project, current_user, declared_params(include_missing: false))
+ .execute
if result[:status] == :success
- present result[:release], with: Entities::Release
+ present result[:release], with: Entities::TagRelease
else
render_api_error!(result[:message], result[:http_status])
end
end
end
+
+ helpers do
+ def authorize_create_release!
+ authorize! :create_release, user_project
+ end
+
+ def authorize_update_release!
+ authorize! :update_release, release
+ end
+
+ def release
+ @release ||= user_project.releases.find_by_tag(params[:tag])
+ end
+ end
end
end
diff --git a/lib/backup/manager.rb b/lib/backup/manager.rb
index a0434a66ef1..0add2b3f875 100644
--- a/lib/backup/manager.rb
+++ b/lib/backup/manager.rb
@@ -195,7 +195,7 @@ module Backup
if connection.service == ::Fog::Storage::Local
connection.directories.create(key: remote_directory)
else
- connection.directories.get(remote_directory)
+ connection.directories.new(key: remote_directory)
end
end
diff --git a/lib/banzai/filter/external_link_filter.rb b/lib/banzai/filter/external_link_filter.rb
index 2e6d742de27..4f60b6f84c6 100644
--- a/lib/banzai/filter/external_link_filter.rb
+++ b/lib/banzai/filter/external_link_filter.rb
@@ -9,11 +9,10 @@ module Banzai
def call
links.each do |node|
uri = uri(node['href'].to_s)
- next unless uri
- node.set_attribute('href', uri.to_s)
+ node.set_attribute('href', uri.to_s) if uri
- if SCHEMES.include?(uri.scheme) && external_url?(uri)
+ if SCHEMES.include?(uri&.scheme) && !internal_url?(uri)
node.set_attribute('rel', 'nofollow noreferrer noopener')
node.set_attribute('target', '_blank')
end
@@ -35,11 +34,12 @@ module Banzai
doc.xpath(query)
end
- def external_url?(uri)
+ def internal_url?(uri)
+ return false if uri.nil?
# Relative URLs miss a hostname
- return false unless uri.hostname
+ return true unless uri.hostname
- uri.hostname != internal_url.hostname
+ uri.hostname == internal_url.hostname
end
def internal_url
diff --git a/lib/banzai/filter/label_reference_filter.rb b/lib/banzai/filter/label_reference_filter.rb
index 04ec38209c7..f90a35952e5 100644
--- a/lib/banzai/filter/label_reference_filter.rb
+++ b/lib/banzai/filter/label_reference_filter.rb
@@ -29,7 +29,7 @@ module Banzai
if label
yield match, label.id, project, namespace, $~
else
- match
+ escape_html_entities(match)
end
end
end
@@ -102,6 +102,10 @@ module Banzai
CGI.unescapeHTML(text.to_s)
end
+ def escape_html_entities(text)
+ CGI.escapeHTML(text.to_s)
+ end
+
def object_link_title(object, matches)
# use title of wrapped element instead
nil
diff --git a/lib/gitlab/blob_helper.rb b/lib/gitlab/blob_helper.rb
index 488c1d85387..d3e15a79a8b 100644
--- a/lib/gitlab/blob_helper.rb
+++ b/lib/gitlab/blob_helper.rb
@@ -12,7 +12,7 @@ module Gitlab
end
def viewable?
- !large? && text?
+ !large? && text_in_repo?
end
MEGABYTE = 1024 * 1024
@@ -21,7 +21,7 @@ module Gitlab
size.to_i > MEGABYTE
end
- def binary?
+ def binary_in_repo?
# Large blobs aren't even loaded into memory
if data.nil?
true
@@ -40,8 +40,8 @@ module Gitlab
end
end
- def text?
- !binary?
+ def text_in_repo?
+ !binary_in_repo?
end
def image?
@@ -113,7 +113,7 @@ module Gitlab
def content_type
# rubocop:disable Style/MultilineTernaryOperator
# rubocop:disable Style/NestedTernaryOperator
- @content_type ||= binary_mime_type? || binary? ? mime_type :
+ @content_type ||= binary_mime_type? || binary_in_repo? ? mime_type :
(encoding ? "text/plain; charset=#{encoding.downcase}" : "text/plain")
# rubocop:enable Style/NestedTernaryOperator
# rubocop:enable Style/MultilineTernaryOperator
diff --git a/lib/gitlab/checks/base_checker.rb b/lib/gitlab/checks/base_checker.rb
index f8cda0382fe..7fbcf6a4ff4 100644
--- a/lib/gitlab/checks/base_checker.rb
+++ b/lib/gitlab/checks/base_checker.rb
@@ -33,6 +33,22 @@ module Gitlab
def tag_exists?
project.repository.tag_exists?(tag_name)
end
+
+ def validate_once(resource)
+ Gitlab::SafeRequestStore.fetch(cache_key_for_resource(resource)) do
+ yield(resource)
+
+ true
+ end
+ end
+
+ def cache_key_for_resource(resource)
+ "git_access:#{checker_cache_key}:#{resource.cache_key}"
+ end
+
+ def checker_cache_key
+ self.class.name.demodulize.underscore
+ end
end
end
end
diff --git a/lib/gitlab/checks/diff_check.rb b/lib/gitlab/checks/diff_check.rb
index 8ee345ab45a..63da9a3d6b5 100644
--- a/lib/gitlab/checks/diff_check.rb
+++ b/lib/gitlab/checks/diff_check.rb
@@ -14,13 +14,17 @@ module Gitlab
return if deletion? || newrev.nil?
return unless should_run_diff_validations?
return if commits.empty?
- return unless uses_raw_delta_validations?
file_paths = []
- process_raw_deltas do |diff|
- file_paths << (diff.new_path || diff.old_path)
- validate_diff(diff)
+ process_commits do |commit|
+ validate_once(commit) do
+ commit.raw_deltas.each do |diff|
+ file_paths << (diff.new_path || diff.old_path)
+
+ validate_diff(diff)
+ end
+ end
end
validate_file_paths(file_paths)
@@ -28,17 +32,13 @@ module Gitlab
private
- def should_run_diff_validations?
- validate_lfs_file_locks?
- end
-
def validate_lfs_file_locks?
strong_memoize(:validate_lfs_file_locks) do
project.lfs_enabled? && project.any_lfs_file_locks?
end
end
- def uses_raw_delta_validations?
+ def should_run_diff_validations?
validations_for_diff.present? || path_validations.present?
end
@@ -59,16 +59,14 @@ module Gitlab
validate_lfs_file_locks? ? [lfs_file_locks_validation] : []
end
- def process_raw_deltas
+ def process_commits
logger.log_timed(LOG_MESSAGES[:diff_content_check]) do
# n+1: https://gitlab.com/gitlab-org/gitlab-ee/issues/3593
::Gitlab::GitalyClient.allow_n_plus_1_calls do
commits.each do |commit|
logger.check_timeout_reached
- commit.raw_deltas.each do |diff|
- yield(diff)
- end
+ yield(commit)
end
end
end
diff --git a/lib/gitlab/checks/lfs_check.rb b/lib/gitlab/checks/lfs_check.rb
index e42684e679a..cc6a14d2d9a 100644
--- a/lib/gitlab/checks/lfs_check.rb
+++ b/lib/gitlab/checks/lfs_check.rb
@@ -7,6 +7,7 @@ module Gitlab
ERROR_MESSAGE = 'LFS objects are missing. Ensure LFS is properly set up or try a manual "git lfs push --all".'.freeze
def validate!
+ return unless project.lfs_enabled?
return if skip_lfs_integrity_check
logger.log_timed(LOG_MESSAGE) do
diff --git a/lib/gitlab/ci/pipeline/chain/command.rb b/lib/gitlab/ci/pipeline/chain/command.rb
index 100b9521412..e62d547d862 100644
--- a/lib/gitlab/ci/pipeline/chain/command.rb
+++ b/lib/gitlab/ci/pipeline/chain/command.rb
@@ -10,7 +10,7 @@ module Gitlab
:origin_ref, :checkout_sha, :after_sha, :before_sha,
:trigger_request, :schedule, :merge_request,
:ignore_skip_ci, :save_incompleted,
- :seeds_block, :variables_attributes
+ :seeds_block, :variables_attributes, :push_options
) do
include Gitlab::Utils::StrongMemoize
@@ -54,7 +54,13 @@ module Gitlab
def protected_ref?
strong_memoize(:protected_ref) do
- project.protected_for?(ref)
+ project.protected_for?(origin_ref)
+ end
+ end
+
+ def ambiguous_ref?
+ strong_memoize(:ambiguous_ref) do
+ project.repository.ambiguous_ref?(origin_ref)
end
end
end
diff --git a/lib/gitlab/ci/pipeline/chain/skip.rb b/lib/gitlab/ci/pipeline/chain/skip.rb
index b9707d2f8f5..79bbcc1ed1e 100644
--- a/lib/gitlab/ci/pipeline/chain/skip.rb
+++ b/lib/gitlab/ci/pipeline/chain/skip.rb
@@ -8,6 +8,7 @@ module Gitlab
include ::Gitlab::Utils::StrongMemoize
SKIP_PATTERN = /\[(ci[ _-]skip|skip[ _-]ci)\]/i
+ SKIP_PUSH_OPTION = 'ci.skip'
def perform!
if skipped?
@@ -16,7 +17,7 @@ module Gitlab
end
def skipped?
- !@command.ignore_skip_ci && commit_message_skips_ci?
+ !@command.ignore_skip_ci && (commit_message_skips_ci? || push_option_skips_ci?)
end
def break?
@@ -32,6 +33,10 @@ module Gitlab
!!(@pipeline.git_commit_message =~ SKIP_PATTERN)
end
end
+
+ def push_option_skips_ci?
+ !!(@command.push_options&.include?(SKIP_PUSH_OPTION))
+ end
end
end
end
diff --git a/lib/gitlab/ci/pipeline/chain/validate/repository.rb b/lib/gitlab/ci/pipeline/chain/validate/repository.rb
index d88851d8245..9c6c2bc8e25 100644
--- a/lib/gitlab/ci/pipeline/chain/validate/repository.rb
+++ b/lib/gitlab/ci/pipeline/chain/validate/repository.rb
@@ -16,6 +16,10 @@ module Gitlab
unless @command.sha
return error('Commit not found')
end
+
+ if @command.ambiguous_ref?
+ return error('Ref is ambiguous')
+ end
end
def break?
diff --git a/lib/gitlab/ci/templates/Ruby.gitlab-ci.yml b/lib/gitlab/ci/templates/Ruby.gitlab-ci.yml
index 93cb31f48c0..0d12cbc6460 100644
--- a/lib/gitlab/ci/templates/Ruby.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Ruby.gitlab-ci.yml
@@ -24,7 +24,6 @@ before_script:
- ruby -v # Print out ruby version for debugging
# Uncomment next line if your rails app needs a JS runtime:
# - apt-get update -q && apt-get install nodejs -yqq
- - gem install bundler --no-ri --no-rdoc # Bundler is not installed with the image
- bundle install -j $(nproc) --path vendor # Install dependencies into ./vendor/ruby
# Optional - Delete if not using `rubocop`
diff --git a/lib/gitlab/cleanup/remote_uploads.rb b/lib/gitlab/cleanup/remote_uploads.rb
index eba1faacc3a..03298d960a4 100644
--- a/lib/gitlab/cleanup/remote_uploads.rb
+++ b/lib/gitlab/cleanup/remote_uploads.rb
@@ -67,7 +67,7 @@ module Gitlab
end
def remote_directory
- connection.directories.get(configuration['remote_directory'])
+ connection.directories.new(key: configuration['remote_directory'])
end
def connection
diff --git a/lib/gitlab/current_settings.rb b/lib/gitlab/current_settings.rb
index 477f9101e98..552aad83dd4 100644
--- a/lib/gitlab/current_settings.rb
+++ b/lib/gitlab/current_settings.rb
@@ -7,10 +7,6 @@ module Gitlab
Gitlab::SafeRequestStore.fetch(:current_application_settings) { ensure_application_settings! }
end
- def fake_application_settings(attributes = {})
- Gitlab::FakeApplicationSettings.new(::ApplicationSetting.defaults.merge(attributes || {}))
- end
-
def clear_in_memory_application_settings!
@in_memory_application_settings = nil
end
@@ -50,28 +46,21 @@ module Gitlab
# and other callers from failing, use any loaded settings and return
# defaults for missing columns.
if ActiveRecord::Migrator.needs_migration?
- return fake_application_settings(current_settings&.attributes)
- end
-
- return current_settings if current_settings.present?
-
- with_fallback_to_fake_application_settings do
- ::ApplicationSetting.create_from_defaults || in_memory_application_settings
+ db_attributes = current_settings&.attributes || {}
+ ::ApplicationSetting.build_from_defaults(db_attributes)
+ elsif current_settings.present?
+ current_settings
+ else
+ ::ApplicationSetting.create_from_defaults
end
end
- def in_memory_application_settings
- with_fallback_to_fake_application_settings do
- @in_memory_application_settings ||= ::ApplicationSetting.build_from_defaults
- end
+ def fake_application_settings(attributes = {})
+ Gitlab::FakeApplicationSettings.new(::ApplicationSetting.defaults.merge(attributes || {}))
end
- def with_fallback_to_fake_application_settings(&block)
- yield
- rescue
- # In case the application_settings table is not created yet, or if a new
- # ApplicationSetting column is not yet migrated we fallback to a simple OpenStruct
- fake_application_settings
+ def in_memory_application_settings
+ @in_memory_application_settings ||= ::ApplicationSetting.build_from_defaults
end
def connect_to_db?
diff --git a/lib/gitlab/data_builder/push.rb b/lib/gitlab/data_builder/push.rb
index 9bf2f9291a8..862127110b9 100644
--- a/lib/gitlab/data_builder/push.rb
+++ b/lib/gitlab/data_builder/push.rb
@@ -31,7 +31,11 @@ module Gitlab
}
}
],
- total_commits_count: 1
+ total_commits_count: 1,
+ push_options: [
+ "ci.skip",
+ "custom option"
+ ]
}.freeze
# Produce a hash of post-receive data
@@ -52,10 +56,12 @@ module Gitlab
# homepage: String,
# },
# commits: Array,
- # total_commits_count: Fixnum
+ # total_commits_count: Fixnum,
+ # push_options: Array
# }
#
- def build(project, user, oldrev, newrev, ref, commits = [], message = nil, commits_count: nil)
+ # rubocop:disable Metrics/ParameterLists
+ def build(project, user, oldrev, newrev, ref, commits = [], message = nil, commits_count: nil, push_options: [])
commits = Array(commits)
# Total commits count
@@ -93,6 +99,7 @@ module Gitlab
project: project.hook_attrs,
commits: commit_attrs,
total_commits_count: commits_count,
+ push_options: push_options,
# DEPRECATED
repository: project.hook_attrs.slice(:name, :url, :description, :homepage,
:git_http_url, :git_ssh_url, :visibility_level)
diff --git a/lib/gitlab/diff/file.rb b/lib/gitlab/diff/file.rb
index b5fc8d364c8..e410d5a8333 100644
--- a/lib/gitlab/diff/file.rb
+++ b/lib/gitlab/diff/file.rb
@@ -3,7 +3,9 @@
module Gitlab
module Diff
class File
- attr_reader :diff, :repository, :diff_refs, :fallback_diff_refs
+ include Gitlab::Utils::StrongMemoize
+
+ attr_reader :diff, :repository, :diff_refs, :fallback_diff_refs, :unique_identifier
delegate :new_file?, :deleted_file?, :renamed_file?,
:old_path, :new_path, :a_mode, :b_mode, :mode_changed?,
@@ -22,12 +24,20 @@ module Gitlab
DiffViewer::Image
].sort_by { |v| v.binary? ? 0 : 1 }.freeze
- def initialize(diff, repository:, diff_refs: nil, fallback_diff_refs: nil, stats: nil)
+ def initialize(
+ diff,
+ repository:,
+ diff_refs: nil,
+ fallback_diff_refs: nil,
+ stats: nil,
+ unique_identifier: nil)
+
@diff = diff
@stats = stats
@repository = repository
@diff_refs = diff_refs
@fallback_diff_refs = fallback_diff_refs
+ @unique_identifier = unique_identifier
@unfolded = false
# Ensure items are collected in the the batch
@@ -67,7 +77,15 @@ module Gitlab
def line_for_position(pos)
return nil unless pos.position_type == 'text'
- diff_lines.find { |line| line.old_line == pos.old_line && line.new_line == pos.new_line }
+ # This method is normally used to find which line the diff was
+ # commented on, and in this context, it's normally the raw diff persisted
+ # at `note_diff_files`, which is a fraction of the entire diff
+ # (it goes from the first line, to the commented line, or
+ # one line below). Therefore it's more performant to fetch
+ # from bottom to top instead of the other way around.
+ diff_lines
+ .reverse_each
+ .find { |line| line.old_line == pos.old_line && line.new_line == pos.new_line }
end
def position_for_line_code(code)
@@ -166,6 +184,10 @@ module Gitlab
@unfolded
end
+ def highlight_loaded?
+ @highlighted_diff_lines.present?
+ end
+
def highlighted_diff_lines
@highlighted_diff_lines ||=
Gitlab::Diff::Highlight.new(self, repository: self.repository).highlight
@@ -212,12 +234,12 @@ module Gitlab
repository.attributes(file_path).fetch('diff') { true }
end
- def binary?
- has_binary_notice? || try_blobs(:binary?)
+ def binary_in_repo?
+ has_binary_notice? || try_blobs(:binary_in_repo?)
end
- def text?
- !binary?
+ def text_in_repo?
+ !binary_in_repo?
end
def external_storage_error?
@@ -259,12 +281,16 @@ module Gitlab
valid_blobs.map(&:empty?).all?
end
- def raw_binary?
- try_blobs(:raw_binary?)
+ def binary?
+ strong_memoize(:is_binary) do
+ try_blobs(:binary?)
+ end
end
- def raw_text?
- !raw_binary? && !different_type?
+ def text?
+ strong_memoize(:is_text) do
+ !binary? && !different_type?
+ end
end
def simple_viewer
@@ -347,19 +373,19 @@ module Gitlab
return DiffViewer::NotDiffable unless diffable?
if content_changed?
- if raw_text?
+ if text?
DiffViewer::Text
else
DiffViewer::NoPreview
end
elsif new_file?
- if raw_text?
+ if text?
DiffViewer::Text
else
DiffViewer::Added
end
elsif deleted_file?
- if raw_text?
+ if text?
DiffViewer::Text
else
DiffViewer::Deleted
diff --git a/lib/gitlab/discussions_diff/file_collection.rb b/lib/gitlab/discussions_diff/file_collection.rb
new file mode 100644
index 00000000000..4ab7314f509
--- /dev/null
+++ b/lib/gitlab/discussions_diff/file_collection.rb
@@ -0,0 +1,76 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module DiscussionsDiff
+ class FileCollection
+ include Gitlab::Utils::StrongMemoize
+
+ def initialize(collection)
+ @collection = collection
+ end
+
+ # Returns a Gitlab::Diff::File with the given ID (`unique_identifier` in
+ # Gitlab::Diff::File).
+ def find_by_id(id)
+ diff_files_indexed_by_id[id]
+ end
+
+ # Writes cache and preloads highlighted diff lines for
+ # object IDs, in @collection.
+ #
+ # highlightable_ids - Diff file `Array` responding to ID. The ID will be used
+ # to generate the cache key.
+ #
+ # - Highlight cache is written just for uncached diff files
+ # - The cache content is not updated (there's no need to do so)
+ def load_highlight(highlightable_ids)
+ preload_highlighted_lines(highlightable_ids)
+ end
+
+ private
+
+ def preload_highlighted_lines(ids)
+ cached_content = read_cache(ids)
+
+ uncached_ids = ids.select.each_with_index { |_, i| cached_content[i].nil? }
+ mapping = highlighted_lines_by_ids(uncached_ids)
+
+ HighlightCache.write_multiple(mapping)
+
+ diffs = diff_files_indexed_by_id.values_at(*ids)
+
+ diffs.zip(cached_content).each do |diff, cached_lines|
+ next unless diff && cached_lines
+
+ diff.highlighted_diff_lines = cached_lines
+ end
+ end
+
+ def read_cache(ids)
+ HighlightCache.read_multiple(ids)
+ end
+
+ def diff_files_indexed_by_id
+ strong_memoize(:diff_files_indexed_by_id) do
+ diff_files.index_by(&:unique_identifier)
+ end
+ end
+
+ def diff_files
+ strong_memoize(:diff_files) do
+ @collection.map(&:raw_diff_file)
+ end
+ end
+
+ # Processes the diff lines highlighting for diff files matching the given
+ # IDs.
+ #
+ # Returns a Hash with { id => [Array of Gitlab::Diff::line], ...]
+ def highlighted_lines_by_ids(ids)
+ diff_files_indexed_by_id.slice(*ids).each_with_object({}) do |(id, file), hash|
+ hash[id] = file.highlighted_diff_lines.map(&:to_hash)
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/discussions_diff/highlight_cache.rb b/lib/gitlab/discussions_diff/highlight_cache.rb
new file mode 100644
index 00000000000..270cfb89488
--- /dev/null
+++ b/lib/gitlab/discussions_diff/highlight_cache.rb
@@ -0,0 +1,67 @@
+# frozen_string_literal: true
+#
+module Gitlab
+ module DiscussionsDiff
+ class HighlightCache
+ class << self
+ VERSION = 1
+ EXPIRATION = 1.week
+
+ # Sets multiple keys to a given value. The value
+ # is serialized as JSON.
+ #
+ # mapping - Write multiple cache values at once
+ def write_multiple(mapping)
+ Redis::Cache.with do |redis|
+ redis.multi do |multi|
+ mapping.each do |raw_key, value|
+ key = cache_key_for(raw_key)
+
+ multi.set(key, value.to_json, ex: EXPIRATION)
+ end
+ end
+ end
+ end
+
+ # Reads multiple cache keys at once.
+ #
+ # raw_keys - An Array of unique cache keys, without namespaces.
+ #
+ # It returns a list of deserialized diff lines. Ex.:
+ # [[Gitlab::Diff::Line, ...], [Gitlab::Diff::Line]]
+ def read_multiple(raw_keys)
+ return [] if raw_keys.empty?
+
+ keys = raw_keys.map { |id| cache_key_for(id) }
+
+ content =
+ Redis::Cache.with do |redis|
+ redis.mget(keys)
+ end
+
+ content.map! do |lines|
+ next unless lines
+
+ JSON.parse(lines).map! do |line|
+ line = line.with_indifferent_access
+ rich_text = line[:rich_text]
+ line[:rich_text] = rich_text&.html_safe
+
+ Gitlab::Diff::Line.init_from_hash(line)
+ end
+ end
+ end
+
+ def cache_key_for(raw_key)
+ "#{cache_key_prefix}:#{raw_key}"
+ end
+
+ private
+
+ def cache_key_prefix
+ "#{Redis::Cache::CACHE_NAMESPACE}:#{VERSION}:discussion-highlight"
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/git.rb b/lib/gitlab/git.rb
index c4aac228b2f..44a62586a23 100644
--- a/lib/gitlab/git.rb
+++ b/lib/gitlab/git.rb
@@ -54,11 +54,11 @@ module Gitlab
end
def tag_ref?(ref)
- ref.start_with?(TAG_REF_PREFIX)
+ ref =~ /^#{TAG_REF_PREFIX}.+/
end
def branch_ref?(ref)
- ref.start_with?(BRANCH_REF_PREFIX)
+ ref =~ /^#{BRANCH_REF_PREFIX}.+/
end
def blank_ref?(ref)
diff --git a/lib/gitlab/git/blob.rb b/lib/gitlab/git/blob.rb
index 2d25389594e..259a2b7911a 100644
--- a/lib/gitlab/git/blob.rb
+++ b/lib/gitlab/git/blob.rb
@@ -100,7 +100,7 @@ module Gitlab
@loaded_all_data = @loaded_size == size
end
- def binary?
+ def binary_in_repo?
@binary.nil? ? super : @binary == true
end
@@ -174,7 +174,7 @@ module Gitlab
private
def has_lfs_version_key?
- !empty? && text? && data.start_with?("version https://git-lfs.github.com/spec")
+ !empty? && text_in_repo? && data.start_with?("version https://git-lfs.github.com/spec")
end
end
end
diff --git a/lib/gitlab/git_post_receive.rb b/lib/gitlab/git_post_receive.rb
index cf2329e489d..426436c2164 100644
--- a/lib/gitlab/git_post_receive.rb
+++ b/lib/gitlab/git_post_receive.rb
@@ -3,12 +3,13 @@
module Gitlab
class GitPostReceive
include Gitlab::Identifier
- attr_reader :project, :identifier, :changes
+ attr_reader :project, :identifier, :changes, :push_options
- def initialize(project, identifier, changes)
+ def initialize(project, identifier, changes, push_options)
@project = project
@identifier = identifier
@changes = deserialize_changes(changes)
+ @push_options = push_options
end
def identify
diff --git a/lib/gitlab/gitaly_client.rb b/lib/gitlab/gitaly_client.rb
index 11021ee06b3..8bf8a3b53cd 100644
--- a/lib/gitlab/gitaly_client.rb
+++ b/lib/gitlab/gitaly_client.rb
@@ -26,6 +26,7 @@ module Gitlab
end
end
+ PEM_REGEX = /\-+BEGIN CERTIFICATE\-+.+?\-+END CERTIFICATE\-+/m
SERVER_VERSION_FILE = 'GITALY_SERVER_VERSION'
MAXIMUM_GITALY_CALLS = 35
CLIENT_NAME = (Sidekiq.server? ? 'gitlab-sidekiq' : 'gitlab-web').freeze
@@ -50,11 +51,42 @@ module Gitlab
@stubs[storage][name] ||= begin
klass = stub_class(name)
addr = stub_address(storage)
- klass.new(addr, :this_channel_is_insecure)
+ creds = stub_creds(storage)
+ klass.new(addr, creds)
end
end
end
+ def self.stub_cert_paths
+ cert_paths = Dir["#{OpenSSL::X509::DEFAULT_CERT_DIR}/*"]
+ cert_paths << OpenSSL::X509::DEFAULT_CERT_FILE if File.exist? OpenSSL::X509::DEFAULT_CERT_FILE
+ cert_paths
+ end
+
+ def self.stub_certs
+ return @certs if @certs
+
+ @certs = stub_cert_paths.flat_map do |cert_file|
+ File.read(cert_file).scan(PEM_REGEX).map do |cert|
+ begin
+ OpenSSL::X509::Certificate.new(cert).to_pem
+ rescue OpenSSL::OpenSSLError => e
+ Rails.logger.error "Could not load certificate #{cert_file} #{e}"
+ Gitlab::Sentry.track_exception(e, extra: { cert_file: cert_file })
+ nil
+ end
+ end.compact
+ end.uniq.join("\n")
+ end
+
+ def self.stub_creds(storage)
+ if URI(address(storage)).scheme == 'tls'
+ GRPC::Core::ChannelCredentials.new stub_certs
+ else
+ :this_channel_is_insecure
+ end
+ end
+
def self.stub_class(name)
if name == :health_check
Grpc::Health::V1::Health::Stub
@@ -64,9 +96,7 @@ module Gitlab
end
def self.stub_address(storage)
- addr = address(storage)
- addr = addr.sub(%r{^tcp://}, '') if URI(addr).scheme == 'tcp'
- addr
+ address(storage).sub(%r{^tcp://|^tls://}, '')
end
def self.clear_stubs!
@@ -88,8 +118,8 @@ module Gitlab
raise "storage #{storage.inspect} is missing a gitaly_address"
end
- unless URI(address).scheme.in?(%w(tcp unix))
- raise "Unsupported Gitaly address: #{address.inspect} does not use URL scheme 'tcp' or 'unix'"
+ unless URI(address).scheme.in?(%w(tcp unix tls))
+ raise "Unsupported Gitaly address: #{address.inspect} does not use URL scheme 'tcp' or 'unix' or 'tls'"
end
address
diff --git a/lib/gitlab/import_export/command_line_util.rb b/lib/gitlab/import_export/command_line_util.rb
index c9e2a6a78d9..bdecff0931c 100644
--- a/lib/gitlab/import_export/command_line_util.rb
+++ b/lib/gitlab/import_export/command_line_util.rb
@@ -3,7 +3,8 @@
module Gitlab
module ImportExport
module CommandLineUtil
- DEFAULT_MODE = 0700
+ UNTAR_MASK = 'u+rwX,go+rX,go-w'
+ DEFAULT_DIR_MODE = 0700
def tar_czf(archive:, dir:)
tar_with_options(archive: archive, dir: dir, options: 'czf')
@@ -14,8 +15,8 @@ module Gitlab
end
def mkdir_p(path)
- FileUtils.mkdir_p(path, mode: DEFAULT_MODE)
- FileUtils.chmod(DEFAULT_MODE, path)
+ FileUtils.mkdir_p(path, mode: DEFAULT_DIR_MODE)
+ FileUtils.chmod(DEFAULT_DIR_MODE, path)
end
private
@@ -41,6 +42,7 @@ module Gitlab
def untar_with_options(archive:, dir:, options:)
execute(%W(tar -#{options} #{archive} -C #{dir}))
+ execute(%W(chmod -R #{UNTAR_MASK} #{dir}))
end
def execute(cmd)
diff --git a/lib/gitlab/group_hierarchy.rb b/lib/gitlab/object_hierarchy.rb
index 97cbdc6cb39..f2772c733c7 100644
--- a/lib/gitlab/group_hierarchy.rb
+++ b/lib/gitlab/object_hierarchy.rb
@@ -1,16 +1,16 @@
# frozen_string_literal: true
module Gitlab
- # Retrieving of parent or child groups based on a base ActiveRecord relation.
+ # Retrieving of parent or child objects based on a base ActiveRecord relation.
#
# This class uses recursive CTEs and as a result will only work on PostgreSQL.
- class GroupHierarchy
+ class ObjectHierarchy
attr_reader :ancestors_base, :descendants_base, :model
# ancestors_base - An instance of ActiveRecord::Relation for which to
- # get parent groups.
+ # get parent objects.
# descendants_base - An instance of ActiveRecord::Relation for which to
- # get child groups. If omitted, ancestors_base is used.
+ # get child objects. If omitted, ancestors_base is used.
def initialize(ancestors_base, descendants_base = ancestors_base)
raise ArgumentError.new("Model of ancestors_base does not match model of descendants_base") if ancestors_base.model != descendants_base.model
@@ -39,7 +39,7 @@ module Gitlab
end
# rubocop: enable CodeReuse/ActiveRecord
- # Returns a relation that includes the ancestors_base set of groups
+ # Returns a relation that includes the ancestors_base set of objects
# and all their ancestors (recursively).
#
# Passing an `upto` will stop the recursion once the specified parent_id is
@@ -47,13 +47,13 @@ module Gitlab
# included.
#
# Passing a `hierarchy_order` with either `:asc` or `:desc` will cause the
- # recursive query order from most nested group to root or from the root
- # ancestor to most nested group respectively. This uses a `depth` column
+ # recursive query order from most nested object to root or from the root
+ # ancestor to most nested object respectively. This uses a `depth` column
# where `1` is defined as the depth for the base and increment as we go up
# each parent.
# rubocop: disable CodeReuse/ActiveRecord
def base_and_ancestors(upto: nil, hierarchy_order: nil)
- return ancestors_base unless Group.supports_nested_groups?
+ return ancestors_base unless hierarchy_supported?
recursive_query = base_and_ancestors_cte(upto, hierarchy_order).apply_to(model.all)
recursive_query = recursive_query.order(depth: hierarchy_order) if hierarchy_order
@@ -62,16 +62,16 @@ module Gitlab
end
# rubocop: enable CodeReuse/ActiveRecord
- # Returns a relation that includes the descendants_base set of groups
+ # Returns a relation that includes the descendants_base set of objects
# and all their descendants (recursively).
def base_and_descendants
- return descendants_base unless Group.supports_nested_groups?
+ return descendants_base unless hierarchy_supported?
read_only(base_and_descendants_cte.apply_to(model.all))
end
- # Returns a relation that includes the base groups, their ancestors,
- # and the descendants of the base groups.
+ # Returns a relation that includes the base objects, their ancestors,
+ # and the descendants of the base objects.
#
# The resulting query will roughly look like the following:
#
@@ -91,16 +91,16 @@ module Gitlab
# Using this approach allows us to further add criteria to the relation with
# Rails thinking it's selecting data the usual way.
#
- # If nested groups are not supported, ancestors_base is returned.
+ # If nested objects are not supported, ancestors_base is returned.
# rubocop: disable CodeReuse/ActiveRecord
- def all_groups
- return ancestors_base unless Group.supports_nested_groups?
+ def all_objects
+ return ancestors_base unless hierarchy_supported?
ancestors = base_and_ancestors_cte
descendants = base_and_descendants_cte
- ancestors_table = ancestors.alias_to(groups_table)
- descendants_table = descendants.alias_to(groups_table)
+ ancestors_table = ancestors.alias_to(objects_table)
+ descendants_table = descendants.alias_to(objects_table)
relation = model
.unscoped
@@ -117,23 +117,27 @@ module Gitlab
private
+ def hierarchy_supported?
+ Gitlab::Database.postgresql?
+ end
+
# rubocop: disable CodeReuse/ActiveRecord
def base_and_ancestors_cte(stop_id = nil, hierarchy_order = nil)
cte = SQL::RecursiveCTE.new(:base_and_ancestors)
depth_column = :depth
base_query = ancestors_base.except(:order)
- base_query = base_query.select("1 as #{depth_column}", groups_table[Arel.star]) if hierarchy_order
+ base_query = base_query.select("1 as #{depth_column}", objects_table[Arel.star]) if hierarchy_order
cte << base_query
# Recursively get all the ancestors of the base set.
parent_query = model
- .from([groups_table, cte.table])
- .where(groups_table[:id].eq(cte.table[:parent_id]))
+ .from([objects_table, cte.table])
+ .where(objects_table[:id].eq(cte.table[:parent_id]))
.except(:order)
- parent_query = parent_query.select(cte.table[depth_column] + 1, groups_table[Arel.star]) if hierarchy_order
+ parent_query = parent_query.select(cte.table[depth_column] + 1, objects_table[Arel.star]) if hierarchy_order
parent_query = parent_query.where(cte.table[:parent_id].not_eq(stop_id)) if stop_id
cte << parent_query
@@ -149,15 +153,15 @@ module Gitlab
# Recursively get all the descendants of the base set.
cte << model
- .from([groups_table, cte.table])
- .where(groups_table[:parent_id].eq(cte.table[:id]))
+ .from([objects_table, cte.table])
+ .where(objects_table[:parent_id].eq(cte.table[:id]))
.except(:order)
cte
end
# rubocop: enable CodeReuse/ActiveRecord
- def groups_table
+ def objects_table
model.arel_table
end
diff --git a/lib/gitlab/prometheus/metric_group.rb b/lib/gitlab/prometheus/metric_group.rb
index 8f30cdee232..394556e8708 100644
--- a/lib/gitlab/prometheus/metric_group.rb
+++ b/lib/gitlab/prometheus/metric_group.rb
@@ -10,9 +10,15 @@ module Gitlab
validates :name, :priority, :metrics, presence: true
def self.common_metrics
- ::PrometheusMetric.common.group_by(&:group_title).map do |name, metrics|
- MetricGroup.new(name: name, priority: 0, metrics: metrics.map(&:to_query_metric))
+ all_groups = ::PrometheusMetric.common.group_by(&:group_title).map do |name, metrics|
+ MetricGroup.new(
+ name: name,
+ priority: metrics.map(&:priority).max,
+ metrics: metrics.map(&:to_query_metric)
+ )
end
+
+ all_groups.sort_by(&:priority).reverse
end
# EE only
diff --git a/lib/gitlab/upgrader.rb b/lib/gitlab/upgrader.rb
deleted file mode 100644
index ccab0e4dd73..00000000000
--- a/lib/gitlab/upgrader.rb
+++ /dev/null
@@ -1,111 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- class Upgrader
- def execute
- puts "GitLab #{current_version.major} upgrade tool"
- puts "Your version is #{current_version}"
- puts "Latest available version for GitLab #{current_version.major} is #{latest_version}"
-
- if latest_version?
- puts "You are using the latest GitLab version"
- else
- puts "Newer GitLab version is available"
-
- answer = if ARGV.first == "-y"
- "yes"
- else
- prompt("Do you want to upgrade (yes/no)? ", %w{yes no})
- end
-
- if answer == "yes"
- upgrade
- else
- exit 0
- end
- end
- end
-
- def latest_version?
- current_version >= latest_version
- end
-
- def current_version
- @current_version ||= Gitlab::VersionInfo.parse(current_version_raw)
- end
-
- def latest_version
- @latest_version ||= Gitlab::VersionInfo.parse(latest_version_raw)
- end
-
- def current_version_raw
- File.read(File.join(gitlab_path, "VERSION")).strip
- end
-
- def latest_version_raw
- git_tags = fetch_git_tags
- git_tags = git_tags.select { |version| version =~ /v\d+\.\d+\.\d+\Z/ }
- git_versions = git_tags.map { |tag| Gitlab::VersionInfo.parse(tag.match(/v\d+\.\d+\.\d+/).to_s) }
- "v#{git_versions.sort.last}"
- end
-
- def fetch_git_tags
- remote_tags, _ = Gitlab::Popen.popen(%W(#{Gitlab.config.git.bin_path} ls-remote --tags https://gitlab.com/gitlab-org/gitlab-ce.git))
- remote_tags.split("\n").grep(%r{tags/v#{current_version.major}})
- end
-
- def update_commands
- {
- "Stash changed files" => %W(#{Gitlab.config.git.bin_path} stash),
- "Get latest code" => %W(#{Gitlab.config.git.bin_path} fetch),
- "Switch to new version" => %W(#{Gitlab.config.git.bin_path} checkout v#{latest_version}),
- "Install gems" => %w(bundle),
- "Migrate DB" => %w(bundle exec rake db:migrate),
- "Recompile assets" => %w(bundle exec rake yarn:install gitlab:assets:clean gitlab:assets:compile),
- "Clear cache" => %w(bundle exec rake cache:clear)
- }
- end
-
- def env
- {
- 'RAILS_ENV' => 'production',
- 'NODE_ENV' => 'production'
- }
- end
-
- def upgrade
- update_commands.each do |title, cmd|
- puts title
- puts " -> #{cmd.join(' ')}"
-
- if system(env, *cmd)
- puts " -> OK"
- else
- puts " -> FAILED"
- puts "Failed to upgrade. Try to repeat task or proceed with upgrade manually "
- exit 1
- end
- end
-
- puts "Done"
- end
-
- def gitlab_path
- File.expand_path(File.join(File.dirname(__FILE__), '../..'))
- end
-
- # Prompt the user to input something
- #
- # message - the message to display before input
- # choices - array of strings of acceptable answers or nil for any answer
- #
- # Returns the user's answer
- def prompt(message, choices = nil)
- begin
- print(message)
- answer = STDIN.gets.chomp
- end while !choices.include?(answer)
- answer
- end
- end
-end
diff --git a/lib/gitlab/utils/override.rb b/lib/gitlab/utils/override.rb
index c412961ea3f..c87e97d0213 100644
--- a/lib/gitlab/utils/override.rb
+++ b/lib/gitlab/utils/override.rb
@@ -4,16 +4,11 @@ module Gitlab
module Utils
module Override
class Extension
- def self.verify_class!(klass, method_name)
- instance_method_defined?(klass, method_name) ||
- raise(
- NotImplementedError.new(
- "#{klass}\##{method_name} doesn't exist!"))
- end
-
- def self.instance_method_defined?(klass, name, include_super: true)
- klass.instance_methods(include_super).include?(name) ||
- klass.private_instance_methods(include_super).include?(name)
+ def self.verify_class!(klass, method_name, arity)
+ extension = new(klass)
+ parents = extension.parents_for(klass)
+ extension.verify_method!(
+ klass: klass, parents: parents, method_name: method_name, sub_method_arity: arity)
end
attr_reader :subject
@@ -22,35 +17,77 @@ module Gitlab
@subject = subject
end
- def add_method_name(method_name)
- method_names << method_name
- end
-
- def add_class(klass)
- classes << klass
+ def parents_for(klass)
+ index = klass.ancestors.index(subject)
+ klass.ancestors.drop(index + 1)
end
def verify!
classes.each do |klass|
- index = klass.ancestors.index(subject)
- parents = klass.ancestors.drop(index + 1)
-
- method_names.each do |method_name|
- parents.any? do |parent|
- self.class.instance_method_defined?(
- parent, method_name, include_super: false)
- end ||
- raise(
- NotImplementedError.new(
- "#{klass}\##{method_name} doesn't exist!"))
+ parents = parents_for(klass)
+
+ method_names.each_pair do |method_name, arity|
+ verify_method!(
+ klass: klass,
+ parents: parents,
+ method_name: method_name,
+ sub_method_arity: arity)
end
end
end
+ def verify_method!(klass:, parents:, method_name:, sub_method_arity:)
+ overridden_parent = parents.find do |parent|
+ instance_method_defined?(parent, method_name)
+ end
+
+ raise NotImplementedError.new("#{klass}\##{method_name} doesn't exist!") unless overridden_parent
+
+ super_method_arity = find_direct_method(overridden_parent, method_name).arity
+
+ unless arity_compatible?(sub_method_arity, super_method_arity)
+ raise NotImplementedError.new("#{subject}\##{method_name} has arity of #{sub_method_arity}, but #{overridden_parent}\##{method_name} has arity of #{super_method_arity}")
+ end
+ end
+
+ def add_method_name(method_name, arity = nil)
+ method_names[method_name] = arity
+ end
+
+ def add_class(klass)
+ classes << klass
+ end
+
+ def verify_override?(method_name)
+ method_names.has_key?(method_name)
+ end
+
private
+ def instance_method_defined?(klass, name)
+ klass.instance_methods(false).include?(name) ||
+ klass.private_instance_methods(false).include?(name)
+ end
+
+ def find_direct_method(klass, name)
+ method = klass.instance_method(name)
+ method = method.super_method until method && klass == method.owner
+ method
+ end
+
+ def arity_compatible?(sub_method_arity, super_method_arity)
+ if sub_method_arity >= 0 && super_method_arity >= 0
+ # Regular arguments
+ sub_method_arity == super_method_arity
+ else
+ # It's too complex to check this case, just allow sub-method having negative arity
+ # But we don't allow sub_method_arity > 0 yet super_method_arity < 0
+ sub_method_arity < 0
+ end
+ end
+
def method_names
- @method_names ||= []
+ @method_names ||= {}
end
def classes
@@ -80,11 +117,21 @@ module Gitlab
def override(method_name)
return unless ENV['STATIC_VERIFICATION']
+ Override.extensions[self] ||= Extension.new(self)
+ Override.extensions[self].add_method_name(method_name)
+ end
+
+ def method_added(method_name)
+ super
+
+ return unless ENV['STATIC_VERIFICATION']
+ return unless Override.extensions[self]&.verify_override?(method_name)
+
+ method_arity = instance_method(method_name).arity
if is_a?(Class)
- Extension.verify_class!(self, method_name)
+ Extension.verify_class!(self, method_name, method_arity)
else # We delay the check for modules
- Override.extensions[self] ||= Extension.new(self)
- Override.extensions[self].add_method_name(method_name)
+ Override.extensions[self].add_method_name(method_name, method_arity)
end
end
diff --git a/lib/json_web_token/hmac_token.rb b/lib/json_web_token/hmac_token.rb
index ceb1b9c913f..ec0917ab49d 100644
--- a/lib/json_web_token/hmac_token.rb
+++ b/lib/json_web_token/hmac_token.rb
@@ -18,7 +18,7 @@ module JSONWebToken
end
def encoded
- JWT.encode(payload, secret, JWT_ALGORITHM)
+ JWT.encode(payload, secret, JWT_ALGORITHM, { typ: 'JWT' })
end
private
diff --git a/lib/json_web_token/rsa_token.rb b/lib/json_web_token/rsa_token.rb
index 160e1e506f1..bcce811cd28 100644
--- a/lib/json_web_token/rsa_token.rb
+++ b/lib/json_web_token/rsa_token.rb
@@ -11,7 +11,8 @@ module JSONWebToken
def encoded
headers = {
- kid: kid
+ kid: kid,
+ typ: 'JWT'
}
JWT.encode(payload, key, 'RS256', headers)
end
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index fed490309cc..ddfd5599883 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -19,6 +19,9 @@ msgstr ""
msgid " Status"
msgstr ""
+msgid " or "
+msgstr ""
+
msgid "%d addition"
msgid_plural "%d additions"
msgstr[0] ""
@@ -97,9 +100,6 @@ msgstr[1] ""
msgid "%{actionText} & %{openOrClose} %{noteable}"
msgstr ""
-msgid "%{bio} at %{organization}"
-msgstr ""
-
msgid "%{commit_author_link} authored %{commit_timeago}"
msgstr ""
@@ -188,6 +188,9 @@ msgstr ""
msgid "+ %{moreCount} more"
msgstr ""
+msgid ", or "
+msgstr ""
+
msgid "- Runner is active and can process any new jobs"
msgstr ""
@@ -438,9 +441,15 @@ msgstr ""
msgid "AdminProjects|Delete project"
msgstr ""
+msgid "AdminSettings|Environment variables are protected by default"
+msgstr ""
+
msgid "AdminSettings|Specify a domain to use by default for every project's Auto Review Apps and Auto Deploy stages."
msgstr ""
+msgid "AdminSettings|When creating a new environment variable it will be protected by default."
+msgstr ""
+
msgid "AdminUsers|Block user"
msgstr ""
@@ -2746,6 +2755,15 @@ msgstr ""
msgid "Enter the merge request title"
msgstr ""
+msgid "Environment variables"
+msgstr ""
+
+msgid "Environment variables are applied to environments via the runner. They can be protected by only exposing them to protected branches or tags. You can use environment variables for passwords, secret keys, or whatever you want."
+msgstr ""
+
+msgid "Environment variables are configured by your administrator to be %{link_start}protected%{link_end} by default"
+msgstr ""
+
msgid "Environments"
msgstr ""
@@ -4135,6 +4153,9 @@ msgstr ""
msgid "MergeRequests|started a discussion on %{linkStart}the diff%{linkEnd}"
msgstr ""
+msgid "MergeRequests|started a discussion on an outdated change in commit %{linkStart}%{commitId}%{linkEnd}"
+msgstr ""
+
msgid "MergeRequests|started a discussion on commit %{linkStart}%{commitId}%{linkEnd}"
msgstr ""
@@ -4395,6 +4416,9 @@ msgstr ""
msgid "No"
msgstr ""
+msgid "No activities found"
+msgstr ""
+
msgid "No assignee"
msgstr ""
@@ -6218,7 +6242,7 @@ msgstr ""
msgid "SortOptions|Least popular"
msgstr ""
-msgid "SortOptions|Milestone"
+msgid "SortOptions|Milestone due date"
msgstr ""
msgid "SortOptions|Milestone due later"
@@ -6683,7 +6707,7 @@ msgstr ""
msgid "Third party offers"
msgstr ""
-msgid "This %{viewer} could not be displayed because %{reason}."
+msgid "This %{viewer} could not be displayed because %{reason}. You can %{options} instead."
msgstr ""
msgid "This GitLab instance does not provide any shared Runners yet. Instance administrators can register shared Runners in the admin area."
@@ -6806,6 +6830,9 @@ msgstr ""
msgid "This page will be removed in a future release."
msgstr ""
+msgid "This pipeline is run in a merge request context"
+msgstr ""
+
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by <b>Auto DevOps.</b>"
msgstr ""
@@ -7350,12 +7377,6 @@ msgstr ""
msgid "Users requesting access to"
msgstr ""
-msgid "Variables"
-msgstr ""
-
-msgid "Variables are applied to environments via the runner. They can be protected by only exposing them to protected branches or tags. You can use variables for passwords, secret keys, or whatever you want."
-msgstr ""
-
msgid "Various container registry settings."
msgstr ""
@@ -7879,6 +7900,9 @@ msgstr ""
msgid "https://your-bitbucket-server"
msgstr ""
+msgid "image diff"
+msgstr ""
+
msgid "import flow"
msgstr ""
@@ -7891,6 +7915,15 @@ msgstr ""
msgid "issue boards"
msgstr ""
+msgid "it is stored externally"
+msgstr ""
+
+msgid "it is stored in LFS"
+msgstr ""
+
+msgid "it is too large"
+msgstr ""
+
msgid "latest deployment"
msgstr ""
@@ -8131,6 +8164,9 @@ msgstr ""
msgid "remove due date"
msgstr ""
+msgid "rendered diff"
+msgstr ""
+
msgid "reply"
msgid_plural "replies"
msgstr[0] ""
@@ -8142,6 +8178,9 @@ msgstr ""
msgid "source"
msgstr ""
+msgid "source diff"
+msgstr ""
+
msgid "spendCommand|%{slash_command} will update the sum of the time spent."
msgstr ""
@@ -8163,6 +8202,9 @@ msgstr ""
msgid "view it on GitLab"
msgstr ""
+msgid "view the blob"
+msgstr ""
+
msgid "with %{additions} additions, %{deletions} deletions."
msgstr ""
diff --git a/package.json b/package.json
index e445fb457a3..1dc9797c59b 100644
--- a/package.json
+++ b/package.json
@@ -27,7 +27,7 @@
"@babel/preset-env": "^7.1.0",
"@gitlab/csslab": "^1.8.0",
"@gitlab/svgs": "^1.43.0",
- "@gitlab/ui": "^1.16.0",
+ "@gitlab/ui": "^1.18.0",
"apollo-boost": "^0.1.20",
"apollo-client": "^2.4.5",
"autosize": "^4.0.0",
diff --git a/qa/Dockerfile b/qa/Dockerfile
index 9956ced0ef6..ca7f9accb70 100644
--- a/qa/Dockerfile
+++ b/qa/Dockerfile
@@ -1,4 +1,4 @@
-FROM ruby:2.4-stretch
+FROM ruby:2.5-stretch
LABEL maintainer "Grzegorz Bizon <grzegorz@gitlab.com>"
ENV DEBIAN_FRONTEND noninteractive
diff --git a/qa/qa/page/base.rb b/qa/qa/page/base.rb
index 88ade66f47d..5788dceaaae 100644
--- a/qa/qa/page/base.rb
+++ b/qa/qa/page/base.rb
@@ -80,8 +80,8 @@ module QA
page.evaluate_script('xhr.status') == 200
end
- def find_element(name, wait: Capybara.default_max_wait_time)
- find(element_selector_css(name), wait: wait)
+ def find_element(name, text_filter = nil, wait: Capybara.default_max_wait_time)
+ find(element_selector_css(name), wait: wait, text: text_filter)
end
def all_elements(name)
@@ -108,8 +108,12 @@ module QA
element.select value.to_s.capitalize
end
- def has_element?(name)
- has_css?(element_selector_css(name))
+ def has_element?(name, wait: Capybara.default_max_wait_time)
+ has_css?(element_selector_css(name), wait: wait)
+ end
+
+ def has_no_text?(text)
+ page.has_no_text? text
end
def within_element(name)
diff --git a/qa/qa/page/main/login.rb b/qa/qa/page/main/login.rb
index 97ffe0e5716..cb83ace20b6 100644
--- a/qa/qa/page/main/login.rb
+++ b/qa/qa/page/main/login.rb
@@ -35,13 +35,21 @@ module QA
element :saml_login_button
end
+ view 'app/views/layouts/devise.html.haml' do
+ element :login_page
+ end
+
def initialize
# The login page is usually the entry point for all the scenarios so
# we need to wait for the instance to start. That said, in some cases
# we are already logged-in so we check both cases here.
+ # Check if we're already logged in first. If we don't then we have to
+ # wait 10 seconds for the check for the login page to fail every time
+ # we use this class when we're already logged in (E.g., whenever we
+ # create a personal access token to use for API access).
wait(max: 500) do
- has_css?('.login-page') ||
- Page::Main::Menu.act { has_personal_area?(wait: 0) }
+ Page::Main::Menu.act { has_personal_area?(wait: 0) } ||
+ has_element?(:login_page)
end
end
diff --git a/qa/qa/page/main/menu.rb b/qa/qa/page/main/menu.rb
index cc2724618e9..6804cc8fb20 100644
--- a/qa/qa/page/main/menu.rb
+++ b/qa/qa/page/main/menu.rb
@@ -63,15 +63,11 @@ module QA
end
def has_personal_area?(wait: Capybara.default_max_wait_time)
- using_wait_time(wait) do
- page.has_selector?(element_selector_css(:user_avatar))
- end
+ has_element?(:user_avatar, wait: wait)
end
def has_admin_area_link?(wait: Capybara.default_max_wait_time)
- using_wait_time(wait) do
- page.has_selector?(element_selector_css(:admin_area_link))
- end
+ has_element?(:admin_area_link, wait: wait)
end
private
diff --git a/qa/qa/page/project/issue/show.rb b/qa/qa/page/project/issue/show.rb
index 23def93c7dd..9ec6d90719e 100644
--- a/qa/qa/page/project/issue/show.rb
+++ b/qa/qa/page/project/issue/show.rb
@@ -37,17 +37,17 @@ module QA
def select_comments_only_filter
click_element :discussion_filter
- all_elements(:filter_options)[1].click
+ find_element(:filter_options, "Show comments only").click
end
def select_history_only_filter
click_element :discussion_filter
- all_elements(:filter_options).last.click
+ find_element(:filter_options, "Show history only").click
end
def select_all_activities_filter
click_element :discussion_filter
- all_elements(:filter_options).first.click
+ find_element(:filter_options, "Show all activity").click
end
end
end
diff --git a/qa/qa/support/page/logging.rb b/qa/qa/support/page/logging.rb
index 43bc16d8c9a..cfccbb910b7 100644
--- a/qa/qa/support/page/logging.rb
+++ b/qa/qa/support/page/logging.rb
@@ -37,8 +37,11 @@ module QA
exists
end
- def find_element(name, wait: Capybara.default_max_wait_time)
- log("finding :#{name} (wait: #{wait})")
+ def find_element(name, text_filter = nil, wait: Capybara.default_max_wait_time)
+ msg = ["finding :#{name}"]
+ msg << %Q(with text_filter "#{text_filter}") if text_filter
+ msg << "(wait: #{wait})"
+ log(msg.compact.join(' '))
element = super
@@ -77,7 +80,7 @@ module QA
super
end
- def has_element?(name)
+ def has_element?(name, wait: Capybara.default_max_wait_time)
found = super
log("has_element? :#{name} returned #{found}")
@@ -85,6 +88,14 @@ module QA
found
end
+ def has_no_text?(text)
+ found = super
+
+ log(%Q{has_no_text?('#{text}') returned #{found}})
+
+ found
+ end
+
def within_element(name)
log("within element :#{name}")
diff --git a/qa/spec/page/logging_spec.rb b/qa/spec/page/logging_spec.rb
index 9d56353062b..f108a5ca318 100644
--- a/qa/spec/page/logging_spec.rb
+++ b/qa/spec/page/logging_spec.rb
@@ -47,6 +47,15 @@ describe QA::Support::Page::Logging do
it 'logs find_element' do
expect { subject.find_element(:element) }
+ .to output(/finding :element/).to_stdout_from_any_process
+ expect { subject.find_element(:element) }
+ .to output(/found :element/).to_stdout_from_any_process
+ end
+
+ it 'logs find_element with text_filter' do
+ expect { subject.find_element(:element, 'foo') }
+ .to output(/finding :element with text_filter "foo"/).to_stdout_from_any_process
+ expect { subject.find_element(:element, 'foo') }
.to output(/found :element/).to_stdout_from_any_process
end
@@ -65,6 +74,13 @@ describe QA::Support::Page::Logging do
.to output(/has_element\? :element returned true/).to_stdout_from_any_process
end
+ it 'logs has_no_text?' do
+ allow(page).to receive(:has_no_text?).with('foo').and_return(true)
+
+ expect { subject.has_no_text? 'foo' }
+ .to output(/has_no_text\?\('foo'\) returned true/).to_stdout_from_any_process
+ end
+
it 'logs within_element' do
expect { subject.within_element(:element) }
.to output(/within element :element/).to_stdout_from_any_process
diff --git a/scripts/prepare_build.sh b/scripts/prepare_build.sh
index d85c53090a4..58b74f2f07d 100644
--- a/scripts/prepare_build.sh
+++ b/scripts/prepare_build.sh
@@ -10,7 +10,7 @@ fi
# Only install knapsack after bundle install! Otherwise oddly some native
# gems could not be found under some circumstance. No idea why, hours wasted.
-retry gem install knapsack --no-ri --no-rdoc
+retry gem install knapsack --no-document
cp config/gitlab.yml.example config/gitlab.yml
sed -i 's/bin_path: \/usr\/bin\/git/bin_path: \/usr\/local\/bin\/git/' config/gitlab.yml
diff --git a/spec/controllers/groups/group_members_controller_spec.rb b/spec/controllers/groups/group_members_controller_spec.rb
index 00a00306ff9..ed38dadfd6b 100644
--- a/spec/controllers/groups/group_members_controller_spec.rb
+++ b/spec/controllers/groups/group_members_controller_spec.rb
@@ -78,9 +78,11 @@ describe Groups::GroupMembersController do
Gitlab::Access.options.each do |label, value|
it "can change the access level to #{label}" do
- xhr :put, :update, group_member: { access_level: value },
- group_id: group,
- id: requester
+ put :update, params: {
+ group_member: { access_level: value },
+ group_id: group,
+ id: requester
+ }, xhr: true
expect(requester.reload.human_access).to eq(label)
end
@@ -130,7 +132,7 @@ describe Groups::GroupMembersController do
end
it '[JS] removes user from members' do
- xhr :delete, :destroy, group_id: group, id: member
+ delete :destroy, params: { group_id: group, id: member }, xhr: true
expect(response).to be_success
expect(group.members).not_to include member
diff --git a/spec/controllers/groups/settings/ci_cd_controller_spec.rb b/spec/controllers/groups/settings/ci_cd_controller_spec.rb
index b7f04f732b9..40673d10b91 100644
--- a/spec/controllers/groups/settings/ci_cd_controller_spec.rb
+++ b/spec/controllers/groups/settings/ci_cd_controller_spec.rb
@@ -5,30 +5,65 @@ describe Groups::Settings::CiCdController do
let(:user) { create(:user) }
before do
- group.add_maintainer(user)
sign_in(user)
end
describe 'GET #show' do
- it 'renders show with 200 status code' do
- get :show, params: { group_id: group }
+ context 'when user is owner' do
+ before do
+ group.add_owner(user)
+ end
- expect(response).to have_gitlab_http_status(200)
- expect(response).to render_template(:show)
+ it 'renders show with 200 status code' do
+ get :show, params: { group_id: group }
+
+ expect(response).to have_gitlab_http_status(200)
+ expect(response).to render_template(:show)
+ end
+ end
+
+ context 'when user is not owner' do
+ before do
+ group.add_maintainer(user)
+ end
+
+ it 'renders a 404' do
+ get :show, params: { group_id: group }
+
+ expect(response).to have_gitlab_http_status(404)
+ end
end
end
describe 'PUT #reset_registration_token' do
subject { put :reset_registration_token, params: { group_id: group } }
- it 'resets runner registration token' do
- expect { subject }.to change { group.reload.runners_token }
+ context 'when user is owner' do
+ before do
+ group.add_owner(user)
+ end
+
+ it 'resets runner registration token' do
+ expect { subject }.to change { group.reload.runners_token }
+ end
+
+ it 'redirects the user to admin runners page' do
+ subject
+
+ expect(response).to redirect_to(group_settings_ci_cd_path)
+ end
end
- it 'redirects the user to admin runners page' do
- subject
+ context 'when user is not owner' do
+ before do
+ group.add_maintainer(user)
+ end
+
+ it 'renders a 404' do
+ subject
- expect(response).to redirect_to(group_settings_ci_cd_path)
+ expect(response).to have_gitlab_http_status(404)
+ end
end
end
end
diff --git a/spec/controllers/projects/avatars_controller_spec.rb b/spec/controllers/projects/avatars_controller_spec.rb
index 40ab81395ea..95b7ae5885a 100644
--- a/spec/controllers/projects/avatars_controller_spec.rb
+++ b/spec/controllers/projects/avatars_controller_spec.rb
@@ -26,37 +26,13 @@ describe Projects::AvatarsController do
context 'when the avatar is stored in the repository' do
let(:filepath) { 'files/images/logo-white.png' }
- context 'when feature flag workhorse_set_content_type is' do
- before do
- stub_feature_flags(workhorse_set_content_type: flag_value)
- end
+ it 'sends the avatar' do
+ subject
- context 'enabled' do
- let(:flag_value) { true }
-
- it 'sends the avatar' do
- subject
-
- expect(response).to have_gitlab_http_status(200)
- expect(response.header['Content-Disposition']).to eq('inline')
- expect(response.header['Content-Type']).to eq 'image/png'
- expect(response.header[Gitlab::Workhorse::SEND_DATA_HEADER]).to start_with('git-blob:')
- expect(response.header[Gitlab::Workhorse::DETECT_HEADER]).to eq "true"
- end
- end
-
- context 'disabled' do
- let(:flag_value) { false }
-
- it 'sends the avatar' do
- subject
-
- expect(response).to have_gitlab_http_status(200)
- expect(response.header['Content-Type']).to eq('image/png')
- expect(response.header[Gitlab::Workhorse::SEND_DATA_HEADER]).to start_with('git-blob:')
- expect(response.header[Gitlab::Workhorse::DETECT_HEADER]).to eq nil
- end
- end
+ expect(response).to have_gitlab_http_status(200)
+ expect(response.header['Content-Disposition']).to eq('inline')
+ expect(response.header[Gitlab::Workhorse::SEND_DATA_HEADER]).to start_with('git-blob:')
+ expect(response.header[Gitlab::Workhorse::DETECT_HEADER]).to eq "true"
end
end
diff --git a/spec/controllers/projects/ci/lints_controller_spec.rb b/spec/controllers/projects/ci/lints_controller_spec.rb
index 82c1374aa4f..cfa010c2d1c 100644
--- a/spec/controllers/projects/ci/lints_controller_spec.rb
+++ b/spec/controllers/projects/ci/lints_controller_spec.rb
@@ -51,7 +51,6 @@ describe Projects::Ci::LintsController do
- apt-get update -qq && apt-get install -y -qq sqlite3 libsqlite3-dev nodejs
- ruby -v
- which ruby
- - gem install bundler --no-ri --no-rdoc
- bundle install --jobs $(nproc) "${FLAGS[@]}"
HEREDOC
end
diff --git a/spec/controllers/projects/clusters_controller_spec.rb b/spec/controllers/projects/clusters_controller_spec.rb
index ea266384446..d94c18ddc02 100644
--- a/spec/controllers/projects/clusters_controller_spec.rb
+++ b/spec/controllers/projects/clusters_controller_spec.rb
@@ -311,7 +311,7 @@ describe Projects::ClustersController do
describe 'security' do
before do
- allow(ClusterPlatformConfigureWorker).to receive(:perform_async)
+ allow(ClusterConfigureWorker).to receive(:perform_async)
stub_kubeclient_get_namespace('https://kubernetes.example.com', namespace: 'my-namespace')
end
@@ -409,7 +409,7 @@ describe Projects::ClustersController do
end
before do
- allow(ClusterPlatformConfigureWorker).to receive(:perform_async)
+ allow(ClusterConfigureWorker).to receive(:perform_async)
stub_kubeclient_get_namespace('https://kubernetes.example.com', namespace: 'my-namespace')
end
diff --git a/spec/controllers/projects/issues_controller_spec.rb b/spec/controllers/projects/issues_controller_spec.rb
index f9193513a6a..a239ac16c0d 100644
--- a/spec/controllers/projects/issues_controller_spec.rb
+++ b/spec/controllers/projects/issues_controller_spec.rb
@@ -206,12 +206,12 @@ describe Projects::IssuesController do
describe 'Redirect after sign in' do
context 'with an AJAX request' do
it 'does not store the visited URL' do
- xhr :get,
- :show,
+ get :show, params: {
format: :json,
namespace_id: project.namespace,
project_id: project,
id: issue.iid
+ }, xhr: true
expect(session['user_return_to']).to be_blank
end
diff --git a/spec/controllers/projects/jobs_controller_spec.rb b/spec/controllers/projects/jobs_controller_spec.rb
index e1133fdd562..7f65fe551e9 100644
--- a/spec/controllers/projects/jobs_controller_spec.rb
+++ b/spec/controllers/projects/jobs_controller_spec.rb
@@ -892,36 +892,13 @@ describe Projects::JobsController, :clean_gitlab_redis_shared_state do
context "when job has a trace artifact" do
let(:job) { create(:ci_build, :trace_artifact, pipeline: pipeline) }
- context 'when feature flag workhorse_set_content_type is' do
- before do
- stub_feature_flags(workhorse_set_content_type: flag_value)
- end
-
- context 'enabled' do
- let(:flag_value) { true }
-
- it "sets #{Gitlab::Workhorse::DETECT_HEADER} header" do
- response = subject
-
- expect(response).to have_gitlab_http_status(:ok)
- expect(response.headers["Content-Type"]).to eq("text/plain; charset=utf-8")
- expect(response.body).to eq(job.job_artifacts_trace.open.read)
- expect(response.header[Gitlab::Workhorse::DETECT_HEADER]).to eq "true"
- end
- end
-
- context 'disabled' do
- let(:flag_value) { false }
-
- it 'returns a trace' do
- response = subject
+ it "sets #{Gitlab::Workhorse::DETECT_HEADER} header" do
+ response = subject
- expect(response).to have_gitlab_http_status(:ok)
- expect(response.headers["Content-Type"]).to eq("text/plain; charset=utf-8")
- expect(response.body).to eq(job.job_artifacts_trace.open.read)
- expect(response.header[Gitlab::Workhorse::DETECT_HEADER]).to be nil
- end
- end
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response.headers["Content-Type"]).to eq("text/plain; charset=utf-8")
+ expect(response.body).to eq(job.job_artifacts_trace.open.read)
+ expect(response.header[Gitlab::Workhorse::DETECT_HEADER]).to eq "true"
end
end
diff --git a/spec/controllers/projects/merge_requests_controller_spec.rb b/spec/controllers/projects/merge_requests_controller_spec.rb
index 962dfb91c9f..d46b9ffb3ce 100644
--- a/spec/controllers/projects/merge_requests_controller_spec.rb
+++ b/spec/controllers/projects/merge_requests_controller_spec.rb
@@ -30,19 +30,6 @@ describe Projects::MergeRequestsController do
end
end
- shared_examples "loads labels" do |action|
- it "loads labels into the @labels variable" do
- get action,
- params: {
- namespace_id: project.namespace.to_param,
- project_id: project,
- id: merge_request.iid
- },
- format: 'html'
- expect(assigns(:labels)).not_to be_nil
- end
- end
-
describe "GET show" do
def go(extra_params = {})
params = {
@@ -54,8 +41,6 @@ describe Projects::MergeRequestsController do
get :show, params: params.merge(extra_params)
end
- it_behaves_like "loads labels", :show
-
describe 'as html' do
context 'when diff files were cleaned' do
render_views
@@ -333,7 +318,7 @@ describe Projects::MergeRequestsController do
before do
project.add_reporter(user)
- xhr :post, :merge, params: base_params
+ post :merge, params: base_params, xhr: true
end
it 'returns 404' do
@@ -681,13 +666,14 @@ describe Projects::MergeRequestsController do
merge_request.title = merge_request.wip_title
merge_request.save
- xhr :post, :remove_wip,
- format: :json,
+ post :remove_wip,
params: {
+ format: :json,
namespace_id: merge_request.project.namespace.to_param,
project_id: merge_request.project,
id: merge_request.iid
- }
+ },
+ xhr: true
end
it 'removes the wip status' do
@@ -701,13 +687,14 @@ describe Projects::MergeRequestsController do
describe 'POST cancel_merge_when_pipeline_succeeds' do
subject do
- xhr :post, :cancel_merge_when_pipeline_succeeds,
- format: :json,
+ post :cancel_merge_when_pipeline_succeeds,
params: {
+ format: :json,
namespace_id: merge_request.project.namespace.to_param,
project_id: merge_request.project,
id: merge_request.iid
- }
+ },
+ xhr: true
end
it 'calls MergeRequests::MergeWhenPipelineSucceedsService' do
@@ -955,6 +942,70 @@ describe Projects::MergeRequestsController do
end
end
+ describe 'GET discussions' do
+ context 'when authenticated' do
+ before do
+ project.add_developer(user)
+ sign_in(user)
+ end
+
+ it 'returns 200' do
+ get :discussions, namespace_id: project.namespace, project_id: project, id: merge_request.iid
+
+ expect(response.status).to eq(200)
+ end
+
+ context 'highlight preloading' do
+ context 'with commit diff notes' do
+ let!(:commit_diff_note) do
+ create(:diff_note_on_commit, project: merge_request.project)
+ end
+
+ it 'preloads notes diffs highlights' do
+ expect_next_instance_of(Gitlab::DiscussionsDiff::FileCollection) do |collection|
+ note_diff_file = commit_diff_note.note_diff_file
+
+ expect(collection).to receive(:load_highlight).with([note_diff_file.id]).and_call_original
+ expect(collection).to receive(:find_by_id).with(note_diff_file.id).and_call_original
+ end
+
+ get :discussions, namespace_id: project.namespace, project_id: project, id: merge_request.iid
+ end
+ end
+
+ context 'with diff notes' do
+ let!(:diff_note) do
+ create(:diff_note_on_merge_request, noteable: merge_request, project: merge_request.project)
+ end
+
+ it 'preloads notes diffs highlights' do
+ expect_next_instance_of(Gitlab::DiscussionsDiff::FileCollection) do |collection|
+ note_diff_file = diff_note.note_diff_file
+
+ expect(collection).to receive(:load_highlight).with([note_diff_file.id]).and_call_original
+ expect(collection).to receive(:find_by_id).with(note_diff_file.id).and_call_original
+ end
+
+ get :discussions, namespace_id: project.namespace, project_id: project, id: merge_request.iid
+ end
+
+ it 'does not preload highlights when diff note is resolved' do
+ Notes::ResolveService.new(diff_note.project, user).execute(diff_note)
+
+ expect_next_instance_of(Gitlab::DiscussionsDiff::FileCollection) do |collection|
+ note_diff_file = diff_note.note_diff_file
+
+ expect(collection).to receive(:load_highlight).with([]).and_call_original
+ expect(collection).to receive(:find_by_id).with(note_diff_file.id).and_call_original
+ end
+
+ get :discussions, namespace_id: project.namespace, project_id: project, id: merge_request.iid
+ end
+ end
+ end
+ end
+ end
+
describe 'GET edit' do
it 'responds successfully' do
get :edit, params: { namespace_id: project.namespace, project_id: project, id: merge_request }
diff --git a/spec/controllers/projects/project_members_controller_spec.rb b/spec/controllers/projects/project_members_controller_spec.rb
index 009f85903b5..3cc3fe69fba 100644
--- a/spec/controllers/projects/project_members_controller_spec.rb
+++ b/spec/controllers/projects/project_members_controller_spec.rb
@@ -82,10 +82,12 @@ describe Projects::ProjectMembersController do
Gitlab::Access.options.each do |label, value|
it "can change the access level to #{label}" do
- xhr :put, :update, project_member: { access_level: value },
- namespace_id: project.namespace,
- project_id: project,
- id: requester
+ put :update, params: {
+ project_member: { access_level: value },
+ namespace_id: project.namespace,
+ project_id: project,
+ id: requester
+ }, xhr: true
expect(requester.reload.human_access).to eq(label)
end
@@ -148,9 +150,11 @@ describe Projects::ProjectMembersController do
end
it '[JS] removes user from members' do
- xhr :delete, :destroy, namespace_id: project.namespace,
- project_id: project,
- id: member
+ delete :destroy, params: {
+ namespace_id: project.namespace,
+ project_id: project,
+ id: member
+ }, xhr: true
expect(response).to be_success
expect(project.members).not_to include member
diff --git a/spec/controllers/projects/raw_controller_spec.rb b/spec/controllers/projects/raw_controller_spec.rb
index 24e2441cf9d..cffdf30da6b 100644
--- a/spec/controllers/projects/raw_controller_spec.rb
+++ b/spec/controllers/projects/raw_controller_spec.rb
@@ -16,74 +16,27 @@ describe Projects::RawController do
context 'regular filename' do
let(:filepath) { 'master/README.md' }
- context 'when feature flag workhorse_set_content_type is' do
- before do
- stub_feature_flags(workhorse_set_content_type: flag_value)
-
- subject
- end
-
- context 'enabled' do
- let(:flag_value) { true }
-
- it 'delivers ASCII file' do
- expect(response).to have_gitlab_http_status(200)
- expect(response.header['Content-Type']).to eq('text/plain; charset=utf-8')
- expect(response.header['Content-Disposition']).to eq('inline')
- expect(response.header[Gitlab::Workhorse::DETECT_HEADER]).to eq "true"
- expect(response.header[Gitlab::Workhorse::SEND_DATA_HEADER]).to start_with('git-blob:')
- end
- end
-
- context 'disabled' do
- let(:flag_value) { false }
-
- it 'delivers ASCII file' do
- expect(response).to have_gitlab_http_status(200)
- expect(response.header['Content-Type']).to eq('text/plain; charset=utf-8')
- expect(response.header['Content-Disposition']).to eq('inline')
- expect(response.header[Gitlab::Workhorse::DETECT_HEADER]).to eq nil
- expect(response.header[Gitlab::Workhorse::SEND_DATA_HEADER]).to start_with('git-blob:')
- end
- end
+ it 'delivers ASCII file' do
+ subject
+
+ expect(response).to have_gitlab_http_status(200)
+ expect(response.header['Content-Type']).to eq('text/plain; charset=utf-8')
+ expect(response.header['Content-Disposition']).to eq('inline')
+ expect(response.header[Gitlab::Workhorse::DETECT_HEADER]).to eq "true"
+ expect(response.header[Gitlab::Workhorse::SEND_DATA_HEADER]).to start_with('git-blob:')
end
end
context 'image header' do
let(:filepath) { 'master/files/images/6049019_460s.jpg' }
- context 'when feature flag workhorse_set_content_type is' do
- before do
- stub_feature_flags(workhorse_set_content_type: flag_value)
- end
-
- context 'enabled' do
- let(:flag_value) { true }
-
- it 'leaves image content disposition' do
- subject
-
- expect(response).to have_gitlab_http_status(200)
- expect(response.header['Content-Type']).to eq('image/jpeg')
- expect(response.header['Content-Disposition']).to eq('inline')
- expect(response.header[Gitlab::Workhorse::DETECT_HEADER]).to eq "true"
- expect(response.header[Gitlab::Workhorse::SEND_DATA_HEADER]).to start_with('git-blob:')
- end
- end
-
- context 'disabled' do
- let(:flag_value) { false }
-
- it 'sets image content type header' do
- subject
+ it 'leaves image content disposition' do
+ subject
- expect(response).to have_gitlab_http_status(200)
- expect(response.header['Content-Type']).to eq('image/jpeg')
- expect(response.header['Content-Disposition']).to eq('inline')
- expect(response.header[Gitlab::Workhorse::DETECT_HEADER]).to eq nil
- expect(response.header[Gitlab::Workhorse::SEND_DATA_HEADER]).to start_with('git-blob:')
- end
- end
+ expect(response).to have_gitlab_http_status(200)
+ expect(response.header['Content-Disposition']).to eq('inline')
+ expect(response.header[Gitlab::Workhorse::DETECT_HEADER]).to eq "true"
+ expect(response.header[Gitlab::Workhorse::SEND_DATA_HEADER]).to start_with('git-blob:')
end
end
diff --git a/spec/controllers/projects/refs_controller_spec.rb b/spec/controllers/projects/refs_controller_spec.rb
index ea299e1e8c5..62f2af947e4 100644
--- a/spec/controllers/projects/refs_controller_spec.rb
+++ b/spec/controllers/projects/refs_controller_spec.rb
@@ -22,13 +22,13 @@ describe Projects::RefsController do
end
def xhr_get(format = :html)
- xhr :get,
- :logs_tree,
- namespace_id: project.namespace.to_param,
- project_id: project,
- id: 'master',
- path: 'foo/bar/baz.html',
- format: format
+ get :logs_tree, params: {
+ namespace_id: project.namespace.to_param,
+ project_id: project,
+ id: 'master',
+ path: 'foo/bar/baz.html',
+ format: format
+ }, xhr: true
end
it 'never throws MissingTemplate' do
diff --git a/spec/controllers/projects/snippets_controller_spec.rb b/spec/controllers/projects/snippets_controller_spec.rb
index 1a3fb4da15f..e4b78aff25d 100644
--- a/spec/controllers/projects/snippets_controller_spec.rb
+++ b/spec/controllers/projects/snippets_controller_spec.rb
@@ -379,6 +379,46 @@ describe Projects::SnippetsController do
end
end
+ describe "GET #show for embeddable content" do
+ let(:project_snippet) { create(:project_snippet, snippet_permission, project: project, author: user) }
+
+ before do
+ sign_in(user)
+
+ get :show, namespace_id: project.namespace, project_id: project, id: project_snippet.to_param, format: :js
+ end
+
+ context 'when snippet is private' do
+ let(:snippet_permission) { :private }
+
+ it 'responds with status 404' do
+ expect(response).to have_gitlab_http_status(404)
+ end
+ end
+
+ context 'when snippet is public' do
+ let(:snippet_permission) { :public }
+
+ it 'responds with status 200' do
+ expect(assigns(:snippet)).to eq(project_snippet)
+ expect(response).to have_gitlab_http_status(200)
+ end
+ end
+
+ context 'when the project is private' do
+ let(:project) { create(:project_empty_repo, :private) }
+
+ context 'when snippet is public' do
+ let(:project_snippet) { create(:project_snippet, :public, project: project, author: user) }
+
+ it 'responds with status 404' do
+ expect(assigns(:snippet)).to eq(project_snippet)
+ expect(response).to have_gitlab_http_status(404)
+ end
+ end
+ end
+ end
+
describe 'GET #raw' do
let(:project_snippet) do
create(
diff --git a/spec/controllers/projects/tags/releases_controller_spec.rb b/spec/controllers/projects/tags/releases_controller_spec.rb
index 6bf4ac65a45..29f206c574b 100644
--- a/spec/controllers/projects/tags/releases_controller_spec.rb
+++ b/spec/controllers/projects/tags/releases_controller_spec.rb
@@ -18,7 +18,7 @@ describe Projects::Tags::ReleasesController do
tag_id = release.tag
project.releases.destroy_all # rubocop: disable DestroyAll
- get :edit, namespace_id: project.namespace, project_id: project, tag_id: tag_id
+ get :edit, params: { namespace_id: project.namespace, project_id: project, tag_id: tag_id }
release = assigns(:release)
expect(release).not_to be_nil
@@ -26,7 +26,7 @@ describe Projects::Tags::ReleasesController do
end
it 'retrieves an existing release' do
- get :edit, namespace_id: project.namespace, project_id: project, tag_id: release.tag
+ get :edit, params: { namespace_id: project.namespace, project_id: project, tag_id: release.tag }
release = assigns(:release)
expect(release).not_to be_nil
@@ -48,10 +48,11 @@ describe Projects::Tags::ReleasesController do
end
def update_release(description)
- put :update,
+ put :update, params: {
namespace_id: project.namespace.to_param,
project_id: project,
tag_id: release.tag,
release: { description: description }
+ }
end
end
diff --git a/spec/controllers/projects/wikis_controller_spec.rb b/spec/controllers/projects/wikis_controller_spec.rb
index 341bf244397..b2f40231796 100644
--- a/spec/controllers/projects/wikis_controller_spec.rb
+++ b/spec/controllers/projects/wikis_controller_spec.rb
@@ -52,56 +52,24 @@ describe Projects::WikisController do
let(:path) { upload_file_to_wiki(project, user, file_name) }
- subject { get :show, params: { namespace_id: project.namespace, project_id: project, id: path } }
+ before do
+ get :show, params: { namespace_id: project.namespace, project_id: project, id: path }
+ end
context 'when file is an image' do
let(:file_name) { 'dk.png' }
- context 'when feature flag workhorse_set_content_type is' do
- before do
- stub_feature_flags(workhorse_set_content_type: flag_value)
-
- subject
- end
-
- context 'enabled' do
- let(:flag_value) { true }
-
- it 'delivers the image' do
- expect(response.headers['Content-Type']).to eq('image/png')
- expect(response.headers['Content-Disposition']).to match(/^inline/)
- expect(response.headers[Gitlab::Workhorse::DETECT_HEADER]).to eq "true"
- end
-
- context 'when file is a svg' do
- let(:file_name) { 'unsanitized.svg' }
-
- it 'delivers the image' do
- expect(response.headers['Content-Type']).to eq('image/svg+xml')
- expect(response.headers['Content-Disposition']).to match(/^attachment/)
- expect(response.headers[Gitlab::Workhorse::DETECT_HEADER]).to eq "true"
- end
- end
- end
-
- context 'disabled' do
- let(:flag_value) { false }
-
- it 'renders the content inline' do
- expect(response.headers['Content-Type']).to eq('image/png')
- expect(response.headers['Content-Disposition']).to match(/^inline/)
- expect(response.headers[Gitlab::Workhorse::DETECT_HEADER]).to eq nil
- end
+ it 'delivers the image' do
+ expect(response.headers['Content-Disposition']).to match(/^inline/)
+ expect(response.headers[Gitlab::Workhorse::DETECT_HEADER]).to eq "true"
+ end
- context 'when file is a svg' do
- let(:file_name) { 'unsanitized.svg' }
+ context 'when file is a svg' do
+ let(:file_name) { 'unsanitized.svg' }
- it 'renders the content as an attachment' do
- expect(response.headers['Content-Type']).to eq('image/svg+xml')
- expect(response.headers['Content-Disposition']).to match(/^attachment/)
- expect(response.headers[Gitlab::Workhorse::DETECT_HEADER]).to eq nil
- end
- end
+ it 'delivers the image' do
+ expect(response.headers['Content-Disposition']).to match(/^inline/)
+ expect(response.headers[Gitlab::Workhorse::DETECT_HEADER]).to eq "true"
end
end
end
@@ -109,32 +77,9 @@ describe Projects::WikisController do
context 'when file is a pdf' do
let(:file_name) { 'git-cheat-sheet.pdf' }
- context 'when feature flag workhorse_set_content_type is' do
- before do
- stub_feature_flags(workhorse_set_content_type: flag_value)
-
- subject
- end
-
- context 'enabled' do
- let(:flag_value) { true }
-
- it 'sets the content type to sets the content response headers' do
- expect(response.headers['Content-Type']).to eq 'application/octet-stream'
- expect(response.headers['Content-Disposition']).to match(/^inline/)
- expect(response.headers[Gitlab::Workhorse::DETECT_HEADER]).to eq "true"
- end
- end
-
- context 'disabled' do
- let(:flag_value) { false }
-
- it 'sets the content response headers' do
- expect(response.headers['Content-Type']).to eq 'application/octet-stream'
- expect(response.headers['Content-Disposition']).to match(/^inline/)
- expect(response.headers[Gitlab::Workhorse::DETECT_HEADER]).to eq nil
- end
- end
+ it 'sets the content type to sets the content response headers' do
+ expect(response.headers['Content-Disposition']).to match(/^inline/)
+ expect(response.headers[Gitlab::Workhorse::DETECT_HEADER]).to eq "true"
end
end
end
diff --git a/spec/controllers/projects_controller_spec.rb b/spec/controllers/projects_controller_spec.rb
index ea067a01295..4747d837273 100644
--- a/spec/controllers/projects_controller_spec.rb
+++ b/spec/controllers/projects_controller_spec.rb
@@ -621,10 +621,10 @@ describe ProjectsController do
end
describe "GET refs" do
- let(:public_project) { create(:project, :public, :repository) }
+ let(:project) { create(:project, :public, :repository) }
it 'gets a list of branches and tags' do
- get :refs, params: { namespace_id: public_project.namespace, id: public_project, sort: 'updated_desc' }
+ get :refs, params: { namespace_id: project.namespace, id: project, sort: 'updated_desc' }
parsed_body = JSON.parse(response.body)
expect(parsed_body['Branches']).to include('master')
@@ -634,7 +634,7 @@ describe ProjectsController do
end
it "gets a list of branches, tags and commits" do
- get :refs, params: { namespace_id: public_project.namespace, id: public_project, ref: "123456" }
+ get :refs, params: { namespace_id: project.namespace, id: project, ref: "123456" }
parsed_body = JSON.parse(response.body)
expect(parsed_body["Branches"]).to include("master")
@@ -649,7 +649,7 @@ describe ProjectsController do
end
it "gets a list of branches, tags and commits" do
- get :refs, params: { namespace_id: public_project.namespace, id: public_project, ref: "123456" }
+ get :refs, params: { namespace_id: project.namespace, id: project, ref: "123456" }
parsed_body = JSON.parse(response.body)
expect(parsed_body["Branches"]).to include("master")
@@ -657,6 +657,22 @@ describe ProjectsController do
expect(parsed_body["Commits"]).to include("123456")
end
end
+
+ context 'when private project' do
+ let(:project) { create(:project, :repository) }
+
+ context 'as a guest' do
+ it 'renders forbidden' do
+ user = create(:user)
+ project.add_guest(user)
+
+ sign_in(user)
+ get :refs, namespace_id: project.namespace, id: project
+
+ expect(response).to have_gitlab_http_status(404)
+ end
+ end
+ end
end
describe 'POST #preview_markdown' do
diff --git a/spec/controllers/snippets_controller_spec.rb b/spec/controllers/snippets_controller_spec.rb
index 01a5161f775..d762531da7e 100644
--- a/spec/controllers/snippets_controller_spec.rb
+++ b/spec/controllers/snippets_controller_spec.rb
@@ -80,6 +80,12 @@ describe SnippetsController do
expect(assigns(:snippet)).to eq(personal_snippet)
expect(response).to have_gitlab_http_status(200)
end
+
+ it 'responds with status 404 when embeddable content is requested' do
+ get :show, id: personal_snippet.to_param, format: :js
+
+ expect(response).to have_gitlab_http_status(404)
+ end
end
end
@@ -106,6 +112,12 @@ describe SnippetsController do
expect(assigns(:snippet)).to eq(personal_snippet)
expect(response).to have_gitlab_http_status(200)
end
+
+ it 'responds with status 404 when embeddable content is requested' do
+ get :show, id: personal_snippet.to_param, format: :js
+
+ expect(response).to have_gitlab_http_status(404)
+ end
end
context 'when not signed in' do
@@ -131,6 +143,13 @@ describe SnippetsController do
expect(assigns(:snippet)).to eq(personal_snippet)
expect(response).to have_gitlab_http_status(200)
end
+
+ it 'responds with status 200 when embeddable content is requested' do
+ get :show, id: personal_snippet.to_param, format: :js
+
+ expect(assigns(:snippet)).to eq(personal_snippet)
+ expect(response).to have_gitlab_http_status(200)
+ end
end
context 'when not signed in' do
@@ -437,10 +456,7 @@ describe SnippetsController do
end
context 'when signed in user is the author' do
- let(:flag_value) { false }
-
before do
- stub_feature_flags(workhorse_set_content_type: flag_value)
get :raw, params: { id: personal_snippet.to_param }
end
@@ -455,22 +471,9 @@ describe SnippetsController do
expect(response.header['Content-Disposition']).to match(/inline/)
end
- context 'when feature flag workhorse_set_content_type is' do
- context 'enabled' do
- let(:flag_value) { true }
-
- it "sets #{Gitlab::Workhorse::DETECT_HEADER} header" do
- expect(response).to have_gitlab_http_status(200)
- expect(response.header[Gitlab::Workhorse::DETECT_HEADER]).to eq "true"
- end
- end
-
- context 'disabled' do
- it "does not set #{Gitlab::Workhorse::DETECT_HEADER} header" do
- expect(response).to have_gitlab_http_status(200)
- expect(response.header[Gitlab::Workhorse::DETECT_HEADER]).to be nil
- end
- end
+ it "sets #{Gitlab::Workhorse::DETECT_HEADER} header" do
+ expect(response).to have_gitlab_http_status(200)
+ expect(response.header[Gitlab::Workhorse::DETECT_HEADER]).to eq "true"
end
end
end
diff --git a/spec/db/importers/common_metrics_importer_spec.rb b/spec/db/importers/common_metrics_importer_spec.rb
index 68260820958..6133b17ac61 100644
--- a/spec/db/importers/common_metrics_importer_spec.rb
+++ b/spec/db/importers/common_metrics_importer_spec.rb
@@ -4,12 +4,18 @@ require 'rails_helper'
require Rails.root.join("db", "importers", "common_metrics_importer.rb")
describe Importers::PrometheusMetric do
+ let(:existing_group_titles) do
+ ::PrometheusMetric::GROUP_DETAILS.each_with_object({}) do |(key, value), memo|
+ memo[key] = value[:group_title]
+ end
+ end
+
it 'group enum equals ::PrometheusMetric' do
expect(described_class.groups).to eq(::PrometheusMetric.groups)
end
it 'GROUP_TITLES equals ::PrometheusMetric' do
- expect(described_class::GROUP_TITLES).to eq(::PrometheusMetric::GROUP_TITLES)
+ expect(described_class::GROUP_TITLES).to eq(existing_group_titles)
end
end
diff --git a/spec/factories/appearances.rb b/spec/factories/appearances.rb
index 18c7453bd1b..dd5129229d4 100644
--- a/spec/factories/appearances.rb
+++ b/spec/factories/appearances.rb
@@ -15,6 +15,10 @@ FactoryBot.define do
header_logo { fixture_file_upload('spec/fixtures/dk.png') }
end
+ trait :with_favicon do
+ favicon { fixture_file_upload('spec/fixtures/dk.png') }
+ end
+
trait :with_logos do
with_logo
with_header_logo
diff --git a/spec/factories/notes.rb b/spec/factories/notes.rb
index 2d1f48bf249..c51f2f958f9 100644
--- a/spec/factories/notes.rb
+++ b/spec/factories/notes.rb
@@ -64,6 +64,21 @@ FactoryBot.define do
resolved_at { Time.now }
resolved_by { create(:user) }
end
+
+ factory :image_diff_note_on_merge_request do
+ position do
+ Gitlab::Diff::Position.new(
+ old_path: "files/images/any_image.png",
+ new_path: "files/images/any_image.png",
+ width: 10,
+ height: 10,
+ x: 1,
+ y: 1,
+ diff_refs: diff_refs,
+ position_type: "image"
+ )
+ end
+ end
end
factory :diff_note_on_commit, traits: [:on_commit], class: DiffNote do
diff --git a/spec/factories/releases.rb b/spec/factories/releases.rb
index 18047c74a5d..cab6b4a811f 100644
--- a/spec/factories/releases.rb
+++ b/spec/factories/releases.rb
@@ -1,8 +1,15 @@
FactoryBot.define do
factory :release do
tag "v1.1.0"
+ sha 'b83d6e391c22777fca1ed3012fce84f633d7fed0'
name { tag }
description "Awesome release"
project
+ author
+
+ trait :legacy do
+ sha nil
+ author nil
+ end
end
end
diff --git a/spec/features/admin/admin_disables_git_access_protocol_spec.rb b/spec/features/admin/admin_disables_git_access_protocol_spec.rb
index 91c22e7ad82..f066b088800 100644
--- a/spec/features/admin/admin_disables_git_access_protocol_spec.rb
+++ b/spec/features/admin/admin_disables_git_access_protocol_spec.rb
@@ -1,7 +1,8 @@
require 'rails_helper'
-describe 'Admin disables Git access protocol' do
+describe 'Admin disables Git access protocol', :js do
include StubENV
+ include MobileHelpers
let(:project) { create(:project, :empty_repo) }
let(:admin) { create(:admin) }
@@ -20,7 +21,24 @@ describe 'Admin disables Git access protocol' do
visit_project
expect(page).to have_content("git clone #{project.ssh_url_to_repo}")
- expect(page).not_to have_selector('#clone-dropdown')
+
+ find('.clone-dropdown-btn').click
+
+ within('.git-clone-holder') do
+ expect(page).to have_content('Clone with SSH')
+ expect(page).not_to have_content('Clone with HTTP')
+ end
+ end
+
+ context 'mobile component' do
+ it 'shows only the SSH clone information' do
+ resize_screen_xs
+ visit_project
+ find('.dropdown-toggle').click
+
+ expect(page).to have_content('Copy SSH clone URL')
+ expect(page).not_to have_content('Copy HTTP clone URL')
+ end
end
end
@@ -31,9 +49,25 @@ describe 'Admin disables Git access protocol' do
it 'shows only HTTP url' do
visit_project
+ find('.clone-dropdown-btn').click
expect(page).to have_content("git clone #{project.http_url_to_repo}")
- expect(page).not_to have_selector('#clone-dropdown')
+
+ within('.git-clone-holder') do
+ expect(page).to have_content('Clone with HTTP')
+ expect(page).not_to have_content('Clone with SSH')
+ end
+ end
+
+ context 'mobile component' do
+ it 'shows only the HTTP clone information' do
+ resize_screen_xs
+ visit_project
+ find('.dropdown-toggle').click
+
+ expect(page).to have_content('Copy HTTP clone URL')
+ expect(page).not_to have_content('Copy SSH clone URL')
+ end
end
end
@@ -46,7 +80,24 @@ describe 'Admin disables Git access protocol' do
visit_project
expect(page).to have_content("git clone #{project.ssh_url_to_repo}")
- expect(page).to have_selector('#clone-dropdown')
+
+ find('.clone-dropdown-btn').click
+
+ within('.git-clone-holder') do
+ expect(page).to have_content('Clone with SSH')
+ expect(page).to have_content('Clone with HTTP')
+ end
+ end
+
+ context 'mobile component' do
+ it 'shows both SSH and HTTP clone information' do
+ resize_screen_xs
+ visit_project
+ find('.dropdown-toggle').click
+
+ expect(page).to have_content('Copy HTTP clone URL')
+ expect(page).to have_content('Copy SSH clone URL')
+ end
end
end
diff --git a/spec/features/group_variables_spec.rb b/spec/features/group_variables_spec.rb
index 89e0cdd8ed7..57e3ddfb39c 100644
--- a/spec/features/group_variables_spec.rb
+++ b/spec/features/group_variables_spec.rb
@@ -7,7 +7,7 @@ describe 'Group variables', :js do
let(:page_path) { group_settings_ci_cd_path(group) }
before do
- group.add_maintainer(user)
+ group.add_owner(user)
gitlab_sign_in(user)
visit page_path
diff --git a/spec/features/groups/show_spec.rb b/spec/features/groups/show_spec.rb
index 4e6f73ef58a..9671a4d8c49 100644
--- a/spec/features/groups/show_spec.rb
+++ b/spec/features/groups/show_spec.rb
@@ -65,7 +65,7 @@ describe 'Group show page' do
context 'when subgroups are supported', :js, :nested_groups do
before do
- allow(Group).to receive(:supports_nested_groups?) { true }
+ allow(Group).to receive(:supports_nested_objects?) { true }
visit path
end
@@ -76,7 +76,7 @@ describe 'Group show page' do
context 'when subgroups are not supported' do
before do
- allow(Group).to receive(:supports_nested_groups?) { false }
+ allow(Group).to receive(:supports_nested_objects?) { false }
visit path
end
diff --git a/spec/features/issues/gfm_autocomplete_spec.rb b/spec/features/issues/gfm_autocomplete_spec.rb
index d7531d5fcd9..3b7a17ef355 100644
--- a/spec/features/issues/gfm_autocomplete_spec.rb
+++ b/spec/features/issues/gfm_autocomplete_spec.rb
@@ -3,6 +3,8 @@ 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(: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') }
@@ -25,10 +27,14 @@ describe 'GFM autocomplete', :js do
simulate_input('#issue-description', "@#{user.name[0...3]}")
+ wait_for_requests
+
find('.atwho-view .cur').click
click_button 'Save changes'
+ wait_for_requests
+
expect(find('.description')).to have_content(user.to_reference)
end
@@ -47,6 +53,8 @@ describe 'GFM autocomplete', :js do
find('#note-body').native.send_keys('#')
end
+ wait_for_requests
+
expect(page).to have_selector('.atwho-container')
page.within '.atwho-container #at-view-issues' do
@@ -59,6 +67,8 @@ describe 'GFM autocomplete', :js do
find('#note-body').native.send_keys('@ev')
end
+ wait_for_requests
+
expect(page).to have_selector('.atwho-container')
page.within '.atwho-container #at-view-users' do
@@ -66,6 +76,22 @@ describe 'GFM autocomplete', :js do
end
end
+ it 'opens autocomplete menu for Milestone when field starts with text with item escaping HTML characters' do
+ create(:milestone, project: project, title: milestone_xss_title)
+
+ page.within '.timeline-content-form' do
+ find('#note-body').native.send_keys('%')
+ end
+
+ wait_for_requests
+
+ expect(page).to have_selector('.atwho-container')
+
+ page.within '.atwho-container #at-view-milestones' do
+ expect(find('li').text).to have_content('alert milestone')
+ end
+ end
+
it 'doesnt open autocomplete menu character is prefixed with text' do
page.within '.timeline-content-form' do
find('#note-body').native.send_keys('testing')
@@ -258,12 +284,28 @@ describe 'GFM autocomplete', :js do
let!(:bug) { create(:label, project: project, title: 'bug') }
let!(:feature_proposal) { create(:label, project: project, title: 'feature proposal') }
+ it 'opens autocomplete menu for Labels when field starts with text with item escaping HTML characters' do
+ create(:label, project: project, title: label_xss_title)
+
+ note = find('#note-body')
+
+ # It should show all the labels on "~".
+ type(note, '~')
+
+ wait_for_requests
+
+ page.within '.atwho-container #at-view-labels' do
+ expect(find('.atwho-view-ul').text).to have_content('alert label')
+ end
+ end
+
context 'when no labels are assigned' do
it 'shows labels' do
note = find('#note-body')
# It should show all the labels on "~".
type(note, '~')
+ wait_for_requests
expect_labels(shown: [backend, bug, feature_proposal])
# It should show all the labels on "/label ~".
@@ -290,6 +332,7 @@ describe 'GFM autocomplete', :js do
# It should show all the labels on "~".
type(note, '~')
+ wait_for_requests
expect_labels(shown: [backend, bug, feature_proposal])
# It should show only unset labels on "/label ~".
@@ -316,6 +359,7 @@ describe 'GFM autocomplete', :js do
# It should show all the labels on "~".
type(note, '~')
+ wait_for_requests
expect_labels(shown: [backend, bug, feature_proposal])
# It should show no labels on "/label ~".
diff --git a/spec/features/issues/user_creates_issue_spec.rb b/spec/features/issues/user_creates_issue_spec.rb
index 830d56035aa..e60486f6dcb 100644
--- a/spec/features/issues/user_creates_issue_spec.rb
+++ b/spec/features/issues/user_creates_issue_spec.rb
@@ -14,7 +14,7 @@ describe "User creates issue" do
visit(new_project_issue_path(project))
end
- it "creates issue" do
+ it "creates issue", :js do
page.within(".issue-form") do
expect(page).to have_no_content("Assign to")
.and have_no_content("Labels")
@@ -27,11 +27,15 @@ describe "User creates issue" do
issue_title = "500 error on profile"
fill_in("Title", with: issue_title)
+ first('.js-md').click
+ first('.qa-issuable-form-description').native.send_keys('Description')
+
click_button("Submit issue")
expect(page).to have_content(issue_title)
.and have_content(user.name)
.and have_content(project.name)
+ expect(page).to have_selector('strong', text: 'Description')
end
end
diff --git a/spec/features/merge_request/user_creates_image_diff_notes_spec.rb b/spec/features/merge_request/user_creates_image_diff_notes_spec.rb
index d790bdc82ce..d19408ee87f 100644
--- a/spec/features/merge_request/user_creates_image_diff_notes_spec.rb
+++ b/spec/features/merge_request/user_creates_image_diff_notes_spec.rb
@@ -90,9 +90,6 @@ describe 'Merge request > User creates image diff notes', :js do
%w(inline parallel).each do |view|
context "#{view} view" do
- let(:merge_request) { create(:merge_request_with_diffs, :with_image_diffs, source_project: project, author: user) }
- let(:path) { "files/images/ee_repo_logo.png" }
-
let(:position) do
Gitlab::Diff::Position.new(
old_path: path,
@@ -108,9 +105,11 @@ describe 'Merge request > User creates image diff notes', :js do
let!(:note) { create(:diff_note_on_merge_request, project: project, noteable: merge_request, position: position) }
- describe 'creating a new diff note' do
+ shared_examples 'creates image diff note' do
before do
visit diffs_project_merge_request_path(project, merge_request, view: view)
+ wait_for_requests
+
create_image_diff_note
end
@@ -132,6 +131,32 @@ describe 'Merge request > User creates image diff notes', :js do
expect(page).to have_content('image diff test comment')
end
end
+
+ context 'when images are not stored in LFS' do
+ let(:merge_request) { create(:merge_request_with_diffs, :with_image_diffs, source_project: project, author: user) }
+ let(:path) { 'files/images/ee_repo_logo.png' }
+
+ it_behaves_like 'creates image diff note'
+ end
+
+ context 'when images are stored in LFS' do
+ let(:merge_request) { create(:merge_request, source_project: project, target_project: project, source_branch: 'png-lfs', target_branch: 'master', author: user) }
+ let(:path) { 'files/images/logo-black.png' }
+
+ before do
+ allow(Gitlab.config.lfs).to receive(:enabled).and_return(true)
+ project.update_attribute(:lfs_enabled, true)
+ end
+
+ it 'shows lfs badges' do
+ visit diffs_project_merge_request_path(project, merge_request, view: view)
+ wait_for_requests
+
+ expect(page.all('.diff-file span.label-lfs', visible: :all)).not_to be_empty
+ end
+
+ it_behaves_like 'creates image diff note'
+ end
end
end
diff --git a/spec/features/merge_request/user_sees_diff_spec.rb b/spec/features/merge_request/user_sees_diff_spec.rb
index 0df9e4bbc1a..04b07525919 100644
--- a/spec/features/merge_request/user_sees_diff_spec.rb
+++ b/spec/features/merge_request/user_sees_diff_spec.rb
@@ -87,20 +87,6 @@ describe 'Merge request > User sees diff', :js do
let(:current_user) { project.owner }
let(:branch_name) {"test_branch"}
- def create_file(branch_name, file_name, content)
- Files::CreateService.new(
- project,
- current_user,
- start_branch: branch_name,
- branch_name: branch_name,
- commit_message: "Create file",
- file_path: file_name,
- file_content: content
- ).execute
-
- project.commit(branch_name)
- end
-
it 'escapes any HTML special characters in the diff chunk header' do
file_content =
<<~CONTENT
@@ -136,5 +122,61 @@ describe 'Merge request > User sees diff', :js do
expect(page).to have_css(".line[lang='rust'] .k")
end
end
+
+ context 'when file is stored in LFS' do
+ let(:merge_request) { create(:merge_request, source_project: project) }
+ let(:current_user) { project.owner }
+
+ context 'when LFS is enabled on the project' do
+ before do
+ allow(Gitlab.config.lfs).to receive(:enabled).and_return(true)
+ project.update_attribute(:lfs_enabled, true)
+
+ create_file('master', file_name, project.repository.blob_at('master', 'files/lfs/lfs_object.iso').data)
+
+ visit diffs_project_merge_request_path(project, merge_request)
+ end
+
+ context 'when file is an image', :js do
+ let(:file_name) { 'files/lfs/image.png' }
+
+ it 'shows an error message' do
+ expect(page).not_to have_content('could not be displayed because it is stored in LFS')
+ end
+ end
+
+ context 'when file is not an image' do
+ let(:file_name) { 'files/lfs/ruby.rb' }
+
+ it 'shows an error message' do
+ expect(page).to have_content('This source diff could not be displayed because it is stored in LFS')
+ end
+ end
+ end
+
+ context 'when LFS is not enabled' do
+ before do
+ visit diffs_project_merge_request_path(project, merge_request)
+ end
+
+ it 'displays the diff' do
+ expect(page).to have_content('size 1575078')
+ end
+ end
+ end
+
+ def create_file(branch_name, file_name, content)
+ Files::CreateService.new(
+ project,
+ current_user,
+ start_branch: branch_name,
+ branch_name: branch_name,
+ commit_message: "Create file",
+ file_path: file_name,
+ file_content: content
+ ).execute
+
+ project.commit(branch_name)
+ end
end
end
diff --git a/spec/features/merge_request/user_sees_versions_spec.rb b/spec/features/merge_request/user_sees_versions_spec.rb
index f7512294bef..63d8decc2d2 100644
--- a/spec/features/merge_request/user_sees_versions_spec.rb
+++ b/spec/features/merge_request/user_sees_versions_spec.rb
@@ -64,6 +64,17 @@ describe 'Merge request > User sees versions', :js do
end
end
+ it 'shows the commit SHAs for every version in the dropdown' do
+ page.within '.mr-version-dropdown' do
+ find('.btn-default').click
+
+ page.within('.dropdown-content') do
+ shas = merge_request.merge_request_diffs.map { |diff| Commit.truncate_sha(diff.head_commit_sha) }
+ shas.each { |sha| expect(page).to have_content(sha) }
+ end
+ end
+ end
+
it 'shows comments that were last relevant at that version' do
expect(page).to have_content '5 changed files'
diff --git a/spec/features/merge_request/user_tries_to_access_private_repository_through_new_mr_spec.rb b/spec/features/merge_request/user_tries_to_access_private_repository_through_new_mr_spec.rb
new file mode 100644
index 00000000000..9318b5f1ebb
--- /dev/null
+++ b/spec/features/merge_request/user_tries_to_access_private_repository_through_new_mr_spec.rb
@@ -0,0 +1,37 @@
+require 'spec_helper'
+
+describe 'Merge Request > Tries to access private repo of public project' do
+ let(:current_user) { create(:user) }
+ let(:private_project) do
+ create(:project, :public, :repository,
+ path: 'nothing-to-see-here',
+ name: 'nothing to see here',
+ repository_access_level: ProjectFeature::PRIVATE)
+ end
+ let(:owned_project) do
+ create(:project, :public, :repository,
+ namespace: current_user.namespace,
+ creator: current_user)
+ end
+
+ context 'when the user enters the querystring info for the other project' do
+ let(:mr_path) do
+ project_new_merge_request_diffs_path(
+ owned_project,
+ merge_request: {
+ source_project_id: private_project.id,
+ source_branch: 'feature'
+ }
+ )
+ end
+
+ before do
+ sign_in current_user
+ visit mr_path
+ end
+
+ it "does not mention the project the user can't see the repo of" do
+ expect(page).not_to have_content('nothing-to-see-here')
+ end
+ end
+end
diff --git a/spec/features/profiles/user_edit_profile_spec.rb b/spec/features/profiles/user_edit_profile_spec.rb
index 5e0434c1c2c..f45bcabd196 100644
--- a/spec/features/profiles/user_edit_profile_spec.rb
+++ b/spec/features/profiles/user_edit_profile_spec.rb
@@ -147,6 +147,9 @@ describe 'User edit profile' do
end
context 'user menu' do
+ let(:issue) { create(:issue, project: project)}
+ let(:project) { create(:project) }
+
def open_user_status_modal
find('.header-user-dropdown-toggle').click
@@ -205,6 +208,17 @@ describe 'User edit profile' do
end
end
+ it 'does not update the awards panel emoji' do
+ project.add_maintainer(user)
+ visit(project_issue_path(project, issue))
+
+ emoji = 'biohazard'
+ open_user_status_modal
+ select_emoji(emoji, true)
+
+ expect(page.all('.award-control .js-counter')).to all(have_content('0'))
+ end
+
it 'adds message to user status' do
message = 'I have something to say'
open_user_status_modal
diff --git a/spec/features/projects/clusters/gcp_spec.rb b/spec/features/projects/clusters/gcp_spec.rb
index 3d17eb3a73a..06e30571336 100644
--- a/spec/features/projects/clusters/gcp_spec.rb
+++ b/spec/features/projects/clusters/gcp_spec.rb
@@ -130,7 +130,7 @@ describe 'Gcp Cluster', :js do
context 'when user changes cluster parameters' do
before do
- allow(ClusterPlatformConfigureWorker).to receive(:perform_async)
+ allow(ClusterConfigureWorker).to receive(:perform_async)
fill_in 'cluster_platform_kubernetes_attributes_namespace', with: 'my-namespace'
page.within('#js-cluster-details') { click_button 'Save changes' }
end
diff --git a/spec/features/projects/commits/user_browses_commits_spec.rb b/spec/features/projects/commits/user_browses_commits_spec.rb
index 2159adf49fc..574a8aefd63 100644
--- a/spec/features/projects/commits/user_browses_commits_spec.rb
+++ b/spec/features/projects/commits/user_browses_commits_spec.rb
@@ -93,7 +93,7 @@ describe 'User browses commits' do
it 'shows a blank label' do
allow_any_instance_of(Gitlab::Diff::File).to receive(:blob).and_return(nil)
- allow_any_instance_of(Gitlab::Diff::File).to receive(:raw_binary?).and_return(true)
+ allow_any_instance_of(Gitlab::Diff::File).to receive(:binary?).and_return(true)
visit(project_commit_path(project, commit))
diff --git a/spec/features/runners_spec.rb b/spec/features/runners_spec.rb
index cb7a912946c..09de983f669 100644
--- a/spec/features/runners_spec.rb
+++ b/spec/features/runners_spec.rb
@@ -259,8 +259,9 @@ describe 'Runners' do
context 'group runners in group settings' do
let(:group) { create(:group) }
+
before do
- group.add_maintainer(user)
+ group.add_owner(user)
end
context 'group with no runners' do
diff --git a/spec/features/users/overview_spec.rb b/spec/features/users/overview_spec.rb
index 34ed771340f..8748230fa0c 100644
--- a/spec/features/users/overview_spec.rb
+++ b/spec/features/users/overview_spec.rb
@@ -33,6 +33,8 @@ describe 'Overview tab on a user profile', :js do
it 'does not show any entries in the list of activities' do
page.within('.activities-block') do
+ expect(page).to have_selector('.loading', visible: false)
+ expect(page).to have_content('No activities found')
expect(page).not_to have_selector('.event-item')
end
end
@@ -93,6 +95,7 @@ describe 'Overview tab on a user profile', :js do
it 'it shows an empty project list with an info message' do
page.within('.projects-block') do
+ expect(page).to have_selector('.loading', visible: false)
expect(page).to have_content('No projects found')
expect(page).not_to have_selector('.project-row')
end
@@ -119,6 +122,12 @@ describe 'Overview tab on a user profile', :js do
it 'shows a link to the project list' do
expect(find('#js-overview .projects-block')).to have_selector('.js-view-all', visible: true)
end
+
+ it 'shows projects in "compact mode"' do
+ page.within('#js-overview .projects-block') do
+ expect(find('.js-projects-list-holder')).to have_selector('.compact')
+ end
+ end
end
describe 'user has more than ten personal projects' do
diff --git a/spec/finders/releases_finder_spec.rb b/spec/finders/releases_finder_spec.rb
new file mode 100644
index 00000000000..32ee15134a2
--- /dev/null
+++ b/spec/finders/releases_finder_spec.rb
@@ -0,0 +1,42 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe ReleasesFinder do
+ let(:user) { create(:user) }
+ let(:project) { create(:project, :repository) }
+ let(:repository) { project.repository }
+ let(:v1_0_0) { create(:release, project: project, tag: 'v1.0.0') }
+ let(:v1_1_0) { create(:release, project: project, tag: 'v1.1.0') }
+
+ 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)
+ end
+
+ describe '#execute' do
+ context 'when the user is not part of the project' do
+ it 'returns no releases' do
+ releases = subject.execute
+
+ expect(releases).to be_empty
+ end
+ end
+
+ context 'when the user is a project developer' do
+ before do
+ project.add_developer(user)
+ end
+
+ it 'sorts by creation date' do
+ releases = subject.execute
+
+ expect(releases).to be_present
+ expect(releases.size).to eq(2)
+ expect(releases).to eq([v1_1_0, v1_0_0])
+ end
+ end
+ end
+end
diff --git a/spec/fixtures/api/schemas/entities/diff_viewer.json b/spec/fixtures/api/schemas/entities/diff_viewer.json
index 19780f49a88..81325cd86c6 100644
--- a/spec/fixtures/api/schemas/entities/diff_viewer.json
+++ b/spec/fixtures/api/schemas/entities/diff_viewer.json
@@ -1,8 +1,20 @@
{
"type": "object",
- "required": ["name"],
+ "required": [
+ "name"
+ ],
"properties": {
- "name": { "type": ["string"] }
+ "name": {
+ "type": [
+ "string"
+ ]
+ },
+ "error": {
+ "type": [
+ "string",
+ "null"
+ ]
+ }
},
"additionalProperties": false
}
diff --git a/spec/fixtures/api/schemas/entities/issuable_sidebar_todo.json b/spec/fixtures/api/schemas/entities/issuable_sidebar_todo.json
new file mode 100644
index 00000000000..b77e60ece12
--- /dev/null
+++ b/spec/fixtures/api/schemas/entities/issuable_sidebar_todo.json
@@ -0,0 +1,8 @@
+{
+ "type": ["object", "null"],
+ "properties" : {
+ "id": { "type": "integer" },
+ "delete_path": { "type": "string" }
+ },
+ "additionalProperties": false
+}
diff --git a/spec/fixtures/api/schemas/entities/issue_sidebar.json b/spec/fixtures/api/schemas/entities/issue_sidebar.json
index 682e345d5f5..93adb493d1b 100644
--- a/spec/fixtures/api/schemas/entities/issue_sidebar.json
+++ b/spec/fixtures/api/schemas/entities/issue_sidebar.json
@@ -2,20 +2,46 @@
"type": "object",
"properties" : {
"id": { "type": "integer" },
- "iid": { "type": "integer" },
- "subscribed": { "type": "boolean" },
- "time_estimate": { "type": "integer" },
- "total_time_spent": { "type": "integer" },
- "human_time_estimate": { "type": ["integer", "null"] },
- "human_total_time_spent": { "type": ["integer", "null"] },
- "participants": {
- "type": "array",
- "items": { "$ref": "../public_api/v4/user/basic.json" }
+ "type": { "type": "string" },
+ "author_id": { "type": "integer" },
+ "project_id": { "type": "integer" },
+ "discussion_locked": { "type": ["boolean", "null"] },
+ "due_date": { "type": "date" },
+ "confidential": { "type": "boolean" },
+ "reference": { "type": "string" },
+ "current_user": {
+ "allOf": [
+ { "$ref": "../public_api/v4/user/basic.json" },
+ { "type": "object",
+ "properties" : {
+ "todo": { "$ref": "issuable_sidebar_todo.json" },
+ "can_edit": { "type": "boolean" },
+ "can_move": { "type": "boolean" },
+ "can_admin_label": { "type": "boolean" }
+ }
+ }
+ ]
+ },
+ "milestone": {
+ "oneOf": [
+ { "type": "null" },
+ { "$ref": "../public_api/v4/milestone.json" }
+ ]
},
- "assignees": {
+ "labels": {
"type": "array",
- "items": { "$ref": "../public_api/v4/user/basic.json" }
- }
- },
- "additionalProperties": false
+ "items": { "$ref": "label.json" }
+ },
+ "issuable_json_path": { "type": "string" },
+ "namespace_path": { "type": "string" },
+ "project_path": { "type": "string" },
+ "project_full_path": { "type": "string" },
+ "project_issuables_path": { "type": "string" },
+ "create_todo_path": { "type": "string" },
+ "project_milestones_path": { "type": "string" },
+ "project_labels_path": { "type": "string" },
+ "toggle_subscription_path": { "type": "string" },
+ "move_issue_path": { "type": "string" },
+ "projects_autocomplete_path": { "type": "string" }
+ }
}
diff --git a/spec/fixtures/api/schemas/entities/issue_sidebar_extras.json b/spec/fixtures/api/schemas/entities/issue_sidebar_extras.json
new file mode 100644
index 00000000000..11be903b083
--- /dev/null
+++ b/spec/fixtures/api/schemas/entities/issue_sidebar_extras.json
@@ -0,0 +1,18 @@
+{
+ "type": "object",
+ "properties" : {
+ "subscribed": { "type": "boolean" },
+ "time_estimate": { "type": "integer" },
+ "total_time_spent": { "type": "integer" },
+ "human_time_estimate": { "type": ["integer", "null"] },
+ "human_total_time_spent": { "type": ["integer", "null"] },
+ "participants": {
+ "type": "array",
+ "items": { "$ref": "../public_api/v4/user/basic.json" }
+ },
+ "assignees": {
+ "type": "array",
+ "items": { "$ref": "../public_api/v4/user/basic.json" }
+ }
+ }
+}
diff --git a/spec/fixtures/api/schemas/entities/merge_request_basic.json b/spec/fixtures/api/schemas/entities/merge_request_basic.json
index cf257ac00de..4c04c838cb8 100644
--- a/spec/fixtures/api/schemas/entities/merge_request_basic.json
+++ b/spec/fixtures/api/schemas/entities/merge_request_basic.json
@@ -4,15 +4,9 @@
"state": { "type": "string" },
"merge_status": { "type": "string" },
"source_branch_exists": { "type": "boolean" },
- "time_estimate": { "type": "integer" },
- "total_time_spent": { "type": "integer" },
- "human_time_estimate": { "type": ["string", "null"] },
- "human_total_time_spent": { "type": ["string", "null"] },
"merge_error": { "type": ["string", "null"] },
"rebase_in_progress": { "type": "boolean" },
"assignee_id": { "type": ["integer", "null"] },
- "subscribed": { "type": ["boolean", "null"] },
- "participants": { "type": "array" },
"allow_collaboration": { "type": "boolean"},
"allow_maintainer_to_push": { "type": "boolean"},
"assignee": {
diff --git a/spec/fixtures/api/schemas/entities/merge_request_sidebar.json b/spec/fixtures/api/schemas/entities/merge_request_sidebar.json
new file mode 100644
index 00000000000..7e9e048a9fd
--- /dev/null
+++ b/spec/fixtures/api/schemas/entities/merge_request_sidebar.json
@@ -0,0 +1,56 @@
+{
+ "type": "object",
+ "properties" : {
+ "id": { "type": "integer" },
+ "type": { "type": "string" },
+ "author_id": { "type": "integer" },
+ "project_id": { "type": "integer" },
+ "discussion_locked": { "type": ["boolean", "null"] },
+ "reference": { "type": "string" },
+ "current_user": {
+ "allOf": [
+ { "$ref": "../public_api/v4/user/basic.json" },
+ { "type": "object",
+ "properties" : {
+ "todo": { "$ref": "issuable_sidebar_todo.json" },
+ "can_edit": { "type": "boolean" },
+ "can_move": { "type": "boolean" },
+ "can_admin_label": { "type": "boolean" }
+ }
+ }
+ ]
+ },
+ "milestone": {
+ "oneOf": [
+ { "type": "null" },
+ { "$ref": "../public_api/v4/milestones.json" }
+ ]
+ },
+ "labels": {
+ "type": "array",
+ "items": { "$ref": "label.json" }
+ },
+ "assignee": {
+ "allOf": [
+ { "$ref": "../public_api/v4/user/basic.json" },
+ { "type": "object",
+ "properties" : {
+ "can_merge": { "type": "boolean" }
+ }
+ }
+ ]
+ },
+ "issuable_json_path": { "type": "string" },
+ "namespace_path": { "type": "string" },
+ "project_path": { "type": "string" },
+ "project_full_path": { "type": "string" },
+ "project_issuables_path": { "type": "string" },
+ "create_todo_path": { "type": "string" },
+ "project_milestones_path": { "type": "string" },
+ "project_labels_path": { "type": "string" },
+ "toggle_subscription_path": { "type": "string" },
+ "move_issue_path": { "type": "string" },
+ "projects_autocomplete_path": { "type": "string" }
+ },
+ "additionalProperties": false
+}
diff --git a/spec/fixtures/api/schemas/entities/merge_request_sidebar_extras.json b/spec/fixtures/api/schemas/entities/merge_request_sidebar_extras.json
new file mode 100644
index 00000000000..682e345d5f5
--- /dev/null
+++ b/spec/fixtures/api/schemas/entities/merge_request_sidebar_extras.json
@@ -0,0 +1,21 @@
+{
+ "type": "object",
+ "properties" : {
+ "id": { "type": "integer" },
+ "iid": { "type": "integer" },
+ "subscribed": { "type": "boolean" },
+ "time_estimate": { "type": "integer" },
+ "total_time_spent": { "type": "integer" },
+ "human_time_estimate": { "type": ["integer", "null"] },
+ "human_total_time_spent": { "type": ["integer", "null"] },
+ "participants": {
+ "type": "array",
+ "items": { "$ref": "../public_api/v4/user/basic.json" }
+ },
+ "assignees": {
+ "type": "array",
+ "items": { "$ref": "../public_api/v4/user/basic.json" }
+ }
+ },
+ "additionalProperties": false
+}
diff --git a/spec/fixtures/api/schemas/public_api/v4/milestone.json b/spec/fixtures/api/schemas/public_api/v4/milestone.json
new file mode 100644
index 00000000000..6ca2e88ae91
--- /dev/null
+++ b/spec/fixtures/api/schemas/public_api/v4/milestone.json
@@ -0,0 +1,22 @@
+{
+ "type": "object",
+ "properties" : {
+ "id": { "type": "integer" },
+ "iid": { "type": "integer" },
+ "project_id": { "type": ["integer", "null"] },
+ "group_id": { "type": ["integer", "null"] },
+ "title": { "type": "string" },
+ "description": { "type": ["string", "null"] },
+ "state": { "type": "string" },
+ "created_at": { "type": "date" },
+ "updated_at": { "type": "date" },
+ "start_date": { "type": "date" },
+ "due_date": { "type": "date" },
+ "web_url": { "type": "string" }
+ },
+ "required": [
+ "id", "iid", "title", "description", "state",
+ "state", "created_at", "updated_at", "start_date", "due_date"
+ ],
+ "additionalProperties": false
+}
diff --git a/spec/fixtures/api/schemas/public_api/v4/milestones.json b/spec/fixtures/api/schemas/public_api/v4/milestones.json
index 448e97d6c85..dcbc1910bfe 100644
--- a/spec/fixtures/api/schemas/public_api/v4/milestones.json
+++ b/spec/fixtures/api/schemas/public_api/v4/milestones.json
@@ -1,25 +1,6 @@
{
"type": "array",
"items": {
- "type": "object",
- "properties" : {
- "id": { "type": "integer" },
- "iid": { "type": "integer" },
- "project_id": { "type": ["integer", "null"] },
- "group_id": { "type": ["integer", "null"] },
- "title": { "type": "string" },
- "description": { "type": ["string", "null"] },
- "state": { "type": "string" },
- "created_at": { "type": "date" },
- "updated_at": { "type": "date" },
- "start_date": { "type": "date" },
- "due_date": { "type": "date" },
- "web_url": { "type": "string" }
- },
- "required": [
- "id", "iid", "title", "description", "state",
- "state", "created_at", "updated_at", "start_date", "due_date"
- ],
- "additionalProperties": false
+ "$ref": "./milestone.json"
}
}
diff --git a/spec/fixtures/api/schemas/release.json b/spec/fixtures/api/schemas/release.json
new file mode 100644
index 00000000000..844405c3acd
--- /dev/null
+++ b/spec/fixtures/api/schemas/release.json
@@ -0,0 +1,18 @@
+{
+ "type": "object",
+ "required": ["name", "tag_name"],
+ "properties": {
+ "name": { "type": "string" },
+ "tag_name": { "type": "string" },
+ "description": { "type": "string" },
+ "description_html": { "type": "string" },
+ "created_at": { "type": "date" },
+ "commit": {
+ "oneOf": [{ "type": "null" }, { "$ref": "public_api/v4/commit/basic.json" }]
+ },
+ "author": {
+ "oneOf": [{ "type": "null" }, { "$ref": "public_api/v4/user/basic.json" }]
+ }
+ },
+ "additionalProperties": false
+}
diff --git a/spec/fixtures/api/schemas/releases.json b/spec/fixtures/api/schemas/releases.json
new file mode 100644
index 00000000000..e26215707fe
--- /dev/null
+++ b/spec/fixtures/api/schemas/releases.json
@@ -0,0 +1,4 @@
+{
+ "type": "array",
+ "items": { "$ref": "release.json" }
+}
diff --git a/spec/fixtures/gitlab/ci/external_files/.gitlab-ci-template-1.yml b/spec/fixtures/gitlab/ci/external_files/.gitlab-ci-template-1.yml
index 0bab94a7c2e..1e88cd120aa 100644
--- a/spec/fixtures/gitlab/ci/external_files/.gitlab-ci-template-1.yml
+++ b/spec/fixtures/gitlab/ci/external_files/.gitlab-ci-template-1.yml
@@ -2,7 +2,6 @@ before_script:
- apt-get update -qq && apt-get install -y -qq sqlite3 libsqlite3-dev nodejs
- ruby -v
- which ruby
- - gem install bundler --no-ri --no-rdoc
- bundle install --jobs $(nproc) "${FLAGS[@]}"
rspec:
diff --git a/spec/fixtures/symlink_export.tar.gz b/spec/fixtures/symlink_export.tar.gz
new file mode 100644
index 00000000000..f295f69c56c
--- /dev/null
+++ b/spec/fixtures/symlink_export.tar.gz
Binary files differ
diff --git a/spec/helpers/diff_helper_spec.rb b/spec/helpers/diff_helper_spec.rb
index 53c010fa0db..5396243f44d 100644
--- a/spec/helpers/diff_helper_spec.rb
+++ b/spec/helpers/diff_helper_spec.rb
@@ -256,43 +256,6 @@ describe DiffHelper do
end
end
- context 'viewer related' do
- let(:viewer) { diff_file.simple_viewer }
-
- before do
- assign(:project, project)
- end
-
- describe '#diff_render_error_reason' do
- context 'for error :too_large' do
- before do
- expect(viewer).to receive(:render_error).and_return(:too_large)
- end
-
- it 'returns an error message' do
- expect(helper.diff_render_error_reason(viewer)).to eq('it is too large')
- end
- end
-
- context 'for error :server_side_but_stored_externally' do
- before do
- expect(viewer).to receive(:render_error).and_return(:server_side_but_stored_externally)
- expect(diff_file).to receive(:external_storage).and_return(:lfs)
- end
-
- it 'returns an error message' do
- expect(helper.diff_render_error_reason(viewer)).to eq('it is stored in LFS')
- end
- end
- end
-
- describe '#diff_render_error_options' do
- it 'includes a "view the blob" link' do
- expect(helper.diff_render_error_options(viewer)).to include(/view the blob/)
- end
- end
- end
-
context '#diff_file_path_text' do
it 'returns full path by default' do
expect(diff_file_path_text(diff_file)).to eq(diff_file.new_path)
diff --git a/spec/helpers/issuables_helper_spec.rb b/spec/helpers/issuables_helper_spec.rb
index 4af98bc3678..81231cca085 100644
--- a/spec/helpers/issuables_helper_spec.rb
+++ b/spec/helpers/issuables_helper_spec.rb
@@ -43,16 +43,19 @@ describe IssuablesHelper do
end
describe '#issuable_labels_tooltip' do
+ let(:label_entity) { LabelEntity.represent(label).as_json }
+ let(:label2_entity) { LabelEntity.represent(label2).as_json }
+
it 'returns label text with no labels' do
expect(issuable_labels_tooltip([])).to eq("Labels")
end
it 'returns label text with labels within max limit' do
- expect(issuable_labels_tooltip([label])).to eq(label.title)
+ expect(issuable_labels_tooltip([label_entity])).to eq(label[:title])
end
it 'returns label text with labels exceeding max limit' do
- expect(issuable_labels_tooltip([label, label2], limit: 1)).to eq("#{label.title}, and 1 more")
+ expect(issuable_labels_tooltip([label_entity, label2_entity], limit: 1)).to eq("#{label[:title]}, and 1 more")
end
end
@@ -197,33 +200,4 @@ describe IssuablesHelper do
expect(helper.issuable_initial_data(issue)).to eq(expected_data)
end
end
-
- describe '#selected_labels' do
- context 'if label_name param is a string' do
- it 'returns a new label with title' do
- allow(helper).to receive(:params)
- .and_return(ActionController::Parameters.new(label_name: 'test label'))
-
- labels = helper.selected_labels
-
- expect(labels).to be_an(Array)
- expect(labels.size).to eq(1)
- expect(labels.first.title).to eq('test label')
- end
- end
-
- context 'if label_name param is an array' do
- it 'returns a new label with title for each element' do
- allow(helper).to receive(:params)
- .and_return(ActionController::Parameters.new(label_name: ['test label 1', 'test label 2']))
-
- labels = helper.selected_labels
-
- expect(labels).to be_an(Array)
- expect(labels.size).to eq(2)
- expect(labels.first.title).to eq('test label 1')
- expect(labels.second.title).to eq('test label 2')
- end
- end
- end
end
diff --git a/spec/helpers/projects_helper_spec.rb b/spec/helpers/projects_helper_spec.rb
index 486416c3370..edd680ee1d1 100644
--- a/spec/helpers/projects_helper_spec.rb
+++ b/spec/helpers/projects_helper_spec.rb
@@ -519,4 +519,114 @@ describe ProjectsHelper do
expect(helper.legacy_render_context({})).to be_empty
end
end
+
+ describe '#explore_projects_tab?' do
+ subject { helper.explore_projects_tab? }
+
+ it 'returns true when on the "All" tab under "Explore projects"' do
+ allow(@request).to receive(:path) { explore_projects_path }
+
+ expect(subject).to be_truthy
+ end
+
+ it 'returns true when on the "Trending" tab under "Explore projects"' do
+ allow(@request).to receive(:path) { trending_explore_projects_path }
+
+ expect(subject).to be_truthy
+ end
+
+ it 'returns true when on the "Starred" tab under "Explore projects"' do
+ allow(@request).to receive(:path) { starred_explore_projects_path }
+
+ expect(subject).to be_truthy
+ end
+
+ it 'returns false when on the "Your projects" tab' do
+ allow(@request).to receive(:path) { dashboard_projects_path }
+
+ expect(subject).to be_falsey
+ end
+ end
+
+ describe '#show_merge_request_count' do
+ context 'when the feature flag is enabled' do
+ before do
+ stub_feature_flags(project_list_show_mr_count: true)
+ end
+
+ it 'returns true if compact mode is disabled' do
+ expect(helper.show_merge_request_count?).to be_truthy
+ end
+
+ it 'returns false if compact mode is enabled' do
+ expect(helper.show_merge_request_count?(compact_mode: true)).to be_falsey
+ end
+ end
+
+ context 'when the feature flag is disabled' do
+ before do
+ stub_feature_flags(project_list_show_mr_count: false)
+ end
+
+ it 'always returns false' do
+ expect(helper.show_merge_request_count?(disabled: false)).to be_falsy
+ expect(helper.show_merge_request_count?(disabled: true)).to be_falsy
+ end
+ end
+
+ context 'disabled flag' do
+ before do
+ stub_feature_flags(project_list_show_mr_count: true)
+ end
+
+ it 'returns false if disabled flag is true' do
+ expect(helper.show_merge_request_count?(disabled: true)).to be_falsey
+ end
+
+ it 'returns true if disabled flag is false' do
+ expect(helper.show_merge_request_count?).to be_truthy
+ end
+ end
+ end
+
+ describe '#show_issue_count?' do
+ context 'when the feature flag is enabled' do
+ before do
+ stub_feature_flags(project_list_show_issue_count: true)
+ end
+
+ it 'returns true if compact mode is disabled' do
+ expect(helper.show_issue_count?).to be_truthy
+ end
+
+ it 'returns false if compact mode is enabled' do
+ expect(helper.show_issue_count?(compact_mode: true)).to be_falsey
+ end
+ end
+
+ context 'when the feature flag is disabled' do
+ before do
+ stub_feature_flags(project_list_show_issue_count: false)
+ end
+
+ it 'always returns false' do
+ expect(helper.show_issue_count?(disabled: false)).to be_falsy
+ expect(helper.show_issue_count?(disabled: true)).to be_falsy
+ end
+ end
+
+ context 'disabled flag' do
+ before do
+ stub_feature_flags(project_list_show_issue_count: true)
+ end
+
+ it 'returns false if disabled flag is true' do
+ expect(helper.show_issue_count?(disabled: true)).to be_falsey
+ end
+
+ it 'returns true if disabled flag is false' do
+ expect(helper.show_issue_count?).to be_truthy
+ end
+ end
+ end
end
diff --git a/spec/initializers/active_record_locking_spec.rb b/spec/initializers/active_record_locking_spec.rb
new file mode 100644
index 00000000000..5a16aef78e6
--- /dev/null
+++ b/spec/initializers/active_record_locking_spec.rb
@@ -0,0 +1,44 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe 'ActiveRecord locking' do
+ let(:issue) { create(:issue) }
+
+ shared_examples 'locked model' do
+ before do
+ issue.update_column(:lock_version, start_lock_version)
+ end
+
+ it 'can be updated' do
+ issue.update(title: "New title")
+
+ expect(issue.reload.lock_version).to eq(new_lock_version)
+ end
+
+ it 'can be deleted' do
+ expect { issue.destroy }.to change { Issue.count }.by(-1)
+ end
+ end
+
+ context 'when lock_version is NULL' do
+ let(:start_lock_version) { nil }
+ let(:new_lock_version) { 1 }
+
+ it_behaves_like 'locked model'
+ end
+
+ context 'when lock_version is 0' do
+ let(:start_lock_version) { 0 }
+ let(:new_lock_version) { 1 }
+
+ it_behaves_like 'locked model'
+ end
+
+ context 'when lock_version is 1' do
+ let(:start_lock_version) { 1 }
+ let(:new_lock_version) { 2 }
+
+ it_behaves_like 'locked model'
+ end
+end
diff --git a/spec/initializers/8_metrics_spec.rb b/spec/initializers/zz_metrics_spec.rb
index 80c77057065..3eaccfe8d8b 100644
--- a/spec/initializers/8_metrics_spec.rb
+++ b/spec/initializers/zz_metrics_spec.rb
@@ -16,7 +16,7 @@ describe 'instrument_classes' do
end
it 'can autoload and instrument all files' do
- require_relative '../../config/initializers/8_metrics'
+ require_relative '../../config/initializers/zz_metrics'
expect { instrument_classes(config) }.not_to raise_error
end
end
diff --git a/spec/javascripts/ci_variable_list/ci_variable_list_spec.js b/spec/javascripts/ci_variable_list/ci_variable_list_spec.js
index 30b15011def..bef59b86d0c 100644
--- a/spec/javascripts/ci_variable_list/ci_variable_list_spec.js
+++ b/spec/javascripts/ci_variable_list/ci_variable_list_spec.js
@@ -118,6 +118,8 @@ describe('VariableList', () => {
loadFixtures('projects/ci_cd_settings.html.raw');
$wrapper = $('.js-ci-variable-list-section');
+ $wrapper.find('.js-ci-variable-input-protected').attr('data-default', 'false');
+
variableList = new VariableList({
container: $wrapper,
formField: 'variables',
diff --git a/spec/javascripts/fixtures/blob.rb b/spec/javascripts/fixtures/blob.rb
index 81e8a51a902..1b2a3b484bb 100644
--- a/spec/javascripts/fixtures/blob.rb
+++ b/spec/javascripts/fixtures/blob.rb
@@ -22,10 +22,11 @@ describe Projects::BlobController, '(JavaScript fixtures)', type: :controller do
end
it 'blob/show.html.raw' do |example|
- get(:show,
- namespace_id: project.namespace,
- project_id: project,
- id: 'add-ipython-files/files/ipython/basic.ipynb')
+ get(:show, params: {
+ namespace_id: project.namespace,
+ project_id: project,
+ id: 'add-ipython-files/files/ipython/basic.ipynb'
+ })
expect(response).to be_success
store_frontend_fixture(response, example.description)
diff --git a/spec/javascripts/fixtures/boards.rb b/spec/javascripts/fixtures/boards.rb
index 494c9cabdcc..1d675e008ba 100644
--- a/spec/javascripts/fixtures/boards.rb
+++ b/spec/javascripts/fixtures/boards.rb
@@ -18,9 +18,10 @@ describe Projects::BoardsController, '(JavaScript fixtures)', type: :controller
end
it 'boards/show.html.raw' do |example|
- get(:index,
- namespace_id: project.namespace,
- project_id: project)
+ get(:index, params: {
+ namespace_id: project.namespace,
+ project_id: project
+ })
expect(response).to be_success
store_frontend_fixture(response, example.description)
diff --git a/spec/javascripts/fixtures/branches.rb b/spec/javascripts/fixtures/branches.rb
index 4fc072d2585..3cc713ef90f 100644
--- a/spec/javascripts/fixtures/branches.rb
+++ b/spec/javascripts/fixtures/branches.rb
@@ -22,9 +22,10 @@ describe Projects::BranchesController, '(JavaScript fixtures)', type: :controlle
end
it 'branches/new_branch.html.raw' do |example|
- get :new,
+ get :new, params: {
namespace_id: project.namespace.to_param,
project_id: project
+ }
expect(response).to be_success
store_frontend_fixture(response, example.description)
diff --git a/spec/javascripts/fixtures/clusters.rb b/spec/javascripts/fixtures/clusters.rb
index 8e74c4f859c..69dbe54ffc2 100644
--- a/spec/javascripts/fixtures/clusters.rb
+++ b/spec/javascripts/fixtures/clusters.rb
@@ -23,10 +23,11 @@ describe Projects::ClustersController, '(JavaScript fixtures)', type: :controlle
end
it 'clusters/show_cluster.html.raw' do |example|
- get :show,
+ get :show, params: {
namespace_id: project.namespace.to_param,
project_id: project,
id: cluster
+ }
expect(response).to be_success
store_frontend_fixture(response, example.description)
diff --git a/spec/javascripts/fixtures/commit.rb b/spec/javascripts/fixtures/commit.rb
index 24ab8159a18..f0e4bb50c67 100644
--- a/spec/javascripts/fixtures/commit.rb
+++ b/spec/javascripts/fixtures/commit.rb
@@ -25,7 +25,7 @@ describe Projects::CommitController, '(JavaScript fixtures)', type: :controller
id: commit.id
}
- get :show, params
+ get :show, params: params
expect(response).to be_success
store_frontend_fixture(response, example.description)
diff --git a/spec/javascripts/fixtures/deploy_keys.rb b/spec/javascripts/fixtures/deploy_keys.rb
index 24699c3043a..efbda955972 100644
--- a/spec/javascripts/fixtures/deploy_keys.rb
+++ b/spec/javascripts/fixtures/deploy_keys.rb
@@ -33,10 +33,10 @@ describe Projects::DeployKeysController, '(JavaScript fixtures)', type: :control
create(:deploy_keys_project, project: project3, deploy_key: project_key)
create(:deploy_keys_project, project: project4, deploy_key: project_key)
- get :index,
+ get :index, params: {
namespace_id: project.namespace.to_param,
- project_id: project,
- format: :json
+ project_id: project
+ }, format: :json
expect(response).to be_success
store_frontend_fixture(response, example.description)
diff --git a/spec/javascripts/fixtures/groups.rb b/spec/javascripts/fixtures/groups.rb
index b42f442557c..f8d55fc97c3 100644
--- a/spec/javascripts/fixtures/groups.rb
+++ b/spec/javascripts/fixtures/groups.rb
@@ -19,8 +19,7 @@ describe 'Groups (JavaScript fixtures)', type: :controller do
describe GroupsController, '(JavaScript fixtures)', type: :controller do
it 'groups/edit.html.raw' do |example|
- get :edit,
- id: group
+ get :edit, params: { id: group }
expect(response).to be_success
store_frontend_fixture(response, example.description)
@@ -29,8 +28,7 @@ describe 'Groups (JavaScript fixtures)', type: :controller do
describe Groups::Settings::CiCdController, '(JavaScript fixtures)', type: :controller do
it 'groups/ci_cd_settings.html.raw' do |example|
- get :show,
- group_id: group
+ get :show, params: { group_id: group }
expect(response).to be_success
store_frontend_fixture(response, example.description)
diff --git a/spec/javascripts/fixtures/issues.rb b/spec/javascripts/fixtures/issues.rb
index 0ee2f82dfd6..18fb1bebf8b 100644
--- a/spec/javascripts/fixtures/issues.rb
+++ b/spec/javascripts/fixtures/issues.rb
@@ -43,9 +43,10 @@ describe Projects::IssuesController, '(JavaScript fixtures)', type: :controller
it 'issues/issue_list.html.raw' do |example|
create(:issue, project: project)
- get :index,
+ get :index, params: {
namespace_id: project.namespace.to_param,
project_id: project
+ }
expect(response).to be_success
store_frontend_fixture(response, example.description)
@@ -54,10 +55,11 @@ describe Projects::IssuesController, '(JavaScript fixtures)', type: :controller
private
def render_issue(fixture_file_name, issue)
- get :show,
+ get :show, params: {
namespace_id: project.namespace.to_param,
project_id: project,
id: issue.to_param
+ }
expect(response).to be_success
store_frontend_fixture(response, fixture_file_name)
diff --git a/spec/javascripts/fixtures/jobs.rb b/spec/javascripts/fixtures/jobs.rb
index 82d7a5e394e..d6b5349594d 100644
--- a/spec/javascripts/fixtures/jobs.rb
+++ b/spec/javascripts/fixtures/jobs.rb
@@ -34,21 +34,22 @@ describe Projects::JobsController, '(JavaScript fixtures)', type: :controller do
end
it 'builds/build-with-artifacts.html.raw' do |example|
- get :show,
+ get :show, params: {
namespace_id: project.namespace.to_param,
project_id: project,
id: build_with_artifacts.to_param
+ }
expect(response).to be_success
store_frontend_fixture(response, example.description)
end
it 'jobs/delayed.json' do |example|
- get :show,
- namespace_id: project.namespace.to_param,
- project_id: project,
- id: delayed_job.to_param,
- format: :json
+ get :show, params: {
+ namespace_id: project.namespace.to_param,
+ project_id: project,
+ id: delayed_job.to_param
+ }, format: :json
expect(response).to be_success
store_frontend_fixture(response, example.description)
diff --git a/spec/javascripts/fixtures/labels.rb b/spec/javascripts/fixtures/labels.rb
index b730d557e21..9420194e675 100644
--- a/spec/javascripts/fixtures/labels.rb
+++ b/spec/javascripts/fixtures/labels.rb
@@ -31,9 +31,9 @@ describe 'Labels (JavaScript fixtures)' do
end
it 'labels/group_labels.json' do |example|
- get :index,
- group_id: group,
- format: 'json'
+ get :index, params: {
+ group_id: group
+ }, format: 'json'
expect(response).to be_success
store_frontend_fixture(response, example.description)
@@ -48,10 +48,10 @@ describe 'Labels (JavaScript fixtures)' do
end
it 'labels/project_labels.json' do |example|
- get :index,
+ get :index, params: {
namespace_id: group,
- project_id: project,
- format: 'json'
+ project_id: project
+ }, format: 'json'
expect(response).to be_success
store_frontend_fixture(response, example.description)
diff --git a/spec/javascripts/fixtures/merge_requests.rb b/spec/javascripts/fixtures/merge_requests.rb
index 7257d0c8556..26e81f06c0b 100644
--- a/spec/javascripts/fixtures/merge_requests.rb
+++ b/spec/javascripts/fixtures/merge_requests.rb
@@ -112,21 +112,21 @@ describe Projects::MergeRequestsController, '(JavaScript fixtures)', type: :cont
private
def render_discussions_json(merge_request, fixture_file_name)
- get :discussions,
+ get :discussions, params: {
namespace_id: project.namespace.to_param,
project_id: project,
- id: merge_request.to_param,
- format: :json
+ id: merge_request.to_param
+ }, format: :json
store_frontend_fixture(response, fixture_file_name)
end
def render_merge_request(fixture_file_name, merge_request)
- get :show,
+ get :show, params: {
namespace_id: project.namespace.to_param,
project_id: project,
- id: merge_request.to_param,
- format: :html
+ id: merge_request.to_param
+ }, format: :html
expect(response).to be_success
store_frontend_fixture(response, fixture_file_name)
diff --git a/spec/javascripts/fixtures/merge_requests_diffs.rb b/spec/javascripts/fixtures/merge_requests_diffs.rb
index afe34b834b0..57462e74bb2 100644
--- a/spec/javascripts/fixtures/merge_requests_diffs.rb
+++ b/spec/javascripts/fixtures/merge_requests_diffs.rb
@@ -57,13 +57,13 @@ describe Projects::MergeRequests::DiffsController, '(JavaScript fixtures)', type
private
def render_merge_request(fixture_file_name, merge_request, view: 'inline', **extra_params)
- get :show,
+ get :show, params: {
namespace_id: project.namespace.to_param,
project_id: project,
id: merge_request.to_param,
- format: :json,
view: view,
**extra_params
+ }, format: :json
expect(response).to be_success
store_frontend_fixture(response, fixture_file_name)
diff --git a/spec/javascripts/fixtures/pipeline_schedules.rb b/spec/javascripts/fixtures/pipeline_schedules.rb
index 56f27ea7df1..05d79ec8de9 100644
--- a/spec/javascripts/fixtures/pipeline_schedules.rb
+++ b/spec/javascripts/fixtures/pipeline_schedules.rb
@@ -22,20 +22,22 @@ describe Projects::PipelineSchedulesController, '(JavaScript fixtures)', type: :
end
it 'pipeline_schedules/edit.html.raw' do |example|
- get :edit,
+ get :edit, params: {
namespace_id: project.namespace.to_param,
project_id: project,
id: pipeline_schedule.id
+ }
expect(response).to be_success
store_frontend_fixture(response, example.description)
end
it 'pipeline_schedules/edit_with_variables.html.raw' do |example|
- get :edit,
+ get :edit, params: {
namespace_id: project.namespace.to_param,
project_id: project,
id: pipeline_schedule_populated.id
+ }
expect(response).to be_success
store_frontend_fixture(response, example.description)
diff --git a/spec/javascripts/fixtures/pipelines.rb b/spec/javascripts/fixtures/pipelines.rb
index bb85da50f0f..42b552e81c0 100644
--- a/spec/javascripts/fixtures/pipelines.rb
+++ b/spec/javascripts/fixtures/pipelines.rb
@@ -24,10 +24,10 @@ describe Projects::PipelinesController, '(JavaScript fixtures)', type: :controll
end
it 'pipelines/pipelines.json' do |example|
- get :index,
+ get :index, params: {
namespace_id: namespace,
- project_id: project,
- format: :json
+ project_id: project
+ }, format: :json
expect(response).to be_success
store_frontend_fixture(response, example.description)
diff --git a/spec/javascripts/fixtures/projects.rb b/spec/javascripts/fixtures/projects.rb
index d98f7f55b20..9b48646f8f0 100644
--- a/spec/javascripts/fixtures/projects.rb
+++ b/spec/javascripts/fixtures/projects.rb
@@ -28,27 +28,30 @@ describe 'Projects (JavaScript fixtures)', type: :controller do
describe ProjectsController, '(JavaScript fixtures)', type: :controller do
it 'projects/dashboard.html.raw' do |example|
- get :show,
+ get :show, params: {
namespace_id: project.namespace.to_param,
id: project
+ }
expect(response).to be_success
store_frontend_fixture(response, example.description)
end
it 'projects/overview.html.raw' do |example|
- get :show,
+ get :show, params: {
namespace_id: project_with_repo.namespace.to_param,
id: project_with_repo
+ }
expect(response).to be_success
store_frontend_fixture(response, example.description)
end
it 'projects/edit.html.raw' do |example|
- get :edit,
+ get :edit, params: {
namespace_id: project.namespace.to_param,
id: project
+ }
expect(response).to be_success
store_frontend_fixture(response, example.description)
@@ -57,18 +60,20 @@ describe 'Projects (JavaScript fixtures)', type: :controller do
describe Projects::Settings::CiCdController, '(JavaScript fixtures)', type: :controller do
it 'projects/ci_cd_settings.html.raw' do |example|
- get :show,
+ get :show, params: {
namespace_id: project.namespace.to_param,
project_id: project
+ }
expect(response).to be_success
store_frontend_fixture(response, example.description)
end
it 'projects/ci_cd_settings_with_variables.html.raw' do |example|
- get :show,
+ get :show, params: {
namespace_id: project_variable_populated.namespace.to_param,
project_id: project_variable_populated
+ }
expect(response).to be_success
store_frontend_fixture(response, example.description)
diff --git a/spec/javascripts/fixtures/prometheus_service.rb b/spec/javascripts/fixtures/prometheus_service.rb
index f95f8038ffb..746fbfd66dd 100644
--- a/spec/javascripts/fixtures/prometheus_service.rb
+++ b/spec/javascripts/fixtures/prometheus_service.rb
@@ -23,10 +23,11 @@ describe Projects::ServicesController, '(JavaScript fixtures)', type: :controlle
end
it 'services/prometheus/prometheus_service.html.raw' do |example|
- get :edit,
+ get :edit, params: {
namespace_id: namespace,
project_id: project,
id: service.to_param
+ }
expect(response).to be_success
store_frontend_fixture(response, example.description)
diff --git a/spec/javascripts/fixtures/services.rb b/spec/javascripts/fixtures/services.rb
index 9280ed5a7f1..6ccd74a07ff 100644
--- a/spec/javascripts/fixtures/services.rb
+++ b/spec/javascripts/fixtures/services.rb
@@ -23,10 +23,11 @@ describe Projects::ServicesController, '(JavaScript fixtures)', type: :controlle
end
it 'services/edit_service.html.raw' do |example|
- get :edit,
+ get :edit, params: {
namespace_id: namespace,
project_id: project,
id: service.to_param
+ }
expect(response).to be_success
store_frontend_fixture(response, example.description)
diff --git a/spec/javascripts/fixtures/snippet.rb b/spec/javascripts/fixtures/snippet.rb
index 38fc963caf7..a14837e4d4a 100644
--- a/spec/javascripts/fixtures/snippet.rb
+++ b/spec/javascripts/fixtures/snippet.rb
@@ -24,7 +24,7 @@ describe SnippetsController, '(JavaScript fixtures)', type: :controller do
end
it 'snippets/show.html.raw' do |example|
- get(:show, id: snippet.to_param)
+ get(:show, params: { id: snippet.to_param })
expect(response).to be_success
store_frontend_fixture(response, example.description)
diff --git a/spec/javascripts/fixtures/todos.rb b/spec/javascripts/fixtures/todos.rb
index 426b854fe8b..b5f6620873b 100644
--- a/spec/javascripts/fixtures/todos.rb
+++ b/spec/javascripts/fixtures/todos.rb
@@ -42,12 +42,12 @@ describe 'Todos (JavaScript fixtures)' do
end
it 'todos/todos.json' do |example|
- post :create,
+ post :create, params: {
namespace_id: namespace,
project_id: project,
issuable_type: 'issue',
- issuable_id: issue_2.id,
- format: 'json'
+ issuable_id: issue_2.id
+ }, format: 'json'
expect(response).to be_success
store_frontend_fixture(response, example.description)
diff --git a/spec/javascripts/fixtures/u2f.rb b/spec/javascripts/fixtures/u2f.rb
index e3d7986f2cf..f0aa874bf75 100644
--- a/spec/javascripts/fixtures/u2f.rb
+++ b/spec/javascripts/fixtures/u2f.rb
@@ -21,7 +21,7 @@ context 'U2F' do
it 'u2f/authenticate.html.raw' do |example|
allow(controller).to receive(:find_user).and_return(user)
- post :create, user: { login: user.username, password: user.password }
+ post :create, params: { user: { login: user.username, password: user.password } }
expect(response).to be_success
store_frontend_fixture(response, example.description)
diff --git a/spec/javascripts/notes/components/discussion_filter_spec.js b/spec/javascripts/notes/components/discussion_filter_spec.js
index 9070d968cfd..5efcab436e4 100644
--- a/spec/javascripts/notes/components/discussion_filter_spec.js
+++ b/spec/javascripts/notes/components/discussion_filter_spec.js
@@ -7,8 +7,9 @@ import { discussionFiltersMock, discussionMock } from '../mock_data';
describe('DiscussionFilter component', () => {
let vm;
let store;
+ let eventHub;
- beforeEach(() => {
+ const mountComponent = () => {
store = createStore();
const discussions = [
@@ -22,7 +23,7 @@ describe('DiscussionFilter component', () => {
const selectedValue = discussionFiltersMock[0].value;
store.state.discussions = discussions;
- vm = mountComponentWithStore(Component, {
+ return mountComponentWithStore(Component, {
el: null,
store,
props: {
@@ -30,6 +31,11 @@ describe('DiscussionFilter component', () => {
selectedValue,
},
});
+ };
+
+ beforeEach(() => {
+ window.mrTabs = undefined;
+ vm = mountComponent();
});
afterEach(() => {
@@ -83,4 +89,30 @@ describe('DiscussionFilter component', () => {
expect(defaultFilter.lastChild.classList).toContain('dropdown-divider');
});
+
+ describe('Merge request tabs', () => {
+ eventHub = new Vue();
+
+ beforeEach(() => {
+ window.mrTabs = {
+ eventHub,
+ currentTab: 'show',
+ };
+
+ vm = mountComponent();
+ });
+
+ afterEach(() => {
+ window.mrTabs = undefined;
+ });
+
+ it('only renders when discussion tab is active', done => {
+ eventHub.$emit('MergeRequestTabChange', 'commit');
+
+ vm.$nextTick(() => {
+ expect(vm.$el.querySelector).toBeUndefined();
+ done();
+ });
+ });
+ });
});
diff --git a/spec/javascripts/notes/components/noteable_discussion_spec.js b/spec/javascripts/notes/components/noteable_discussion_spec.js
index 106a4ac2546..3aff2dd0641 100644
--- a/spec/javascripts/notes/components/noteable_discussion_spec.js
+++ b/spec/javascripts/notes/components/noteable_discussion_spec.js
@@ -133,8 +133,10 @@ describe('noteable_discussion component', () => {
});
});
- describe('commit discussion', () => {
+ describe('action text', () => {
const commitId = 'razupaltuff';
+ const truncatedCommitId = commitId.substr(0, 8);
+ let commitElement;
beforeEach(() => {
vm.$destroy();
@@ -143,7 +145,6 @@ describe('noteable_discussion component', () => {
projectPath: 'something',
};
- vm.$destroy();
vm = new Component({
propsData: {
discussion: {
@@ -159,17 +160,73 @@ describe('noteable_discussion component', () => {
},
store,
}).$mount();
+
+ commitElement = vm.$el.querySelector('.commit-sha');
+ });
+
+ describe('for commit discussions', () => {
+ it('should display a monospace started a discussion on commit', () => {
+ expect(vm.$el).toContainText(`started a discussion on commit ${truncatedCommitId}`);
+ expect(commitElement).not.toBe(null);
+ expect(commitElement).toHaveText(truncatedCommitId);
+ });
});
- it('displays a monospace started a discussion on commit', () => {
- const truncatedCommitId = commitId.substr(0, 8);
+ describe('for diff discussion with a commit id', () => {
+ it('should display started discussion on commit header', done => {
+ vm.discussion.for_commit = false;
- expect(vm.$el).toContainText(`started a discussion on commit ${truncatedCommitId}`);
+ vm.$nextTick(() => {
+ expect(vm.$el).toContainText(`started a discussion on commit ${truncatedCommitId}`);
+ expect(commitElement).not.toBe(null);
- const commitElement = vm.$el.querySelector('.commit-sha');
+ done();
+ });
+ });
- expect(commitElement).not.toBe(null);
- expect(commitElement).toHaveText(truncatedCommitId);
+ it('should display outdated change on commit header', done => {
+ vm.discussion.for_commit = false;
+ vm.discussion.active = false;
+
+ vm.$nextTick(() => {
+ expect(vm.$el).toContainText(
+ `started a discussion on an outdated change in commit ${truncatedCommitId}`,
+ );
+
+ expect(commitElement).not.toBe(null);
+
+ done();
+ });
+ });
+ });
+
+ describe('for diff discussions without a commit id', () => {
+ it('should show started a discussion on the diff text', done => {
+ Object.assign(vm.discussion, {
+ for_commit: false,
+ commit_id: null,
+ });
+
+ vm.$nextTick(() => {
+ expect(vm.$el).toContainText('started a discussion on the diff');
+
+ done();
+ });
+ });
+
+ it('should show discussion on older version text', done => {
+ Object.assign(vm.discussion, {
+ for_commit: false,
+ commit_id: null,
+ active: false,
+ });
+
+ vm.$nextTick(() => {
+ expect(vm.$el).toContainText('started a discussion on an old version of the diff');
+
+ done();
+ });
+ });
});
});
});
diff --git a/spec/javascripts/releases/components/release_block_spec.js b/spec/javascripts/releases/components/release_block_spec.js
index 19aecbb3636..29420216bc4 100644
--- a/spec/javascripts/releases/components/release_block_spec.js
+++ b/spec/javascripts/releases/components/release_block_spec.js
@@ -15,6 +15,16 @@ describe('Release block', () => {
author_name: 'Release bot',
author_email: 'release-bot@example.com',
created_at: '2012-05-28T05:00:00-07:00',
+ author: {
+ avatar_url: 'uploads/-/system/user/avatar/johndoe/avatar.png',
+ id: 482476,
+ name: 'John Doe',
+ path: '/johndoe',
+ state: 'active',
+ status_tooltip_html: null,
+ username: 'johndoe',
+ web_url: 'https://gitlab.com/johndoe',
+ },
commit: {
id: '2695effb5807a22ff3d138d593fd856244e155e7',
short_id: '2695effb',
@@ -28,16 +38,6 @@ describe('Release block', () => {
committer_name: 'Jack Smith',
committer_email: 'jack@example.com',
committed_date: '2012-05-28T04:42:42-07:00',
- author: {
- avatar_url: 'uploads/-/system/user/avatar/johndoe/avatar.png',
- id: 482476,
- name: 'John Doe',
- path: '/johndoe',
- state: 'active',
- status_tooltip_html: null,
- username: 'johndoe',
- web_url: 'https://gitlab.com/johndoe',
- },
},
assets: {
count: 6,
diff --git a/spec/javascripts/sidebar/mock_data.js b/spec/javascripts/sidebar/mock_data.js
index fcd7bea3f6d..7f20b0da991 100644
--- a/spec/javascripts/sidebar/mock_data.js
+++ b/spec/javascripts/sidebar/mock_data.js
@@ -66,7 +66,7 @@ const RESPONSE_MAP = {
},
labels: [],
},
- '/gitlab-org/gitlab-shell/issues/5.json?serializer=sidebar': {
+ '/gitlab-org/gitlab-shell/issues/5.json?serializer=sidebar_extras': {
assignees: [
{
name: 'User 0',
@@ -181,7 +181,7 @@ const RESPONSE_MAP = {
const mockData = {
responseMap: RESPONSE_MAP,
mediator: {
- endpoint: '/gitlab-org/gitlab-shell/issues/5.json?serializer=sidebar',
+ endpoint: '/gitlab-org/gitlab-shell/issues/5.json?serializer=sidebar_extras',
toggleSubscriptionEndpoint: '/gitlab-org/gitlab-shell/issues/5/toggle_subscription',
moveIssueEndpoint: '/gitlab-org/gitlab-shell/issues/5/move',
projectsAutocompleteEndpoint: '/autocomplete/projects?project_id=15',
diff --git a/spec/javascripts/sidebar/sidebar_mediator_spec.js b/spec/javascripts/sidebar/sidebar_mediator_spec.js
index 2d853970fc4..6c69c08e733 100644
--- a/spec/javascripts/sidebar/sidebar_mediator_spec.js
+++ b/spec/javascripts/sidebar/sidebar_mediator_spec.js
@@ -37,7 +37,7 @@ describe('Sidebar mediator', function() {
it('fetches the data', done => {
const mockData =
- Mock.responseMap.GET['/gitlab-org/gitlab-shell/issues/5.json?serializer=sidebar'];
+ Mock.responseMap.GET['/gitlab-org/gitlab-shell/issues/5.json?serializer=sidebar_extras'];
spyOn(this.mediator, 'processFetchedData').and.callThrough();
this.mediator
@@ -51,7 +51,7 @@ describe('Sidebar mediator', function() {
it('processes fetched data', () => {
const mockData =
- Mock.responseMap.GET['/gitlab-org/gitlab-shell/issues/5.json?serializer=sidebar'];
+ Mock.responseMap.GET['/gitlab-org/gitlab-shell/issues/5.json?serializer=sidebar_extras'];
this.mediator.processFetchedData(mockData);
expect(this.mediator.store.assignees).toEqual(mockData.assignees);
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 f72bf627c10..99b80df766a 100644
--- a/spec/javascripts/vue_mr_widget/mr_widget_options_spec.js
+++ b/spec/javascripts/vue_mr_widget/mr_widget_options_spec.js
@@ -18,6 +18,8 @@ describe('mrWidgetOptions', () => {
let vm;
let MrWidgetOptions;
+ const COLLABORATION_MESSAGE = 'Allows commits from members who can merge to the target branch';
+
beforeEach(() => {
// Prevent component mounting
delete mrWidgetOptions.el;
@@ -132,6 +134,53 @@ describe('mrWidgetOptions', () => {
expect(vm.shouldRenderSourceBranchRemovalStatus).toEqual(false);
});
});
+
+ describe('shouldRenderCollaborationStatus', () => {
+ describe('when collaboration is allowed', () => {
+ beforeEach(() => {
+ vm.mr.allowCollaboration = true;
+ });
+
+ describe('when merge request is opened', () => {
+ beforeEach(done => {
+ vm.mr.isOpen = true;
+ vm.$nextTick(done);
+ });
+
+ it('should render collaboration status', () => {
+ expect(vm.$el.textContent).toContain(COLLABORATION_MESSAGE);
+ });
+ });
+
+ describe('when merge request is not opened', () => {
+ beforeEach(done => {
+ vm.mr.isOpen = false;
+ vm.$nextTick(done);
+ });
+
+ it('should not render collaboration status', () => {
+ expect(vm.$el.textContent).not.toContain(COLLABORATION_MESSAGE);
+ });
+ });
+ });
+
+ describe('when collaboration is not allowed', () => {
+ beforeEach(() => {
+ vm.mr.allowCollaboration = false;
+ });
+
+ describe('when merge request is opened', () => {
+ beforeEach(done => {
+ vm.mr.isOpen = true;
+ vm.$nextTick(done);
+ });
+
+ it('should not render collaboration status', () => {
+ expect(vm.$el.textContent).not.toContain(COLLABORATION_MESSAGE);
+ });
+ });
+ });
+ });
});
describe('methods', () => {
diff --git a/spec/javascripts/vue_shared/components/user_popover/user_popover_spec.js b/spec/javascripts/vue_shared/components/user_popover/user_popover_spec.js
index e16ab156679..25b6e3b6bc8 100644
--- a/spec/javascripts/vue_shared/components/user_popover/user_popover_spec.js
+++ b/spec/javascripts/vue_shared/components/user_popover/user_popover_spec.js
@@ -89,7 +89,7 @@ describe('User Popover Component', () => {
expect(vm.$el.textContent).toContain('GitLab');
});
- it('should have full job line when we have bio and organization', () => {
+ it('should display bio and organization in separate lines', () => {
const testProps = Object.assign({}, DEFAULT_PROPS);
testProps.user.bio = 'Engineer';
testProps.user.organization = 'GitLab';
@@ -99,20 +99,24 @@ describe('User Popover Component', () => {
target: document.querySelector('.js-user-link'),
});
- expect(vm.$el.textContent).toContain('Engineer at GitLab');
+ expect(vm.$el.querySelector('.js-bio').textContent).toContain('Engineer');
+ expect(vm.$el.querySelector('.js-organization').textContent).toContain('GitLab');
});
- it('should not encode special characters when we have bio and organization', () => {
+ it('should not encode special characters in bio and organization', () => {
const testProps = Object.assign({}, DEFAULT_PROPS);
testProps.user.bio = 'Manager & Team Lead';
- testProps.user.organization = 'GitLab';
+ testProps.user.organization = 'Me & my <funky> Company';
vm = mountComponent(UserPopover, {
...DEFAULT_PROPS,
target: document.querySelector('.js-user-link'),
});
- expect(vm.$el.textContent).toContain('Manager & Team Lead at GitLab');
+ expect(vm.$el.querySelector('.js-bio').textContent).toContain('Manager & Team Lead');
+ expect(vm.$el.querySelector('.js-organization').textContent).toContain(
+ 'Me & my <funky> Company',
+ );
});
});
diff --git a/spec/lib/api/helpers_spec.rb b/spec/lib/api/helpers_spec.rb
index 58a49124ce6..1c73a936e17 100644
--- a/spec/lib/api/helpers_spec.rb
+++ b/spec/lib/api/helpers_spec.rb
@@ -148,4 +148,36 @@ describe API::Helpers do
it_behaves_like 'user namespace finder'
end
+
+ describe '#send_git_blob' do
+ context 'content disposition' do
+ let(:repository) { double }
+ let(:blob) { double(name: 'foobar') }
+
+ let(:send_git_blob) do
+ subject.send(:send_git_blob, repository, blob)
+ end
+
+ before do
+ allow(subject).to receive(:env).and_return({})
+ allow(subject).to receive(:content_type)
+ allow(subject).to receive(:header).and_return({})
+ allow(Gitlab::Workhorse).to receive(:send_git_blob)
+ end
+
+ context 'when blob name is null' do
+ let(:blob) { double(name: nil) }
+
+ it 'returns only the disposition' do
+ expect(send_git_blob['Content-Disposition']).to eq 'attachment'
+ end
+ end
+
+ context 'when blob name is not null' do
+ it 'returns disposition with the blob name' do
+ expect(send_git_blob['Content-Disposition']).to eq 'attachment; filename="foobar"'
+ end
+ end
+ end
+ end
end
diff --git a/spec/lib/banzai/filter/external_link_filter_spec.rb b/spec/lib/banzai/filter/external_link_filter_spec.rb
index 2a3c0cd78b8..e6dae8d5382 100644
--- a/spec/lib/banzai/filter/external_link_filter_spec.rb
+++ b/spec/lib/banzai/filter/external_link_filter_spec.rb
@@ -49,16 +49,16 @@ describe Banzai::Filter::ExternalLinkFilter do
end
context 'for invalid urls' do
- it 'skips broken hrefs' do
+ it 'adds rel and target attributes to broken hrefs' do
doc = filter %q(<p><a href="don't crash on broken urls">Google</a></p>)
- expected = %q(<p><a href="don't%20crash%20on%20broken%20urls">Google</a></p>)
+ expected = %q(<p><a href="don't%20crash%20on%20broken%20urls" rel="nofollow noreferrer noopener" target="_blank">Google</a></p>)
expect(doc.to_html).to eq(expected)
end
- it 'skips improperly formatted mailtos' do
+ it 'adds rel and target to improperly formatted mailtos' do
doc = filter %q(<p><a href="mailto://jblogs@example.com">Email</a></p>)
- expected = %q(<p><a href="mailto://jblogs@example.com">Email</a></p>)
+ expected = %q(<p><a href="mailto://jblogs@example.com" rel="nofollow noreferrer noopener" target="_blank">Email</a></p>)
expect(doc.to_html).to eq(expected)
end
diff --git a/spec/lib/banzai/filter/label_reference_filter_spec.rb b/spec/lib/banzai/filter/label_reference_filter_spec.rb
index 00257ed7904..9cfdb9e53a2 100644
--- a/spec/lib/banzai/filter/label_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/label_reference_filter_spec.rb
@@ -236,6 +236,24 @@ describe Banzai::Filter::LabelReferenceFilter do
end
end
+ context 'References with html entities' do
+ let!(:label) { create(:label, name: '&lt;html&gt;', project: project) }
+
+ it 'links to a valid reference' do
+ doc = reference_filter('See ~"&lt;html&gt;"')
+
+ expect(doc.css('a').first.attr('href')).to eq urls
+ .project_issues_url(project, label_name: label.name)
+ expect(doc.text).to eq 'See <html>'
+ end
+
+ it 'ignores invalid label names and escapes entities' do
+ act = %(Label #{Label.reference_prefix}"&lt;non valid&gt;")
+
+ expect(reference_filter(act).to_html).to eq act
+ end
+ end
+
describe 'consecutive references' do
let(:bug) { create(:label, name: 'bug', project: project) }
let(:feature_proposal) { create(:label, name: 'feature proposal', project: project) }
diff --git a/spec/lib/banzai/filter/milestone_reference_filter_spec.rb b/spec/lib/banzai/filter/milestone_reference_filter_spec.rb
index 1a87cfa5b45..4c94e4fdae0 100644
--- a/spec/lib/banzai/filter/milestone_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/milestone_reference_filter_spec.rb
@@ -59,7 +59,7 @@ describe Banzai::Filter::MilestoneReferenceFilter do
it 'links with adjacent text' do
doc = reference_filter("Milestone (#{reference}.)")
- expect(doc.to_html).to match(%r(\(<a.+>#{milestone.name}</a>\.\)))
+ expect(doc.to_html).to match(%r(\(<a.+>#{milestone.reference_link_text}</a>\.\)))
end
it 'ignores invalid milestone IIDs' do
@@ -80,12 +80,12 @@ describe Banzai::Filter::MilestoneReferenceFilter do
doc = reference_filter("See #{reference}")
expect(doc.css('a').first.attr('href')).to eq urls.milestone_url(milestone)
- expect(doc.text).to eq 'See gfm'
+ expect(doc.text).to eq "See #{milestone.reference_link_text}"
end
it 'links with adjacent text' do
doc = reference_filter("Milestone (#{reference}.)")
- expect(doc.to_html).to match(%r(\(<a.+>#{milestone.name}</a>\.\)))
+ expect(doc.to_html).to match(%r(\(<a.+>#{milestone.reference_link_text}</a>\.\)))
end
it 'ignores invalid milestone names' do
@@ -106,12 +106,12 @@ describe Banzai::Filter::MilestoneReferenceFilter do
doc = reference_filter("See #{reference}")
expect(doc.css('a').first.attr('href')).to eq urls.milestone_url(milestone)
- expect(doc.text).to eq 'See gfm references'
+ expect(doc.text).to eq "See #{milestone.reference_link_text}"
end
it 'links with adjacent text' do
doc = reference_filter("Milestone (#{reference}.)")
- expect(doc.to_html).to match(%r(\(<a.+>#{milestone.name}</a>\.\)))
+ expect(doc.to_html).to match(%r(\(<a.+>#{milestone.reference_link_text}</a>\.\)))
end
it 'ignores invalid milestone names' do
@@ -201,14 +201,14 @@ describe Banzai::Filter::MilestoneReferenceFilter do
doc = reference_filter("See (#{reference}.)")
expect(doc.css('a').first.text)
- .to eq("#{milestone.name} in #{another_project.full_path}")
+ .to eq("#{milestone.reference_link_text} in #{another_project.full_path}")
end
it 'has valid text' do
doc = reference_filter("See (#{reference}.)")
expect(doc.text)
- .to eq("See (#{milestone.name} in #{another_project.full_path}.)")
+ .to eq("See (#{milestone.reference_link_text} in #{another_project.full_path}.)")
end
it 'escapes the name attribute' do
@@ -217,7 +217,7 @@ describe Banzai::Filter::MilestoneReferenceFilter do
doc = reference_filter("See #{reference}")
expect(doc.css('a').first.text)
- .to eq "#{milestone.name} in #{another_project.full_path}"
+ .to eq "#{milestone.reference_link_text} in #{another_project.full_path}"
end
end
@@ -238,14 +238,14 @@ describe Banzai::Filter::MilestoneReferenceFilter do
doc = reference_filter("See (#{reference}.)")
expect(doc.css('a').first.text)
- .to eq("#{milestone.name} in #{another_project.path}")
+ .to eq("#{milestone.reference_link_text} in #{another_project.path}")
end
it 'has valid text' do
doc = reference_filter("See (#{reference}.)")
expect(doc.text)
- .to eq("See (#{milestone.name} in #{another_project.path}.)")
+ .to eq("See (#{milestone.reference_link_text} in #{another_project.path}.)")
end
it 'escapes the name attribute' do
@@ -254,7 +254,7 @@ describe Banzai::Filter::MilestoneReferenceFilter do
doc = reference_filter("See #{reference}")
expect(doc.css('a').first.text)
- .to eq "#{milestone.name} in #{another_project.path}"
+ .to eq "#{milestone.reference_link_text} in #{another_project.path}"
end
end
@@ -275,14 +275,14 @@ describe Banzai::Filter::MilestoneReferenceFilter do
doc = reference_filter("See (#{reference}.)")
expect(doc.css('a').first.text)
- .to eq("#{milestone.name} in #{another_project.path}")
+ .to eq("#{milestone.reference_link_text} in #{another_project.path}")
end
it 'has valid text' do
doc = reference_filter("See (#{reference}.)")
expect(doc.text)
- .to eq("See (#{milestone.name} in #{another_project.path}.)")
+ .to eq("See (#{milestone.reference_link_text} in #{another_project.path}.)")
end
it 'escapes the name attribute' do
@@ -291,7 +291,7 @@ describe Banzai::Filter::MilestoneReferenceFilter do
doc = reference_filter("See #{reference}")
expect(doc.css('a').first.text)
- .to eq "#{milestone.name} in #{another_project.path}"
+ .to eq "#{milestone.reference_link_text} in #{another_project.path}"
end
end
@@ -346,7 +346,7 @@ describe Banzai::Filter::MilestoneReferenceFilter do
milestone.update!(group: parent_group)
doc = reference_filter("See #{reference}")
- expect(doc.css('a').first.text).to eq(milestone.name)
+ expect(doc.css('a').first.text).to eq(milestone.reference_link_text)
end
end
diff --git a/spec/lib/gitlab/bare_repository_import/importer_spec.rb b/spec/lib/gitlab/bare_repository_import/importer_spec.rb
index 3c63e601abc..f4759b69538 100644
--- a/spec/lib/gitlab/bare_repository_import/importer_spec.rb
+++ b/spec/lib/gitlab/bare_repository_import/importer_spec.rb
@@ -192,7 +192,7 @@ describe Gitlab::BareRepositoryImport::Importer, :seed_helper do
let(:project_path) { 'a-group/a-sub-group/a-project' }
before do
- expect(Group).to receive(:supports_nested_groups?) { false }
+ expect(Group).to receive(:supports_nested_objects?) { false }
end
describe '#create_project_if_needed' do
diff --git a/spec/lib/gitlab/blob_helper_spec.rb b/spec/lib/gitlab/blob_helper_spec.rb
index 0b56f8687c3..e057385b35f 100644
--- a/spec/lib/gitlab/blob_helper_spec.rb
+++ b/spec/lib/gitlab/blob_helper_spec.rb
@@ -53,11 +53,11 @@ describe Gitlab::BlobHelper do
describe '#text?' do
it 'returns true' do
- expect(blob.text?).to be_truthy
+ expect(blob.text_in_repo?).to be_truthy
end
it 'returns false' do
- expect(large_blob.text?).to be_falsey
+ expect(large_blob.text_in_repo?).to be_falsey
end
end
diff --git a/spec/lib/gitlab/checks/diff_check_spec.rb b/spec/lib/gitlab/checks/diff_check_spec.rb
index eeec1e83179..a341dfa5636 100644
--- a/spec/lib/gitlab/checks/diff_check_spec.rb
+++ b/spec/lib/gitlab/checks/diff_check_spec.rb
@@ -47,5 +47,43 @@ describe Gitlab::Checks::DiffCheck do
end
end
end
+
+ context 'commit diff validations' do
+ before do
+ allow(subject).to receive(:validations_for_diff).and_return([lambda { |diff| return }])
+
+ expect_any_instance_of(Commit).to receive(:raw_deltas).and_call_original
+
+ subject.validate!
+ end
+
+ context 'when request store is inactive' do
+ it 'are run for every commit' do
+ expect_any_instance_of(Commit).to receive(:raw_deltas).and_call_original
+
+ subject.validate!
+ end
+ end
+
+ context 'when request store is active', :request_store do
+ it 'are cached for every commit' do
+ expect_any_instance_of(Commit).not_to receive(:raw_deltas)
+
+ subject.validate!
+ end
+
+ it 'are run for not cached commits' do
+ allow(project.repository).to receive(:new_commits).and_return(
+ project.repository.commits_between('be93687618e4b132087f430a4d8fc3a609c9b77c', 'a5391128b0ef5d21df5dd23d98557f4ef12fae20')
+ )
+ change_access.instance_variable_set(:@commits, project.repository.new_commits)
+
+ expect(project.repository.new_commits.first).not_to receive(:raw_deltas).and_call_original
+ expect(project.repository.new_commits.last).to receive(:raw_deltas).and_call_original
+
+ subject.validate!
+ end
+ end
+ end
end
end
diff --git a/spec/lib/gitlab/ci/config/external/file/local_spec.rb b/spec/lib/gitlab/ci/config/external/file/local_spec.rb
index 541deb13b97..645db642e29 100644
--- a/spec/lib/gitlab/ci/config/external/file/local_spec.rb
+++ b/spec/lib/gitlab/ci/config/external/file/local_spec.rb
@@ -44,7 +44,6 @@ describe Gitlab::Ci::Config::External::File::Local do
- apt-get update -qq && apt-get install -y -qq sqlite3 libsqlite3-dev nodejs
- ruby -v
- which ruby
- - gem install bundler --no-ri --no-rdoc
- bundle install --jobs $(nproc) "${FLAGS[@]}"
HEREDOC
end
diff --git a/spec/lib/gitlab/ci/config/external/file/remote_spec.rb b/spec/lib/gitlab/ci/config/external/file/remote_spec.rb
index 7c1a1c38736..eaf621e4140 100644
--- a/spec/lib/gitlab/ci/config/external/file/remote_spec.rb
+++ b/spec/lib/gitlab/ci/config/external/file/remote_spec.rb
@@ -11,7 +11,6 @@ describe Gitlab::Ci::Config::External::File::Remote do
- apt-get update -qq && apt-get install -y -qq sqlite3 libsqlite3-dev nodejs
- ruby -v
- which ruby
- - gem install bundler --no-ri --no-rdoc
- bundle install --jobs $(nproc) "${FLAGS[@]}"
HEREDOC
end
diff --git a/spec/lib/gitlab/ci/config/external/processor_spec.rb b/spec/lib/gitlab/ci/config/external/processor_spec.rb
index 1a05f716247..dbd28e9745c 100644
--- a/spec/lib/gitlab/ci/config/external/processor_spec.rb
+++ b/spec/lib/gitlab/ci/config/external/processor_spec.rb
@@ -51,7 +51,6 @@ describe Gitlab::Ci::Config::External::Processor do
- apt-get update -qq && apt-get install -y -qq sqlite3 libsqlite3-dev nodejs
- ruby -v
- which ruby
- - gem install bundler --no-ri --no-rdoc
- bundle install --jobs $(nproc) "${FLAGS[@]}"
rspec:
@@ -86,7 +85,6 @@ describe Gitlab::Ci::Config::External::Processor do
- apt-get update -qq && apt-get install -y -qq sqlite3 libsqlite3-dev nodejs
- ruby -v
- which ruby
- - gem install bundler --no-ri --no-rdoc
- bundle install --jobs $(nproc) "${FLAGS[@]}"
HEREDOC
end
diff --git a/spec/lib/gitlab/ci/config_spec.rb b/spec/lib/gitlab/ci/config_spec.rb
index 975e11e8cc1..ea6f1e20014 100644
--- a/spec/lib/gitlab/ci/config_spec.rb
+++ b/spec/lib/gitlab/ci/config_spec.rb
@@ -170,7 +170,6 @@ describe Gitlab::Ci::Config do
before_script_values = [
"apt-get update -qq && apt-get install -y -qq sqlite3 libsqlite3-dev nodejs", "ruby -v",
"which ruby",
- "gem install bundler --no-ri --no-rdoc",
"bundle install --jobs $(nproc) \"${FLAGS[@]}\""
]
variables = {
diff --git a/spec/lib/gitlab/ci/pipeline/chain/command_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/command_spec.rb
index 75a177d2d1f..6aa802ce6fd 100644
--- a/spec/lib/gitlab/ci/pipeline/chain/command_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/chain/command_spec.rb
@@ -182,4 +182,24 @@ describe Gitlab::Ci::Pipeline::Chain::Command do
it { is_expected.to eq(false) }
end
end
+
+ describe '#ambiguous_ref' do
+ let(:project) { create(:project, :repository) }
+ let(:command) { described_class.new(project: project, origin_ref: 'ref') }
+
+ subject { command.ambiguous_ref? }
+
+ context 'when ref is not ambiguous' do
+ it { is_expected. to eq(false) }
+ end
+
+ context 'when ref is ambiguous' do
+ before do
+ project.repository.add_tag(project.creator, 'ref', 'master')
+ project.repository.add_branch(project.creator, 'ref', 'master')
+ end
+
+ it { is_expected. to eq(true) }
+ end
+ end
end
diff --git a/spec/lib/gitlab/ci/pipeline/chain/populate_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/populate_spec.rb
index 284aed91e29..1b014ecfaa4 100644
--- a/spec/lib/gitlab/ci/pipeline/chain/populate_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/chain/populate_spec.rb
@@ -14,6 +14,7 @@ describe Gitlab::Ci::Pipeline::Chain::Populate do
Gitlab::Ci::Pipeline::Chain::Command.new(
project: project,
current_user: user,
+ origin_ref: 'master',
seeds_block: nil)
end
@@ -106,6 +107,7 @@ describe Gitlab::Ci::Pipeline::Chain::Populate do
Gitlab::Ci::Pipeline::Chain::Command.new(
project: project,
current_user: user,
+ origin_ref: 'master',
seeds_block: seeds_block)
end
diff --git a/spec/lib/gitlab/ci/pipeline/chain/validate/repository_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/validate/repository_spec.rb
index fb1b53fc55c..a7cad423d09 100644
--- a/spec/lib/gitlab/ci/pipeline/chain/validate/repository_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/chain/validate/repository_spec.rb
@@ -42,6 +42,27 @@ describe Gitlab::Ci::Pipeline::Chain::Validate::Repository do
end
end
+ context 'when ref is ambiguous' do
+ let(:project) do
+ create(:project, :repository).tap do |proj|
+ proj.repository.add_tag(user, 'master', 'master')
+ end
+ end
+ let(:command) do
+ Gitlab::Ci::Pipeline::Chain::Command.new(
+ project: project, current_user: user, origin_ref: 'master')
+ end
+
+ it 'breaks the chain' do
+ expect(step.break?).to be true
+ end
+
+ it 'adds an error about missing ref' do
+ expect(pipeline.errors.to_a)
+ .to include 'Ref is ambiguous'
+ end
+ end
+
context 'when does not have existing SHA set' do
let(:command) do
Gitlab::Ci::Pipeline::Chain::Command.new(
diff --git a/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb b/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb
index fffa727c2ed..2cf812b26dc 100644
--- a/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb
@@ -1,7 +1,8 @@
require 'spec_helper'
describe Gitlab::Ci::Pipeline::Seed::Build do
- let(:pipeline) { create(:ci_empty_pipeline) }
+ let(:project) { create(:project, :repository) }
+ let(:pipeline) { create(:ci_empty_pipeline, project: project) }
let(:attributes) do
{ name: 'rspec',
diff --git a/spec/lib/gitlab/ci/pipeline/seed/stage_spec.rb b/spec/lib/gitlab/ci/pipeline/seed/stage_spec.rb
index 05ce3412fd8..82f741845db 100644
--- a/spec/lib/gitlab/ci/pipeline/seed/stage_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/seed/stage_spec.rb
@@ -1,7 +1,8 @@
require 'spec_helper'
describe Gitlab::Ci::Pipeline::Seed::Stage do
- let(:pipeline) { create(:ci_empty_pipeline) }
+ let(:project) { create(:project, :repository) }
+ let(:pipeline) { create(:ci_empty_pipeline, project: project) }
let(:attributes) do
{ name: 'test',
diff --git a/spec/lib/gitlab/cleanup/remote_uploads_spec.rb b/spec/lib/gitlab/cleanup/remote_uploads_spec.rb
index 8d03baeb07b..35642cd6e50 100644
--- a/spec/lib/gitlab/cleanup/remote_uploads_spec.rb
+++ b/spec/lib/gitlab/cleanup/remote_uploads_spec.rb
@@ -25,7 +25,7 @@ describe Gitlab::Cleanup::RemoteUploads do
expect(::Fog::Storage).to receive(:new).and_return(connection)
- expect(connection).to receive(:directories).and_return(double(get: directory))
+ expect(connection).to receive(:directories).and_return(double(new: directory))
expect(directory).to receive(:files).and_return(remote_files)
end
diff --git a/spec/lib/gitlab/current_settings_spec.rb b/spec/lib/gitlab/current_settings_spec.rb
index 55490f37ac7..caf9fc5442c 100644
--- a/spec/lib/gitlab/current_settings_spec.rb
+++ b/spec/lib/gitlab/current_settings_spec.rb
@@ -54,7 +54,7 @@ describe Gitlab::CurrentSettings do
expect(ApplicationSetting).not_to receive(:current)
end
- it 'returns an in-memory ApplicationSetting object' do
+ it 'returns a FakeApplicationSettings object' do
expect(described_class.current_application_settings).to be_a(Gitlab::FakeApplicationSettings)
end
@@ -91,6 +91,14 @@ describe Gitlab::CurrentSettings do
allow(ActiveRecord::Base.connection).to receive(:cached_table_exists?).with('application_settings').and_return(true)
end
+ context 'with RequestStore enabled', :request_store do
+ it 'fetches the settings from DB only once' do
+ described_class.current_application_settings # warm the cache
+
+ expect(ActiveRecord::QueryRecorder.new { described_class.current_application_settings }.count).to eq(0)
+ end
+ end
+
it 'creates default ApplicationSettings if none are present' do
settings = described_class.current_application_settings
@@ -99,34 +107,45 @@ describe Gitlab::CurrentSettings do
expect(settings).to have_attributes(settings_from_defaults)
end
- context 'with migrations pending' do
+ context 'with pending migrations' do
before do
expect(ActiveRecord::Migrator).to receive(:needs_migration?).and_return(true)
end
- it 'returns an in-memory ApplicationSetting object' do
- settings = described_class.current_application_settings
+ shared_examples 'a non-persisted ApplicationSetting object' do
+ let(:current_settings) { described_class.current_application_settings }
+
+ it 'returns a non-persisted ApplicationSetting object' do
+ expect(current_settings).to be_a(ApplicationSetting)
+ expect(current_settings).not_to be_persisted
+ end
+
+ it 'uses the default value from ApplicationSetting.defaults' do
+ expect(current_settings.signup_enabled).to eq(ApplicationSetting.defaults[:signup_enabled])
+ end
+
+ it 'uses the default value from custom ApplicationSetting accessors' do
+ expect(current_settings.commit_email_hostname).to eq(ApplicationSetting.default_commit_email_hostname)
+ end
+
+ it 'responds to predicate methods' do
+ expect(current_settings.signup_enabled?).to eq(current_settings.signup_enabled)
+ end
+ end
- expect(settings).to be_a(Gitlab::FakeApplicationSettings)
- expect(settings.sign_in_enabled?).to eq(settings.sign_in_enabled)
- expect(settings.sign_up_enabled?).to eq(settings.sign_up_enabled)
+ context 'with no ApplicationSetting DB record' do
+ it_behaves_like 'a non-persisted ApplicationSetting object'
end
- it 'uses the existing database settings and falls back to defaults' do
- db_settings = create(:application_setting,
- home_page_url: 'http://mydomain.com',
- signup_enabled: false)
- settings = described_class.current_application_settings
- app_defaults = ApplicationSetting.last
-
- expect(settings).to be_a(Gitlab::FakeApplicationSettings)
- expect(settings.home_page_url).to eq(db_settings.home_page_url)
- expect(settings.signup_enabled?).to be_falsey
- expect(settings.signup_enabled).to be_falsey
-
- # Check that unspecified values use the defaults
- settings.reject! { |key, _| [:home_page_url, :signup_enabled].include? key }
- settings.each { |key, _| expect(settings[key]).to eq(app_defaults[key]) }
+ context 'with an existing ApplicationSetting DB record' do
+ let!(:db_settings) { ApplicationSetting.build_from_defaults(home_page_url: 'http://mydomain.com').save! && ApplicationSetting.last }
+ let(:current_settings) { described_class.current_application_settings }
+
+ it_behaves_like 'a non-persisted ApplicationSetting object'
+
+ it 'uses the value from the DB attribute if present and not overriden by an accessor' do
+ expect(current_settings.home_page_url).to eq(db_settings.home_page_url)
+ end
end
end
@@ -138,17 +157,12 @@ describe Gitlab::CurrentSettings do
end
end
- context 'when the application_settings table does not exists' do
- it 'returns an in-memory ApplicationSetting object' do
- expect(ApplicationSetting).to receive(:create_from_defaults).and_raise(ActiveRecord::StatementInvalid)
-
- expect(described_class.current_application_settings).to be_a(Gitlab::FakeApplicationSettings)
- end
- end
-
- context 'when the application_settings table is not fully migrated' do
- it 'returns an in-memory ApplicationSetting object' do
- expect(ApplicationSetting).to receive(:create_from_defaults).and_raise(ActiveRecord::UnknownAttributeError)
+ context 'when the application_settings table does not exist' do
+ it 'returns a FakeApplicationSettings object' do
+ expect(Gitlab::Database)
+ .to receive(:cached_table_exists?)
+ .with('application_settings')
+ .and_return(false)
expect(described_class.current_application_settings).to be_a(Gitlab::FakeApplicationSettings)
end
diff --git a/spec/lib/gitlab/diff/file_spec.rb b/spec/lib/gitlab/diff/file_spec.rb
index b15d22c634a..862590268ca 100644
--- a/spec/lib/gitlab/diff/file_spec.rb
+++ b/spec/lib/gitlab/diff/file_spec.rb
@@ -310,7 +310,7 @@ describe Gitlab::Diff::File do
context 'when the content changed' do
context 'when the file represented by the diff file is binary' do
before do
- allow(diff_file).to receive(:raw_binary?).and_return(true)
+ allow(diff_file).to receive(:binary?).and_return(true)
end
it 'returns a No Preview viewer' do
@@ -345,7 +345,7 @@ describe Gitlab::Diff::File do
context 'when the file represented by the diff file is binary' do
before do
- allow(diff_file).to receive(:raw_binary?).and_return(true)
+ allow(diff_file).to receive(:binary?).and_return(true)
end
it 'returns an Added viewer' do
@@ -380,7 +380,7 @@ describe Gitlab::Diff::File do
context 'when the file represented by the diff file is binary' do
before do
- allow(diff_file).to receive(:raw_binary?).and_return(true)
+ allow(diff_file).to receive(:binary?).and_return(true)
end
it 'returns a Deleted viewer' do
@@ -436,7 +436,7 @@ describe Gitlab::Diff::File do
allow(diff_file).to receive(:deleted_file?).and_return(false)
allow(diff_file).to receive(:renamed_file?).and_return(false)
allow(diff_file).to receive(:mode_changed?).and_return(false)
- allow(diff_file).to receive(:raw_text?).and_return(false)
+ allow(diff_file).to receive(:text?).and_return(false)
end
it 'returns a No Preview viewer' do
diff --git a/spec/lib/gitlab/diff/lines_unfolder_spec.rb b/spec/lib/gitlab/diff/lines_unfolder_spec.rb
index 8e00c8e0e30..f22c2c90334 100644
--- a/spec/lib/gitlab/diff/lines_unfolder_spec.rb
+++ b/spec/lib/gitlab/diff/lines_unfolder_spec.rb
@@ -185,7 +185,7 @@ describe Gitlab::Diff::LinesUnfolder do
let(:project) { create(:project) }
- let(:old_blob) { Gitlab::Git::Blob.new(data: raw_old_blob) }
+ let(:old_blob) { Blob.decorate(Gitlab::Git::Blob.new(data: raw_old_blob, size: 10)) }
let(:diff) do
Gitlab::Git::Diff.new(diff: raw_diff,
diff --git a/spec/lib/gitlab/discussions_diff/file_collection_spec.rb b/spec/lib/gitlab/discussions_diff/file_collection_spec.rb
new file mode 100644
index 00000000000..0489206458b
--- /dev/null
+++ b/spec/lib/gitlab/discussions_diff/file_collection_spec.rb
@@ -0,0 +1,61 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Gitlab::DiscussionsDiff::FileCollection do
+ let(:merge_request) { create(:merge_request) }
+ let!(:diff_note_a) { create(:diff_note_on_merge_request, project: merge_request.project, noteable: merge_request) }
+ let!(:diff_note_b) { create(:diff_note_on_merge_request, project: merge_request.project, noteable: merge_request) }
+ let(:note_diff_file_a) { diff_note_a.note_diff_file }
+ let(:note_diff_file_b) { diff_note_b.note_diff_file }
+
+ subject { described_class.new([note_diff_file_a, note_diff_file_b]) }
+
+ describe '#load_highlight', :clean_gitlab_redis_shared_state do
+ it 'writes uncached diffs highlight' do
+ file_a_caching_content = diff_note_a.diff_file.highlighted_diff_lines.map(&:to_hash)
+ file_b_caching_content = diff_note_b.diff_file.highlighted_diff_lines.map(&:to_hash)
+
+ expect(Gitlab::DiscussionsDiff::HighlightCache)
+ .to receive(:write_multiple)
+ .with({ note_diff_file_a.id => file_a_caching_content,
+ note_diff_file_b.id => file_b_caching_content })
+ .and_call_original
+
+ subject.load_highlight([note_diff_file_a.id, note_diff_file_b.id])
+ end
+
+ it 'does not write cache for already cached file' do
+ subject.load_highlight([note_diff_file_a.id])
+
+ file_b_caching_content = diff_note_b.diff_file.highlighted_diff_lines.map(&:to_hash)
+
+ expect(Gitlab::DiscussionsDiff::HighlightCache)
+ .to receive(:write_multiple)
+ .with({ note_diff_file_b.id => file_b_caching_content })
+ .and_call_original
+
+ subject.load_highlight([note_diff_file_a.id, note_diff_file_b.id])
+ end
+
+ it 'does not err when given ID does not exist in @collection' do
+ expect { subject.load_highlight([999]) }.not_to raise_error
+ end
+
+ it 'loaded diff files have highlighted lines loaded' do
+ subject.load_highlight([note_diff_file_a.id])
+
+ diff_file = subject.find_by_id(note_diff_file_a.id)
+
+ expect(diff_file.highlight_loaded?).to be(true)
+ end
+
+ it 'not loaded diff files does not have highlighted lines loaded' do
+ subject.load_highlight([note_diff_file_a.id])
+
+ diff_file = subject.find_by_id(note_diff_file_b.id)
+
+ expect(diff_file.highlight_loaded?).to be(false)
+ end
+ end
+end
diff --git a/spec/lib/gitlab/discussions_diff/highlight_cache_spec.rb b/spec/lib/gitlab/discussions_diff/highlight_cache_spec.rb
new file mode 100644
index 00000000000..fe26ebb8796
--- /dev/null
+++ b/spec/lib/gitlab/discussions_diff/highlight_cache_spec.rb
@@ -0,0 +1,102 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Gitlab::DiscussionsDiff::HighlightCache, :clean_gitlab_redis_cache do
+ describe '#write_multiple' do
+ it 'sets multiple keys serializing content as JSON' do
+ mapping = {
+ 3 => [
+ {
+ text: 'foo',
+ type: 'new',
+ index: 2,
+ old_pos: 10,
+ new_pos: 11,
+ line_code: 'xpto',
+ rich_text: '<blips>blops</blips>'
+ },
+ {
+ text: 'foo',
+ type: 'new',
+ index: 3,
+ old_pos: 11,
+ new_pos: 12,
+ line_code: 'xpto',
+ rich_text: '<blops>blips</blops>'
+ }
+ ]
+ }
+
+ described_class.write_multiple(mapping)
+
+ mapping.each do |key, value|
+ full_key = described_class.cache_key_for(key)
+ found = Gitlab::Redis::Cache.with { |r| r.get(full_key) }
+
+ expect(found).to eq(value.to_json)
+ end
+ end
+ end
+
+ describe '#read_multiple' do
+ it 'reads multiple keys and serializes content into Gitlab::Diff::Line objects' do
+ mapping = {
+ 3 => [
+ {
+ text: 'foo',
+ type: 'new',
+ index: 2,
+ old_pos: 11,
+ new_pos: 12,
+ line_code: 'xpto',
+ rich_text: '<blips>blops</blips>'
+ },
+ {
+ text: 'foo',
+ type: 'new',
+ index: 3,
+ old_pos: 10,
+ new_pos: 11,
+ line_code: 'xpto',
+ rich_text: '<blips>blops</blips>'
+ }
+ ]
+ }
+
+ described_class.write_multiple(mapping)
+
+ found = described_class.read_multiple(mapping.keys)
+
+ expect(found.size).to eq(1)
+ expect(found.first.size).to eq(2)
+ expect(found.first).to all(be_a(Gitlab::Diff::Line))
+ end
+
+ it 'returns nil when cached key is not found' do
+ mapping = {
+ 3 => [
+ {
+ text: 'foo',
+ type: 'new',
+ index: 2,
+ old_pos: 11,
+ new_pos: 12,
+ line_code: 'xpto',
+ rich_text: '<blips>blops</blips>'
+ }
+ ]
+ }
+
+ described_class.write_multiple(mapping)
+
+ found = described_class.read_multiple([2, 3])
+
+ expect(found.size).to eq(2)
+
+ expect(found.first).to eq(nil)
+ expect(found.second.size).to eq(1)
+ expect(found.second).to all(be_a(Gitlab::Diff::Line))
+ end
+ end
+end
diff --git a/spec/lib/gitlab/git/blob_spec.rb b/spec/lib/gitlab/git/blob_spec.rb
index 80dd3dcc58e..1bcec04d28f 100644
--- a/spec/lib/gitlab/git/blob_spec.rb
+++ b/spec/lib/gitlab/git/blob_spec.rb
@@ -59,7 +59,7 @@ describe Gitlab::Git::Blob, :seed_helper do
it { expect(blob.data[0..10]).to eq("*.rbc\n*.sas") }
it { expect(blob.size).to eq(241) }
it { expect(blob.mode).to eq("100644") }
- it { expect(blob).not_to be_binary }
+ it { expect(blob).not_to be_binary_in_repo }
end
context 'file in root with leading slash' do
@@ -92,7 +92,7 @@ describe Gitlab::Git::Blob, :seed_helper do
end
it 'does not mark the blob as binary' do
- expect(blob).not_to be_binary
+ expect(blob).not_to be_binary_in_repo
end
end
@@ -123,7 +123,7 @@ describe Gitlab::Git::Blob, :seed_helper do
.with(hash_including(binary: true))
.and_call_original
- expect(blob).to be_binary
+ expect(blob).to be_binary_in_repo
end
end
end
@@ -196,7 +196,7 @@ describe Gitlab::Git::Blob, :seed_helper do
it { expect(blob.id).to eq('409f37c4f05865e4fb208c771485f211a22c4c2d') }
it { expect(blob.data).to eq('') }
it 'does not mark the blob as binary' do
- expect(blob).not_to be_binary
+ expect(blob).not_to be_binary_in_repo
end
end
diff --git a/spec/lib/gitlab/git_access_spec.rb b/spec/lib/gitlab/git_access_spec.rb
index a417ef77c9e..8d8eb50ad76 100644
--- a/spec/lib/gitlab/git_access_spec.rb
+++ b/spec/lib/gitlab/git_access_spec.rb
@@ -709,10 +709,22 @@ describe Gitlab::GitAccess do
project.add_developer(user)
end
- it 'checks LFS integrity only for first change' do
- expect_any_instance_of(Gitlab::Checks::LfsIntegrity).to receive(:objects_missing?).exactly(1).times
+ context 'when LFS is not enabled' do
+ it 'does not run LFSIntegrity check' do
+ expect(Gitlab::Checks::LfsIntegrity).not_to receive(:new)
- push_access_check
+ push_access_check
+ end
+ end
+
+ context 'when LFS is enabled' do
+ it 'checks LFS integrity only for first change' do
+ allow(project).to receive(:lfs_enabled?).and_return(true)
+
+ expect_any_instance_of(Gitlab::Checks::LfsIntegrity).to receive(:objects_missing?).exactly(1).times
+
+ push_access_check
+ end
end
end
diff --git a/spec/lib/gitlab/gitaly_client/blobs_stitcher_spec.rb b/spec/lib/gitlab/gitaly_client/blobs_stitcher_spec.rb
index 9db710e759e..742b2872c40 100644
--- a/spec/lib/gitlab/gitaly_client/blobs_stitcher_spec.rb
+++ b/spec/lib/gitlab/gitaly_client/blobs_stitcher_spec.rb
@@ -21,7 +21,7 @@ describe Gitlab::GitalyClient::BlobsStitcher do
expect(blobs[0].size).to eq(1642)
expect(blobs[0].commit_id).to eq('f00ba7')
expect(blobs[0].data).to eq("first-line\nsecond-line")
- expect(blobs[0].binary?).to be false
+ expect(blobs[0].binary_in_repo?).to be false
expect(blobs[1].id).to eq('abcdef2')
expect(blobs[1].mode).to eq('100644')
@@ -30,7 +30,7 @@ describe Gitlab::GitalyClient::BlobsStitcher do
expect(blobs[1].size).to eq(2461)
expect(blobs[1].commit_id).to eq('f00ba8')
expect(blobs[1].data).to eq("GIF87a\x90\x01".b)
- expect(blobs[1].binary?).to be true
+ expect(blobs[1].binary_in_repo?).to be true
end
end
end
diff --git a/spec/lib/gitlab/gitaly_client_spec.rb b/spec/lib/gitlab/gitaly_client_spec.rb
index 5eda4d041a8..e41a75c37a7 100644
--- a/spec/lib/gitlab/gitaly_client_spec.rb
+++ b/spec/lib/gitlab/gitaly_client_spec.rb
@@ -3,6 +3,20 @@ require 'spec_helper'
# We stub Gitaly in `spec/support/gitaly.rb` for other tests. We don't want
# those stubs while testing the GitalyClient itself.
describe Gitlab::GitalyClient do
+ let(:sample_cert) { Rails.root.join('spec/fixtures/clusters/sample_cert.pem').to_s }
+
+ before do
+ allow(described_class)
+ .to receive(:stub_cert_paths)
+ .and_return([sample_cert])
+ end
+
+ def stub_repos_storages(address)
+ allow(Gitlab.config.repositories).to receive(:storages).and_return({
+ 'default' => { 'gitaly_address' => address }
+ })
+ end
+
describe '.stub_class' do
it 'returns the gRPC health check stub' do
expect(described_class.stub_class(:health_check)).to eq(::Grpc::Health::V1::Health::Stub)
@@ -15,12 +29,8 @@ describe Gitlab::GitalyClient do
describe '.stub_address' do
it 'returns the same result after being called multiple times' do
- address = 'localhost:9876'
- prefixed_address = "tcp://#{address}"
-
- allow(Gitlab.config.repositories).to receive(:storages).and_return({
- 'default' => { 'gitaly_address' => prefixed_address }
- })
+ address = 'tcp://localhost:9876'
+ stub_repos_storages address
2.times do
expect(described_class.stub_address('default')).to eq('localhost:9876')
@@ -28,6 +38,45 @@ describe Gitlab::GitalyClient do
end
end
+ describe '.stub_certs' do
+ it 'skips certificates if OpenSSLError is raised and report it' do
+ expect(Rails.logger).to receive(:error).at_least(:once)
+ expect(Gitlab::Sentry)
+ .to receive(:track_exception)
+ .with(
+ a_kind_of(OpenSSL::X509::CertificateError),
+ extra: { cert_file: a_kind_of(String) }).at_least(:once)
+
+ expect(OpenSSL::X509::Certificate)
+ .to receive(:new)
+ .and_raise(OpenSSL::X509::CertificateError).at_least(:once)
+
+ expect(described_class.stub_certs).to be_a(String)
+ end
+ end
+ describe '.stub_creds' do
+ it 'returns :this_channel_is_insecure if unix' do
+ address = 'unix:/tmp/gitaly.sock'
+ stub_repos_storages address
+
+ expect(described_class.stub_creds('default')).to eq(:this_channel_is_insecure)
+ end
+
+ it 'returns :this_channel_is_insecure if tcp' do
+ address = 'tcp://localhost:9876'
+ stub_repos_storages address
+
+ expect(described_class.stub_creds('default')).to eq(:this_channel_is_insecure)
+ end
+
+ it 'returns Credentials object if tls' do
+ address = 'tls://localhost:9876'
+ stub_repos_storages address
+
+ expect(described_class.stub_creds('default')).to be_a(GRPC::Core::ChannelCredentials)
+ end
+ end
+
describe '.stub' do
# Notice that this is referring to gRPC "stubs", not rspec stubs
before do
@@ -37,9 +86,19 @@ describe Gitlab::GitalyClient do
context 'when passed a UNIX socket address' do
it 'passes the address as-is to GRPC' do
address = 'unix:/tmp/gitaly.sock'
- allow(Gitlab.config.repositories).to receive(:storages).and_return({
- 'default' => { 'gitaly_address' => address }
- })
+ stub_repos_storages address
+
+ expect(Gitaly::CommitService::Stub).to receive(:new).with(address, any_args)
+
+ described_class.stub(:commit_service, 'default')
+ end
+ end
+
+ context 'when passed a TLS address' do
+ it 'strips tls:// prefix before passing it to GRPC::Core::Channel initializer' do
+ address = 'localhost:9876'
+ prefixed_address = "tls://#{address}"
+ stub_repos_storages prefixed_address
expect(Gitaly::CommitService::Stub).to receive(:new).with(address, any_args)
@@ -51,10 +110,7 @@ describe Gitlab::GitalyClient do
it 'strips tcp:// prefix before passing it to GRPC::Core::Channel initializer' do
address = 'localhost:9876'
prefixed_address = "tcp://#{address}"
-
- allow(Gitlab.config.repositories).to receive(:storages).and_return({
- 'default' => { 'gitaly_address' => prefixed_address }
- })
+ stub_repos_storages prefixed_address
expect(Gitaly::CommitService::Stub).to receive(:new).with(address, any_args)
diff --git a/spec/lib/gitlab/import_export/command_line_util_spec.rb b/spec/lib/gitlab/import_export/command_line_util_spec.rb
new file mode 100644
index 00000000000..8e5e0aefac0
--- /dev/null
+++ b/spec/lib/gitlab/import_export/command_line_util_spec.rb
@@ -0,0 +1,38 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Gitlab::ImportExport::CommandLineUtil do
+ include ExportFileHelper
+
+ let(:path) { "#{Dir.tmpdir}/symlink_test" }
+ let(:archive) { 'spec/fixtures/symlink_export.tar.gz' }
+ let(:shared) { Gitlab::ImportExport::Shared.new(nil) }
+
+ subject do
+ Class.new do
+ include Gitlab::ImportExport::CommandLineUtil
+
+ def initialize
+ @shared = Gitlab::ImportExport::Shared.new(nil)
+ end
+ end.new
+ end
+
+ before do
+ FileUtils.mkdir_p(path)
+ subject.untar_zxf(archive: archive, dir: path)
+ end
+
+ after do
+ FileUtils.rm_rf(path)
+ end
+
+ it 'has the right mask for project.json' do
+ expect(file_permissions("#{path}/project.json")).to eq(0755) # originally 777
+ end
+
+ it 'has the right mask for uploads' do
+ expect(file_permissions("#{path}/uploads")).to eq(0755) # originally 555
+ end
+end
diff --git a/spec/lib/gitlab/import_export/file_importer_spec.rb b/spec/lib/gitlab/import_export/file_importer_spec.rb
index bf34cefe18f..fbc9bcd2df5 100644
--- a/spec/lib/gitlab/import_export/file_importer_spec.rb
+++ b/spec/lib/gitlab/import_export/file_importer_spec.rb
@@ -1,6 +1,8 @@
require 'spec_helper'
describe Gitlab::ImportExport::FileImporter do
+ include ExportFileHelper
+
let(:shared) { Gitlab::ImportExport::Shared.new(nil) }
let(:storage_path) { "#{Dir.tmpdir}/file_importer_spec" }
let(:valid_file) { "#{shared.export_path}/valid.json" }
@@ -8,6 +10,7 @@ describe Gitlab::ImportExport::FileImporter do
let(:hidden_symlink_file) { "#{shared.export_path}/.hidden" }
let(:subfolder_symlink_file) { "#{shared.export_path}/subfolder/invalid.json" }
let(:evil_symlink_file) { "#{shared.export_path}/.\nevil" }
+ let(:custom_mode_symlink_file) { "#{shared.export_path}/symlink.mode" }
before do
stub_const('Gitlab::ImportExport::FileImporter::MAX_RETRIES', 0)
@@ -45,10 +48,18 @@ describe Gitlab::ImportExport::FileImporter do
expect(File.exist?(subfolder_symlink_file)).to be false
end
+ it 'removes symlinks without any file permissions' do
+ expect(File.exist?(custom_mode_symlink_file)).to be false
+ end
+
it 'does not remove a valid file' do
expect(File.exist?(valid_file)).to be true
end
+ it 'does not change a valid file permissions' do
+ expect(file_permissions(valid_file)).not_to eq(0000)
+ end
+
it 'creates the file in the right subfolder' do
expect(shared.export_path).to include('test/abcd')
end
@@ -84,5 +95,7 @@ describe Gitlab::ImportExport::FileImporter do
FileUtils.ln_s(valid_file, subfolder_symlink_file)
FileUtils.ln_s(valid_file, hidden_symlink_file)
FileUtils.ln_s(valid_file, evil_symlink_file)
+ FileUtils.ln_s(valid_file, custom_mode_symlink_file)
+ FileUtils.chmod_R(0000, custom_mode_symlink_file)
end
end
diff --git a/spec/lib/gitlab/legacy_github_import/importer_spec.rb b/spec/lib/gitlab/legacy_github_import/importer_spec.rb
index d2df21d7bb5..6bc3792eb22 100644
--- a/spec/lib/gitlab/legacy_github_import/importer_spec.rb
+++ b/spec/lib/gitlab/legacy_github_import/importer_spec.rb
@@ -138,7 +138,7 @@ describe Gitlab::LegacyGithubImport::Importer do
let(:release2) do
double(
- tag_name: 'v2.0.0',
+ tag_name: 'v1.1.0',
name: 'Second release',
body: nil,
draft: false,
diff --git a/spec/lib/gitlab/group_hierarchy_spec.rb b/spec/lib/gitlab/object_hierarchy_spec.rb
index f3de7adcec7..4700a7ad2e1 100644
--- a/spec/lib/gitlab/group_hierarchy_spec.rb
+++ b/spec/lib/gitlab/object_hierarchy_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::GroupHierarchy, :postgresql do
+describe Gitlab::ObjectHierarchy, :postgresql do
let!(:parent) { create(:group) }
let!(:child1) { create(:group, parent: parent) }
let!(:child2) { create(:group, parent: child1) }
@@ -105,9 +105,9 @@ describe Gitlab::GroupHierarchy, :postgresql do
end
end
- describe '#all_groups' do
+ describe '#all_objects' do
let(:relation) do
- described_class.new(Group.where(id: child1.id)).all_groups
+ described_class.new(Group.where(id: child1.id)).all_objects
end
it 'includes the base rows' do
@@ -123,13 +123,13 @@ describe Gitlab::GroupHierarchy, :postgresql do
end
it 'uses ancestors_base #initialize argument for ancestors' do
- relation = described_class.new(Group.where(id: child1.id), Group.where(id: Group.maximum(:id).succ)).all_groups
+ relation = described_class.new(Group.where(id: child1.id), Group.where(id: Group.maximum(:id).succ)).all_objects
expect(relation).to include(parent)
end
it 'uses descendants_base #initialize argument for descendants' do
- relation = described_class.new(Group.where(id: Group.maximum(:id).succ), Group.where(id: child1.id)).all_groups
+ relation = described_class.new(Group.where(id: Group.maximum(:id).succ), Group.where(id: child1.id)).all_objects
expect(relation).to include(child2)
end
diff --git a/spec/lib/gitlab/project_authorizations_spec.rb b/spec/lib/gitlab/project_authorizations_spec.rb
index 00c62c7bf96..bd0bc2c9044 100644
--- a/spec/lib/gitlab/project_authorizations_spec.rb
+++ b/spec/lib/gitlab/project_authorizations_spec.rb
@@ -20,7 +20,7 @@ describe Gitlab::ProjectAuthorizations do
end
let(:authorizations) do
- klass = if Group.supports_nested_groups?
+ klass = if Group.supports_nested_objects?
Gitlab::ProjectAuthorizations::WithNestedGroups
else
Gitlab::ProjectAuthorizations::WithoutNestedGroups
@@ -46,7 +46,7 @@ describe Gitlab::ProjectAuthorizations do
expect(mapping[group_project.id]).to eq(Gitlab::Access::DEVELOPER)
end
- if Group.supports_nested_groups?
+ if Group.supports_nested_objects?
context 'with nested groups' do
let!(:nested_group) { create(:group, parent: group) }
let!(:nested_project) { create(:project, namespace: nested_group) }
diff --git a/spec/lib/gitlab/prometheus/metric_group_spec.rb b/spec/lib/gitlab/prometheus/metric_group_spec.rb
index e7d16e73663..5cc6827488b 100644
--- a/spec/lib/gitlab/prometheus/metric_group_spec.rb
+++ b/spec/lib/gitlab/prometheus/metric_group_spec.rb
@@ -21,6 +21,13 @@ describe Gitlab::Prometheus::MetricGroup do
common_metric_group_a.id, common_metric_group_b_q1.id,
common_metric_group_b_q2.id)
end
+
+ it 'orders by priority' do
+ priorities = subject.map(&:priority)
+ names = subject.map(&:name)
+ expect(priorities).to eq([10, 5])
+ expect(names).to eq(['Response metrics (AWS ELB)', 'System metrics (Kubernetes)'])
+ end
end
describe '.for_project' do
diff --git a/spec/lib/gitlab/upgrader_spec.rb b/spec/lib/gitlab/upgrader_spec.rb
deleted file mode 100644
index 6106f13c774..00000000000
--- a/spec/lib/gitlab/upgrader_spec.rb
+++ /dev/null
@@ -1,40 +0,0 @@
-require 'spec_helper'
-
-describe Gitlab::Upgrader do
- let(:upgrader) { described_class.new }
- let(:current_version) { Gitlab::VERSION }
-
- describe 'current_version_raw' do
- it { expect(upgrader.current_version_raw).to eq(current_version) }
- end
-
- describe 'latest_version?' do
- it 'is true if newest version' do
- allow(upgrader).to receive(:latest_version_raw).and_return(current_version)
- expect(upgrader.latest_version?).to be_truthy
- end
- end
-
- describe 'latest_version_raw' do
- it 'is the latest version for GitLab 5' do
- allow(upgrader).to receive(:current_version_raw).and_return("5.3.0")
- expect(upgrader.latest_version_raw).to eq("v5.4.2")
- end
-
- it 'gets the latest version from tags' do
- allow(upgrader).to receive(:fetch_git_tags).and_return([
- '6f0733310546402c15d3ae6128a95052f6c8ea96 refs/tags/v7.1.1',
- 'facfec4b242ce151af224e20715d58e628aa5e74 refs/tags/v7.1.1^{}',
- 'f7068d99c79cf79befbd388030c051bb4b5e86d4 refs/tags/v7.10.4',
- '337225a4fcfa9674e2528cb6d41c46556bba9dfa refs/tags/v7.10.4^{}',
- '880e0ba0adbed95d087f61a9a17515e518fc6440 refs/tags/v7.11.1',
- '6584346b604f981f00af8011cd95472b2776d912 refs/tags/v7.11.1^{}',
- '43af3e65a486a9237f29f56d96c3b3da59c24ae0 refs/tags/v7.11.2',
- 'dac18e7728013a77410e926a1e64225703754a2d refs/tags/v7.11.2^{}',
- '0bf21fd4b46c980c26fd8c90a14b86a4d90cc950 refs/tags/v7.9.4',
- 'b10de29edbaff7219547dc506cb1468ee35065c3 refs/tags/v7.9.4^{}'
- ])
- expect(upgrader.latest_version_raw).to eq("v7.11.2")
- end
- end
-end
diff --git a/spec/lib/gitlab/utils/override_spec.rb b/spec/lib/gitlab/utils/override_spec.rb
index fc08ebcfc6d..9e7c97f8095 100644
--- a/spec/lib/gitlab/utils/override_spec.rb
+++ b/spec/lib/gitlab/utils/override_spec.rb
@@ -25,11 +25,21 @@ describe Gitlab::Utils::Override do
let(:klass) { subject }
- def good(mod)
+ def good(mod, bad_arity: false, negative_arity: false)
mod.module_eval do
override :good
- def good
- super.succ
+
+ if bad_arity
+ def good(num)
+ end
+ elsif negative_arity
+ def good(*args)
+ super.succ
+ end
+ else
+ def good
+ super.succ
+ end
end
end
@@ -56,6 +66,14 @@ describe Gitlab::Utils::Override do
described_class.verify!
end
+ it 'checks ok for overriding method using negative arity' do
+ good(subject, negative_arity: true)
+ result = instance.good
+
+ expect(result).to eq(1)
+ described_class.verify!
+ end
+
it 'raises NotImplementedError when it is not overriding anything' do
expect do
bad(subject)
@@ -63,6 +81,14 @@ describe Gitlab::Utils::Override do
described_class.verify!
end.to raise_error(NotImplementedError)
end
+
+ it 'raises NotImplementedError when overriding a method with different arity' do
+ expect do
+ good(subject, bad_arity: true)
+ instance.good(1)
+ described_class.verify!
+ end.to raise_error(NotImplementedError)
+ end
end
shared_examples 'checking as intended, nothing was overridden' do
diff --git a/spec/lib/json_web_token/rsa_token_spec.rb b/spec/lib/json_web_token/rsa_token_spec.rb
index d6edc964844..a3c54651e80 100644
--- a/spec/lib/json_web_token/rsa_token_spec.rb
+++ b/spec/lib/json_web_token/rsa_token_spec.rb
@@ -25,7 +25,7 @@ describe JSONWebToken::RSAToken do
rsa_token['key'] = 'value'
end
- subject { JWT.decode(rsa_encoded, rsa_key) }
+ subject { JWT.decode(rsa_encoded, rsa_key, true, { algorithm: 'RS256' }) }
it { expect {subject}.not_to raise_error }
it { expect(subject.first).to include('key' => 'value') }
@@ -39,7 +39,7 @@ describe JSONWebToken::RSAToken do
context 'for invalid key to raise an exception' do
let(:new_key) { OpenSSL::PKey::RSA.generate(512) }
- subject { JWT.decode(rsa_encoded, new_key) }
+ subject { JWT.decode(rsa_encoded, new_key, true, { algorithm: 'RS256' }) }
it { expect {subject}.to raise_error(JWT::DecodeError) }
end
diff --git a/spec/mailers/notify_spec.rb b/spec/mailers/notify_spec.rb
index f6e5c9d33ac..f2d99872401 100644
--- a/spec/mailers/notify_spec.rb
+++ b/spec/mailers/notify_spec.rb
@@ -890,22 +890,14 @@ describe Notify do
shared_examples 'an email for a note on a diff discussion' do |model|
let(:note) { create(model, author: note_author) }
- context 'when note is on image' do
+ context 'when note is not on text' do
before do
- allow_any_instance_of(DiffDiscussion).to receive(:on_image?).and_return(true)
+ allow_any_instance_of(DiffDiscussion).to receive(:on_text?).and_return(false)
end
it 'does not include diffs with character-level highlighting' do
is_expected.not_to have_body_text '<span class="p">}</span></span>'
end
-
- it 'ends the intro with a dot' do
- is_expected.to have_body_text "#{note.diff_file.file_path}</a>."
- end
- end
-
- it 'ends the intro with a colon' do
- is_expected.to have_body_text "#{note.diff_file.file_path}</a>:"
end
it 'includes diffs with character-level highlighting' do
diff --git a/spec/migrations/migrate_cluster_configure_worker_sidekiq_queue_spec.rb b/spec/migrations/migrate_cluster_configure_worker_sidekiq_queue_spec.rb
new file mode 100644
index 00000000000..b2d8f476bb2
--- /dev/null
+++ b/spec/migrations/migrate_cluster_configure_worker_sidekiq_queue_spec.rb
@@ -0,0 +1,68 @@
+require 'spec_helper'
+require Rails.root.join('db', 'post_migrate', '20181219145520_migrate_cluster_configure_worker_sidekiq_queue.rb')
+
+describe MigrateClusterConfigureWorkerSidekiqQueue, :sidekiq, :redis do
+ include Gitlab::Database::MigrationHelpers
+
+ context 'when there are jobs in the queue' do
+ it 'correctly migrates queue when migrating up' do
+ Sidekiq::Testing.disable! do
+ stubbed_worker(queue: 'gcp_cluster:cluster_platform_configure').perform_async('Something', [1])
+ stubbed_worker(queue: 'gcp_cluster:cluster_configure').perform_async('Something', [1])
+
+ described_class.new.up
+
+ expect(sidekiq_queue_length('gcp_cluster:cluster_platform_configure')).to eq 0
+ expect(sidekiq_queue_length('gcp_cluster:cluster_configure')).to eq 2
+ end
+ end
+
+ it 'does not affect other queues under the same namespace' do
+ Sidekiq::Testing.disable! do
+ stubbed_worker(queue: 'gcp_cluster:cluster_install_app').perform_async('Something', [1])
+ stubbed_worker(queue: 'gcp_cluster:cluster_provision').perform_async('Something', [1])
+ stubbed_worker(queue: 'gcp_cluster:cluster_wait_for_app_installation').perform_async('Something', [1])
+ stubbed_worker(queue: 'gcp_cluster:wait_for_cluster_creation').perform_async('Something', [1])
+ stubbed_worker(queue: 'gcp_cluster:cluster_wait_for_ingress_ip_address').perform_async('Something', [1])
+ stubbed_worker(queue: 'gcp_cluster:cluster_project_configure').perform_async('Something', [1])
+
+ described_class.new.up
+
+ expect(sidekiq_queue_length('gcp_cluster:cluster_install_app')).to eq 1
+ expect(sidekiq_queue_length('gcp_cluster:cluster_provision')).to eq 1
+ expect(sidekiq_queue_length('gcp_cluster:cluster_wait_for_app_installation')).to eq 1
+ expect(sidekiq_queue_length('gcp_cluster:wait_for_cluster_creation')).to eq 1
+ expect(sidekiq_queue_length('gcp_cluster:cluster_wait_for_ingress_ip_address')).to eq 1
+ expect(sidekiq_queue_length('gcp_cluster:cluster_project_configure')).to eq 1
+ end
+ end
+
+ it 'correctly migrates queue when migrating down' do
+ Sidekiq::Testing.disable! do
+ stubbed_worker(queue: 'gcp_cluster:cluster_configure').perform_async('Something', [1])
+
+ described_class.new.down
+
+ expect(sidekiq_queue_length('gcp_cluster:cluster_platform_configure')).to eq 1
+ expect(sidekiq_queue_length('gcp_cluster:cluster_configure')).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
+
+ def stubbed_worker(queue:)
+ Class.new do
+ include Sidekiq::Worker
+ sidekiq_options queue: queue
+ end
+ end
+end
diff --git a/spec/models/appearance_spec.rb b/spec/models/appearance_spec.rb
index 35415030154..ec2e7d672f0 100644
--- a/spec/models/appearance_spec.rb
+++ b/spec/models/appearance_spec.rb
@@ -26,4 +26,34 @@ describe Appearance do
let(:uploader_class) { AttachmentUploader }
end
end
+
+ shared_examples 'logo paths' do |logo_type|
+ let(:appearance) { create(:appearance, "with_#{logo_type}".to_sym) }
+ let(:filename) { 'dk.png' }
+ let(:expected_path) { "/uploads/-/system/appearance/#{logo_type}/#{appearance.id}/#{filename}" }
+
+ it 'returns nil when there is no upload' do
+ expect(subject.send("#{logo_type}_path")).to be_nil
+ end
+
+ it 'returns a local path using the system route' do
+ expect(appearance.send("#{logo_type}_path")).to eq(expected_path)
+ end
+
+ describe 'with asset host configured' do
+ let(:asset_host) { 'https://gitlab-assets.example.com' }
+
+ before do
+ allow(ActionController::Base).to receive(:asset_host) { asset_host }
+ end
+
+ it 'returns a full URL with the system path' do
+ expect(appearance.send("#{logo_type}_path")).to eq("#{asset_host}#{expected_path}")
+ end
+ end
+ end
+
+ %i(logo header_logo favicon).each do |logo_type|
+ it_behaves_like 'logo paths', logo_type
+ end
end
diff --git a/spec/models/blob_spec.rb b/spec/models/blob_spec.rb
index e8c03b587e2..05cf242e84d 100644
--- a/spec/models/blob_spec.rb
+++ b/spec/models/blob_spec.rb
@@ -122,14 +122,14 @@ describe Blob do
end
end
- describe '#raw_binary?' do
+ describe '#binary?' do
context 'if the blob is stored externally' do
context 'if the extension has a rich viewer' do
context 'if the viewer is binary' do
it 'returns true' do
blob = fake_blob(path: 'file.pdf', lfs: true)
- expect(blob.raw_binary?).to be_truthy
+ expect(blob.binary?).to be_truthy
end
end
@@ -137,7 +137,7 @@ describe Blob do
it 'return false' do
blob = fake_blob(path: 'file.md', lfs: true)
- expect(blob.raw_binary?).to be_falsey
+ expect(blob.binary?).to be_falsey
end
end
end
@@ -148,7 +148,7 @@ describe Blob do
it 'returns false' do
blob = fake_blob(path: 'file.txt', lfs: true)
- expect(blob.raw_binary?).to be_falsey
+ expect(blob.binary?).to be_falsey
end
end
@@ -156,7 +156,7 @@ describe Blob do
it 'returns false' do
blob = fake_blob(path: 'file.ics', lfs: true)
- expect(blob.raw_binary?).to be_falsey
+ expect(blob.binary?).to be_falsey
end
end
end
@@ -166,7 +166,7 @@ describe Blob do
it 'returns false' do
blob = fake_blob(path: 'file.rb', lfs: true)
- expect(blob.raw_binary?).to be_falsey
+ expect(blob.binary?).to be_falsey
end
end
@@ -174,7 +174,7 @@ describe Blob do
it 'returns true' do
blob = fake_blob(path: 'file.exe', lfs: true)
- expect(blob.raw_binary?).to be_truthy
+ expect(blob.binary?).to be_truthy
end
end
end
@@ -184,7 +184,7 @@ describe Blob do
it 'returns false' do
blob = fake_blob(path: 'file.ini', lfs: true)
- expect(blob.raw_binary?).to be_falsey
+ expect(blob.binary?).to be_falsey
end
end
@@ -192,7 +192,7 @@ describe Blob do
it 'returns true' do
blob = fake_blob(path: 'file.wtf', lfs: true)
- expect(blob.raw_binary?).to be_truthy
+ expect(blob.binary?).to be_truthy
end
end
end
@@ -204,7 +204,7 @@ describe Blob do
it 'returns true' do
blob = fake_blob(path: 'file.pdf', binary: true)
- expect(blob.raw_binary?).to be_truthy
+ expect(blob.binary?).to be_truthy
end
end
@@ -212,7 +212,7 @@ describe Blob do
it 'return false' do
blob = fake_blob(path: 'file.md')
- expect(blob.raw_binary?).to be_falsey
+ expect(blob.binary?).to be_falsey
end
end
end
diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb
index fe7f5f8e1e3..7baf4d93804 100644
--- a/spec/models/ci/build_spec.rb
+++ b/spec/models/ci/build_spec.rb
@@ -2386,6 +2386,8 @@ describe Ci::Build do
end
context 'when protected variable is defined' do
+ let(:ref) { Gitlab::Git::BRANCH_REF_PREFIX + build.ref }
+
let(:protected_variable) do
{ key: 'PROTECTED_KEY', value: 'protected_value', public: false }
end
@@ -2398,7 +2400,7 @@ describe Ci::Build do
context 'when the branch is protected' do
before do
- allow(build.project).to receive(:protected_for?).with(build.ref).and_return(true)
+ allow(build.project).to receive(:protected_for?).with(ref).and_return(true)
end
it { is_expected.to include(protected_variable) }
@@ -2406,7 +2408,7 @@ describe Ci::Build do
context 'when the tag is protected' do
before do
- allow(build.project).to receive(:protected_for?).with(build.ref).and_return(true)
+ allow(build.project).to receive(:protected_for?).with(ref).and_return(true)
end
it { is_expected.to include(protected_variable) }
@@ -2431,6 +2433,8 @@ describe Ci::Build do
end
context 'when group protected variable is defined' do
+ let(:ref) { Gitlab::Git::BRANCH_REF_PREFIX + build.ref }
+
let(:protected_variable) do
{ key: 'PROTECTED_KEY', value: 'protected_value', public: false }
end
@@ -2443,7 +2447,7 @@ describe Ci::Build do
context 'when the branch is protected' do
before do
- allow(build.project).to receive(:protected_for?).with(build.ref).and_return(true)
+ allow(build.project).to receive(:protected_for?).with(ref).and_return(true)
end
it { is_expected.to include(protected_variable) }
@@ -2451,7 +2455,7 @@ describe Ci::Build do
context 'when the tag is protected' do
before do
- allow(build.project).to receive(:protected_for?).with(build.ref).and_return(true)
+ allow(build.project).to receive(:protected_for?).with(ref).and_return(true)
end
it { is_expected.to include(protected_variable) }
diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb
index b67c6a4cffa..17f33785fda 100644
--- a/spec/models/ci/pipeline_spec.rb
+++ b/spec/models/ci/pipeline_spec.rb
@@ -397,6 +397,10 @@ describe Ci::Pipeline, :mailer do
end
describe '#protected_ref?' do
+ before do
+ pipeline.project = create(:project, :repository)
+ end
+
it 'delegates method to project' do
expect(pipeline).not_to be_protected_ref
end
diff --git a/spec/models/clusters/applications/cert_manager_spec.rb b/spec/models/clusters/applications/cert_manager_spec.rb
index 170c6001eaf..e825f3e2392 100644
--- a/spec/models/clusters/applications/cert_manager_spec.rb
+++ b/spec/models/clusters/applications/cert_manager_spec.rb
@@ -14,7 +14,7 @@ describe Clusters::Applications::CertManager do
let(:application) { create(:clusters_applications_cert_managers, :scheduled, version: 'v0.4.0') }
it 'updates the application version' do
- expect(application.reload.version).to eq('v0.5.0')
+ expect(application.reload.version).to eq('v0.5.2')
end
end
end
@@ -28,7 +28,7 @@ describe Clusters::Applications::CertManager do
it 'should be initialized with cert_manager arguments' do
expect(subject.name).to eq('certmanager')
expect(subject.chart).to eq('stable/cert-manager')
- expect(subject.version).to eq('v0.5.0')
+ expect(subject.version).to eq('v0.5.2')
expect(subject).not_to be_rbac
expect(subject.files).to eq(cert_manager.files.merge(cluster_issuer_file))
expect(subject.postinstall).to eq(['/usr/bin/kubectl create -f /data/helm/certmanager/config/cluster_issuer.yaml'])
@@ -57,7 +57,7 @@ describe Clusters::Applications::CertManager do
let(:cert_manager) { create(:clusters_applications_cert_managers, :errored, version: '0.0.1') }
it 'should be initialized with the locked version' do
- expect(subject.version).to eq('v0.5.0')
+ expect(subject.version).to eq('v0.5.2')
end
end
end
diff --git a/spec/models/clusters/applications/runner_spec.rb b/spec/models/clusters/applications/runner_spec.rb
index 47daa79873e..cae23daac8c 100644
--- a/spec/models/clusters/applications/runner_spec.rb
+++ b/spec/models/clusters/applications/runner_spec.rb
@@ -18,7 +18,7 @@ describe Clusters::Applications::Runner do
let(:application) { create(:clusters_applications_runner, :scheduled, version: '0.1.30') }
it 'updates the application version' do
- expect(application.reload.version).to eq('0.1.39')
+ expect(application.reload.version).to eq('0.1.43')
end
end
end
@@ -46,7 +46,7 @@ describe Clusters::Applications::Runner do
it 'should be initialized with 4 arguments' do
expect(subject.name).to eq('runner')
expect(subject.chart).to eq('runner/gitlab-runner')
- expect(subject.version).to eq('0.1.39')
+ expect(subject.version).to eq('0.1.43')
expect(subject).not_to be_rbac
expect(subject.repository).to eq('https://charts.gitlab.io')
expect(subject.files).to eq(gitlab_runner.files)
@@ -64,7 +64,7 @@ describe Clusters::Applications::Runner do
let(:gitlab_runner) { create(:clusters_applications_runner, :errored, runner: ci_runner, version: '0.1.13') }
it 'should be initialized with the locked version' do
- expect(subject.version).to eq('0.1.39')
+ expect(subject.version).to eq('0.1.43')
end
end
end
diff --git a/spec/models/clusters/platforms/kubernetes_spec.rb b/spec/models/clusters/platforms/kubernetes_spec.rb
index 062d2fd0768..e6b076adc76 100644
--- a/spec/models/clusters/platforms/kubernetes_spec.rb
+++ b/spec/models/clusters/platforms/kubernetes_spec.rb
@@ -325,12 +325,13 @@ describe Clusters::Platforms::Kubernetes, :use_clean_rails_memory_store_caching
context 'with valid pods' do
let(:pod) { kube_pod(app: environment.slug) }
+ let(:pod_with_no_terminal) { kube_pod(app: environment.slug, status: "Pending") }
let(:terminals) { kube_terminals(service, pod) }
before do
stub_reactive_cache(
service,
- pods: [pod, pod, kube_pod(app: "should-be-filtered-out")]
+ pods: [pod, pod, pod_with_no_terminal, kube_pod(app: "should-be-filtered-out")]
)
end
@@ -394,7 +395,7 @@ describe Clusters::Platforms::Kubernetes, :use_clean_rails_memory_store_caching
context 'when namespace is updated' do
it 'should call ConfigureWorker' do
- expect(ClusterPlatformConfigureWorker).to receive(:perform_async).with(cluster.id).once
+ expect(ClusterConfigureWorker).to receive(:perform_async).with(cluster.id).once
platform.namespace = 'new-namespace'
platform.save
@@ -403,7 +404,7 @@ describe Clusters::Platforms::Kubernetes, :use_clean_rails_memory_store_caching
context 'when namespace is not updated' do
it 'should not call ConfigureWorker' do
- expect(ClusterPlatformConfigureWorker).not_to receive(:perform_async)
+ expect(ClusterConfigureWorker).not_to receive(:perform_async)
platform.username = "new-username"
platform.save
diff --git a/spec/models/concerns/cacheable_attributes_spec.rb b/spec/models/concerns/cacheable_attributes_spec.rb
index 827fbc9d7d5..689e7d3058f 100644
--- a/spec/models/concerns/cacheable_attributes_spec.rb
+++ b/spec/models/concerns/cacheable_attributes_spec.rb
@@ -20,6 +20,10 @@ describe CacheableAttributes do
@_last ||= new('foo' => 'a', 'bar' => 'b')
end
+ def self.column_names
+ %w[foo bar baz]
+ end
+
attr_accessor :attributes
def initialize(attrs = {}, *)
@@ -75,13 +79,13 @@ describe CacheableAttributes do
context 'without any attributes given' do
it 'intializes a new object with the defaults' do
- expect(minimal_test_class.build_from_defaults.attributes).to eq(minimal_test_class.defaults)
+ expect(minimal_test_class.build_from_defaults.attributes).to eq(minimal_test_class.defaults.stringify_keys)
end
end
context 'with attributes given' do
it 'intializes a new object with the given attributes merged into the defaults' do
- expect(minimal_test_class.build_from_defaults(foo: 'd').attributes[:foo]).to eq('d')
+ expect(minimal_test_class.build_from_defaults(foo: 'd').attributes['foo']).to eq('d')
end
end
diff --git a/spec/models/concerns/discussion_on_diff_spec.rb b/spec/models/concerns/discussion_on_diff_spec.rb
index 73eb7a1160d..4b16e6e3902 100644
--- a/spec/models/concerns/discussion_on_diff_spec.rb
+++ b/spec/models/concerns/discussion_on_diff_spec.rb
@@ -50,11 +50,17 @@ describe DiscussionOnDiff do
end
context "when the diff line does not exist on a legacy diff note" do
+ subject { create(:legacy_diff_note_on_merge_request).to_discussion }
+
it "returns an empty array" do
- legacy_note = LegacyDiffNote.new
+ expect(truncated_lines).to eq([])
+ end
+ end
- allow(subject).to receive(:first_note).and_return(legacy_note)
+ context 'when the discussion is on an image' do
+ subject { create(:image_diff_note_on_merge_request).to_discussion }
+ it 'returns an empty array' do
expect(truncated_lines).to eq([])
end
end
diff --git a/spec/models/concerns/has_ref_spec.rb b/spec/models/concerns/has_ref_spec.rb
new file mode 100644
index 00000000000..8aed72d77a4
--- /dev/null
+++ b/spec/models/concerns/has_ref_spec.rb
@@ -0,0 +1,59 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe HasRef do
+ describe '#branch?' do
+ let(:build) { create(:ci_build) }
+
+ subject { build.branch? }
+
+ context 'is not a tag' do
+ before do
+ build.tag = false
+ end
+
+ it 'return true when tag is set to false' do
+ is_expected.to be_truthy
+ end
+ end
+
+ context 'is not a tag' do
+ before do
+ build.tag = true
+ end
+
+ it 'return false when tag is set to true' do
+ is_expected.to be_falsey
+ end
+ end
+ end
+
+ describe '#git_ref' do
+ subject { build.git_ref }
+
+ context 'when tag is true' do
+ let(:build) { create(:ci_build, tag: true) }
+
+ it 'returns a tag ref' do
+ is_expected.to start_with(Gitlab::Git::TAG_REF_PREFIX)
+ end
+ end
+
+ context 'when tag is false' do
+ let(:build) { create(:ci_build, tag: false) }
+
+ it 'returns a branch ref' do
+ is_expected.to start_with(Gitlab::Git::BRANCH_REF_PREFIX)
+ end
+ end
+
+ context 'when tag is nil' do
+ let(:build) { create(:ci_build, tag: nil) }
+
+ it 'returns a branch ref' do
+ is_expected.to start_with(Gitlab::Git::BRANCH_REF_PREFIX)
+ end
+ end
+ end
+end
diff --git a/spec/models/diff_note_spec.rb b/spec/models/diff_note_spec.rb
index 40ce8ab736a..fda00a693f0 100644
--- a/spec/models/diff_note_spec.rb
+++ b/spec/models/diff_note_spec.rb
@@ -337,24 +337,9 @@ describe DiffNote do
end
describe "image diff notes" do
- let(:path) { "files/images/any_image.png" }
-
- let!(:position) do
- Gitlab::Diff::Position.new(
- old_path: path,
- new_path: path,
- width: 10,
- height: 10,
- x: 1,
- y: 1,
- diff_refs: merge_request.diff_refs,
- position_type: "image"
- )
- end
+ subject { build(:image_diff_note_on_merge_request, project: project, noteable: merge_request) }
describe "validations" do
- subject { build(:diff_note_on_merge_request, project: project, position: position, noteable: merge_request) }
-
it { is_expected.not_to validate_presence_of(:line_code) }
it "does not validate diff line" do
diff --git a/spec/models/diff_viewer/base_spec.rb b/spec/models/diff_viewer/base_spec.rb
index c90b32c5d77..f4efe5a7b3a 100644
--- a/spec/models/diff_viewer/base_spec.rb
+++ b/spec/models/diff_viewer/base_spec.rb
@@ -58,7 +58,7 @@ describe DiffViewer::Base do
context 'when the binaryness does not match' do
before do
- allow_any_instance_of(Blob).to receive(:binary?).and_return(true)
+ allow_any_instance_of(Blob).to receive(:binary_in_repo?).and_return(true)
end
it 'returns false' do
@@ -141,4 +141,25 @@ describe DiffViewer::Base do
end
end
end
+
+ describe '#render_error_message' do
+ it 'returns nothing when no render_error' do
+ expect(viewer.render_error).to be_nil
+ expect(viewer.render_error_message).to be_nil
+ end
+
+ context 'when render_error error' do
+ before do
+ allow(viewer).to receive(:render_error).and_return(:too_large)
+ end
+
+ it 'returns an error message' do
+ expect(viewer.render_error_message).to include('it is too large')
+ end
+
+ it 'includes a "view the blob" link' do
+ expect(viewer.render_error_message).to include('view the blob')
+ end
+ end
+ end
end
diff --git a/spec/models/diff_viewer/server_side_spec.rb b/spec/models/diff_viewer/server_side_spec.rb
index 98a8f6d4cc9..86b14b6ebf3 100644
--- a/spec/models/diff_viewer/server_side_spec.rb
+++ b/spec/models/diff_viewer/server_side_spec.rb
@@ -32,4 +32,24 @@ describe DiffViewer::ServerSide do
end
end
end
+
+ describe '#render_error_reason' do
+ context 'when the diff file is stored externally' do
+ before do
+ allow(diff_file).to receive(:stored_externally?).and_return(true)
+ end
+
+ it 'returns error message if stored in LFS' do
+ allow(diff_file).to receive(:external_storage).and_return(:lfs)
+
+ expect(subject.render_error_message).to include('it is stored in LFS')
+ end
+
+ it 'returns error message if stored externally' do
+ allow(diff_file).to receive(:external_storage).and_return(:foo)
+
+ expect(subject.render_error_message).to include('it is stored externally')
+ end
+ end
+ end
end
diff --git a/spec/models/event_spec.rb b/spec/models/event_spec.rb
index 81748681528..a64720f1876 100644
--- a/spec/models/event_spec.rb
+++ b/spec/models/event_spec.rb
@@ -243,6 +243,20 @@ describe Event do
expect(event.visible_to_user?(admin)).to eq true
end
end
+
+ context 'private project' do
+ let(:project) { create(:project, :private) }
+ let(:target) { note_on_issue }
+
+ it do
+ expect(event.visible_to_user?(non_member)).to eq false
+ expect(event.visible_to_user?(author)).to eq false
+ expect(event.visible_to_user?(assignee)).to eq false
+ expect(event.visible_to_user?(member)).to eq true
+ expect(event.visible_to_user?(guest)).to eq true
+ expect(event.visible_to_user?(admin)).to eq true
+ end
+ end
end
context 'merge request diff note event' do
@@ -265,8 +279,8 @@ describe Event do
it do
expect(event.visible_to_user?(non_member)).to eq false
- expect(event.visible_to_user?(author)).to eq true
- expect(event.visible_to_user?(assignee)).to eq true
+ expect(event.visible_to_user?(author)).to eq false
+ expect(event.visible_to_user?(assignee)).to eq false
expect(event.visible_to_user?(member)).to eq true
expect(event.visible_to_user?(guest)).to eq false
expect(event.visible_to_user?(admin)).to eq true
diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb
index 6793d4e8718..4cc3a6a3644 100644
--- a/spec/models/merge_request_spec.rb
+++ b/spec/models/merge_request_spec.rb
@@ -559,6 +559,57 @@ describe MergeRequest do
end
end
+ describe '#preload_discussions_diff_highlight' do
+ let(:merge_request) { create(:merge_request) }
+
+ context 'with commit diff note' do
+ let(:other_merge_request) { create(:merge_request) }
+
+ let!(:diff_note) do
+ create(:diff_note_on_commit, project: merge_request.project)
+ end
+
+ let!(:other_mr_diff_note) do
+ create(:diff_note_on_commit, project: other_merge_request.project)
+ end
+
+ it 'preloads diff highlighting' do
+ expect_next_instance_of(Gitlab::DiscussionsDiff::FileCollection) do |collection|
+ note_diff_file = diff_note.note_diff_file
+
+ expect(collection)
+ .to receive(:load_highlight)
+ .with([note_diff_file.id]).and_call_original
+ end
+
+ merge_request.preload_discussions_diff_highlight
+ end
+ end
+
+ context 'with merge request diff note' do
+ let!(:unresolved_diff_note) do
+ create(:diff_note_on_merge_request, project: merge_request.project, noteable: merge_request)
+ end
+
+ let!(:resolved_diff_note) do
+ create(:diff_note_on_merge_request, :resolved, project: merge_request.project, noteable: merge_request)
+ end
+
+ it 'preloads diff highlighting' do
+ expect_next_instance_of(Gitlab::DiscussionsDiff::FileCollection) do |collection|
+ note_diff_file = unresolved_diff_note.note_diff_file
+
+ expect(collection)
+ .to receive(:load_highlight)
+ .with([note_diff_file.id])
+ .and_call_original
+ end
+
+ merge_request.preload_discussions_diff_highlight
+ end
+ end
+ end
+
describe '#diff_size' do
let(:merge_request) do
build(:merge_request, source_branch: 'expand-collapse-files', target_branch: 'master')
diff --git a/spec/models/milestone_spec.rb b/spec/models/milestone_spec.rb
index d11eb46159e..b3d31e65c85 100644
--- a/spec/models/milestone_spec.rb
+++ b/spec/models/milestone_spec.rb
@@ -316,6 +316,15 @@ describe Milestone do
end
end
+ describe '#reference_link_text' do
+ let(:project) { build_stubbed(:project, name: 'sample-project') }
+ let(:milestone) { build_stubbed(:milestone, iid: 1, project: project, name: 'milestone') }
+
+ it 'returns the title with the reference prefix' do
+ expect(milestone.reference_link_text).to eq '%milestone'
+ end
+ end
+
describe '#participants' do
let(:project) { build(:project, name: 'sample-project') }
let(:milestone) { build(:milestone, iid: 1, project: project) }
diff --git a/spec/models/namespace_spec.rb b/spec/models/namespace_spec.rb
index 18b54cce834..475fbe56e4d 100644
--- a/spec/models/namespace_spec.rb
+++ b/spec/models/namespace_spec.rb
@@ -337,32 +337,40 @@ describe Namespace do
end
end
- it 'updates project full path in .git/config for each project inside namespace' do
- parent = create(:group, name: 'mygroup', path: 'mygroup')
- subgroup = create(:group, name: 'mysubgroup', path: 'mysubgroup', parent: parent)
- project_in_parent_group = create(:project, :legacy_storage, :repository, namespace: parent, name: 'foo1')
- hashed_project_in_subgroup = create(:project, :repository, namespace: subgroup, name: 'foo2')
- legacy_project_in_subgroup = create(:project, :legacy_storage, :repository, namespace: subgroup, name: 'foo3')
-
- parent.update(path: 'mygroup_new')
-
- # Routes are loaded when creating the projects, so we need to manually
- # reload them for the below code to be aware of the above UPDATE.
- [
- project_in_parent_group,
- hashed_project_in_subgroup,
- legacy_project_in_subgroup
- ].each do |project|
- project.route.reload
+ context 'for each project inside the namespace' do
+ let!(:parent) { create(:group, name: 'mygroup', path: 'mygroup') }
+ let!(:subgroup) { create(:group, name: 'mysubgroup', path: 'mysubgroup', parent: parent) }
+ let!(:project_in_parent_group) { create(:project, :legacy_storage, :repository, namespace: parent, name: 'foo1') }
+ let!(:hashed_project_in_subgroup) { create(:project, :repository, namespace: subgroup, name: 'foo2') }
+ let!(:legacy_project_in_subgroup) { create(:project, :legacy_storage, :repository, namespace: subgroup, name: 'foo3') }
+
+ it 'updates project full path in .git/config' do
+ parent.update(path: 'mygroup_new')
+
+ expect(project_rugged(project_in_parent_group).config['gitlab.fullpath']).to eq "mygroup_new/#{project_in_parent_group.path}"
+ expect(project_rugged(hashed_project_in_subgroup).config['gitlab.fullpath']).to eq "mygroup_new/mysubgroup/#{hashed_project_in_subgroup.path}"
+ expect(project_rugged(legacy_project_in_subgroup).config['gitlab.fullpath']).to eq "mygroup_new/mysubgroup/#{legacy_project_in_subgroup.path}"
end
- expect(project_rugged(project_in_parent_group).config['gitlab.fullpath']).to eq "mygroup_new/#{project_in_parent_group.path}"
- expect(project_rugged(hashed_project_in_subgroup).config['gitlab.fullpath']).to eq "mygroup_new/mysubgroup/#{hashed_project_in_subgroup.path}"
- expect(project_rugged(legacy_project_in_subgroup).config['gitlab.fullpath']).to eq "mygroup_new/mysubgroup/#{legacy_project_in_subgroup.path}"
- end
+ it 'updates the project storage location' do
+ repository_project_in_parent_group = create(:project_repository, project: project_in_parent_group)
+ repository_hashed_project_in_subgroup = create(:project_repository, project: hashed_project_in_subgroup)
+ repository_legacy_project_in_subgroup = create(:project_repository, project: legacy_project_in_subgroup)
+
+ parent.update(path: 'mygroup_moved')
+
+ expect(repository_project_in_parent_group.reload.disk_path).to eq "mygroup_moved/#{project_in_parent_group.path}"
+ expect(repository_hashed_project_in_subgroup.reload.disk_path).to eq hashed_project_in_subgroup.disk_path
+ expect(repository_legacy_project_in_subgroup.reload.disk_path).to eq "mygroup_moved/mysubgroup/#{legacy_project_in_subgroup.path}"
+ end
+
+ def project_rugged(project)
+ # Routes are loaded when creating the projects, so we need to manually
+ # reload them for the below code to be aware of the above UPDATE.
+ project.route.reload
- def project_rugged(project)
- rugged_repo(project.repository)
+ rugged_repo(project.repository)
+ end
end
end
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index 3ba00e2f25d..4b6592020c1 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -299,6 +299,13 @@ describe Project do
expect(project.errors[:import_url].first).to include('Requests to localhost are not allowed')
end
+ it 'does not allow import_url pointing to the local network' do
+ project = build(:project, import_url: 'https://192.168.1.1')
+
+ expect(project).to be_invalid
+ expect(project.errors[:import_url].first).to include('Requests to the local network are not allowed')
+ end
+
it "does not allow import_url with invalid ports for new projects" do
project = build(:project, import_url: 'http://github.com:25/t.git')
@@ -1651,26 +1658,54 @@ describe Project do
end
describe '#track_project_repository' do
- let(:project) { create(:project, :repository) }
+ shared_examples 'tracks storage location' do
+ context 'when a project repository entry does not exist' do
+ it 'creates a new entry' do
+ expect { project.track_project_repository }.to change(project, :project_repository)
+ end
+
+ it 'tracks the project storage location' do
+ project.track_project_repository
+
+ expect(project.project_repository).to have_attributes(
+ disk_path: project.disk_path,
+ shard_name: project.repository_storage
+ )
+ end
+ end
- it 'creates a project_repository' do
- project.track_project_repository
+ context 'when a tracking entry exists' do
+ let!(:project_repository) { create(:project_repository, project: project) }
+ let!(:shard) { create(:shard, name: 'foo') }
- expect(project.reload.project_repository).to be_present
- expect(project.project_repository.disk_path).to eq(project.disk_path)
- expect(project.project_repository.shard_name).to eq(project.repository_storage)
+ it 'does not create a new entry in the database' do
+ expect { project.track_project_repository }.not_to change(project, :project_repository)
+ end
+
+ it 'updates the project storage location' do
+ allow(project).to receive(:disk_path).and_return('fancy/new/path')
+ allow(project).to receive(:repository_storage).and_return('foo')
+
+ project.track_project_repository
+
+ expect(project.project_repository).to have_attributes(
+ disk_path: 'fancy/new/path',
+ shard_name: 'foo'
+ )
+ end
+ end
end
- it 'updates the project_repository' do
- project.track_project_repository
+ context 'with projects on legacy storage' do
+ let(:project) { create(:project, :repository, :legacy_storage) }
- allow(project).to receive(:disk_path).and_return('@fancy/new/path')
+ it_behaves_like 'tracks storage location'
+ end
- expect do
- project.track_project_repository
- end.not_to change(ProjectRepository, :count)
+ context 'with projects on hashed storage' do
+ let(:project) { create(:project, :repository) }
- expect(project.reload.project_repository.disk_path).to eq(project.disk_path)
+ it_behaves_like 'tracks storage location'
end
end
@@ -2515,6 +2550,10 @@ describe Project do
end
context 'when the ref is not protected' do
+ before do
+ allow(project).to receive(:protected_for?).with('ref').and_return(false)
+ end
+
it 'contains only the CI variables' do
is_expected.to contain_exactly(ci_variable)
end
@@ -2554,42 +2593,139 @@ describe Project do
end
describe '#protected_for?' do
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
- subject { project.protected_for?('ref') }
+ subject { project.protected_for?(ref) }
- context 'when the ref is not protected' do
+ shared_examples 'ref is not protected' do
before do
stub_application_setting(
default_branch_protection: Gitlab::Access::PROTECTION_NONE)
end
it 'returns false' do
- is_expected.to be_falsey
+ is_expected.to be false
end
end
- context 'when the ref is a protected branch' do
+ shared_examples 'ref is protected branch' do
before do
- allow(project).to receive(:repository).and_call_original
- allow(project).to receive_message_chain(:repository, :branch_exists?).and_return(true)
- create(:protected_branch, name: 'ref', project: project)
+ create(:protected_branch, name: 'master', project: project)
end
it 'returns true' do
- is_expected.to be_truthy
+ is_expected.to be true
end
end
- context 'when the ref is a protected tag' do
+ shared_examples 'ref is protected tag' do
before do
- allow(project).to receive_message_chain(:repository, :branch_exists?).and_return(false)
- allow(project).to receive_message_chain(:repository, :tag_exists?).and_return(true)
- create(:protected_tag, name: 'ref', project: project)
+ create(:protected_tag, name: 'v1.0.0', project: project)
end
it 'returns true' do
- is_expected.to be_truthy
+ is_expected.to be true
+ end
+ end
+
+ context 'when ref is nil' do
+ let(:ref) { nil }
+
+ it 'returns false' do
+ is_expected.to be false
+ end
+ end
+
+ context 'when ref is ref name' do
+ context 'when ref is ambiguous' do
+ let(:ref) { 'ref' }
+
+ before do
+ project.repository.add_branch(project.creator, 'ref', 'master')
+ project.repository.add_tag(project.creator, 'ref', 'master')
+ end
+
+ it 'raises an error' do
+ expect { subject }.to raise_error(Repository::AmbiguousRefError)
+ end
+ end
+
+ context 'when the ref is not protected' do
+ let(:ref) { 'master' }
+
+ it_behaves_like 'ref is not protected'
+ end
+
+ context 'when the ref is a protected branch' do
+ let(:ref) { 'master' }
+
+ it_behaves_like 'ref is protected branch'
+ end
+
+ context 'when the ref is a protected tag' do
+ let(:ref) { 'v1.0.0' }
+
+ it_behaves_like 'ref is protected tag'
+ end
+
+ context 'when ref does not exist' do
+ let(:ref) { 'something' }
+
+ it 'returns false' do
+ is_expected.to be false
+ end
+ end
+ end
+
+ context 'when ref is full ref' do
+ context 'when the ref is not protected' do
+ let(:ref) { 'refs/heads/master' }
+
+ it_behaves_like 'ref is not protected'
+ end
+
+ context 'when the ref is a protected branch' do
+ let(:ref) { 'refs/heads/master' }
+
+ it_behaves_like 'ref is protected branch'
+ end
+
+ context 'when the ref is a protected tag' do
+ let(:ref) { 'refs/tags/v1.0.0' }
+
+ it_behaves_like 'ref is protected tag'
+ end
+
+ context 'when branch ref name is a full tag ref' do
+ let(:ref) { 'refs/tags/something' }
+
+ before do
+ project.repository.add_branch(project.creator, ref, 'master')
+ end
+
+ context 'when ref is not protected' do
+ it 'returns false' do
+ is_expected.to be false
+ end
+ end
+
+ context 'when ref is a protected branch' do
+ before do
+ create(:protected_branch, name: 'refs/tags/something', project: project)
+ end
+
+ it 'returns true' do
+ is_expected.to be true
+ end
+ end
+ end
+
+ context 'when ref does not exist' do
+ let(:ref) { 'refs/heads/something' }
+
+ it 'returns false' do
+ is_expected.to be false
+ end
end
end
end
@@ -2809,7 +2945,7 @@ describe Project do
it 'shows full error updating an invalid MR' do
error_message = 'Failed to replace merge_requests because one or more of the new records could not be saved.'\
- ' Validate fork Source project is not a fork of the target project'
+ ' Validate fork Source project is not a fork of the target project'
expect { project.append_or_update_attribute(:merge_requests, [create(:merge_request)]) }
.to raise_error(ActiveRecord::RecordNotSaved, error_message)
@@ -3675,7 +3811,7 @@ describe Project do
expect(project.badges.count).to eq 3
end
- if Group.supports_nested_groups?
+ if Group.supports_nested_objects?
context 'with nested_groups' do
let(:parent_group) { create(:group) }
diff --git a/spec/models/prometheus_metric_spec.rb b/spec/models/prometheus_metric_spec.rb
index 3692fe9a559..2b978c1c8ff 100644
--- a/spec/models/prometheus_metric_spec.rb
+++ b/spec/models/prometheus_metric_spec.rb
@@ -59,11 +59,65 @@ describe PrometheusMetric do
end
end
+ it_behaves_like 'group_title', :nginx_ingress_vts, 'Response metrics (NGINX Ingress VTS)'
+ it_behaves_like 'group_title', :nginx_ingress, 'Response metrics (NGINX Ingress)'
+ it_behaves_like 'group_title', :ha_proxy, 'Response metrics (HA Proxy)'
+ it_behaves_like 'group_title', :aws_elb, 'Response metrics (AWS ELB)'
+ it_behaves_like 'group_title', :nginx, 'Response metrics (NGINX)'
+ it_behaves_like 'group_title', :kubernetes, 'System metrics (Kubernetes)'
it_behaves_like 'group_title', :business, 'Business metrics (Custom)'
it_behaves_like 'group_title', :response, 'Response metrics (Custom)'
it_behaves_like 'group_title', :system, 'System metrics (Custom)'
end
+ describe '#priority' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:group, :priority) do
+ :nginx_ingress_vts | 10
+ :nginx_ingress | 10
+ :ha_proxy | 10
+ :aws_elb | 10
+ :nginx | 10
+ :kubernetes | 5
+ :business | 0
+ :response | -5
+ :system | -10
+ end
+
+ with_them do
+ before do
+ subject.group = group
+ end
+
+ it { expect(subject.priority).to eq(priority) }
+ end
+ end
+
+ describe '#required_metrics' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:group, :required_metrics) do
+ :nginx_ingress_vts | %w(nginx_upstream_responses_total nginx_upstream_response_msecs_avg)
+ :nginx_ingress | %w(nginx_ingress_controller_requests nginx_ingress_controller_ingress_upstream_latency_seconds_sum)
+ :ha_proxy | %w(haproxy_frontend_http_requests_total haproxy_frontend_http_responses_total)
+ :aws_elb | %w(aws_elb_request_count_sum aws_elb_latency_average aws_elb_httpcode_backend_5_xx_sum)
+ :nginx | %w(nginx_server_requests nginx_server_requestMsec)
+ :kubernetes | %w(container_memory_usage_bytes container_cpu_usage_seconds_total)
+ :business | %w()
+ :response | %w()
+ :system | %w()
+ end
+
+ with_them do
+ before do
+ subject.group = group
+ end
+
+ it { expect(subject.required_metrics).to eq(required_metrics) }
+ end
+ end
+
describe '#to_query_metric' do
it 'converts to queryable metric object' do
expect(subject.to_query_metric).to be_instance_of(Gitlab::Prometheus::Metric)
diff --git a/spec/models/release_spec.rb b/spec/models/release_spec.rb
index 51725eeacac..92ba2d82f58 100644
--- a/spec/models/release_spec.rb
+++ b/spec/models/release_spec.rb
@@ -1,7 +1,9 @@
require 'rails_helper'
RSpec.describe Release do
- let(:release) { create(:release) }
+ let(:user) { create(:user) }
+ let(:project) { create(:project, :public, :repository) }
+ let(:release) { create(:release, project: project, author: user) }
it { expect(release).to be_valid }
diff --git a/spec/models/remote_mirror_spec.rb b/spec/models/remote_mirror_spec.rb
index 5d3c25062d5..224bc9ed935 100644
--- a/spec/models/remote_mirror_spec.rb
+++ b/spec/models/remote_mirror_spec.rb
@@ -24,6 +24,20 @@ describe RemoteMirror, :mailer do
expect(remote_mirror).to be_invalid
expect(remote_mirror.errors[:url].first).to include('Username needs to start with an alphanumeric character')
end
+
+ it 'does not allow url pointing to localhost' do
+ remote_mirror = build(:remote_mirror, url: 'http://127.0.0.2/t.git')
+
+ expect(remote_mirror).to be_invalid
+ expect(remote_mirror.errors[:url].first).to include('Requests to loopback addresses are not allowed')
+ end
+
+ it 'does not allow url pointing to the local network' do
+ remote_mirror = build(:remote_mirror, url: 'https://192.168.1.1')
+
+ expect(remote_mirror).to be_invalid
+ expect(remote_mirror.errors[:url].first).to include('Requests to the local network are not allowed')
+ end
end
end
diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb
index f09b4b67061..2063b4bbe75 100644
--- a/spec/models/repository_spec.rb
+++ b/spec/models/repository_spec.rb
@@ -1005,6 +1005,67 @@ describe Repository do
end
end
+ describe '#ambiguous_ref?' do
+ let(:ref) { 'ref' }
+
+ subject { repository.ambiguous_ref?(ref) }
+
+ context 'when ref is ambiguous' do
+ before do
+ repository.add_tag(project.creator, ref, 'master')
+ repository.add_branch(project.creator, ref, 'master')
+ end
+
+ it 'should be true' do
+ is_expected.to eq(true)
+ end
+ end
+
+ context 'when ref is not ambiguous' do
+ before do
+ repository.add_tag(project.creator, ref, 'master')
+ end
+
+ it 'should be false' do
+ is_expected.to eq(false)
+ end
+ end
+ end
+
+ describe '#expand_ref' do
+ let(:ref) { 'ref' }
+
+ subject { repository.expand_ref(ref) }
+
+ context 'when ref is not tag or branch name' do
+ let(:ref) { 'refs/heads/master' }
+
+ it 'returns nil' do
+ is_expected.to eq(nil)
+ end
+ end
+
+ context 'when ref is tag name' do
+ before do
+ repository.add_tag(project.creator, ref, 'master')
+ end
+
+ it 'returns the tag ref' do
+ is_expected.to eq("refs/tags/#{ref}")
+ end
+ end
+
+ context 'when ref is branch name' do
+ before do
+ repository.add_branch(project.creator, ref, 'master')
+ end
+
+ it 'returns the branch ref' do
+ is_expected.to eq("refs/heads/#{ref}")
+ end
+ end
+ end
+
describe '#add_branch' do
let(:branch_name) { 'new_feature' }
let(:target) { 'master' }
diff --git a/spec/models/snippet_spec.rb b/spec/models/snippet_spec.rb
index 7a7272ccb60..664dc3fa145 100644
--- a/spec/models/snippet_spec.rb
+++ b/spec/models/snippet_spec.rb
@@ -423,4 +423,41 @@ describe Snippet do
expect(blob.data).to eq(snippet.content)
end
end
+
+ describe '#embeddable?' do
+ context 'project snippet' do
+ [
+ { project: :public, snippet: :public, embeddable: true },
+ { project: :internal, snippet: :public, embeddable: false },
+ { project: :private, snippet: :public, embeddable: false },
+ { project: :public, snippet: :internal, embeddable: false },
+ { project: :internal, snippet: :internal, embeddable: false },
+ { project: :private, snippet: :internal, embeddable: false },
+ { project: :public, snippet: :private, embeddable: false },
+ { project: :internal, snippet: :private, embeddable: false },
+ { project: :private, snippet: :private, embeddable: false }
+ ].each do |combination|
+ it 'only returns true when both project and snippet are public' do
+ project = create(:project, combination[:project])
+ snippet = create(:project_snippet, combination[:snippet], project: project)
+
+ expect(snippet.embeddable?).to eq(combination[:embeddable])
+ end
+ end
+ end
+
+ context 'personal snippet' do
+ [
+ { snippet: :public, embeddable: true },
+ { snippet: :internal, embeddable: false },
+ { snippet: :private, embeddable: false }
+ ].each do |combination|
+ it 'only returns true when snippet is public' do
+ snippet = create(:personal_snippet, combination[:snippet])
+
+ expect(snippet.embeddable?).to eq(combination[:embeddable])
+ end
+ end
+ end
+ end
end
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index 8b3021113bc..33842e74b92 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -1966,7 +1966,7 @@ describe User do
subject { user.membership_groups }
- if Group.supports_nested_groups?
+ if Group.supports_nested_objects?
it { is_expected.to contain_exactly parent_group, child_group }
else
it { is_expected.to contain_exactly parent_group }
@@ -2347,7 +2347,7 @@ describe User do
group.add_owner(user)
end
- if Group.supports_nested_groups?
+ if Group.supports_nested_objects?
it 'returns all groups' do
is_expected.to match_array [
group,
diff --git a/spec/policies/group_policy_spec.rb b/spec/policies/group_policy_spec.rb
index 9d0093e8159..be1804c5ce0 100644
--- a/spec/policies/group_policy_spec.rb
+++ b/spec/policies/group_policy_spec.rb
@@ -25,7 +25,8 @@ describe GroupPolicy do
:read_cluster,
:create_cluster,
:update_cluster,
- :admin_cluster
+ :admin_cluster,
+ :add_cluster
]
end
@@ -147,7 +148,7 @@ describe GroupPolicy do
let(:current_user) { owner }
it do
- allow(Group).to receive(:supports_nested_groups?).and_return(true)
+ allow(Group).to receive(:supports_nested_objects?).and_return(true)
expect_allowed(*guest_permissions)
expect_allowed(*reporter_permissions)
@@ -161,7 +162,7 @@ describe GroupPolicy do
let(:current_user) { admin }
it do
- allow(Group).to receive(:supports_nested_groups?).and_return(true)
+ allow(Group).to receive(:supports_nested_objects?).and_return(true)
expect_allowed(*guest_permissions)
expect_allowed(*reporter_permissions)
@@ -173,7 +174,7 @@ describe GroupPolicy do
describe 'when nested group support feature is disabled' do
before do
- allow(Group).to receive(:supports_nested_groups?).and_return(false)
+ allow(Group).to receive(:supports_nested_objects?).and_return(false)
end
context 'admin' do
@@ -282,7 +283,7 @@ describe GroupPolicy do
let(:current_user) { owner }
it do
- allow(Group).to receive(:supports_nested_groups?).and_return(true)
+ allow(Group).to receive(:supports_nested_objects?).and_return(true)
expect_allowed(*guest_permissions)
expect_allowed(*reporter_permissions)
@@ -382,4 +383,14 @@ describe GroupPolicy do
it { expect_disallowed(:change_share_with_group_lock) }
end
end
+
+ it_behaves_like 'clusterable policies' do
+ let(:clusterable) { create(:group) }
+ let(:cluster) do
+ create(:cluster,
+ :provided_by_gcp,
+ :group,
+ groups: [clusterable])
+ end
+ end
end
diff --git a/spec/policies/issuable_policy_spec.rb b/spec/policies/issuable_policy_spec.rb
index d1bf98995e7..db3df760472 100644
--- a/spec/policies/issuable_policy_spec.rb
+++ b/spec/policies/issuable_policy_spec.rb
@@ -7,6 +7,33 @@ describe IssuablePolicy, models: true do
let(:policies) { described_class.new(user, issue) }
describe '#rules' do
+ context 'when user is author of issuable' do
+ let(:merge_request) { create(:merge_request, source_project: project, author: user) }
+ let(:policies) { described_class.new(user, merge_request) }
+
+ context 'when user is able to read project' do
+ it 'enables user to read and update issuables' do
+ expect(policies).to be_allowed(:read_issue, :update_issue, :reopen_issue, :read_merge_request, :update_merge_request)
+ end
+ end
+
+ context 'when project is private' do
+ let(:project) { create(:project, :private) }
+
+ context 'when user belongs to the projects team' do
+ it 'enables user to read and update issuables' do
+ project.add_maintainer(user)
+
+ expect(policies).to be_allowed(:read_issue, :update_issue, :reopen_issue, :read_merge_request, :update_merge_request)
+ end
+ end
+
+ it 'disallows user from reading and updating issuables from that project' do
+ expect(policies).to be_disallowed(:read_issue, :update_issue, :reopen_issue, :read_merge_request, :update_merge_request)
+ end
+ end
+ end
+
context 'when discussion is locked for the issuable' do
let(:issue) { create(:issue, project: project, discussion_locked: true) }
diff --git a/spec/policies/project_policy_spec.rb b/spec/policies/project_policy_spec.rb
index 69468f9ad85..9cb20854f6e 100644
--- a/spec/policies/project_policy_spec.rb
+++ b/spec/policies/project_policy_spec.rb
@@ -15,7 +15,7 @@ describe ProjectPolicy do
read_project_for_iids read_issue_iid read_merge_request_iid read_label
read_milestone read_project_snippet read_project_member read_note
create_project create_issue create_note upload_file create_merge_request_in
- award_emoji
+ award_emoji read_release
]
end
@@ -38,7 +38,7 @@ describe ProjectPolicy do
update_commit_status create_build update_build create_pipeline
update_pipeline create_merge_request_from create_wiki push_code
resolve_note create_container_image update_container_image
- create_environment create_deployment
+ create_environment create_deployment create_release update_release
]
end
@@ -48,7 +48,7 @@ describe ProjectPolicy do
update_deployment admin_project_snippet
admin_project_member admin_note admin_wiki admin_project
admin_commit_status admin_build admin_container_image
- admin_pipeline admin_environment admin_deployment
+ admin_pipeline admin_environment admin_deployment destroy_release add_cluster
]
end
@@ -56,7 +56,7 @@ describe ProjectPolicy do
%i[
download_code fork_project read_commit_status read_pipeline
read_container_image build_download_code build_read_container_image
- download_wiki_code
+ download_wiki_code read_release
]
end
@@ -183,7 +183,8 @@ describe ProjectPolicy do
:create_pipeline_schedule, :read_pipeline_schedule, :update_pipeline_schedule, :admin_pipeline_schedule, :destroy_pipeline_schedule,
:create_environment, :read_environment, :update_environment, :admin_environment, :destroy_environment,
:create_cluster, :read_cluster, :update_cluster, :admin_cluster,
- :create_deployment, :read_deployment, :update_deployment, :admin_deployment, :destroy_deployment
+ :create_deployment, :read_deployment, :update_deployment, :admin_deployment, :destroy_deployment,
+ :destroy_release
]
expect_disallowed(*repository_permissions)
@@ -465,4 +466,14 @@ describe ProjectPolicy do
expect_disallowed(*maintainer_abilities)
end
end
+
+ it_behaves_like 'clusterable policies' do
+ let(:clusterable) { create(:project, :repository) }
+ let(:cluster) do
+ create(:cluster,
+ :provided_by_gcp,
+ :project,
+ projects: [clusterable])
+ end
+ end
end
diff --git a/spec/presenters/clusterable_presenter_spec.rb b/spec/presenters/clusterable_presenter_spec.rb
index 4f4ae5e07c5..05afe5347d1 100644
--- a/spec/presenters/clusterable_presenter_spec.rb
+++ b/spec/presenters/clusterable_presenter_spec.rb
@@ -14,4 +14,68 @@ describe ClusterablePresenter do
expect(subject).to be_kind_of(ProjectClusterablePresenter)
end
end
+
+ shared_examples 'appropriate member permissions' do
+ context 'with a developer' do
+ before do
+ clusterable.add_developer(user)
+ end
+
+ it { is_expected.to be_falsy }
+ end
+
+ context 'with a maintainer' do
+ before do
+ clusterable.add_maintainer(user)
+ end
+
+ it { is_expected.to be_truthy }
+ end
+ end
+
+ describe '#can_create_cluster?' do
+ let(:user) { create(:user) }
+
+ subject { described_class.new(clusterable).can_create_cluster? }
+
+ before do
+ allow(clusterable).to receive(:current_user).and_return(user)
+ end
+
+ context 'when clusterable is a group' do
+ let(:clusterable) { create(:group) }
+
+ it_behaves_like 'appropriate member permissions'
+ end
+
+ context 'when clusterable is a project' do
+ let(:clusterable) { create(:project, :repository) }
+
+ it_behaves_like 'appropriate member permissions'
+ end
+ end
+
+ describe '#can_add_cluster?' do
+ let(:user) { create(:user) }
+
+ subject { described_class.new(clusterable).can_add_cluster? }
+
+ before do
+ clusterable.add_maintainer(user)
+
+ allow(clusterable).to receive(:current_user).and_return(user)
+ end
+
+ context 'when clusterable is a group' do
+ let(:clusterable) { create(:group) }
+
+ it_behaves_like 'appropriate member permissions'
+ end
+
+ context 'when clusterable is a project' do
+ let(:clusterable) { create(:project, :repository) }
+
+ it_behaves_like 'appropriate member permissions'
+ end
+ end
end
diff --git a/spec/requests/api/branches_spec.rb b/spec/requests/api/branches_spec.rb
index 93c411476bb..b38cd66986f 100644
--- a/spec/requests/api/branches_spec.rb
+++ b/spec/requests/api/branches_spec.rb
@@ -20,6 +20,12 @@ describe API::Branches do
let(:route) { "/projects/#{project_id}/repository/branches" }
shared_examples_for 'repository branches' do
+ RSpec::Matchers.define :has_merged_branch_names_count do |expected|
+ match do |actual|
+ actual[:merged_branch_names].count == expected
+ end
+ end
+
it 'returns the repository branches' do
get api(route, current_user), params: { per_page: 100 }
@@ -30,6 +36,12 @@ describe API::Branches do
expect(branch_names).to match_array(project.repository.branch_names)
end
+ it 'determines only a limited number of merged branch names' do
+ expect(API::Entities::Branch).to receive(:represent).with(anything, has_merged_branch_names_count(2))
+
+ get api(route, current_user), params: { per_page: 2 }
+ end
+
context 'when repository is disabled' do
include_context 'disabled repository'
diff --git a/spec/requests/api/events_spec.rb b/spec/requests/api/events_spec.rb
index 8c58ba45ce9..0ac23505de7 100644
--- a/spec/requests/api/events_spec.rb
+++ b/spec/requests/api/events_spec.rb
@@ -226,7 +226,7 @@ describe API::Events do
end
it 'correctly returns the second page without inaccessible events' do
- get api("/projects/#{public_project.id}/events", user), per_page: 2, page: 2
+ get api("/projects/#{public_project.id}/events", user), params: { per_page: 2, page: 2 }
titles = json_response.map { |event| event['target_title'] }
@@ -235,7 +235,7 @@ describe API::Events do
end
it 'correctly returns the first page without inaccessible events' do
- get api("/projects/#{public_project.id}/events", user), per_page: 2, page: 1
+ get api("/projects/#{public_project.id}/events", user), params: { per_page: 2, page: 1 }
titles = json_response.map { |event| event['target_title'] }
diff --git a/spec/requests/api/files_spec.rb b/spec/requests/api/files_spec.rb
index e6d82448c0d..a0aee937185 100644
--- a/spec/requests/api/files_spec.rb
+++ b/spec/requests/api/files_spec.rb
@@ -54,7 +54,7 @@ describe API::Files do
describe "HEAD /projects/:id/repository/files/:file_path" do
shared_examples_for 'repository files' do
it 'returns file attributes in headers' do
- head api(route(file_path), current_user), params
+ head api(route(file_path), current_user), params: params
expect(response).to have_gitlab_http_status(200)
expect(response.headers['X-Gitlab-File-Path']).to eq(CGI.unescape(file_path))
@@ -68,7 +68,7 @@ describe API::Files do
file_path = "files%2Fjs%2Fcommit%2Ejs%2Ecoffee"
params[:ref] = "6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9"
- head api(route(file_path), current_user), params
+ head api(route(file_path), current_user), params: params
expect(response).to have_gitlab_http_status(200)
expect(response.headers['X-Gitlab-File-Name']).to eq('commit.js.coffee')
@@ -87,7 +87,7 @@ describe API::Files do
it "responds with a 404 status" do
params[:ref] = 'master'
- head api(route('app%2Fmodels%2Fapplication%2Erb'), current_user), params
+ head api(route('app%2Fmodels%2Fapplication%2Erb'), current_user), params: params
expect(response).to have_gitlab_http_status(404)
end
@@ -97,7 +97,7 @@ describe API::Files do
include_context 'disabled repository'
it "responds with a 403 status" do
- head api(route(file_path), current_user), params
+ head api(route(file_path), current_user), params: params
expect(response).to have_gitlab_http_status(403)
end
@@ -115,7 +115,7 @@ describe API::Files do
it "responds with a 404 status" do
current_user = nil
- head api(route(file_path), current_user), params
+ head api(route(file_path), current_user), params: params
expect(response).to have_gitlab_http_status(404)
end
@@ -136,7 +136,7 @@ describe API::Files do
context 'when authenticated', 'as a guest' do
it_behaves_like '403 response' do
- let(:request) { head api(route(file_path), guest), params }
+ let(:request) { head api(route(file_path), guest), params: params }
end
end
end
@@ -190,7 +190,7 @@ describe API::Files do
get api(url, current_user), params: params
- expect(headers['Content-Disposition']).to match(/^attachment/)
+ expect(headers['Content-Disposition']).to eq('attachment; filename="popen.rb"')
end
context 'when mandatory params are not given' do
diff --git a/spec/requests/api/internal_spec.rb b/spec/requests/api/internal_spec.rb
index 589816b5d8f..0fe63e2e517 100644
--- a/spec/requests/api/internal_spec.rb
+++ b/spec/requests/api/internal_spec.rb
@@ -809,7 +809,8 @@ describe API::Internal do
gl_repository: gl_repository,
secret_token: secret_token,
identifier: identifier,
- changes: changes
+ changes: changes,
+ push_options: push_options
}
end
@@ -817,6 +818,11 @@ describe API::Internal do
"#{Gitlab::Git::BLANK_SHA} 570e7b2abdd848b95f2f578043fc23bd6f6fd24d refs/heads/new_branch"
end
+ let(:push_options) do
+ ['ci.skip',
+ 'another push option']
+ end
+
before do
project.add_developer(user)
allow(described_class).to receive(:identify).and_return(user)
@@ -825,7 +831,7 @@ describe API::Internal do
it 'enqueues a PostReceive worker job' do
expect(PostReceive).to receive(:perform_async)
- .with(gl_repository, identifier, changes)
+ .with(gl_repository, identifier, changes, push_options)
post api("/internal/post_receive"), params: valid_params
end
diff --git a/spec/requests/api/jobs_spec.rb b/spec/requests/api/jobs_spec.rb
index 73131dba542..97aa71bf231 100644
--- a/spec/requests/api/jobs_spec.rb
+++ b/spec/requests/api/jobs_spec.rb
@@ -142,10 +142,20 @@ describe API::Jobs do
end
context 'unauthorized user' do
- let(:api_user) { nil }
+ context 'when user is not logged in' do
+ let(:api_user) { nil }
- it 'does not return project jobs' do
- expect(response).to have_gitlab_http_status(401)
+ it 'does not return project jobs' do
+ expect(response).to have_gitlab_http_status(401)
+ end
+ end
+
+ context 'when user is guest' do
+ let(:api_user) { guest }
+
+ it 'does not return project jobs' do
+ expect(response).to have_gitlab_http_status(403)
+ end
end
end
@@ -241,10 +251,20 @@ describe API::Jobs do
end
context 'unauthorized user' do
- let(:api_user) { nil }
+ context 'when user is not logged in' do
+ let(:api_user) { nil }
- it 'does not return jobs' do
- expect(response).to have_gitlab_http_status(401)
+ it 'does not return jobs' do
+ expect(response).to have_gitlab_http_status(401)
+ end
+ end
+
+ context 'when user is guest' do
+ let(:api_user) { guest }
+
+ it 'does not return jobs' do
+ expect(response).to have_gitlab_http_status(403)
+ end
end
end
end
diff --git a/spec/requests/api/releases_spec.rb b/spec/requests/api/releases_spec.rb
new file mode 100644
index 00000000000..a44e37f9cd5
--- /dev/null
+++ b/spec/requests/api/releases_spec.rb
@@ -0,0 +1,532 @@
+require 'spec_helper'
+
+describe API::Releases do
+ let(:project) { create(:project, :repository, :private) }
+ let(:maintainer) { create(:user) }
+ let(:reporter) { create(:user) }
+ let(:non_project_member) { create(:user) }
+ let(:commit) { create(:commit, project: project) }
+
+ before do
+ project.add_maintainer(maintainer)
+ project.add_reporter(reporter)
+
+ project.repository.add_tag(maintainer, 'v0.1', commit.id)
+ project.repository.add_tag(maintainer, 'v0.2', commit.id)
+ end
+
+ describe 'GET /projects/:id/releases' do
+ context 'when there are two releases' do
+ let!(:release_1) do
+ create(:release,
+ project: project,
+ tag: 'v0.1',
+ author: maintainer,
+ created_at: 2.days.ago)
+ end
+
+ let!(:release_2) do
+ create(:release,
+ project: project,
+ tag: 'v0.2',
+ author: maintainer,
+ created_at: 1.day.ago)
+ end
+
+ it 'returns 200 HTTP status' do
+ get api("/projects/#{project.id}/releases", maintainer)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+
+ it 'returns releases ordered by created_at' do
+ get api("/projects/#{project.id}/releases", maintainer)
+
+ expect(json_response.count).to eq(2)
+ expect(json_response.first['tag_name']).to eq(release_2.tag)
+ expect(json_response.second['tag_name']).to eq(release_1.tag)
+ end
+
+ it 'matches response schema' do
+ get api("/projects/#{project.id}/releases", maintainer)
+
+ expect(response).to match_response_schema('releases')
+ end
+ end
+
+ context 'when tag does not exist in git repository' do
+ let!(:release) { create(:release, project: project, tag: 'v1.1.5') }
+
+ it 'returns the tag' do
+ get api("/projects/#{project.id}/releases", maintainer)
+
+ expect(json_response.count).to eq(1)
+ expect(json_response.first['tag_name']).to eq('v1.1.5')
+ expect(release).to be_tag_missing
+ end
+ end
+
+ context 'when user is not a project member' do
+ it 'cannot find the project' do
+ get api("/projects/#{project.id}/releases", non_project_member)
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+
+ context 'when project is public' do
+ let(:project) { create(:project, :repository, :public) }
+
+ it 'allows the request' do
+ get api("/projects/#{project.id}/releases", non_project_member)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+ end
+ end
+
+ context 'when feature flag is disabled' do
+ before do
+ stub_feature_flags(releases_page: false)
+ end
+
+ it 'cannot find the API' do
+ get api("/projects/#{project.id}/releases", maintainer)
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+ end
+
+ describe 'GET /projects/:id/releases/:tag_name' do
+ context 'when there is a release' do
+ let!(:release) do
+ create(:release,
+ project: project,
+ tag: 'v0.1',
+ sha: commit.id,
+ author: maintainer,
+ description: 'This is v0.1')
+ end
+
+ it 'returns 200 HTTP status' do
+ get api("/projects/#{project.id}/releases/v0.1", maintainer)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+
+ it 'returns a release entry' do
+ get api("/projects/#{project.id}/releases/v0.1", maintainer)
+
+ expect(json_response['tag_name']).to eq(release.tag)
+ expect(json_response['description']).to eq('This is v0.1')
+ expect(json_response['author']['name']).to eq(maintainer.name)
+ expect(json_response['commit']['id']).to eq(commit.id)
+ end
+
+ it 'matches response schema' do
+ get api("/projects/#{project.id}/releases/v0.1", maintainer)
+
+ expect(response).to match_response_schema('release')
+ end
+ end
+
+ context 'when specified tag is not found in the project' do
+ it 'cannot find the release entry' do
+ get api("/projects/#{project.id}/releases/non_exist_tag", maintainer)
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ end
+ end
+
+ context 'when user is not a project member' do
+ let!(:release) { create(:release, tag: 'v0.1', project: project) }
+
+ it 'cannot find the project' do
+ get api("/projects/#{project.id}/releases/v0.1", non_project_member)
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+
+ context 'when project is public' do
+ let(:project) { create(:project, :repository, :public) }
+
+ it 'allows the request' do
+ get api("/projects/#{project.id}/releases/v0.1", non_project_member)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+ end
+ end
+
+ context 'when feature flag is disabled' do
+ before do
+ stub_feature_flags(releases_page: false)
+ end
+
+ it 'cannot find the API' do
+ get api("/projects/#{project.id}/releases/v0.1", maintainer)
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+ end
+
+ describe 'POST /projects/:id/releases' do
+ let(:params) do
+ {
+ name: 'New release',
+ tag_name: 'v0.1',
+ description: 'Super nice release'
+ }
+ end
+
+ it 'accepts the request' do
+ post api("/projects/#{project.id}/releases", maintainer), params: params
+
+ expect(response).to have_gitlab_http_status(:created)
+ end
+
+ it 'creates a new release' do
+ expect do
+ post api("/projects/#{project.id}/releases", maintainer), params: params
+ end.to change { Release.count }.by(1)
+
+ expect(project.releases.last.name).to eq('New release')
+ expect(project.releases.last.tag).to eq('v0.1')
+ expect(project.releases.last.description).to eq('Super nice release')
+ end
+
+ context 'when description is empty' do
+ let(:params) do
+ {
+ name: 'New release',
+ tag_name: 'v0.1',
+ description: ''
+ }
+ end
+
+ it 'returns an error as validation failure' do
+ expect do
+ post api("/projects/#{project.id}/releases", maintainer), params: params
+ end.not_to change { Release.count }
+
+ expect(response).to have_gitlab_http_status(:bad_request)
+ expect(json_response['message'])
+ .to eq("Validation failed: Description can't be blank")
+ end
+ end
+
+ it 'matches response schema' do
+ post api("/projects/#{project.id}/releases", maintainer), params: params
+
+ expect(response).to match_response_schema('release')
+ end
+
+ it 'does not create a new tag' do
+ expect do
+ post api("/projects/#{project.id}/releases", maintainer), params: params
+ end.not_to change { Project.find_by_id(project.id).repository.tag_count }
+ end
+
+ context 'when user is a reporter' do
+ it 'forbids the request' do
+ post api("/projects/#{project.id}/releases", reporter), params: params
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ end
+ end
+
+ context 'when user is not a project member' do
+ it 'forbids the request' do
+ post api("/projects/#{project.id}/releases", non_project_member),
+ params: params
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+
+ context 'when project is public' do
+ let(:project) { create(:project, :repository, :public) }
+
+ it 'forbids the request' do
+ post api("/projects/#{project.id}/releases", non_project_member),
+ params: params
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ end
+ end
+ end
+
+ context 'when tag does not exist in git repository' do
+ let(:params) do
+ {
+ name: 'Android ~ Ice Cream Sandwich ~',
+ tag_name: tag_name,
+ description: 'Android 4.0–4.0.4 "Ice Cream Sandwich" is the ninth' \
+ 'version of the Android mobile operating system developed' \
+ 'by Google.',
+ ref: 'master'
+ }
+ end
+
+ let(:tag_name) { 'v4.0' }
+
+ it 'creates a new tag' do
+ expect do
+ post api("/projects/#{project.id}/releases", maintainer), params: params
+ end.to change { Project.find_by_id(project.id).repository.tag_count }.by(1)
+
+ expect(project.repository.find_tag('v4.0').dereferenced_target.id)
+ .to eq(project.repository.commit('master').id)
+ end
+
+ it 'creates a new release' do
+ expect do
+ post api("/projects/#{project.id}/releases", maintainer), params: params
+ end.to change { Release.count }.by(1)
+
+ expect(project.releases.last.name).to eq('Android ~ Ice Cream Sandwich ~')
+ expect(project.releases.last.tag).to eq('v4.0')
+ expect(project.releases.last.description).to eq(
+ 'Android 4.0–4.0.4 "Ice Cream Sandwich" is the ninth' \
+ 'version of the Android mobile operating system developed' \
+ 'by Google.')
+ end
+
+ context 'when tag name is HEAD' do
+ let(:tag_name) { 'HEAD' }
+
+ it 'returns an error as failure on tag creation' do
+ post api("/projects/#{project.id}/releases", maintainer), params: params
+
+ expect(response).to have_gitlab_http_status(:internal_server_error)
+ expect(json_response['message']).to eq('Tag name invalid')
+ end
+ end
+
+ context 'when tag name is empty' do
+ let(:tag_name) { '' }
+
+ it 'returns an error as failure on tag creation' do
+ post api("/projects/#{project.id}/releases", maintainer), params: params
+
+ expect(response).to have_gitlab_http_status(:internal_server_error)
+ expect(json_response['message']).to eq('Tag name invalid')
+ end
+ end
+ end
+
+ context 'when release already exists' do
+ before do
+ create(:release, project: project, tag: 'v0.1', name: 'New release')
+ end
+
+ it 'returns an error as conflicted request' do
+ post api("/projects/#{project.id}/releases", maintainer), params: params
+
+ expect(response).to have_gitlab_http_status(:conflict)
+ end
+ end
+
+ context 'when feature flag is disabled' do
+ before do
+ stub_feature_flags(releases_page: false)
+ end
+
+ it 'cannot find the API' do
+ post api("/projects/#{project.id}/releases", maintainer), params: params
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+ end
+
+ describe 'PUT /projects/:id/releases/:tag_name' do
+ let(:params) { { description: 'Best release ever!' } }
+
+ let!(:release) do
+ create(:release,
+ project: project,
+ tag: 'v0.1',
+ name: 'New release',
+ description: 'Super nice release')
+ end
+
+ it 'accepts the request' do
+ put api("/projects/#{project.id}/releases/v0.1", maintainer), params: params
+
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+
+ it 'updates the description' do
+ put api("/projects/#{project.id}/releases/v0.1", maintainer), params: params
+
+ expect(project.releases.last.description).to eq('Best release ever!')
+ end
+
+ it 'does not change other attributes' do
+ put api("/projects/#{project.id}/releases/v0.1", maintainer), params: params
+
+ expect(project.releases.last.tag).to eq('v0.1')
+ expect(project.releases.last.name).to eq('New release')
+ end
+
+ it 'matches response schema' do
+ put api("/projects/#{project.id}/releases/v0.1", maintainer), params: params
+
+ expect(response).to match_response_schema('release')
+ end
+
+ context 'when user tries to update sha' do
+ let(:params) { { sha: 'xxx' } }
+
+ it 'does not allow the request' do
+ put api("/projects/#{project.id}/releases/v0.1", maintainer), params: params
+
+ expect(response).to have_gitlab_http_status(:bad_request)
+ end
+ end
+
+ context 'when params is empty' do
+ let(:params) { {} }
+
+ it 'does not allow the request' do
+ put api("/projects/#{project.id}/releases/v0.1", maintainer), params: params
+
+ expect(response).to have_gitlab_http_status(:bad_request)
+ end
+ end
+
+ context 'when there are no corresponding releases' do
+ let!(:release) { }
+
+ it 'forbids the request' do
+ put api("/projects/#{project.id}/releases/v0.1", maintainer), params: params
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ end
+ end
+
+ context 'when user is a reporter' do
+ it 'forbids the request' do
+ put api("/projects/#{project.id}/releases/v0.1", reporter), params: params
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ end
+ end
+
+ context 'when user is not a project member' do
+ it 'forbids the request' do
+ put api("/projects/#{project.id}/releases/v0.1", non_project_member),
+ params: params
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+
+ context 'when project is public' do
+ let(:project) { create(:project, :repository, :public) }
+
+ it 'forbids the request' do
+ put api("/projects/#{project.id}/releases/v0.1", non_project_member),
+ params: params
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ end
+ end
+ end
+
+ context 'when feature flag is disabled' do
+ before do
+ stub_feature_flags(releases_page: false)
+ end
+
+ it 'cannot find the API' do
+ put api("/projects/#{project.id}/releases/v0.1", non_project_member),
+ params: params
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+ end
+
+ describe 'DELETE /projects/:id/releases/:tag_name' do
+ let!(:release) do
+ create(:release,
+ project: project,
+ tag: 'v0.1',
+ name: 'New release',
+ description: 'Super nice release')
+ end
+
+ it 'accepts the request' do
+ delete api("/projects/#{project.id}/releases/v0.1", maintainer)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+
+ it 'destroys the release' do
+ expect do
+ delete api("/projects/#{project.id}/releases/v0.1", maintainer)
+ end.to change { Release.count }.by(-1)
+ end
+
+ it 'does not remove a tag in repository' do
+ expect do
+ delete api("/projects/#{project.id}/releases/v0.1", maintainer)
+ end.not_to change { Project.find_by_id(project.id).repository.tag_count }
+ end
+
+ it 'matches response schema' do
+ delete api("/projects/#{project.id}/releases/v0.1", maintainer)
+
+ expect(response).to match_response_schema('release')
+ end
+
+ context 'when there are no corresponding releases' do
+ let!(:release) { }
+
+ it 'forbids the request' do
+ delete api("/projects/#{project.id}/releases/v0.1", maintainer)
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ end
+ end
+
+ context 'when user is a reporter' do
+ it 'forbids the request' do
+ delete api("/projects/#{project.id}/releases/v0.1", reporter)
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ end
+ end
+
+ context 'when user is not a project member' do
+ it 'forbids the request' do
+ delete api("/projects/#{project.id}/releases/v0.1", non_project_member)
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+
+ context 'when project is public' do
+ let(:project) { create(:project, :repository, :public) }
+
+ it 'forbids the request' do
+ delete api("/projects/#{project.id}/releases/v0.1", non_project_member)
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ end
+ end
+ end
+
+ context 'when feature flag is disabled' do
+ before do
+ stub_feature_flags(releases_page: false)
+ end
+
+ it 'cannot find the API' do
+ delete api("/projects/#{project.id}/releases/v0.1", non_project_member)
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+ end
+end
diff --git a/spec/requests/api/repositories_spec.rb b/spec/requests/api/repositories_spec.rb
index 181fe6246ae..b6b57803a6a 100644
--- a/spec/requests/api/repositories_spec.rb
+++ b/spec/requests/api/repositories_spec.rb
@@ -171,7 +171,7 @@ describe API::Repositories do
it 'forces attachment content disposition' do
get api(route, current_user)
- expect(headers['Content-Disposition']).to match(/^attachment/)
+ expect(headers['Content-Disposition']).to eq 'attachment'
end
context 'when sha does not exist' do
diff --git a/spec/requests/api/runner_spec.rb b/spec/requests/api/runner_spec.rb
index c63621fe7d1..2f322cc7054 100644
--- a/spec/requests/api/runner_spec.rb
+++ b/spec/requests/api/runner_spec.rb
@@ -1320,7 +1320,7 @@ describe API::Runner, :clean_gitlab_redis_shared_state do
end
before do
- fog_connection.directories.get('artifacts').files.create(
+ fog_connection.directories.new(key: 'artifacts').files.create(
key: 'tmp/uploads/12312300',
body: 'content'
)
diff --git a/spec/requests/api/tags_spec.rb b/spec/requests/api/tags_spec.rb
index 12cfac96d31..d09b6fe72b1 100644
--- a/spec/requests/api/tags_spec.rb
+++ b/spec/requests/api/tags_spec.rb
@@ -107,9 +107,12 @@ describe API::Tags do
context 'with releases' do
let(:description) { 'Awesome release!' }
- before do
- release = project.releases.find_or_initialize_by(tag: tag_name)
- release.update(description: description)
+ let!(:release) do
+ create(:release,
+ :legacy,
+ project: project,
+ tag: tag_name,
+ description: description)
end
it 'returns an array of project tags with release info' do
@@ -373,7 +376,7 @@ describe API::Tags do
it_behaves_like '404 response' do
let(:request) { post api(route, current_user), params: { description: description } }
- let(:message) { 'Tag does not exist' }
+ let(:message) { '404 Tag Not Found' }
end
end
@@ -398,10 +401,7 @@ describe API::Tags do
end
context 'on tag with existing release' do
- before do
- release = project.releases.find_or_initialize_by(tag: tag_name)
- release.update(description: description)
- end
+ let!(:release) { create(:release, :legacy, project: project, tag: tag_name, description: description) }
it 'returns 409 if there is already a release' do
post api(route, user), params: { description: description }
@@ -420,9 +420,12 @@ describe API::Tags do
shared_examples_for 'repository update release' do
context 'on tag with existing release' do
- before do
- release = project.releases.find_or_initialize_by(tag: tag_name)
- release.update(description: description)
+ let!(:release) do
+ create(:release,
+ :legacy,
+ project: project,
+ tag: tag_name,
+ description: description)
end
it 'updates the release description' do
@@ -437,9 +440,9 @@ describe API::Tags do
context 'when tag does not exist' do
let(:tag_name) { 'unknown' }
- it_behaves_like '404 response' do
+ it_behaves_like '403 response' do
let(:request) { put api(route, current_user), params: { description: new_description } }
- let(:message) { 'Tag does not exist' }
+ let(:message) { '403 Forbidden' }
end
end
@@ -464,9 +467,9 @@ describe API::Tags do
end
context 'when release does not exist' do
- it_behaves_like '404 response' do
+ it_behaves_like '403 response' do
let(:request) { put api(route, current_user), params: { description: new_description } }
- let(:message) { 'Release does not exist' }
+ let(:message) { '403 Forbidden' }
end
end
end
diff --git a/spec/requests/lfs_http_spec.rb b/spec/requests/lfs_http_spec.rb
index 3cc29a7076d..f1514e90eb2 100644
--- a/spec/requests/lfs_http_spec.rb
+++ b/spec/requests/lfs_http_spec.rb
@@ -1123,7 +1123,7 @@ describe 'Git LFS API and storage' do
context 'with valid remote_id' do
before do
- fog_connection.directories.get('lfs-objects').files.create(
+ fog_connection.directories.new(key: 'lfs-objects').files.create(
key: 'tmp/uploads/12312300',
body: 'content'
)
diff --git a/spec/requests/openid_connect_spec.rb b/spec/requests/openid_connect_spec.rb
index ec546db335a..2b148c1b563 100644
--- a/spec/requests/openid_connect_spec.rb
+++ b/spec/requests/openid_connect_spec.rb
@@ -104,7 +104,7 @@ describe 'OpenID Connect requests' do
expect(json_response).to match(id_token_claims.merge(user_info_claims))
expected_groups = [group1.full_path, group3.full_path]
- expected_groups << group4.full_path if Group.supports_nested_groups?
+ expected_groups << group4.full_path if Group.supports_nested_objects?
expect(json_response['groups']).to match_array(expected_groups)
end
diff --git a/spec/requests/rack_attack_global_spec.rb b/spec/requests/rack_attack_global_spec.rb
index c27e27d3648..49021f5d1b7 100644
--- a/spec/requests/rack_attack_global_spec.rb
+++ b/spec/requests/rack_attack_global_spec.rb
@@ -345,7 +345,7 @@ describe 'Rack Attack global throttles' do
end
def api_get_args_with_token_headers(partial_url, token_headers)
- ["/api/#{API::API.version}#{partial_url}", nil, token_headers]
+ ["/api/#{API::API.version}#{partial_url}", params: nil, headers: token_headers]
end
def rss_url(user)
diff --git a/spec/serializers/entity_date_helper_spec.rb b/spec/serializers/entity_date_helper_spec.rb
index 36da8d33a44..ae0f917415c 100644
--- a/spec/serializers/entity_date_helper_spec.rb
+++ b/spec/serializers/entity_date_helper_spec.rb
@@ -50,7 +50,7 @@ describe EntityDateHelper do
end
context 'when less than 31 days remaining' do
- let(:milestone_remaining) { date_helper_class.remaining_days_in_words(build_stubbed(:milestone, due_date: 12.days.from_now.utc)) }
+ let(:milestone_remaining) { date_helper_class.remaining_days_in_words(12.days.from_now.utc.to_date) }
it 'returns days remaining' do
expect(milestone_remaining).to eq("<strong>12</strong> days remaining")
@@ -58,7 +58,7 @@ describe EntityDateHelper do
end
context 'when less than 1 year and more than 30 days remaining' do
- let(:milestone_remaining) { date_helper_class.remaining_days_in_words(build_stubbed(:milestone, due_date: 2.months.from_now.utc)) }
+ let(:milestone_remaining) { date_helper_class.remaining_days_in_words(2.months.from_now.utc.to_date) }
it 'returns months remaining' do
expect(milestone_remaining).to eq("<strong>2</strong> months remaining")
@@ -66,7 +66,7 @@ describe EntityDateHelper do
end
context 'when more than 1 year remaining' do
- let(:milestone_remaining) { date_helper_class.remaining_days_in_words(build_stubbed(:milestone, due_date: (1.year.from_now + 2.days).utc)) }
+ let(:milestone_remaining) { date_helper_class.remaining_days_in_words((1.year.from_now + 2.days).utc.to_date) }
it 'returns years remaining' do
expect(milestone_remaining).to eq("<strong>1</strong> year remaining")
@@ -74,7 +74,7 @@ describe EntityDateHelper do
end
context 'when milestone is expired' do
- let(:milestone_remaining) { date_helper_class.remaining_days_in_words(build_stubbed(:milestone, due_date: 2.days.ago.utc)) }
+ let(:milestone_remaining) { date_helper_class.remaining_days_in_words(2.days.ago.utc.to_date) }
it 'returns "Past due"' do
expect(milestone_remaining).to eq("<strong>Past due</strong>")
@@ -82,7 +82,7 @@ describe EntityDateHelper do
end
context 'when milestone has start_date in the future' do
- let(:milestone_remaining) { date_helper_class.remaining_days_in_words(build_stubbed(:milestone, start_date: 2.days.from_now.utc)) }
+ let(:milestone_remaining) { date_helper_class.remaining_days_in_words(nil, 2.days.from_now.utc.to_date) }
it 'returns "Upcoming"' do
expect(milestone_remaining).to eq("<strong>Upcoming</strong>")
@@ -90,7 +90,7 @@ describe EntityDateHelper do
end
context 'when milestone has start_date in the past' do
- let(:milestone_remaining) { date_helper_class.remaining_days_in_words(build_stubbed(:milestone, start_date: 2.days.ago.utc)) }
+ let(:milestone_remaining) { date_helper_class.remaining_days_in_words(nil, 2.days.ago.utc.to_date) }
it 'returns days elapsed' do
expect(milestone_remaining).to eq("<strong>2</strong> days elapsed")
diff --git a/spec/serializers/issue_serializer_spec.rb b/spec/serializers/issue_serializer_spec.rb
index e8c46c0cdee..b8255e004d0 100644
--- a/spec/serializers/issue_serializer_spec.rb
+++ b/spec/serializers/issue_serializer_spec.rb
@@ -20,11 +20,19 @@ describe IssueSerializer do
context 'sidebar issue serialization' do
let(:serializer) { 'sidebar' }
- it 'matches sidebar issue json schema' do
+ it 'matches issue_sidebar json schema' do
expect(json_entity).to match_schema('entities/issue_sidebar')
end
end
+ context 'sidebar extras issue serialization' do
+ let(:serializer) { 'sidebar_extras' }
+
+ it 'matches issue_sidebar_extras json schema' do
+ expect(json_entity).to match_schema('entities/issue_sidebar_extras')
+ end
+ end
+
context 'board issue serialization' do
let(:serializer) { 'board' }
diff --git a/spec/serializers/merge_request_basic_serializer_spec.rb b/spec/serializers/merge_request_basic_serializer_spec.rb
deleted file mode 100644
index 1fad8e6bc5d..00000000000
--- a/spec/serializers/merge_request_basic_serializer_spec.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-require 'spec_helper'
-
-describe MergeRequestBasicSerializer do
- let(:resource) { create(:merge_request) }
- let(:user) { create(:user) }
-
- let(:json_entity) do
- described_class.new(current_user: user)
- .represent(resource, serializer: 'basic')
- .with_indifferent_access
- end
-
- it 'matches basic merge request json' do
- expect(json_entity).to match_schema('entities/merge_request_basic')
- end
-end
diff --git a/spec/serializers/merge_request_serializer_spec.rb b/spec/serializers/merge_request_serializer_spec.rb
index b259cb92962..276e0f6ff3d 100644
--- a/spec/serializers/merge_request_serializer_spec.rb
+++ b/spec/serializers/merge_request_serializer_spec.rb
@@ -20,8 +20,16 @@ describe MergeRequestSerializer do
context 'sidebar merge request serialization' do
let(:serializer) { 'sidebar' }
- it 'matches basic merge request json schema' do
- expect(json_entity).to match_schema('entities/merge_request_basic')
+ it 'matches merge_request_sidebar json schema' do
+ expect(json_entity).to match_schema('entities/merge_request_sidebar')
+ end
+ end
+
+ context 'sidebar_extras merge request serialization' do
+ let(:serializer) { 'sidebar_extras' }
+
+ it 'matches merge_request_sidebar_extras json schema' do
+ expect(json_entity).to match_schema('entities/merge_request_sidebar_extras')
end
end
diff --git a/spec/services/auth/container_registry_authentication_service_spec.rb b/spec/services/auth/container_registry_authentication_service_spec.rb
index f2e9799452a..8021bd338e0 100644
--- a/spec/services/auth/container_registry_authentication_service_spec.rb
+++ b/spec/services/auth/container_registry_authentication_service_spec.rb
@@ -5,7 +5,7 @@ describe Auth::ContainerRegistryAuthenticationService do
let(:current_user) { nil }
let(:current_params) { {} }
let(:rsa_key) { OpenSSL::PKey::RSA.generate(512) }
- let(:payload) { JWT.decode(subject[:token], rsa_key).first }
+ let(:payload) { JWT.decode(subject[:token], rsa_key, true, { algorithm: 'RS256' }).first }
let(:authentication_abilities) do
[:read_container_image, :create_container_image, :admin_container_image]
diff --git a/spec/services/ci/create_pipeline_service_spec.rb b/spec/services/ci/create_pipeline_service_spec.rb
index ffa47d527f7..87b60387c52 100644
--- a/spec/services/ci/create_pipeline_service_spec.rb
+++ b/spec/services/ci/create_pipeline_service_spec.rb
@@ -19,12 +19,14 @@ describe Ci::CreatePipelineService do
ref: ref_name,
trigger_request: nil,
variables_attributes: nil,
- merge_request: nil)
+ merge_request: nil,
+ push_options: nil)
params = { ref: ref,
before: '00000000',
after: after,
commits: [{ message: message }],
- variables_attributes: variables_attributes }
+ variables_attributes: variables_attributes,
+ push_options: push_options }
described_class.new(project, user, params).execute(
source, trigger_request: trigger_request, merge_request: merge_request)
@@ -357,6 +359,22 @@ describe Ci::CreatePipelineService do
end
end
+ context 'when push options contain ci.skip' do
+ let(:push_options) do
+ ['ci.skip',
+ 'another push option']
+ end
+
+ it 'creates a pipline in the skipped state' do
+ pipeline = execute_service(push_options: push_options)
+
+ # TODO: DRY these up with "skips builds creation if the commit message"
+ expect(pipeline).to be_persisted
+ expect(pipeline.builds.any?).to be false
+ expect(pipeline.status).to eq("skipped")
+ end
+ end
+
context 'when there are no jobs for this pipeline' do
before do
config = YAML.dump({ test: { script: 'ls', only: ['feature'] } })
@@ -667,7 +685,7 @@ describe Ci::CreatePipelineService do
stub_ci_pipeline_yaml_file(YAML.dump(config))
end
- let(:ref_name) { 'feature' }
+ let(:ref_name) { 'refs/heads/feature' }
context 'when source is merge request' do
let(:source) { :merge_request }
@@ -696,7 +714,7 @@ describe Ci::CreatePipelineService do
let(:merge_request) do
create(:merge_request,
source_project: project,
- source_branch: ref_name,
+ source_branch: Gitlab::Git.ref_name(ref_name),
target_project: project,
target_branch: 'master')
end
@@ -709,7 +727,7 @@ describe Ci::CreatePipelineService do
end
context 'when ref is tag' do
- let(:ref_name) { 'v1.1.0' }
+ let(:ref_name) { 'refs/tags/v1.1.0' }
it 'does not create a merge request pipeline' do
expect(pipeline).not_to be_persisted
@@ -721,7 +739,7 @@ describe Ci::CreatePipelineService do
let(:merge_request) do
create(:merge_request,
source_project: project,
- source_branch: ref_name,
+ source_branch: Gitlab::Git.ref_name(ref_name),
target_project: target_project,
target_branch: 'master')
end
@@ -786,7 +804,7 @@ describe Ci::CreatePipelineService do
let(:merge_request) do
create(:merge_request,
source_project: project,
- source_branch: ref_name,
+ source_branch: Gitlab::Git.ref_name(ref_name),
target_project: project,
target_branch: 'master')
end
@@ -928,7 +946,7 @@ describe Ci::CreatePipelineService do
let(:merge_request) do
create(:merge_request,
source_project: project,
- source_branch: ref_name,
+ source_branch: Gitlab::Git.ref_name(ref_name),
target_project: project,
target_branch: 'master')
end
diff --git a/spec/services/ci/register_job_service_spec.rb b/spec/services/ci/register_job_service_spec.rb
index 56e2a405bcd..9d65ac15213 100644
--- a/spec/services/ci/register_job_service_spec.rb
+++ b/spec/services/ci/register_job_service_spec.rb
@@ -244,7 +244,9 @@ module Ci
context 'when first build is stalled' do
before do
- pending_job.update(lock_version: 0)
+ allow_any_instance_of(Ci::RegisterJobService).to receive(:assign_runner!).and_call_original
+ allow_any_instance_of(Ci::RegisterJobService).to receive(:assign_runner!)
+ .with(pending_job, anything).and_raise(ActiveRecord::StaleObjectError)
end
subject { described_class.new(specific_runner).execute }
diff --git a/spec/services/clusters/gcp/finalize_creation_service_spec.rb b/spec/services/clusters/gcp/finalize_creation_service_spec.rb
index d69678c1277..2664649df47 100644
--- a/spec/services/clusters/gcp/finalize_creation_service_spec.rb
+++ b/spec/services/clusters/gcp/finalize_creation_service_spec.rb
@@ -20,7 +20,7 @@ describe Clusters::Gcp::FinalizeCreationService, '#execute' do
subject { described_class.new.execute(provider) }
before do
- allow(ClusterPlatformConfigureWorker).to receive(:perform_async)
+ allow(ClusterConfigureWorker).to receive(:perform_async)
end
shared_examples 'success' do
@@ -43,8 +43,8 @@ describe Clusters::Gcp::FinalizeCreationService, '#execute' do
expect(platform.token).to eq(token)
end
- it 'calls ClusterPlatformConfigureWorker in a ascync fashion' do
- expect(ClusterPlatformConfigureWorker).to receive(:perform_async).with(cluster.id)
+ it 'calls ClusterConfigureWorker in a ascync fashion' do
+ expect(ClusterConfigureWorker).to receive(:perform_async).with(cluster.id)
subject
end
diff --git a/spec/services/clusters/update_service_spec.rb b/spec/services/clusters/update_service_spec.rb
index 73f9be242a3..b2e6ebecd4a 100644
--- a/spec/services/clusters/update_service_spec.rb
+++ b/spec/services/clusters/update_service_spec.rb
@@ -37,7 +37,7 @@ describe Clusters::UpdateService do
end
before do
- allow(ClusterPlatformConfigureWorker).to receive(:perform_async)
+ allow(ClusterConfigureWorker).to receive(:perform_async)
stub_kubeclient_get_namespace('https://kubernetes.example.com', namespace: 'my-namespace')
end
diff --git a/spec/services/create_release_service_spec.rb b/spec/services/create_release_service_spec.rb
deleted file mode 100644
index 1a2dd0b39ee..00000000000
--- a/spec/services/create_release_service_spec.rb
+++ /dev/null
@@ -1,39 +0,0 @@
-require 'spec_helper'
-
-describe CreateReleaseService do
- let(:project) { create(:project, :repository) }
- let(:user) { create(:user) }
- let(:tag_name) { project.repository.tag_names.first }
- let(:description) { 'Awesome release!' }
- let(:service) { described_class.new(project, user) }
- let(:tag) { project.repository.find_tag(tag_name) }
- let(:sha) { tag.dereferenced_target.sha }
-
- it 'creates a new release' do
- result = service.execute(tag_name, description)
- expect(result[:status]).to eq(:success)
- release = project.releases.find_by(tag: tag_name)
- expect(release).not_to be_nil
- expect(release.description).to eq(description)
- expect(release.name).to eq(tag_name)
- expect(release.sha).to eq(sha)
- expect(release.author).to eq(user)
- end
-
- it 'raises an error if the tag does not exist' do
- result = service.execute("foobar", description)
- expect(result[:status]).to eq(:error)
- end
-
- context 'there already exists a release on a tag' do
- before do
- service.execute(tag_name, description)
- end
-
- it 'raises an error and does not update the release' do
- result = service.execute(tag_name, 'The best release!')
- expect(result[:status]).to eq(:error)
- expect(project.releases.find_by(tag: tag_name).description).to eq(description)
- end
- end
-end
diff --git a/spec/services/groups/create_service_spec.rb b/spec/services/groups/create_service_spec.rb
index 224e933bebc..fe6a8691ae0 100644
--- a/spec/services/groups/create_service_spec.rb
+++ b/spec/services/groups/create_service_spec.rb
@@ -55,7 +55,7 @@ describe Groups::CreateService, '#execute' do
context 'when nested groups feature is disabled' do
it 'does not save group and returns an error' do
- allow(Group).to receive(:supports_nested_groups?).and_return(false)
+ allow(Group).to receive(:supports_nested_objects?).and_return(false)
is_expected.not_to be_persisted
expect(subject.errors[:parent_id]).to include('You don’t have permission to create a subgroup in this group.')
@@ -66,7 +66,7 @@ describe Groups::CreateService, '#execute' do
context 'when nested groups feature is enabled' do
before do
- allow(Group).to receive(:supports_nested_groups?).and_return(true)
+ allow(Group).to receive(:supports_nested_objects?).and_return(true)
end
context 'as guest' do
diff --git a/spec/services/groups/nested_create_service_spec.rb b/spec/services/groups/nested_create_service_spec.rb
index 86fdd43c1e5..75d6ddb0a2c 100644
--- a/spec/services/groups/nested_create_service_spec.rb
+++ b/spec/services/groups/nested_create_service_spec.rb
@@ -30,7 +30,7 @@ describe Groups::NestedCreateService do
let(:params) { { group_path: 'a-group' } }
before do
- allow(Group).to receive(:supports_nested_groups?) { false }
+ allow(Group).to receive(:supports_nested_objects?) { false }
end
it 'creates the group' do
diff --git a/spec/services/groups/transfer_service_spec.rb b/spec/services/groups/transfer_service_spec.rb
index dd8a1cee074..6b48c993c57 100644
--- a/spec/services/groups/transfer_service_spec.rb
+++ b/spec/services/groups/transfer_service_spec.rb
@@ -9,7 +9,7 @@ describe Groups::TransferService, :postgresql do
shared_examples 'ensuring allowed transfer for a group' do
context 'with other database than PostgreSQL' do
before do
- allow(Group).to receive(:supports_nested_groups?).and_return(false)
+ allow(Group).to receive(:supports_nested_objects?).and_return(false)
end
it 'should return false' do
diff --git a/spec/services/groups/update_service_spec.rb b/spec/services/groups/update_service_spec.rb
index 84cfa53ea05..d87a7dd234d 100644
--- a/spec/services/groups/update_service_spec.rb
+++ b/spec/services/groups/update_service_spec.rb
@@ -56,7 +56,7 @@ describe Groups::UpdateService do
create(:project, :private, group: internal_group)
expect(TodosDestroyer::GroupPrivateWorker).to receive(:perform_in)
- .with(1.hour, internal_group.id)
+ .with(Todo::WAIT_FOR_DELETE, internal_group.id)
end
it "changes permission level to private" do
diff --git a/spec/services/issuable/bulk_update_service_spec.rb b/spec/services/issuable/bulk_update_service_spec.rb
index f0b0f7956ce..ca366cdf1df 100644
--- a/spec/services/issuable/bulk_update_service_spec.rb
+++ b/spec/services/issuable/bulk_update_service_spec.rb
@@ -28,6 +28,33 @@ describe Issuable::BulkUpdateService do
expect(project.issues.opened).to be_empty
expect(project.issues.closed).not_to be_empty
end
+
+ context 'when issue for a different project is created' do
+ let(:private_project) { create(:project, :private) }
+ let(:issue) { create(:issue, project: private_project, author: user) }
+
+ context 'when user has access to the project' do
+ it 'closes all issues passed' do
+ private_project.add_maintainer(user)
+
+ bulk_update(issues + [issue], state_event: 'close')
+
+ expect(project.issues.opened).to be_empty
+ expect(project.issues.closed).not_to be_empty
+ expect(private_project.issues.closed).not_to be_empty
+ end
+ end
+
+ context 'when user does not have access to project' do
+ it 'only closes all issues that the user has access to' do
+ bulk_update(issues + [issue], state_event: 'close')
+
+ expect(project.issues.opened).to be_empty
+ expect(project.issues.closed).not_to be_empty
+ expect(private_project.issues.closed).to be_empty
+ end
+ end
+ end
end
describe 'reopen issues' do
diff --git a/spec/services/issues/update_service_spec.rb b/spec/services/issues/update_service_spec.rb
index bd519e7f077..ce20bf2bef6 100644
--- a/spec/services/issues/update_service_spec.rb
+++ b/spec/services/issues/update_service_spec.rb
@@ -77,7 +77,7 @@ describe Issues::UpdateService, :mailer do
end
it 'enqueues ConfidentialIssueWorker when an issue is made confidential' do
- expect(TodosDestroyer::ConfidentialIssueWorker).to receive(:perform_in).with(1.hour, issue.id)
+ expect(TodosDestroyer::ConfidentialIssueWorker).to receive(:perform_in).with(Todo::WAIT_FOR_DELETE, issue.id)
update_issue(confidential: true)
end
diff --git a/spec/services/members/destroy_service_spec.rb b/spec/services/members/destroy_service_spec.rb
index 0a5220c7c61..5aa7165e135 100644
--- a/spec/services/members/destroy_service_spec.rb
+++ b/spec/services/members/destroy_service_spec.rb
@@ -22,7 +22,7 @@ describe Members::DestroyService do
shared_examples 'a service destroying a member' do
before do
type = member.is_a?(GroupMember) ? 'Group' : 'Project'
- expect(TodosDestroyer::EntityLeaveWorker).to receive(:perform_in).with(1.hour, member.user_id, member.source_id, type)
+ expect(TodosDestroyer::EntityLeaveWorker).to receive(:perform_in).with(Todo::WAIT_FOR_DELETE, member.user_id, member.source_id, type)
end
it 'destroys the member' do
diff --git a/spec/services/members/update_service_spec.rb b/spec/services/members/update_service_spec.rb
index 6d19a95ffeb..599ed39ca37 100644
--- a/spec/services/members/update_service_spec.rb
+++ b/spec/services/members/update_service_spec.rb
@@ -20,11 +20,28 @@ describe Members::UpdateService do
shared_examples 'a service updating a member' do
it 'updates the member' do
+ expect(TodosDestroyer::EntityLeaveWorker).not_to receive(:perform_in).with(Todo::WAIT_FOR_DELETE, member.user_id, member.source_id, source.class.name)
+
updated_member = described_class.new(current_user, params).execute(member, permission: permission)
expect(updated_member).to be_valid
expect(updated_member.access_level).to eq(Gitlab::Access::MAINTAINER)
end
+
+ context 'when member is downgraded to guest' do
+ let(:params) do
+ { access_level: Gitlab::Access::GUEST }
+ end
+
+ it 'schedules to delete confidential todos' do
+ expect(TodosDestroyer::EntityLeaveWorker).to receive(:perform_in).with(Todo::WAIT_FOR_DELETE, member.user_id, member.source_id, source.class.name).once
+
+ updated_member = described_class.new(current_user, params).execute(member, permission: permission)
+
+ expect(updated_member).to be_valid
+ expect(updated_member.access_level).to eq(Gitlab::Access::GUEST)
+ end
+ end
end
before do
diff --git a/spec/services/merge_requests/build_service_spec.rb b/spec/services/merge_requests/build_service_spec.rb
index 1894d8c8d0e..536d0d345a4 100644
--- a/spec/services/merge_requests/build_service_spec.rb
+++ b/spec/services/merge_requests/build_service_spec.rb
@@ -3,6 +3,7 @@ require 'spec_helper'
describe MergeRequests::BuildService do
using RSpec::Parameterized::TableSyntax
include RepoHelpers
+ include ProjectForksHelper
let(:project) { create(:project, :repository) }
let(:source_project) { nil }
@@ -49,7 +50,7 @@ describe MergeRequests::BuildService do
describe '#execute' do
it 'calls the compare service with the correct arguments' do
- allow_any_instance_of(described_class).to receive(:branches_valid?).and_return(true)
+ allow_any_instance_of(described_class).to receive(:projects_and_branches_valid?).and_return(true)
expect(CompareService).to receive(:new)
.with(project, Gitlab::Git::BRANCH_REF_PREFIX + source_branch)
.and_call_original
@@ -393,11 +394,27 @@ describe MergeRequests::BuildService do
end
end
+ context 'target_project is set but repo is not accessible by current_user' do
+ let(:target_project) do
+ create(:project, :public, :repository, repository_access_level: ProjectFeature::PRIVATE)
+ end
+
+ it 'sets target project correctly' do
+ expect(merge_request.target_project).to eq(project)
+ end
+ end
+
context 'source_project is set and accessible by current_user' do
let(:source_project) { create(:project, :public, :repository)}
let(:commits) { Commit.decorate([commit_1], project) }
- it 'sets target project correctly' do
+ before do
+ # To create merge requests _from_ a project the user needs at least
+ # developer access
+ source_project.add_developer(user)
+ end
+
+ it 'sets source project correctly' do
expect(merge_request.source_project).to eq(source_project)
end
end
@@ -406,11 +423,43 @@ describe MergeRequests::BuildService do
let(:source_project) { create(:project, :private, :repository)}
let(:commits) { Commit.decorate([commit_1], project) }
- it 'sets target project correctly' do
+ it 'sets source project correctly' do
+ expect(merge_request.source_project).to eq(project)
+ end
+ end
+
+ context 'source_project is set but the user cannot create merge requests from the project' do
+ let(:source_project) do
+ create(:project, :public, :repository, merge_requests_access_level: ProjectFeature::PRIVATE)
+ end
+
+ it 'sets the source_project correctly' do
expect(merge_request.source_project).to eq(project)
end
end
+ context 'target_project is not in the fork network of source_project' do
+ let(:target_project) { create(:project, :public, :repository) }
+
+ it 'adds an error to the merge request' do
+ expect(merge_request.errors[:validate_fork]).to contain_exactly('Source project is not a fork of the target project')
+ end
+ end
+
+ context 'target_project is in the fork network of source project but no longer accessible' do
+ let!(:project) { fork_project(target_project, user, namespace: user.namespace, repository: true) }
+ let(:source_project) { project }
+ let(:target_project) { create(:project, :public, :repository) }
+
+ before do
+ target_project.update(visibility_level: Gitlab::VisibilityLevel::PRIVATE)
+ end
+
+ it 'sets the target_project correctly' do
+ expect(merge_request.target_project).to eq(project)
+ end
+ end
+
context 'when specifying target branch in the description' do
let(:description) { "A merge request targeting another branch\n\n/target_branch with-codeowners" }
diff --git a/spec/services/notification_service_spec.rb b/spec/services/notification_service_spec.rb
index 68ac3a00ab0..d20e712d365 100644
--- a/spec/services/notification_service_spec.rb
+++ b/spec/services/notification_service_spec.rb
@@ -2250,7 +2250,7 @@ describe NotificationService, :mailer do
# Creates a nested group only if supported
# to avoid errors on MySQL
def create_nested_group
- if Group.supports_nested_groups?
+ if Group.supports_nested_objects?
parent_group = create(:group, :public)
child_group = create(:group, :public, parent: parent_group)
@@ -2277,7 +2277,7 @@ describe NotificationService, :mailer do
end
def add_member_for_parent_group(user, project)
- return unless Group.supports_nested_groups?
+ return unless Group.supports_nested_objects?
project.reload
@@ -2285,13 +2285,13 @@ describe NotificationService, :mailer do
end
def should_email_nested_group_user(user, times: 1, recipients: email_recipients)
- return unless Group.supports_nested_groups?
+ return unless Group.supports_nested_objects?
should_email(user, times: 1, recipients: email_recipients)
end
def should_not_email_nested_group_user(user, recipients: email_recipients)
- return unless Group.supports_nested_groups?
+ return unless Group.supports_nested_objects?
should_not_email(user, recipients: email_recipients)
end
diff --git a/spec/services/projects/after_rename_service_spec.rb b/spec/services/projects/after_rename_service_spec.rb
index b4718a07204..59c08b30f9f 100644
--- a/spec/services/projects/after_rename_service_spec.rb
+++ b/spec/services/projects/after_rename_service_spec.rb
@@ -99,6 +99,17 @@ describe Projects::AfterRenameService do
expect(rugged_config['gitlab.fullpath']).to eq(project.full_path)
end
+
+ it 'updates storage location' do
+ allow(project_storage).to receive(:rename_repo).and_return(true)
+
+ described_class.new(project).execute
+
+ expect(project.project_repository).to have_attributes(
+ disk_path: project.disk_path,
+ shard_name: project.repository_storage
+ )
+ end
end
context 'using hashed storage' do
@@ -193,6 +204,15 @@ describe Projects::AfterRenameService do
expect(rugged_config['gitlab.fullpath']).to eq(project.full_path)
end
+
+ it 'updates storage location' do
+ described_class.new(project).execute
+
+ expect(project.project_repository).to have_attributes(
+ disk_path: project.disk_path,
+ shard_name: project.repository_storage
+ )
+ end
end
end
end
diff --git a/spec/services/projects/lfs_pointers/lfs_download_service_spec.rb b/spec/services/projects/lfs_pointers/lfs_download_service_spec.rb
index d7d7f1874eb..95c9b6e63b8 100644
--- a/spec/services/projects/lfs_pointers/lfs_download_service_spec.rb
+++ b/spec/services/projects/lfs_pointers/lfs_download_service_spec.rb
@@ -4,17 +4,15 @@ describe Projects::LfsPointers::LfsDownloadService do
let(:project) { create(:project) }
let(:oid) { '9e548e25631dd9ce6b43afd6359ab76da2819d6a5b474e66118c7819e1d8b3e8' }
let(:download_link) { "http://gitlab.com/#{oid}" }
- let(:lfs_content) do
- <<~HEREDOC
- whatever
- HEREDOC
- end
+ let(:lfs_content) { SecureRandom.random_bytes(10) }
subject { described_class.new(project) }
before do
allow(project).to receive(:lfs_enabled?).and_return(true)
WebMock.stub_request(:get, download_link).to_return(body: lfs_content)
+
+ allow(Gitlab::CurrentSettings).to receive(:allow_local_requests_from_hooks_and_services?).and_return(false)
end
describe '#execute' do
@@ -32,7 +30,7 @@ describe Projects::LfsPointers::LfsDownloadService do
it 'stores the content' do
subject.execute(oid, download_link)
- expect(File.read(LfsObject.first.file.file.file)).to eq lfs_content
+ expect(File.binread(LfsObject.first.file.file.file)).to eq lfs_content
end
end
@@ -54,18 +52,61 @@ describe Projects::LfsPointers::LfsDownloadService do
end
end
+ context 'when localhost requests are allowed' do
+ let(:download_link) { 'http://192.168.2.120' }
+
+ before do
+ allow(Gitlab::CurrentSettings).to receive(:allow_local_requests_from_hooks_and_services?).and_return(true)
+ end
+
+ it 'downloads the file' do
+ expect(subject).to receive(:download_and_save_file).and_call_original
+
+ expect { subject.execute(oid, download_link) }.to change { LfsObject.count }.by(1)
+ end
+ end
+
context 'when a bad URL is used' do
- where(download_link: ['/etc/passwd', 'ftp://example.com', 'http://127.0.0.2'])
+ where(download_link: ['/etc/passwd', 'ftp://example.com', 'http://127.0.0.2', 'http://192.168.2.120'])
with_them do
it 'does not download the file' do
- expect(subject).not_to receive(:download_and_save_file)
-
expect { subject.execute(oid, download_link) }.not_to change { LfsObject.count }
end
end
end
+ context 'when the URL points to a redirected URL' do
+ context 'that is blocked' do
+ where(redirect_link: ['ftp://example.com', 'http://127.0.0.2', 'http://192.168.2.120'])
+
+ with_them do
+ before do
+ WebMock.stub_request(:get, download_link).to_return(status: 301, headers: { 'Location' => redirect_link })
+ end
+
+ it 'does not follow the redirection' do
+ expect(Rails.logger).to receive(:error).with(/LFS file with oid #{oid} couldn't be downloaded/)
+
+ expect { subject.execute(oid, download_link) }.not_to change { LfsObject.count }
+ end
+ end
+ end
+
+ context 'that is valid' do
+ let(:redirect_link) { "http://example.com/"}
+
+ before do
+ WebMock.stub_request(:get, download_link).to_return(status: 301, headers: { 'Location' => redirect_link })
+ WebMock.stub_request(:get, redirect_link).to_return(body: lfs_content)
+ end
+
+ it 'follows the redirection' do
+ expect { subject.execute(oid, download_link) }.to change { LfsObject.count }.from(0).to(1)
+ end
+ end
+ end
+
context 'when an lfs object with the same oid already exists' do
before do
create(:lfs_object, oid: 'oid')
diff --git a/spec/services/projects/transfer_service_spec.rb b/spec/services/projects/transfer_service_spec.rb
index 132ad9a2646..766276fdba3 100644
--- a/spec/services/projects/transfer_service_spec.rb
+++ b/spec/services/projects/transfer_service_spec.rb
@@ -63,6 +63,15 @@ describe Projects::TransferService do
expect(rugged_config['gitlab.fullpath']).to eq "#{group.full_path}/#{project.path}"
end
+ it 'updates storage location' do
+ transfer_project(project, user, group)
+
+ expect(project.project_repository).to have_attributes(
+ disk_path: "#{group.full_path}/#{project.path}",
+ shard_name: project.repository_storage
+ )
+ end
+
context 'new group has a kubernetes cluster' do
let(:group_cluster) { create(:cluster, :group, :provided_by_gcp) }
let(:group) { group_cluster.group }
@@ -139,6 +148,17 @@ describe Projects::TransferService do
expect(service).not_to receive(:execute_system_hooks)
end
end
+
+ it 'does not update storage location' do
+ create(:project_repository, project: project)
+
+ attempt_project_transfer
+
+ expect(project.project_repository).to have_attributes(
+ disk_path: project.disk_path,
+ shard_name: project.repository_storage
+ )
+ end
end
context 'namespace -> no namespace' do
diff --git a/spec/services/projects/update_service_spec.rb b/spec/services/projects/update_service_spec.rb
index d58ff2cedc0..8adfc63222e 100644
--- a/spec/services/projects/update_service_spec.rb
+++ b/spec/services/projects/update_service_spec.rb
@@ -41,7 +41,7 @@ describe Projects::UpdateService do
end
it 'updates the project to private' do
- expect(TodosDestroyer::ProjectPrivateWorker).to receive(:perform_in).with(1.hour, project.id)
+ expect(TodosDestroyer::ProjectPrivateWorker).to receive(:perform_in).with(Todo::WAIT_FOR_DELETE, project.id)
result = update_project(project, user, visibility_level: Gitlab::VisibilityLevel::PRIVATE)
@@ -191,7 +191,7 @@ describe Projects::UpdateService do
context 'when changing feature visibility to private' do
it 'updates the visibility correctly' do
expect(TodosDestroyer::PrivateFeaturesWorker)
- .to receive(:perform_in).with(1.hour, project.id)
+ .to receive(:perform_in).with(Todo::WAIT_FOR_DELETE, project.id)
result = update_project(project, user, project_feature_attributes:
{ issues_access_level: ProjectFeature::PRIVATE }
diff --git a/spec/services/releases/create_service_spec.rb b/spec/services/releases/create_service_spec.rb
new file mode 100644
index 00000000000..612e9f152e7
--- /dev/null
+++ b/spec/services/releases/create_service_spec.rb
@@ -0,0 +1,72 @@
+require 'spec_helper'
+
+describe Releases::CreateService do
+ let(:project) { create(:project, :repository) }
+ let(:user) { create(:user) }
+ let(:tag_name) { project.repository.tag_names.first }
+ let(:tag_sha) { project.repository.find_tag(tag_name).dereferenced_target.sha }
+ let(:name) { 'Bionic Beaver' }
+ let(:description) { 'Awesome release!' }
+ let(:params) { { tag: tag_name, name: name, description: description, ref: ref } }
+ let(:ref) { nil }
+ let(:service) { described_class.new(project, user, params) }
+
+ before do
+ project.add_maintainer(user)
+ end
+
+ describe '#execute' do
+ shared_examples 'a successful release creation' do
+ it 'creates a new release' do
+ result = service.execute
+ expect(result[:status]).to eq(:success)
+ expect(result[:tag]).not_to be_nil
+ expect(result[:release]).not_to be_nil
+ expect(result[:release].description).to eq(description)
+ expect(result[:release].name).to eq(name)
+ expect(result[:release].author).to eq(user)
+ expect(result[:release].sha).to eq(tag_sha)
+ end
+ end
+
+ it_behaves_like 'a successful release creation'
+
+ context 'when the tag does not exist' do
+ let(:tag_name) { 'non-exist-tag' }
+
+ it 'raises an error' do
+ result = service.execute
+
+ expect(result[:status]).to eq(:error)
+ end
+ end
+
+ context 'when ref is provided' do
+ let(:ref) { 'master' }
+ let(:tag_name) { 'foobar' }
+
+ it_behaves_like 'a successful release creation'
+
+ it 'creates a tag if the tag does not exist' do
+ expect(project.repository.ref_exists?("refs/tags/#{tag_name}")).to be_falsey
+
+ result = service.execute
+ expect(result[:status]).to eq(:success)
+ expect(result[:tag]).not_to be_nil
+ expect(result[:release]).not_to be_nil
+ end
+ end
+
+ context 'there already exists a release on a tag' do
+ let!(:release) do
+ create(:release, project: project, tag: tag_name, description: description)
+ end
+
+ it 'raises an error and does not update the release' do
+ result = service.execute
+ expect(result[:status]).to eq(:error)
+ expect(project.releases.find_by(tag: tag_name).description).to eq(description)
+ end
+ end
+ end
+end
diff --git a/spec/services/releases/destroy_service_spec.rb b/spec/services/releases/destroy_service_spec.rb
new file mode 100644
index 00000000000..dd5b8708f36
--- /dev/null
+++ b/spec/services/releases/destroy_service_spec.rb
@@ -0,0 +1,61 @@
+require 'spec_helper'
+
+describe Releases::DestroyService do
+ let(:project) { create(:project, :repository) }
+ let(:mainatiner) { create(:user) }
+ let(:repoter) { create(:user) }
+ let(:tag) { 'v1.1.0' }
+ let!(:release) { create(:release, project: project, tag: tag) }
+ let(:service) { described_class.new(project, user, params) }
+ let(:params) { { tag: tag } }
+ let(:user) { mainatiner }
+
+ before do
+ project.add_maintainer(mainatiner)
+ project.add_reporter(repoter)
+ end
+
+ describe '#execute' do
+ subject { service.execute }
+
+ context 'when there is a release' do
+ it 'removes the release' do
+ expect { subject }.to change { project.releases.count }.by(-1)
+ end
+
+ it 'returns the destroyed object' do
+ is_expected.to include(status: :success, release: release)
+ end
+ end
+
+ context 'when tag is not found' do
+ let(:tag) { 'v1.1.1' }
+
+ it 'returns an error' do
+ is_expected.to include(status: :error,
+ message: 'Tag does not exist',
+ http_status: 404)
+ end
+ end
+
+ context 'when release is not found' do
+ let!(:release) { }
+
+ it 'returns an error' do
+ is_expected.to include(status: :error,
+ message: 'Release does not exist',
+ http_status: 404)
+ end
+ end
+
+ context 'when user does not have permission' do
+ let(:user) { repoter }
+
+ it 'returns an error' do
+ is_expected.to include(status: :error,
+ message: 'Access Denied',
+ http_status: 403)
+ end
+ end
+ end
+end
diff --git a/spec/services/releases/update_service_spec.rb b/spec/services/releases/update_service_spec.rb
new file mode 100644
index 00000000000..6c68f364739
--- /dev/null
+++ b/spec/services/releases/update_service_spec.rb
@@ -0,0 +1,50 @@
+require 'spec_helper'
+
+describe Releases::UpdateService do
+ let(:project) { create(:project, :repository) }
+ let(:user) { create(:user) }
+ let(:new_name) { 'A new name' }
+ let(:new_description) { 'The best release!' }
+ let(:params) { { name: new_name, description: new_description, tag: tag_name } }
+ let(:service) { described_class.new(project, user, params) }
+ let!(:release) { create(:release, project: project, author: user, tag: tag_name) }
+ let(:tag_name) { 'v1.1.0' }
+
+ before do
+ project.add_developer(user)
+ end
+
+ describe '#execute' do
+ shared_examples 'a failed update' do
+ it 'raises an error' do
+ result = service.execute
+ expect(result[:status]).to eq(:error)
+ end
+ end
+
+ it 'successfully updates an existing release' do
+ result = service.execute
+ expect(result[:status]).to eq(:success)
+ expect(result[:release].name).to eq(new_name)
+ expect(result[:release].description).to eq(new_description)
+ end
+
+ context 'when the tag does not exists' do
+ let(:tag_name) { 'foobar' }
+
+ it_behaves_like 'a failed update'
+ end
+
+ context 'when the release does not exist' do
+ let!(:release) { }
+
+ it_behaves_like 'a failed update'
+ end
+
+ context 'with an invalid update' do
+ let(:new_description) { '' }
+
+ it_behaves_like 'a failed update'
+ end
+ end
+end
diff --git a/spec/services/todo_service_spec.rb b/spec/services/todo_service_spec.rb
index c52515aefd8..253f2e44d10 100644
--- a/spec/services/todo_service_spec.rb
+++ b/spec/services/todo_service_spec.rb
@@ -19,6 +19,7 @@ describe TodoService do
before do
project.add_guest(guest)
project.add_developer(author)
+ project.add_developer(assignee)
project.add_developer(member)
project.add_developer(john_doe)
project.add_developer(skipped)
diff --git a/spec/services/update_release_service_spec.rb b/spec/services/update_release_service_spec.rb
deleted file mode 100644
index dc2d0e2d47a..00000000000
--- a/spec/services/update_release_service_spec.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-require 'spec_helper'
-
-describe UpdateReleaseService do
- let(:project) { create(:project, :repository) }
- let(:user) { create(:user) }
- let(:tag_name) { project.repository.tag_names.first }
- let(:description) { 'Awesome release!' }
- let(:new_description) { 'The best release!' }
- let(:service) { described_class.new(project, user) }
-
- context 'with an existing release' do
- let(:create_service) { CreateReleaseService.new(project, user) }
-
- before do
- create_service.execute(tag_name, description)
- end
-
- it 'successfully updates an existing release' do
- result = service.execute(tag_name, new_description)
- expect(result[:status]).to eq(:success)
- expect(project.releases.find_by(tag: tag_name).description).to eq(new_description)
- end
- end
-
- it 'raises an error if the tag does not exist' do
- result = service.execute("foobar", description)
- expect(result[:status]).to eq(:error)
- end
-
- it 'raises an error if the release does not exist' do
- result = service.execute(tag_name, description)
- expect(result[:status]).to eq(:error)
- end
-end
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index fb3421b61d3..89357056c93 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -216,15 +216,19 @@ RSpec.configure do |config|
# Each example may call `migrate!`, so we must ensure we are migrated down every time
config.before(:each, :migration) do
+ use_fake_application_settings
+
schema_migrate_down!
end
config.after(:context, :migration) do
schema_migrate_up!
+
+ Gitlab::CurrentSettings.clear_in_memory_application_settings!
end
config.around(:each, :nested_groups) do |example|
- example.run if Group.supports_nested_groups?
+ example.run if Group.supports_nested_objects?
end
config.around(:each, :postgresql) do |example|
diff --git a/spec/support/api/boards_shared_examples.rb b/spec/support/api/boards_shared_examples.rb
index 943c1f6ffd7..592962ebf7c 100644
--- a/spec/support/api/boards_shared_examples.rb
+++ b/spec/support/api/boards_shared_examples.rb
@@ -88,7 +88,7 @@ shared_examples_for 'group and project boards' do |route_definition, ee = false|
let(:url) { "#{root_url}/#{board.id}/lists" }
it 'creates a new issue board list for labels' do
- post api(url, user), label_id: ux_label.id
+ post api(url, user), params: { label_id: ux_label.id }
expect(response).to have_gitlab_http_status(201)
expect(json_response['label']['name']).to eq(ux_label.title)
@@ -96,13 +96,13 @@ shared_examples_for 'group and project boards' do |route_definition, ee = false|
end
it 'returns 400 when creating a new list if label_id is invalid' do
- post api(url, user), label_id: 23423
+ post api(url, user), params: { label_id: 23423 }
expect(response).to have_gitlab_http_status(400)
end
it 'returns 403 for members with guest role' do
- put api("#{url}/#{test_list.id}", guest), position: 1
+ put api("#{url}/#{test_list.id}", guest), params: { position: 1 }
expect(response).to have_gitlab_http_status(403)
end
@@ -112,23 +112,20 @@ shared_examples_for 'group and project boards' do |route_definition, ee = false|
let(:url) { "#{root_url}/#{board.id}/lists" }
it "updates a list" do
- put api("#{url}/#{test_list.id}", user),
- position: 1
+ put api("#{url}/#{test_list.id}", user), params: { position: 1 }
expect(response).to have_gitlab_http_status(200)
expect(json_response['position']).to eq(1)
end
it "returns 404 error if list id not found" do
- put api("#{url}/44444", user),
- position: 1
+ put api("#{url}/44444", user), params: { position: 1 }
expect(response).to have_gitlab_http_status(404)
end
it "returns 403 for members with guest role" do
- put api("#{url}/#{test_list.id}", guest),
- position: 1
+ put api("#{url}/#{test_list.id}", guest), params: { position: 1 }
expect(response).to have_gitlab_http_status(403)
end
diff --git a/spec/support/api/milestones_shared_examples.rb b/spec/support/api/milestones_shared_examples.rb
index 3bebb7aae90..5f709831ce1 100644
--- a/spec/support/api/milestones_shared_examples.rb
+++ b/spec/support/api/milestones_shared_examples.rb
@@ -45,7 +45,7 @@ shared_examples_for 'group and project milestones' do |route_definition|
it 'returns an array of milestones specified by iids' do
other_milestone = create(:milestone, project: try(:project), group: try(:group))
- get api(route, user), iids: [closed_milestone.iid, other_milestone.iid]
+ get api(route, user), params: { iids: [closed_milestone.iid, other_milestone.iid] }
expect(response).to have_gitlab_http_status(200)
expect(json_response).to be_an Array
@@ -54,7 +54,7 @@ shared_examples_for 'group and project milestones' do |route_definition|
end
it 'does not return any milestone if none found' do
- get api(route, user), iids: [Milestone.maximum(:iid).succ]
+ get api(route, user), params: { iids: [Milestone.maximum(:iid).succ] }
expect(response).to have_gitlab_http_status(200)
expect(json_response).to be_an Array
@@ -73,7 +73,7 @@ shared_examples_for 'group and project milestones' do |route_definition|
end
it 'returns a milestone by searching for title' do
- get api(route, user), search: 'version2'
+ get api(route, user), params: { search: 'version2' }
expect(response).to have_gitlab_http_status(200)
expect(response).to include_pagination_headers
@@ -83,7 +83,7 @@ shared_examples_for 'group and project milestones' do |route_definition|
end
it 'returns a milestones by searching for description' do
- get api(route, user), search: 'open'
+ get api(route, user), params: { search: 'open' }
expect(response).to have_gitlab_http_status(200)
expect(response).to include_pagination_headers
@@ -117,7 +117,7 @@ shared_examples_for 'group and project milestones' do |route_definition|
describe "POST #{route_definition}" do
it 'creates a new milestone' do
- post api(route, user), title: 'new milestone'
+ post api(route, user), params: { title: 'new milestone' }
expect(response).to have_gitlab_http_status(201)
expect(json_response['title']).to eq('new milestone')
@@ -125,8 +125,7 @@ shared_examples_for 'group and project milestones' do |route_definition|
end
it 'creates a new milestone with description and dates' do
- post api(route, user),
- title: 'new milestone', description: 'release', due_date: '2013-03-02', start_date: '2013-02-02'
+ post api(route, user), params: { title: 'new milestone', description: 'release', due_date: '2013-03-02', start_date: '2013-02-02' }
expect(response).to have_gitlab_http_status(201)
expect(json_response['description']).to eq('release')
@@ -141,14 +140,13 @@ shared_examples_for 'group and project milestones' do |route_definition|
end
it 'returns a 400 error if params are invalid (duplicate title)' do
- post api(route, user),
- title: milestone.title, description: 'release', due_date: '2013-03-02'
+ post api(route, user), params: { title: milestone.title, description: 'release', due_date: '2013-03-02' }
expect(response).to have_gitlab_http_status(400)
end
it 'creates a new milestone with reserved html characters' do
- post api(route, user), title: 'foo & bar 1.1 -> 2.2'
+ post api(route, user), params: { title: 'foo & bar 1.1 -> 2.2' }
expect(response).to have_gitlab_http_status(201)
expect(json_response['title']).to eq('foo & bar 1.1 -> 2.2')
@@ -158,8 +156,7 @@ shared_examples_for 'group and project milestones' do |route_definition|
describe "PUT #{route_definition}/:milestone_id" do
it 'updates a milestone' do
- put api(resource_route, user),
- title: 'updated title'
+ put api(resource_route, user), params: { title: 'updated title' }
expect(response).to have_gitlab_http_status(200)
expect(json_response['title']).to eq('updated title')
@@ -168,29 +165,27 @@ shared_examples_for 'group and project milestones' do |route_definition|
it 'removes a due date if nil is passed' do
milestone.update!(due_date: "2016-08-05")
- put api(resource_route, user), due_date: nil
+ put api(resource_route, user), params: { due_date: nil }
expect(response).to have_gitlab_http_status(200)
expect(json_response['due_date']).to be_nil
end
it 'returns a 404 error if milestone id not found' do
- put api("#{route}/1234", user),
- title: 'updated title'
+ put api("#{route}/1234", user), params: { title: 'updated title' }
expect(response).to have_gitlab_http_status(404)
end
it 'closes milestone' do
- put api(resource_route, user),
- state_event: 'close'
+ put api(resource_route, user), params: { state_event: 'close' }
expect(response).to have_gitlab_http_status(200)
expect(json_response['state']).to eq('closed')
end
it 'updates milestone with only start date' do
- put api(resource_route, user), start_date: Date.tomorrow
+ put api(resource_route, user), params: { start_date: Date.tomorrow }
expect(response).to have_gitlab_http_status(200)
end
diff --git a/spec/support/api/scopes/read_user_shared_examples.rb b/spec/support/api/scopes/read_user_shared_examples.rb
index d7cef137989..683234264a8 100644
--- a/spec/support/api/scopes/read_user_shared_examples.rb
+++ b/spec/support/api/scopes/read_user_shared_examples.rb
@@ -77,7 +77,7 @@ shared_examples_for 'does not allow the "read_user" scope' do
let(:token) { create(:personal_access_token, scopes: ['read_user'], user: user) }
it 'returns a "403" response' do
- post api_call.call(path, user, personal_access_token: token), attributes_for(:user, projects_limit: 3)
+ post api_call.call(path, user, personal_access_token: token), params: attributes_for(:user, projects_limit: 3)
expect(response).to have_gitlab_http_status(403)
end
diff --git a/spec/support/api/time_tracking_shared_examples.rb b/spec/support/api/time_tracking_shared_examples.rb
index fee464c15a3..e883d33f671 100644
--- a/spec/support/api/time_tracking_shared_examples.rb
+++ b/spec/support/api/time_tracking_shared_examples.rb
@@ -7,13 +7,13 @@ shared_examples 'time tracking endpoints' do |issuable_name|
describe "POST /projects/:id/#{issuable_collection_name}/:#{issuable_name}_id/time_estimate" do
context 'with an unauthorized user' do
- subject { post(api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.iid}/time_estimate", non_member), duration: '1w') }
+ subject { post(api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.iid}/time_estimate", non_member), params: { duration: '1w' }) }
it_behaves_like 'an unauthorized API user'
end
it "sets the time estimate for #{issuable_name}" do
- post api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.iid}/time_estimate", user), duration: '1w'
+ post api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.iid}/time_estimate", user), params: { duration: '1w' }
expect(response).to have_gitlab_http_status(200)
expect(json_response['human_time_estimate']).to eq('1w')
@@ -21,12 +21,12 @@ shared_examples 'time tracking endpoints' do |issuable_name|
describe 'updating the current estimate' do
before do
- post api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.iid}/time_estimate", user), duration: '1w'
+ post api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.iid}/time_estimate", user), params: { duration: '1w' }
end
context 'when duration has a bad format' do
it 'does not modify the original estimate' do
- post api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.iid}/time_estimate", user), duration: 'foo'
+ post api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.iid}/time_estimate", user), params: { duration: 'foo' }
expect(response).to have_gitlab_http_status(400)
expect(issuable.reload.human_time_estimate).to eq('1w')
@@ -35,7 +35,7 @@ shared_examples 'time tracking endpoints' do |issuable_name|
context 'with a valid duration' do
it 'updates the estimate' do
- post api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.iid}/time_estimate", user), duration: '3w1h'
+ post api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.iid}/time_estimate", user), params: { duration: '3w1h' }
expect(response).to have_gitlab_http_status(200)
expect(issuable.reload.human_time_estimate).to eq('3w 1h')
@@ -62,8 +62,7 @@ shared_examples 'time tracking endpoints' do |issuable_name|
describe "POST /projects/:id/#{issuable_collection_name}/:#{issuable_name}_id/add_spent_time" do
context 'with an unauthorized user' do
subject do
- post api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.iid}/add_spent_time", non_member),
- duration: '2h'
+ post api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.iid}/add_spent_time", non_member), params: { duration: '2h' }
end
it_behaves_like 'an unauthorized API user'
@@ -72,8 +71,7 @@ shared_examples 'time tracking endpoints' do |issuable_name|
it "add spent time for #{issuable_name}" do
Timecop.travel(1.minute.from_now) do
expect do
- post api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.iid}/add_spent_time", user),
- duration: '2h'
+ post api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.iid}/add_spent_time", user), params: { duration: '2h' }
end.to change { issuable.reload.updated_at }
end
@@ -89,8 +87,7 @@ shared_examples 'time tracking endpoints' do |issuable_name|
end.to change { issuable.reload.updated_at }
end
- post api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.iid}/add_spent_time", user),
- duration: '-1h'
+ post api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.iid}/add_spent_time", user), params: { duration: '-1h' }
expect(response).to have_gitlab_http_status(201)
expect(json_response['total_time_spent']).to eq(3600)
@@ -103,8 +100,7 @@ shared_examples 'time tracking endpoints' do |issuable_name|
Timecop.travel(1.minute.from_now) do
expect do
- post api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.iid}/add_spent_time", user),
- duration: '-1w'
+ post api("/projects/#{project.id}/#{issuable_collection_name}/#{issuable.iid}/add_spent_time", user), params: { duration: '-1w' }
end.not_to change { issuable.reload.updated_at }
end
diff --git a/spec/support/controllers/githubish_import_controller_shared_examples.rb b/spec/support/controllers/githubish_import_controller_shared_examples.rb
index 140490f2dc2..697f999e4c4 100644
--- a/spec/support/controllers/githubish_import_controller_shared_examples.rb
+++ b/spec/support/controllers/githubish_import_controller_shared_examples.rb
@@ -17,7 +17,7 @@ shared_examples 'a GitHub-ish import controller: POST personal_access_token' do
allow_any_instance_of(Gitlab::LegacyGithubImport::Client)
.to receive(:user).and_return(true)
- post :personal_access_token, personal_access_token: token
+ post :personal_access_token, params: { personal_access_token: token }
expect(session[:"#{provider}_access_token"]).to eq(token)
expect(controller).to redirect_to(status_import_url)
@@ -29,7 +29,7 @@ shared_examples 'a GitHub-ish import controller: POST personal_access_token' do
allow_any_instance_of(Gitlab::LegacyGithubImport::Client)
.to receive(:user).and_return(true)
- post :personal_access_token, personal_access_token: " #{token} "
+ post :personal_access_token, params: { personal_access_token: " #{token} " }
expect(session[:"#{provider}_access_token"]).to eq(token)
expect(controller).to redirect_to(status_import_url)
@@ -214,7 +214,7 @@ shared_examples 'a GitHub-ish import controller: POST create' do
expect(Gitlab::LegacyGithubImport::ProjectCreator)
.to receive(:new).and_return(double(execute: project))
- expect { post :create, target_namespace: provider_repo.name, format: :json }.to change(Namespace, :count).by(1)
+ expect { post :create, params: { target_namespace: provider_repo.name }, format: :json }.to change(Namespace, :count).by(1)
end
it "takes the new namespace" do
@@ -222,7 +222,7 @@ shared_examples 'a GitHub-ish import controller: POST create' do
.to receive(:new).with(provider_repo, provider_repo.name, an_instance_of(Group), user, access_params, type: provider)
.and_return(double(execute: project))
- post :create, target_namespace: provider_repo.name, format: :json
+ post :create, params: { target_namespace: provider_repo.name }, format: :json
end
end
@@ -261,7 +261,7 @@ shared_examples 'a GitHub-ish import controller: POST create' do
.to receive(:new).with(provider_repo, test_name, test_namespace, user, access_params, type: provider)
.and_return(double(execute: project))
- post :create, { target_namespace: test_namespace.name, new_name: test_name, format: :json }
+ post :create, params: { target_namespace: test_namespace.name, new_name: test_name }, format: :json
end
it 'takes the selected name and default namespace' do
@@ -269,7 +269,7 @@ shared_examples 'a GitHub-ish import controller: POST create' do
.to receive(:new).with(provider_repo, test_name, user.namespace, user, access_params, type: provider)
.and_return(double(execute: project))
- post :create, { new_name: test_name, format: :json }
+ post :create, params: { new_name: test_name }, format: :json
end
end
@@ -288,7 +288,7 @@ shared_examples 'a GitHub-ish import controller: POST create' do
.to receive(:new).with(provider_repo, test_name, nested_namespace, user, access_params, type: provider)
.and_return(double(execute: project))
- post :create, { target_namespace: nested_namespace.full_path, new_name: test_name, format: :json }
+ post :create, params: { target_namespace: nested_namespace.full_path, new_name: test_name }, format: :json
end
end
@@ -300,7 +300,7 @@ shared_examples 'a GitHub-ish import controller: POST create' do
.to receive(:new).with(provider_repo, test_name, kind_of(Namespace), user, access_params, type: provider)
.and_return(double(execute: project))
- post :create, { target_namespace: 'foo/bar', new_name: test_name, format: :json }
+ post :create, params: { target_namespace: 'foo/bar', new_name: test_name }, format: :json
end
it 'creates the namespaces' do
@@ -308,7 +308,7 @@ shared_examples 'a GitHub-ish import controller: POST create' do
.to receive(:new).with(provider_repo, test_name, kind_of(Namespace), user, access_params, type: provider)
.and_return(double(execute: project))
- expect { post :create, { target_namespace: 'foo/bar', new_name: test_name, format: :json } }
+ expect { post :create, params: { target_namespace: 'foo/bar', new_name: test_name }, format: :json }
.to change { Namespace.count }.by(2)
end
@@ -317,7 +317,7 @@ shared_examples 'a GitHub-ish import controller: POST create' do
.to receive(:new).with(provider_repo, test_name, kind_of(Namespace), user, access_params, type: provider)
.and_return(double(execute: project))
- post :create, { target_namespace: 'foo/bar', new_name: test_name, format: :json }
+ post :create, params: { target_namespace: 'foo/bar', new_name: test_name }, format: :json
expect(Namespace.find_by_path_or_name('bar').parent.path).to eq('foo')
end
@@ -336,7 +336,7 @@ shared_examples 'a GitHub-ish import controller: POST create' do
.to receive(:new).with(provider_repo, test_name, kind_of(Namespace), user, access_params, type: provider)
.and_return(double(execute: project))
- post :create, { target_namespace: 'foo/foobar/bar', new_name: test_name, format: :json }
+ post :create, params: { target_namespace: 'foo/foobar/bar', new_name: test_name }, format: :json
end
it 'creates the namespaces' do
@@ -344,7 +344,7 @@ shared_examples 'a GitHub-ish import controller: POST create' do
.to receive(:new).with(provider_repo, test_name, kind_of(Namespace), user, access_params, type: provider)
.and_return(double(execute: project))
- expect { post :create, { target_namespace: 'foo/foobar/bar', new_name: test_name, format: :json } }
+ expect { post :create, params: { target_namespace: 'foo/foobar/bar', new_name: test_name }, format: :json }
.to change { Namespace.count }.by(2)
end
@@ -353,7 +353,7 @@ shared_examples 'a GitHub-ish import controller: POST create' do
.to receive(:new).with(provider_repo, test_name, user.namespace, user, access_params, type: provider)
.and_return(double(execute: build_stubbed(:project)))
- expect { post :create, { target_namespace: "#{user.namespace_path}/test_group", new_name: test_name, format: :js } }
+ expect { post :create, params: { target_namespace: "#{user.namespace_path}/test_group", new_name: test_name }, format: :js }
.not_to change { Namespace.count }
end
end
@@ -367,7 +367,7 @@ shared_examples 'a GitHub-ish import controller: POST create' do
.to receive(:new).with(provider_repo, test_name, user.namespace, user, access_params, type: provider)
.and_return(double(execute: build_stubbed(:project)))
- post :create, { target_namespace: 'foo/foobar/bar', new_name: test_name, format: :js }
+ post :create, params: { target_namespace: 'foo/foobar/bar', new_name: test_name }, format: :js
end
it 'does not create the namespaces' do
@@ -375,7 +375,7 @@ shared_examples 'a GitHub-ish import controller: POST create' do
.to receive(:new).with(provider_repo, test_name, kind_of(Namespace), user, access_params, type: provider)
.and_return(double(execute: build_stubbed(:project)))
- expect { post :create, { target_namespace: 'foo/foobar/bar', new_name: test_name, format: :js } }
+ expect { post :create, params: { target_namespace: 'foo/foobar/bar', new_name: test_name }, format: :js }
.not_to change { Namespace.count }
end
end
@@ -392,7 +392,7 @@ shared_examples 'a GitHub-ish import controller: POST create' do
.to receive(:new).with(provider_repo, test_name, group, user, access_params, type: provider)
.and_return(double(execute: build_stubbed(:project)))
- post :create, { target_namespace: 'foo', new_name: test_name, format: :js }
+ post :create, params: { target_namespace: 'foo', new_name: test_name }, format: :js
end
end
@@ -400,7 +400,7 @@ shared_examples 'a GitHub-ish import controller: POST create' do
it 'returns 422 response' do
other_namespace = create(:group, name: 'other_namespace')
- post :create, { target_namespace: other_namespace.name, format: :json }
+ post :create, params: { target_namespace: other_namespace.name }, format: :json
expect(response).to have_gitlab_http_status(422)
end
diff --git a/spec/support/features/variable_list_shared_examples.rb b/spec/support/features/variable_list_shared_examples.rb
index bce1fb01355..0a464d77cb7 100644
--- a/spec/support/features/variable_list_shared_examples.rb
+++ b/spec/support/features/variable_list_shared_examples.rb
@@ -63,6 +63,52 @@ shared_examples 'variable list' do
end
end
+ context 'defaults to the application setting' do
+ context 'application setting is true' do
+ before do
+ stub_application_setting(protected_ci_variables: true)
+
+ visit page_path
+ end
+
+ it 'defaults to protected' do
+ page.within('.js-ci-variable-list-section .js-row:last-child') do
+ find('.js-ci-variable-input-key').set('key')
+ end
+
+ values = all('.js-ci-variable-input-protected', visible: false).map(&:value)
+
+ expect(values).to eq %w(false true true)
+ end
+
+ it 'shows a message regarding the changed default' do
+ expect(page).to have_content 'Environment variables are configured by your administrator to be protected by default'
+ end
+ end
+
+ context 'application setting is false' do
+ before do
+ stub_application_setting(protected_ci_variables: false)
+
+ visit page_path
+ end
+
+ it 'defaults to unprotected' do
+ page.within('.js-ci-variable-list-section .js-row:last-child') do
+ find('.js-ci-variable-input-key').set('key')
+ end
+
+ values = all('.js-ci-variable-input-protected', visible: false).map(&:value)
+
+ expect(values).to eq %w(false false false)
+ end
+
+ it 'does not show a message regarding the default' do
+ expect(page).not_to have_content 'Environment variables are configured by your administrator to be protected by default'
+ end
+ end
+ end
+
it 'reveals and hides variables' do
page.within('.js-ci-variable-list-section') do
expect(first('.js-ci-variable-input-key').value).to eq(variable.key)
diff --git a/spec/support/gitlab_stubs/gitlab_ci.yml b/spec/support/gitlab_stubs/gitlab_ci.yml
index e55a61b2b94..f3755e52b2c 100644
--- a/spec/support/gitlab_stubs/gitlab_ci.yml
+++ b/spec/support/gitlab_stubs/gitlab_ci.yml
@@ -1,9 +1,8 @@
-image: ruby:2.1
+image: ruby:2.6
services:
- postgres
before_script:
- - gem install bundler
- bundle install
- bundle exec rake db:create
diff --git a/spec/support/helpers/fake_blob_helpers.rb b/spec/support/helpers/fake_blob_helpers.rb
index bc9686ed9cf..801ca8b7412 100644
--- a/spec/support/helpers/fake_blob_helpers.rb
+++ b/spec/support/helpers/fake_blob_helpers.rb
@@ -23,7 +23,7 @@ module FakeBlobHelpers
0
end
- def binary?
+ def binary_in_repo?
@binary
end
diff --git a/spec/support/helpers/git_http_helpers.rb b/spec/support/helpers/git_http_helpers.rb
index 9a5845af90c..cd49bb148f2 100644
--- a/spec/support/helpers/git_http_helpers.rb
+++ b/spec/support/helpers/git_http_helpers.rb
@@ -1,18 +1,18 @@
module GitHttpHelpers
def clone_get(project, options = {})
- get "/#{project}/info/refs", { service: 'git-upload-pack' }, auth_env(*options.values_at(:user, :password, :spnego_request_token))
+ get "/#{project}/info/refs", params: { service: 'git-upload-pack' }, headers: auth_env(*options.values_at(:user, :password, :spnego_request_token))
end
def clone_post(project, options = {})
- post "/#{project}/git-upload-pack", {}, auth_env(*options.values_at(:user, :password, :spnego_request_token))
+ post "/#{project}/git-upload-pack", headers: auth_env(*options.values_at(:user, :password, :spnego_request_token))
end
def push_get(project, options = {})
- get "/#{project}/info/refs", { service: 'git-receive-pack' }, auth_env(*options.values_at(:user, :password, :spnego_request_token))
+ get "/#{project}/info/refs", params: { service: 'git-receive-pack' }, headers: auth_env(*options.values_at(:user, :password, :spnego_request_token))
end
def push_post(project, options = {})
- post "/#{project}/git-receive-pack", {}, auth_env(*options.values_at(:user, :password, :spnego_request_token))
+ post "/#{project}/git-receive-pack", headers: auth_env(*options.values_at(:user, :password, :spnego_request_token))
end
def download(project, user: nil, password: nil, spnego_request_token: nil)
diff --git a/spec/support/helpers/graphql_helpers.rb b/spec/support/helpers/graphql_helpers.rb
index 75827df80dc..dd32ea3985f 100644
--- a/spec/support/helpers/graphql_helpers.rb
+++ b/spec/support/helpers/graphql_helpers.rb
@@ -107,7 +107,7 @@ module GraphqlHelpers
end
def post_graphql(query, current_user: nil, variables: nil)
- post api('/', current_user, version: 'graphql'), query: query, variables: variables
+ post api('/', current_user, version: 'graphql'), params: { query: query, variables: variables }
end
def post_graphql_mutation(mutation, current_user: nil)
diff --git a/spec/support/helpers/kubernetes_helpers.rb b/spec/support/helpers/kubernetes_helpers.rb
index 39bd305d88a..e7d97561bfc 100644
--- a/spec/support/helpers/kubernetes_helpers.rb
+++ b/spec/support/helpers/kubernetes_helpers.rb
@@ -58,6 +58,11 @@ module KubernetesHelpers
.to_return(status: [status, "Internal Server Error"])
end
+ def stub_kubeclient_get_service_account(api_url, name, namespace: 'default')
+ WebMock.stub_request(:get, api_url + "/api/v1/namespaces/#{namespace}/serviceaccounts/#{name}")
+ .to_return(kube_response({}))
+ end
+
def stub_kubeclient_get_service_account_error(api_url, name, namespace: 'default', status: 404)
WebMock.stub_request(:get, api_url + "/api/v1/namespaces/#{namespace}/serviceaccounts/#{name}")
.to_return(status: [status, "Internal Server Error"])
@@ -73,6 +78,11 @@ module KubernetesHelpers
.to_return(status: [500, "Internal Server Error"])
end
+ def stub_kubeclient_put_service_account(api_url, name, namespace: 'default')
+ WebMock.stub_request(:put, api_url + "/api/v1/namespaces/#{namespace}/serviceaccounts/#{name}")
+ .to_return(kube_response({}))
+ end
+
def stub_kubeclient_create_secret(api_url, namespace: 'default')
WebMock.stub_request(:post, api_url + "/api/v1/namespaces/#{namespace}/secrets")
.to_return(kube_response({}))
@@ -93,6 +103,11 @@ module KubernetesHelpers
.to_return(kube_response({}))
end
+ def stub_kubeclient_get_role_binding(api_url, name, namespace: 'default')
+ WebMock.stub_request(:get, api_url + "/apis/rbac.authorization.k8s.io/v1/namespaces/#{namespace}/rolebindings/#{name}")
+ .to_return(kube_response({}))
+ end
+
def stub_kubeclient_get_role_binding_error(api_url, name, namespace: 'default', status: 404)
WebMock.stub_request(:get, api_url + "/apis/rbac.authorization.k8s.io/v1/namespaces/#{namespace}/rolebindings/#{name}")
.to_return(status: [status, "Internal Server Error"])
@@ -103,6 +118,11 @@ module KubernetesHelpers
.to_return(kube_response({}))
end
+ def stub_kubeclient_put_role_binding(api_url, name, namespace: 'default')
+ WebMock.stub_request(:put, api_url + "/apis/rbac.authorization.k8s.io/v1/namespaces/#{namespace}/rolebindings/#{name}")
+ .to_return(kube_response({}))
+ end
+
def stub_kubeclient_create_namespace(api_url)
WebMock.stub_request(:post, api_url + "/api/v1/namespaces")
.to_return(kube_response({}))
diff --git a/spec/support/helpers/migrations_helpers.rb b/spec/support/helpers/migrations_helpers.rb
index 5887c3eab74..cc1a28cb264 100644
--- a/spec/support/helpers/migrations_helpers.rb
+++ b/spec/support/helpers/migrations_helpers.rb
@@ -62,6 +62,22 @@ module MigrationsHelpers
klass.reset_column_information
end
+ # In some migration tests, we're using factories to create records,
+ # however those models might be depending on a schema version which
+ # doesn't have the columns we want in application_settings.
+ # In these cases, we'll need to use the fake application settings
+ # as if we have migrations pending
+ def use_fake_application_settings
+ # We stub this way because we can't stub on
+ # `current_application_settings` due to `method_missing` is
+ # depending on current_application_settings...
+ allow(ActiveRecord::Base.connection)
+ .to receive(:active?)
+ .and_return(false)
+
+ stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false')
+ end
+
def previous_migration
migrations.each_cons(2) do |previous, migration|
break previous if migration.name == described_class.name
diff --git a/spec/support/helpers/test_env.rb b/spec/support/helpers/test_env.rb
index d52c40ff4f1..d352a7cdf1a 100644
--- a/spec/support/helpers/test_env.rb
+++ b/spec/support/helpers/test_env.rb
@@ -62,7 +62,8 @@ module TestEnv
'between-create-delete-modify-move' => '3f5f443',
'after-create-delete-modify-move' => 'ba3faa7',
'with-codeowners' => '219560e',
- 'submodule_inside_folder' => 'b491b92'
+ 'submodule_inside_folder' => 'b491b92',
+ 'png-lfs' => 'fe42f41'
}.freeze
# gitlab-test-fork is a fork of gitlab-fork, but we don't necessarily
diff --git a/spec/support/import_export/export_file_helper.rb b/spec/support/import_export/export_file_helper.rb
index a49036c3b80..ac320934f5a 100644
--- a/spec/support/import_export/export_file_helper.rb
+++ b/spec/support/import_export/export_file_helper.rb
@@ -133,6 +133,6 @@ module ExportFileHelper
end
def file_permissions(file)
- File.stat(file).mode & 0777
+ File.lstat(file).mode & 0777
end
end
diff --git a/spec/support/issuables_requiring_filter_shared_examples.rb b/spec/support/issuables_requiring_filter_shared_examples.rb
index 439ef5ed92e..71bcc82ee58 100644
--- a/spec/support/issuables_requiring_filter_shared_examples.rb
+++ b/spec/support/issuables_requiring_filter_shared_examples.rb
@@ -10,6 +10,6 @@ shared_examples 'issuables requiring filter' do |action|
it "loads issuables if at least one filter is set" do
expect_any_instance_of(described_class).to receive(:issuables_collection).and_call_original
- get action, author_id: user.id
+ get action, params: { author_id: user.id }
end
end
diff --git a/spec/support/shared_examples/controllers/uploads_actions_shared_examples.rb b/spec/support/shared_examples/controllers/uploads_actions_shared_examples.rb
index 7088fb1e5fb..59708173716 100644
--- a/spec/support/shared_examples/controllers/uploads_actions_shared_examples.rb
+++ b/spec/support/shared_examples/controllers/uploads_actions_shared_examples.rb
@@ -8,8 +8,7 @@ shared_examples 'handle uploads' do
describe "POST #create" do
context 'when a user is not authorized to upload a file' do
it 'returns 404 status' do
- post :create, params.merge(file: jpg, format: :json)
-
+ post :create, params: params.merge(file: jpg), format: :json
expect(response.status).to eq(404)
end
end
@@ -22,7 +21,7 @@ shared_examples 'handle uploads' do
context "without params['file']" do
it "returns an error" do
- post :create, params.merge(format: :json)
+ post :create, params: params, format: :json
expect(response).to have_gitlab_http_status(422)
end
@@ -30,7 +29,7 @@ shared_examples 'handle uploads' do
context 'with valid image' do
before do
- post :create, params.merge(file: jpg, format: :json)
+ post :create, params: params.merge(file: jpg), format: :json
end
it 'returns a content with original filename, new link, and correct type.' do
@@ -54,7 +53,7 @@ shared_examples 'handle uploads' do
context 'with valid non-image file' do
before do
- post :create, params.merge(file: txt, format: :json)
+ post :create, params: params.merge(file: txt), format: :json
end
it 'returns a content with original filename, new link, and correct type.' do
@@ -67,7 +66,7 @@ shared_examples 'handle uploads' do
describe "GET #show" do
let(:show_upload) do
- get :show, params.merge(secret: secret, filename: "rails_sample.jpg")
+ get :show, params: params.merge(secret: secret, filename: "rails_sample.jpg")
end
before do
diff --git a/spec/support/shared_examples/milestone_tabs_examples.rb b/spec/support/shared_examples/milestone_tabs_examples.rb
index 70b499198bf..8b757586941 100644
--- a/spec/support/shared_examples/milestone_tabs_examples.rb
+++ b/spec/support/shared_examples/milestone_tabs_examples.rb
@@ -10,7 +10,7 @@ shared_examples 'milestone tabs' do
{ namespace_id: project.namespace.to_param, project_id: project, id: milestone.iid }
end
- get path, params.merge(extra_params)
+ get path, params: params.merge(extra_params)
end
describe '#merge_requests' do
diff --git a/spec/support/shared_examples/policies/clusterable_shared_examples.rb b/spec/support/shared_examples/policies/clusterable_shared_examples.rb
new file mode 100644
index 00000000000..d99f94c76c3
--- /dev/null
+++ b/spec/support/shared_examples/policies/clusterable_shared_examples.rb
@@ -0,0 +1,37 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+shared_examples 'clusterable policies' do
+ describe '#add_cluster?' do
+ let(:current_user) { create(:user) }
+
+ subject { described_class.new(current_user, clusterable) }
+
+ context 'with a developer' do
+ before do
+ clusterable.add_developer(current_user)
+ end
+
+ it { expect_disallowed(:add_cluster) }
+ end
+
+ context 'with a maintainer' do
+ before do
+ clusterable.add_maintainer(current_user)
+ end
+
+ context 'with no clusters' do
+ it { expect_allowed(:add_cluster) }
+ end
+
+ context 'with an existing cluster' do
+ before do
+ cluster
+ end
+
+ it { expect_disallowed(:add_cluster) }
+ end
+ end
+ end
+end
diff --git a/spec/support/shared_examples/requests/api/diff_discussions.rb b/spec/support/shared_examples/requests/api/diff_discussions.rb
index 85a4bd8ca27..366c2955359 100644
--- a/spec/support/shared_examples/requests/api/diff_discussions.rb
+++ b/spec/support/shared_examples/requests/api/diff_discussions.rb
@@ -27,7 +27,8 @@ shared_examples 'diff discussions API' do |parent_type, noteable_type, id_name|
it "creates a new diff note" do
position = diff_note.position.to_h
- post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/discussions", user), body: 'hi!', position: position
+ post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/discussions", user),
+ params: { body: 'hi!', position: position }
expect(response).to have_gitlab_http_status(201)
expect(json_response['notes'].first['body']).to eq('hi!')
@@ -38,7 +39,8 @@ shared_examples 'diff discussions API' do |parent_type, noteable_type, id_name|
it "returns a 400 bad request error when position is invalid" do
position = diff_note.position.to_h.merge(new_line: '100000')
- post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/discussions", user), body: 'hi!', position: position
+ post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/discussions", user),
+ params: { body: 'hi!', position: position }
expect(response).to have_gitlab_http_status(400)
end
@@ -47,7 +49,7 @@ shared_examples 'diff discussions API' do |parent_type, noteable_type, id_name|
describe "POST /#{parent_type}/:id/#{noteable_type}/:noteable_id/discussions/:discussion_id/notes" do
it 'adds a new note to the diff discussion' do
post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/"\
- "discussions/#{diff_note.discussion_id}/notes", user), body: 'hi!'
+ "discussions/#{diff_note.discussion_id}/notes", user), params: { body: 'hi!' }
expect(response).to have_gitlab_http_status(201)
expect(json_response['body']).to eq('hi!')
diff --git a/spec/support/shared_examples/requests/api/discussions.rb b/spec/support/shared_examples/requests/api/discussions.rb
index b6aeb30d69c..e44da4faa5a 100644
--- a/spec/support/shared_examples/requests/api/discussions.rb
+++ b/spec/support/shared_examples/requests/api/discussions.rb
@@ -42,7 +42,7 @@ shared_examples 'discussions API' do |parent_type, noteable_type, id_name|
describe "POST /#{parent_type}/:id/#{noteable_type}/:noteable_id/discussions" do
it "creates a new note" do
- post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/discussions", user), body: 'hi!'
+ post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/discussions", user), params: { body: 'hi!' }
expect(response).to have_gitlab_http_status(201)
expect(json_response['notes'].first['body']).to eq('hi!')
@@ -56,7 +56,7 @@ shared_examples 'discussions API' do |parent_type, noteable_type, id_name|
end
it "returns a 401 unauthorized error if user not authenticated" do
- post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/discussions"), body: 'hi!'
+ post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/discussions"), params: { body: 'hi!' }
expect(response).to have_gitlab_http_status(401)
end
@@ -65,7 +65,7 @@ shared_examples 'discussions API' do |parent_type, noteable_type, id_name|
it 'accepts the creation date to be set' do
creation_time = 2.weeks.ago
post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/discussions", user),
- body: 'hi!', created_at: creation_time
+ params: { body: 'hi!', created_at: creation_time }
expect(response).to have_gitlab_http_status(201)
expect(json_response['notes'].first['body']).to eq('hi!')
@@ -81,7 +81,7 @@ shared_examples 'discussions API' do |parent_type, noteable_type, id_name|
it 'responds with 404' do
post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/discussions", private_user),
- body: 'Foo'
+ params: { body: 'Foo' }
expect(response).to have_gitlab_http_status(404)
end
@@ -91,7 +91,7 @@ shared_examples 'discussions API' do |parent_type, noteable_type, id_name|
describe "POST /#{parent_type}/:id/#{noteable_type}/:noteable_id/discussions/:discussion_id/notes" do
it 'adds a new note to the discussion' do
post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/"\
- "discussions/#{note.discussion_id}/notes", user), body: 'Hello!'
+ "discussions/#{note.discussion_id}/notes", user), params: { body: 'Hello!' }
expect(response).to have_gitlab_http_status(201)
expect(json_response['body']).to eq('Hello!')
@@ -109,7 +109,7 @@ shared_examples 'discussions API' do |parent_type, noteable_type, id_name|
note.update_attribute(:type, nil)
post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/"\
- "discussions/#{note.discussion_id}/notes", user), body: 'hi!'
+ "discussions/#{note.discussion_id}/notes", user), params: { body: 'hi!' }
expect(response).to have_gitlab_http_status(400)
end
@@ -118,7 +118,7 @@ shared_examples 'discussions API' do |parent_type, noteable_type, id_name|
describe "PUT /#{parent_type}/:id/#{noteable_type}/:noteable_id/discussions/:discussion_id/notes/:note_id" do
it 'returns modified note' do
put api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/"\
- "discussions/#{note.discussion_id}/notes/#{note.id}", user), body: 'Hello!'
+ "discussions/#{note.discussion_id}/notes/#{note.id}", user), params: { body: 'Hello!' }
expect(response).to have_gitlab_http_status(200)
expect(json_response['body']).to eq('Hello!')
@@ -127,7 +127,7 @@ shared_examples 'discussions API' do |parent_type, noteable_type, id_name|
it 'returns a 404 error when note id not found' do
put api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/"\
"discussions/#{note.discussion_id}/notes/12345", user),
- body: 'Hello!'
+ params: { body: 'Hello!' }
expect(response).to have_gitlab_http_status(404)
end
diff --git a/spec/support/shared_examples/requests/api/merge_requests_list.rb b/spec/support/shared_examples/requests/api/merge_requests_list.rb
index 92d4dd598d5..453f42251c8 100644
--- a/spec/support/shared_examples/requests/api/merge_requests_list.rb
+++ b/spec/support/shared_examples/requests/api/merge_requests_list.rb
@@ -123,7 +123,7 @@ shared_examples 'merge requests list' do
end
it 'returns an empty array if no issue matches milestone' do
- get api(endpoint_path, user), milestone: '1.0.0'
+ get api(endpoint_path, user), params: { milestone: '1.0.0' }
expect(response).to have_gitlab_http_status(200)
expect(json_response).to be_an Array
@@ -131,7 +131,7 @@ shared_examples 'merge requests list' do
end
it 'returns an empty array if milestone does not exist' do
- get api(endpoint_path, user), milestone: 'foo'
+ get api(endpoint_path, user), params: { milestone: 'foo' }
expect(response).to have_gitlab_http_status(200)
expect(json_response).to be_an Array
@@ -139,7 +139,7 @@ shared_examples 'merge requests list' do
end
it 'returns an array of merge requests in given milestone' do
- get api(endpoint_path, user), milestone: '0.9'
+ get api(endpoint_path, user), params: { milestone: '0.9' }
closed_issues = json_response.select { |mr| mr['id'] == merge_request_closed.id }
expect(closed_issues.length).to eq(1)
@@ -147,7 +147,7 @@ shared_examples 'merge requests list' do
end
it 'returns an array of merge requests matching state in milestone' do
- get api(endpoint_path, user), milestone: '0.9', state: 'closed'
+ get api(endpoint_path, user), params: { milestone: '0.9', state: 'closed' }
expect(response).to have_gitlab_http_status(200)
expect(json_response).to be_an Array
@@ -187,7 +187,7 @@ shared_examples 'merge requests list' do
end
it 'returns an array of merge requests with any label when filtering by any label' do
- get api(endpoint_path, user), labels: IssuesFinder::FILTER_ANY
+ get api(endpoint_path, user), params: { labels: IssuesFinder::FILTER_ANY }
expect_paginated_array_response
expect(json_response.length).to eq(1)
@@ -195,7 +195,7 @@ shared_examples 'merge requests list' do
end
it 'returns an array of merge requests without a label when filtering by no label' do
- get api(endpoint_path, user), labels: IssuesFinder::FILTER_NONE
+ get api(endpoint_path, user), params: { labels: IssuesFinder::FILTER_NONE }
response_ids = json_response.map { |merge_request| merge_request['id'] }
@@ -286,7 +286,7 @@ shared_examples 'merge requests list' do
context 'source_branch param' do
it 'returns merge requests with the given source branch' do
- get api(endpoint_path, user), source_branch: merge_request_closed.source_branch, state: 'all'
+ get api(endpoint_path, user), params: { source_branch: merge_request_closed.source_branch, state: 'all' }
expect_response_contain_exactly(merge_request_closed, merge_request_merged, merge_request_locked)
end
@@ -294,7 +294,7 @@ shared_examples 'merge requests list' do
context 'target_branch param' do
it 'returns merge requests with the given target branch' do
- get api(endpoint_path, user), target_branch: merge_request_closed.target_branch, state: 'all'
+ get api(endpoint_path, user), params: { target_branch: merge_request_closed.target_branch, state: 'all' }
expect_response_contain_exactly(merge_request_closed, merge_request_merged, merge_request_locked)
end
diff --git a/spec/support/shared_examples/requests/api/notes.rb b/spec/support/shared_examples/requests/api/notes.rb
index 0e20dfe0725..71499e85654 100644
--- a/spec/support/shared_examples/requests/api/notes.rb
+++ b/spec/support/shared_examples/requests/api/notes.rb
@@ -86,7 +86,7 @@ shared_examples 'noteable API' do |parent_type, noteable_type, id_name|
describe "POST /#{parent_type}/:id/#{noteable_type}/:noteable_id/notes" do
it "creates a new note" do
- post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", user), body: 'hi!'
+ post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", user), params: { body: 'hi!' }
expect(response).to have_gitlab_http_status(201)
expect(json_response['body']).to eq('hi!')
@@ -100,7 +100,7 @@ shared_examples 'noteable API' do |parent_type, noteable_type, id_name|
end
it "returns a 401 unauthorized error if user not authenticated" do
- post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes"), body: 'hi!'
+ post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes"), params: { body: 'hi!' }
expect(response).to have_gitlab_http_status(401)
end
@@ -108,7 +108,7 @@ shared_examples 'noteable API' do |parent_type, noteable_type, id_name|
it "creates an activity event when a note is created" do
expect(Event).to receive(:create!)
- post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", user), body: 'hi!'
+ post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", user), params: { body: 'hi!' }
end
context 'setting created_at' do
@@ -118,7 +118,7 @@ shared_examples 'noteable API' do |parent_type, noteable_type, id_name|
context 'by an admin' do
it 'sets the creation time on the new note' do
admin = create(:admin)
- post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", admin), params
+ post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", admin), params: params
expect(response).to have_gitlab_http_status(201)
expect(json_response['body']).to eq('hi!')
@@ -131,7 +131,7 @@ shared_examples 'noteable API' do |parent_type, noteable_type, id_name|
if parent_type == 'projects'
context 'by a project owner' do
it 'sets the creation time on the new note' do
- post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", user), params
+ post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", user), params: params
expect(response).to have_gitlab_http_status(201)
expect(json_response['body']).to eq('hi!')
@@ -149,7 +149,7 @@ shared_examples 'noteable API' do |parent_type, noteable_type, id_name|
parent.update!(namespace: group)
user2.refresh_authorized_projects
- post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", user2), params
+ post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", user2), params: params
expect(response).to have_gitlab_http_status(201)
expect(json_response['body']).to eq('hi!')
@@ -161,7 +161,7 @@ shared_examples 'noteable API' do |parent_type, noteable_type, id_name|
elsif parent_type == 'groups'
context 'by a group owner' do
it 'sets the creation time on the new note' do
- post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", user), params
+ post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", user), params: params
expect(response).to have_gitlab_http_status(201)
expect(json_response['body']).to eq('hi!')
@@ -176,7 +176,7 @@ shared_examples 'noteable API' do |parent_type, noteable_type, id_name|
it 'ignores the given creation time' do
user2 = create(:user)
parent.add_developer(user2)
- post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", user2), params
+ post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", user2), params: params
expect(response).to have_gitlab_http_status(201)
expect(json_response['body']).to eq('hi!')
@@ -190,7 +190,7 @@ shared_examples 'noteable API' do |parent_type, noteable_type, id_name|
context 'when the user is posting an award emoji on a noteable created by someone else' do
it 'creates a new note' do
parent.add_developer(private_user)
- post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", private_user), body: ':+1:'
+ post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", private_user), params: { body: ':+1:' }
expect(response).to have_gitlab_http_status(201)
expect(json_response['body']).to eq(':+1:')
@@ -199,7 +199,7 @@ shared_examples 'noteable API' do |parent_type, noteable_type, id_name|
context 'when the user is posting an award emoji on his/her own noteable' do
it 'creates a new note' do
- post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", user), body: ':+1:'
+ post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", user), params: { body: ':+1:' }
expect(response).to have_gitlab_http_status(201)
expect(json_response['body']).to eq(':+1:')
@@ -213,7 +213,7 @@ shared_examples 'noteable API' do |parent_type, noteable_type, id_name|
it 'responds with 404' do
post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", private_user),
- body: 'Foo'
+ params: { body: 'Foo' }
expect(response).to have_gitlab_http_status(404)
end
@@ -223,7 +223,7 @@ shared_examples 'noteable API' do |parent_type, noteable_type, id_name|
describe "PUT /#{parent_type}/:id/#{noteable_type}/:noteable_id/notes/:note_id" do
it 'returns modified note' do
put api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/"\
- "notes/#{note.id}", user), body: 'Hello!'
+ "notes/#{note.id}", user), params: { body: 'Hello!' }
expect(response).to have_gitlab_http_status(200)
expect(json_response['body']).to eq('Hello!')
@@ -231,7 +231,7 @@ shared_examples 'noteable API' do |parent_type, noteable_type, id_name|
it 'returns a 404 error when note id not found' do
put api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes/12345", user),
- body: 'Hello!'
+ params: { body: 'Hello!' }
expect(response).to have_gitlab_http_status(404)
end
diff --git a/spec/support/shared_examples/requests/api/resolvable_discussions.rb b/spec/support/shared_examples/requests/api/resolvable_discussions.rb
index 408ad08cc48..7e2416b23f3 100644
--- a/spec/support/shared_examples/requests/api/resolvable_discussions.rb
+++ b/spec/support/shared_examples/requests/api/resolvable_discussions.rb
@@ -2,7 +2,7 @@ shared_examples 'resolvable discussions API' do |parent_type, noteable_type, id_
describe "PUT /#{parent_type}/:id/#{noteable_type}/:noteable_id/discussions/:discussion_id" do
it "resolves discussion if resolved is true" do
put api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/"\
- "discussions/#{note.discussion_id}", user), resolved: true
+ "discussions/#{note.discussion_id}", user), params: { resolved: true }
expect(response).to have_gitlab_http_status(200)
expect(json_response['notes'].size).to eq(1)
@@ -11,7 +11,7 @@ shared_examples 'resolvable discussions API' do |parent_type, noteable_type, id_
it "unresolves discussion if resolved is false" do
put api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/"\
- "discussions/#{note.discussion_id}", user), resolved: false
+ "discussions/#{note.discussion_id}", user), params: { resolved: false }
expect(response).to have_gitlab_http_status(200)
expect(json_response['notes'].size).to eq(1)
@@ -27,14 +27,14 @@ shared_examples 'resolvable discussions API' do |parent_type, noteable_type, id_
it "returns a 401 unauthorized error if user is not authenticated" do
put api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/"\
- "discussions/#{note.discussion_id}"), resolved: true
+ "discussions/#{note.discussion_id}"), params: { resolved: true }
expect(response).to have_gitlab_http_status(401)
end
it "returns a 403 error if user resolves discussion of someone else" do
put api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/"\
- "discussions/#{note.discussion_id}", private_user), resolved: true
+ "discussions/#{note.discussion_id}", private_user), params: { resolved: true }
expect(response).to have_gitlab_http_status(403)
end
@@ -46,7 +46,7 @@ shared_examples 'resolvable discussions API' do |parent_type, noteable_type, id_
it 'responds with 404' do
put api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/"\
- "discussions/#{note.discussion_id}", private_user), resolved: true
+ "discussions/#{note.discussion_id}", private_user), params: { resolved: true }
expect(response).to have_gitlab_http_status(404)
end
@@ -56,7 +56,7 @@ shared_examples 'resolvable discussions API' do |parent_type, noteable_type, id_
describe "PUT /#{parent_type}/:id/#{noteable_type}/:noteable_id/discussions/:discussion_id/notes/:note_id" do
it 'returns resolved note when resolved parameter is true' do
put api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/"\
- "discussions/#{note.discussion_id}/notes/#{note.id}", user), resolved: true
+ "discussions/#{note.discussion_id}/notes/#{note.id}", user), params: { resolved: true }
expect(response).to have_gitlab_http_status(200)
expect(json_response['resolved']).to eq(true)
@@ -65,7 +65,7 @@ shared_examples 'resolvable discussions API' do |parent_type, noteable_type, id_
it 'returns a 404 error when note id not found' do
put api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/"\
"discussions/#{note.discussion_id}/notes/12345", user),
- body: 'Hello!'
+ params: { body: 'Hello!' }
expect(response).to have_gitlab_http_status(404)
end
@@ -79,7 +79,7 @@ shared_examples 'resolvable discussions API' do |parent_type, noteable_type, id_
it "returns a 403 error if user resolves note of someone else" do
put api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/"\
- "discussions/#{note.discussion_id}/notes/#{note.id}", private_user), resolved: true
+ "discussions/#{note.discussion_id}/notes/#{note.id}", private_user), params: { resolved: true }
expect(response).to have_gitlab_http_status(403)
end
diff --git a/spec/uploaders/file_uploader_spec.rb b/spec/uploaders/file_uploader_spec.rb
index c74e0bf1955..db9e5eb2ad6 100644
--- a/spec/uploaders/file_uploader_spec.rb
+++ b/spec/uploaders/file_uploader_spec.rb
@@ -201,7 +201,7 @@ describe FileUploader do
end
let!(:fog_file) do
- fog_connection.directories.get('uploads').files.create(
+ fog_connection.directories.new(key: 'uploads').files.create(
key: 'tmp/uploads/test/123123',
body: 'content'
)
diff --git a/spec/uploaders/object_storage_spec.rb b/spec/uploaders/object_storage_spec.rb
index 7e673681c31..533e9d87ea6 100644
--- a/spec/uploaders/object_storage_spec.rb
+++ b/spec/uploaders/object_storage_spec.rb
@@ -716,7 +716,7 @@ describe ObjectStorage do
end
let!(:fog_file) do
- fog_connection.directories.get('uploads').files.create(
+ fog_connection.directories.new(key: 'uploads').files.create(
key: 'tmp/uploads/test/123123',
body: 'content'
)
diff --git a/spec/views/notify/changed_milestone_email.html.haml_spec.rb b/spec/views/notify/changed_milestone_email.html.haml_spec.rb
new file mode 100644
index 00000000000..194b58840a3
--- /dev/null
+++ b/spec/views/notify/changed_milestone_email.html.haml_spec.rb
@@ -0,0 +1,35 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe 'notify/changed_milestone_email.html.haml' do
+ let(:milestone) { create(:milestone, title: 'some-milestone') }
+ let(:milestone_link) { milestone_url(milestone) }
+
+ before do
+ assign(:milestone, milestone)
+ assign(:milestone_url, milestone_link)
+ end
+
+ context 'milestone without start and due dates' do
+ it 'renders without date range' do
+ render
+
+ expect(rendered).to have_content('Milestone changed to some-milestone', exact: true)
+ expect(rendered).to have_link('some-milestone', href: milestone_link)
+ end
+ end
+
+ context 'milestone with start and due dates' do
+ before do
+ milestone.update(start_date: '2018-01-01', due_date: '2018-12-31')
+ end
+
+ it 'renders with date range' do
+ render
+
+ expect(rendered).to have_content('Milestone changed to some-milestone (Jan 1, 2018–Dec 31, 2018)', exact: true)
+ expect(rendered).to have_link('some-milestone', href: milestone_link)
+ end
+ end
+end
diff --git a/spec/views/projects/merge_requests/show.html.haml_spec.rb b/spec/views/projects/merge_requests/show.html.haml_spec.rb
index fa6c4ce4ac8..b0042be339c 100644
--- a/spec/views/projects/merge_requests/show.html.haml_spec.rb
+++ b/spec/views/projects/merge_requests/show.html.haml_spec.rb
@@ -32,6 +32,11 @@ describe 'projects/merge_requests/show.html.haml' do
assign(:noteable, closed_merge_request)
assign(:notes, [])
assign(:pipelines, Ci::Pipeline.none)
+ assign(
+ :issuable_sidebar,
+ MergeRequestSerializer.new(current_user: user, project: project)
+ .represent(closed_merge_request, serializer: 'sidebar')
+ )
preload_view_requirements
diff --git a/spec/workers/cluster_platform_configure_worker_spec.rb b/spec/workers/cluster_configure_worker_spec.rb
index 0eead0ab13d..6918ee3d7d8 100644
--- a/spec/workers/cluster_platform_configure_worker_spec.rb
+++ b/spec/workers/cluster_configure_worker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe ClusterPlatformConfigureWorker, '#perform' do
+describe ClusterConfigureWorker, '#perform' do
let(:worker) { described_class.new }
context 'when group cluster' do
diff --git a/spec/workers/cluster_provision_worker_spec.rb b/spec/workers/cluster_provision_worker_spec.rb
index 0a2dfef36a4..da32f29fec0 100644
--- a/spec/workers/cluster_provision_worker_spec.rb
+++ b/spec/workers/cluster_provision_worker_spec.rb
@@ -23,7 +23,7 @@ describe ClusterProvisionWorker do
end
it 'configures kubernetes platform' do
- expect(ClusterPlatformConfigureWorker).to receive(:perform_async).with(cluster.id)
+ expect(ClusterConfigureWorker).to receive(:perform_async).with(cluster.id)
described_class.new.perform(cluster.id)
end
@@ -32,7 +32,7 @@ describe ClusterProvisionWorker do
context 'when cluster does not exist' do
it 'does not provision a cluster' do
expect_any_instance_of(Clusters::Gcp::ProvisionService).not_to receive(:execute)
- expect(ClusterPlatformConfigureWorker).not_to receive(:perform_async)
+ expect(ClusterConfigureWorker).not_to receive(:perform_async)
described_class.new.perform(123)
end
diff --git a/spec/workers/mail_scheduler/notification_service_worker_spec.rb b/spec/workers/mail_scheduler/notification_service_worker_spec.rb
index f725c8763a0..1033557ee88 100644
--- a/spec/workers/mail_scheduler/notification_service_worker_spec.rb
+++ b/spec/workers/mail_scheduler/notification_service_worker_spec.rb
@@ -17,10 +17,21 @@ describe MailScheduler::NotificationServiceWorker do
end
context 'when the arguments cannot be deserialized' do
- it 'does nothing' do
- expect(worker.notification_service).not_to receive(method)
+ context 'when the arguments are not deserializeable' do
+ it 'raises exception' do
+ expect(worker.notification_service).not_to receive(method)
+ expect { worker.perform(method, key.to_global_id.to_s.succ) }.to raise_exception(ArgumentError)
+ end
+ end
+
+ context 'when the arguments are deserializeable' do
+ it 'does nothing' do
+ serialized_arguments = *serialize(key)
+ key.destroy!
- worker.perform(method, key.to_global_id.to_s.succ)
+ expect(worker.notification_service).not_to receive(method)
+ expect { worker.perform(method, serialized_arguments) }.not_to raise_exception
+ end
end
end
diff --git a/yarn.lock b/yarn.lock
index 2ff5a59d769..90d3d6fb7cb 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -641,10 +641,10 @@
resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-1.43.0.tgz#28dee2122d068cd3b925cd9884d97465ebaca12d"
integrity sha512-wuN3NITmyBV9bOXsFfAjtndFrjTlH6Kf3+6aqT5kHKKLe/B4w7uTU1L9H/cyR0wGD7HbOh584a05eDcuH04fPA==
-"@gitlab/ui@^1.16.0":
- version "1.16.2"
- resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-1.16.2.tgz#fecba9f9198db9fa82e922d3c7fe11dd81e3e9a3"
- integrity sha512-8m11f9ZQaQZyxmJ6YlgRp0wh94CY95L+Dz5nDFKakwgJA6U5XxQutL1Szip/SCq7u47MXkvQpo5kUQwoAz7K2Q==
+"@gitlab/ui@^1.18.0":
+ version "1.18.0"
+ resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-1.18.0.tgz#5cc591b2c7958e59fa7b1b443d4235e0e8f956c9"
+ integrity sha512-JqmiRSGYmK0DbGBQJBpjeRrcgjK25rCqG6QW6/GPTVLtRjbPPZYGvVg5PyA6nJUGAnwFoeApUZVML6X3OpnV1Q==
dependencies:
babel-standalone "^6.26.0"
bootstrap-vue "^2.0.0-rc.11"